commet
Version:
Commet SDK for Node.js
488 lines (479 loc) • 14.8 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Commet: () => Commet,
CommetAPIError: () => CommetAPIError,
CommetError: () => CommetError,
CommetValidationError: () => CommetValidationError,
default: () => index_default,
detectEnvironment: () => detectEnvironment,
isDevelopment: () => isDevelopment,
isProduction: () => isProduction
});
module.exports = __toCommonJS(index_exports);
// src/resources/customers.ts
var CustomersResource = class {
constructor(httpClient) {
this.httpClient = httpClient;
}
async create(params, options) {
return this.httpClient.post("/customers", params, options);
}
async retrieve(customerId, options) {
const params = options?.expand ? { expand: options.expand.join(",") } : void 0;
return this.httpClient.get(`/customers/${customerId}`, params);
}
async update(customerId, params, options) {
return this.httpClient.put(`/customers/${customerId}`, params, options);
}
async list(params) {
return this.httpClient.get("/customers", params);
}
/**
* Deactivate a customer (soft delete)
*/
async deactivate(customerId, options) {
return this.httpClient.put(
`/customers/${customerId}`,
{ isActive: false },
options
);
}
};
// src/resources/seats.ts
var SeatsResource = class {
constructor(httpClient) {
this.httpClient = httpClient;
}
async add(customerId, seatType, count, options) {
return this.httpClient.post(
`/customers/${customerId}/seats/${seatType}/add`,
{ count },
options
);
}
async remove(customerId, seatType, count, options) {
return this.httpClient.post(
`/customers/${customerId}/seats/${seatType}/remove`,
{ count },
options
);
}
async set(customerId, seatType, count, options) {
return this.httpClient.post(
`/customers/${customerId}/seats/${seatType}/set`,
{ count },
options
);
}
async bulkUpdate(customerId, seats, options) {
return this.httpClient.post(
`/customers/${customerId}/seats/bulk-update`,
{ seats },
options
);
}
async getBalance(customerId, seatType) {
return this.httpClient.get(
`/customers/${customerId}/seats/${seatType}/balance`
);
}
async getAllBalances(customerId) {
return this.httpClient.get(`/customers/${customerId}/seats/balances`);
}
async getHistory(customerId, seatType, params) {
const queryParams = {
...params,
customerId,
seatType
};
return this.httpClient.get(
`/customers/${customerId}/seats/history`,
queryParams
);
}
async listEvents(params) {
return this.httpClient.get("/seats/events", params);
}
};
// src/resources/usage.ts
var UsageEventsResource = class {
constructor(httpClient) {
this.httpClient = httpClient;
}
async create(params, options) {
const eventData = {
...params,
ts: params.timestamp || (/* @__PURE__ */ new Date()).toISOString()
};
return this.httpClient.post("/usage/events", eventData, options);
}
async createBatch(params, options) {
return this.httpClient.post("/usage/events/batch", params, options);
}
async retrieve(eventId) {
return this.httpClient.get(`/usage/events/${eventId}`);
}
async list(params) {
return this.httpClient.get("/usage/events", params);
}
async delete(eventId, options) {
return this.httpClient.delete(`/usage/events/${eventId}`, options);
}
};
var UsageMetricsResource = class {
constructor(httpClient) {
this.httpClient = httpClient;
}
async list() {
return this.httpClient.get("/usage/metrics");
}
async retrieve(metricId) {
return this.httpClient.get(`/usage/metrics/${metricId}`);
}
};
var UsageResource = class {
constructor(httpClient) {
this.events = new UsageEventsResource(httpClient);
this.metrics = new UsageMetricsResource(httpClient);
}
};
// src/utils/environment.ts
function detectEnvironment() {
try {
if (typeof process !== "undefined" && process.env?.NODE_ENV) {
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") {
return "development";
}
}
if (typeof window !== "undefined" && window.location) {
const hostname = window.location.hostname;
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname.startsWith("192.168.") || hostname.startsWith("10.") || hostname.endsWith(".local")) {
return "development";
}
}
} catch (error) {
}
return "production";
}
function isDevelopment(environment) {
return environment === "development";
}
function isProduction(environment) {
return environment === "production";
}
// src/types/common.ts
var CommetError = class extends Error {
constructor(message, code, statusCode, details) {
super(message);
this.code = code;
this.statusCode = statusCode;
this.details = details;
this.name = "CommetError";
}
};
var CommetAPIError = class extends CommetError {
constructor(message, statusCode, code, details) {
super(message, code, statusCode, details);
this.statusCode = statusCode;
this.code = code;
this.details = details;
this.name = "CommetAPIError";
}
};
var CommetValidationError = class extends CommetError {
constructor(message, validationErrors) {
super(message);
this.validationErrors = validationErrors;
this.name = "CommetValidationError";
}
};
// src/utils/http.ts
var DEFAULT_RETRY_CONFIG = {
maxRetries: 3,
baseDelay: 1e3,
// 1s
maxDelay: 8e3,
// 8s
retryableStatusCodes: [408, 429, 500, 502, 503, 504]
};
var CommetHTTPClient = class {
constructor(config, environment) {
this.config = config;
this.environment = environment;
this.retryConfig = {
...DEFAULT_RETRY_CONFIG,
maxRetries: config.retries ?? DEFAULT_RETRY_CONFIG.maxRetries
};
}
async get(endpoint, params, options) {
return this.request("GET", endpoint, void 0, options, params);
}
async post(endpoint, data, options) {
return this.request("POST", endpoint, data, options);
}
async put(endpoint, data, options) {
return this.request("PUT", endpoint, data, options);
}
async delete(endpoint, options) {
return this.request("DELETE", endpoint, void 0, options);
}
/**
* Core request method with retry logic and dev mode support
*/
async request(method, endpoint, data, options, params) {
const url = this.buildURL(endpoint, params);
if (isDevelopment(this.environment)) {
return this.logDevRequest(method, url, data);
}
return this.executeRequest(method, url, data, options);
}
/**
* Log request in development mode instead of sending to API
*/
logDevRequest(method, url, data) {
console.log("[Commet SDK] Dev mode");
console.log(`Method: ${method}`);
console.log(`Endpoint: ${url}`);
if (data) {
console.log("Data:", JSON.stringify(data, null, 2));
}
console.log("Request logged, not sent to server");
if (this.config.debug) {
console.log("Base URL:", "https://api.commet.co/api");
console.log("Debug mode enabled");
}
return Promise.resolve({
success: true,
devMode: true,
data: { id: `dev_${Date.now()}` }
});
}
/**
* Execute real API request with retry logic
*/
async executeRequest(method, url, data, options, attempt = 1) {
try {
const headers = {
"x-api-key": this.config.apiKey,
"Content-Type": "application/json",
"User-Agent": "@repo/sdk/0.1.0"
};
if (options?.idempotencyKey) {
headers["Idempotency-Key"] = options.idempotencyKey;
} else if (method === "POST" && data) {
headers["Idempotency-Key"] = this.generateIdempotencyKey();
}
const requestConfig = {
method,
headers,
signal: AbortSignal.timeout(
options?.timeout ?? this.config.timeout ?? 3e4
)
};
if (data) {
requestConfig.body = JSON.stringify(data);
}
if (this.config.debug) {
console.log(`[Commet SDK] ${method} ${url}`);
if (data) {
console.log("Request data:", JSON.stringify(data, null, 2));
}
}
const response = await fetch(url, requestConfig);
if (this.config.debug) {
console.log(
`[Commet SDK] Response status: ${response.status} ${response.statusText}`
);
}
let responseData;
let responseText;
try {
const responseClone = response.clone();
responseData = await response.json();
responseText = "";
} catch (jsonError) {
try {
responseText = await response.text();
} catch (textError) {
responseText = "Failed to read response body";
}
if (this.config.debug) {
console.log(
"[Commet SDK] Failed to parse JSON response:",
responseText
);
}
throw new CommetAPIError(
`Invalid JSON response: ${response.status} ${response.statusText}`,
response.status,
"INVALID_JSON",
{ responseText }
);
}
if (!response.ok) {
if (attempt <= this.retryConfig.maxRetries && this.retryConfig.retryableStatusCodes.includes(response.status)) {
const delay = Math.min(
this.retryConfig.baseDelay * 2 ** (attempt - 1),
this.retryConfig.maxDelay
);
if (this.config.debug) {
console.log(
`[Commet SDK] Retrying in ${delay}ms (attempt ${attempt}/${this.retryConfig.maxRetries})`
);
}
await this.sleep(delay);
return this.executeRequest(method, url, data, options, attempt + 1);
}
if (this.config.debug) {
console.log(
"[Commet SDK] Error response:",
JSON.stringify(responseData, null, 2)
);
}
const isErrorResponse = (data2) => {
return typeof data2 === "object" && data2 !== null;
};
const errorData = isErrorResponse(responseData) ? responseData : {};
if (response.status === 400 && errorData.errors) {
throw new CommetValidationError(
errorData.message || "Validation failed",
errorData.errors
);
}
throw new CommetAPIError(
errorData.message || `Request failed with status ${response.status}`,
response.status,
errorData.code,
errorData.details
);
}
if (this.config.debug) {
console.log("[Commet SDK] Response:", responseData);
}
return responseData;
} catch (error) {
if (error instanceof TypeError && error.message.includes("fetch")) {
if (attempt <= this.retryConfig.maxRetries) {
const delay = Math.min(
this.retryConfig.baseDelay * 2 ** (attempt - 1),
this.retryConfig.maxDelay
);
if (this.config.debug) {
console.log(`[Commet SDK] Network error, retrying in ${delay}ms`);
}
await this.sleep(delay);
return this.executeRequest(method, url, data, options, attempt + 1);
}
}
throw error;
}
}
/**
* Build full URL from endpoint and params
*/
buildURL(endpoint, params) {
const baseURL = "https://api.commet.co";
const fullPath = `/api${endpoint.startsWith("/") ? endpoint : `/${endpoint}`}`;
if (this.config.debug) {
console.log(
`[Commet SDK] Building URL - baseURL: ${baseURL}, endpoint: ${endpoint}, fullPath: ${fullPath}`
);
}
const url = new URL(fullPath, baseURL);
if (params) {
for (const [key, value] of Object.entries(params)) {
if (value !== void 0 && value !== null) {
url.searchParams.append(key, String(value));
}
}
}
const finalUrl = url.toString();
if (this.config.debug) {
console.log(`[Commet SDK] Final URL: ${finalUrl}`);
}
return finalUrl;
}
/**
* Generate idempotency key
*/
generateIdempotencyKey() {
return `sdk_${Date.now()}_${Math.random().toString(36).substring(2)}`;
}
/**
* Sleep for specified milliseconds
*/
sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
};
// src/client.ts
var Commet = class {
constructor(config) {
if (!config.apiKey) {
throw new Error("Commet SDK: API key is required");
}
if (!config.apiKey.startsWith("ck_")) {
throw new Error(
"Commet SDK: Invalid API key format. Expected format: ck_xxx..."
);
}
this.environment = config.environment === "auto" ? detectEnvironment() : config.environment || detectEnvironment();
this.httpClient = new CommetHTTPClient(config, this.environment);
this.customers = new CustomersResource(this.httpClient);
this.usage = new UsageResource(this.httpClient);
this.seats = new SeatsResource(this.httpClient);
if (this.environment === "development" || config.debug) {
console.log(`[Commet SDK] Initialized in ${this.environment} mode`);
if (config.debug) {
console.log("API Key:", `${config.apiKey.substring(0, 12)}...`);
console.log("Base URL:", "https://api.commet.co");
if (this.environment === "development") {
console.log(
"Dev mode: Events will be logged to console, not sent to server"
);
}
}
}
}
getEnvironment() {
return this.environment;
}
isDevelopment() {
return this.environment === "development";
}
isProduction() {
return this.environment === "production";
}
};
// src/index.ts
var index_default = Commet;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Commet,
CommetAPIError,
CommetError,
CommetValidationError,
detectEnvironment,
isDevelopment,
isProduction
});
//# sourceMappingURL=index.js.map