userplex
Version:
Simple analytics SDK for Userplex - Track events, identify users, and log conversations
132 lines (129 loc) • 3.77 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
// index.ts
var UserplexError = class extends Error {
constructor(message, statusCode, response) {
super(message);
this.statusCode = statusCode;
this.response = response;
this.name = "UserplexError";
}
};
var Userplex = class {
constructor(apiKey, options = {}) {
if (!apiKey) {
throw new Error("Userplex: API key is required");
}
if (!apiKey.startsWith("upx_")) {
throw new Error('Userplex: API key must start with "upx_"');
}
this.apiKey = apiKey;
this.baseUrl = (options.baseUrl || "https://userplex.vercel.app").replace(/\/$/, "");
this.timeout = options.timeout || 1e4;
this.debug = options.debug || false;
}
/**
* Track an event
*/
async track(userId, event, properties) {
if (!userId || !event) {
throw new Error("userId and event are required");
}
return this.request("/api/events", {
userId,
event,
properties: properties || {}
});
}
/**
* Identify a user
*/
async identify(externalId, properties) {
if (!externalId) {
throw new Error("externalId is required");
}
return this.request("/api/identify", {
externalId,
...properties
}, {
"x-api-key": this.apiKey
// identify endpoint uses this header too
});
}
/**
* Log a conversation
*/
async logConversation(options) {
if (!options.messages || options.messages.length === 0) {
throw new Error("messages array is required and cannot be empty");
}
return this.request("/api/conversations", {
externalUserId: options.userId,
conversationId: options.conversationId,
conversationName: options.conversationName,
messages: options.messages
});
}
/**
* Batch track multiple events
*/
async trackBatch(events) {
if (!events || events.length === 0) {
throw new Error("events array is required and cannot be empty");
}
const promises = events.map((e) => this.track(e.userId, e.event, e.properties));
return Promise.all(promises);
}
async request(endpoint, data, additionalHeaders) {
const url = `${this.baseUrl}${endpoint}`;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
if (this.debug) {
console.log(`[Userplex] POST ${url}`, JSON.stringify(data, null, 2));
}
try {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.apiKey}`,
...additionalHeaders
},
body: JSON.stringify(data),
signal: controller.signal
});
clearTimeout(timeoutId);
const responseData = await response.json();
if (this.debug) {
console.log(`[Userplex] Response:`, JSON.stringify(responseData, null, 2));
}
if (!response.ok) {
throw new UserplexError(
responseData.error || `Request failed with status ${response.status}`,
response.status,
responseData
);
}
return responseData;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === "AbortError") {
throw new UserplexError("Request timeout", 408);
}
if (error instanceof UserplexError) {
throw error;
}
throw new UserplexError(
error.message || "An unexpected error occurred",
void 0,
error
);
}
}
};
var index_default = Userplex;
exports.Userplex = Userplex;
exports.UserplexError = UserplexError;
exports.default = index_default;
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map
;