@tell-rs/node 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +17 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +17 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -412,8 +412,18 @@ var HttpTransport = class {
|
|
|
412
412
|
const body = logs.map((l) => JSON.stringify(l)).join("\n");
|
|
413
413
|
await this.send("/v1/logs", body);
|
|
414
414
|
}
|
|
415
|
+
resolvePort() {
|
|
416
|
+
try {
|
|
417
|
+
const u = new URL(this.endpoint);
|
|
418
|
+
if (u.port) return u.port;
|
|
419
|
+
return u.protocol === "https:" ? "443" : "80";
|
|
420
|
+
} catch {
|
|
421
|
+
return "unknown";
|
|
422
|
+
}
|
|
423
|
+
}
|
|
415
424
|
async send(path, body) {
|
|
416
425
|
const url = `${this.endpoint}${path}`;
|
|
426
|
+
const port = this.resolvePort();
|
|
417
427
|
const headers = {
|
|
418
428
|
"Content-Type": "application/x-ndjson",
|
|
419
429
|
Authorization: `Bearer ${this.apiKey}`
|
|
@@ -466,7 +476,7 @@ var HttpTransport = class {
|
|
|
466
476
|
);
|
|
467
477
|
}
|
|
468
478
|
lastError = new NetworkError(
|
|
469
|
-
`HTTP ${response.status}: ${response.statusText}`,
|
|
479
|
+
`HTTP ${response.status} from ${url} (port ${port}): ${response.statusText}`,
|
|
470
480
|
response.status
|
|
471
481
|
);
|
|
472
482
|
} catch (err) {
|
|
@@ -478,7 +488,12 @@ var HttpTransport = class {
|
|
|
478
488
|
return;
|
|
479
489
|
}
|
|
480
490
|
if (err instanceof TypeError) {
|
|
481
|
-
if (this.onError)
|
|
491
|
+
if (this.onError)
|
|
492
|
+
this.onError(
|
|
493
|
+
new NetworkError(
|
|
494
|
+
`Failed to connect to ${url} (port ${port}): ${err.message}`
|
|
495
|
+
)
|
|
496
|
+
);
|
|
482
497
|
return;
|
|
483
498
|
}
|
|
484
499
|
lastError = err instanceof Error ? err : new NetworkError(String(err));
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../../core/src/constants.ts","../../core/src/errors.ts","../../core/src/validation.ts","../../core/src/batcher.ts","../../core/src/before-send.ts","../../core/src/redact.ts","../src/transport.ts"],"sourcesContent":["import type { TellConfig } from \"./config.js\";\nimport type { JsonEvent, JsonLog, LogLevel, Properties, BeforeSendFn } from \"@tell-rs/core\";\nimport { resolveConfig } from \"./config.js\";\nimport { ClosedError, ValidationError, validateApiKey, validateEventName, validateLogMessage, validateUserId, Batcher, runBeforeSend } from \"@tell-rs/core\";\nimport { HttpTransport } from \"./transport.js\";\n\n// Re-export core types and values\nexport { Events, type EventName } from \"@tell-rs/core\";\nexport type { Properties, LogLevel, JsonEvent, JsonLog, BeforeSendFn } from \"@tell-rs/core\";\nexport { redact, redactLog, SENSITIVE_PARAMS, type RedactOptions } from \"@tell-rs/core\";\nexport { TellError, ConfigurationError, ValidationError, NetworkError, ClosedError, SerializationError } from \"@tell-rs/core\";\n\n// Re-export node-specific config\nexport type { TellConfig } from \"./config.js\";\nexport { development, production } from \"./config.js\";\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n};\n\nfunction uuid(): string {\n return crypto.randomUUID();\n}\n\nexport class Tell {\n private readonly transport: HttpTransport;\n private readonly eventBatcher: Batcher<JsonEvent>;\n private readonly logBatcher: Batcher<JsonLog>;\n private readonly deviceId: string;\n private sessionId: string;\n private readonly onError?: (error: Error) => void;\n private readonly source: string;\n private readonly closeTimeout: number;\n private readonly sdkLogLevel: number;\n private readonly beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n private readonly beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n private superProperties: Properties = {};\n private closed = false;\n private _disabled: boolean;\n\n constructor(config: TellConfig) {\n validateApiKey(config.apiKey);\n\n const resolved = resolveConfig(config);\n this.onError = resolved.onError;\n this.source = resolved.source;\n this.closeTimeout = resolved.closeTimeout;\n this.sdkLogLevel = LOG_LEVELS[resolved.logLevel] ?? 2;\n this._disabled = resolved.disabled;\n this.beforeSend = resolved.beforeSend;\n this.beforeSendLog = resolved.beforeSendLog;\n this.deviceId = uuid();\n this.sessionId = uuid();\n\n this.transport = new HttpTransport({\n endpoint: resolved.endpoint,\n apiKey: resolved.apiKey,\n maxRetries: resolved.maxRetries,\n networkTimeout: resolved.networkTimeout,\n gzip: resolved.gzip,\n onError: this.onError,\n onPayloadTooLarge: () => {\n this.eventBatcher.halveBatchSize();\n this.logBatcher.halveBatchSize();\n this.sdkDebug(\"413 received, halved batch size\");\n },\n });\n\n this.eventBatcher = new Batcher<JsonEvent>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendEvents(items),\n onOverflow: () => {\n this.sdkDebug(\"event queue overflow, dropping oldest item\");\n },\n });\n\n this.logBatcher = new Batcher<JsonLog>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendLogs(items),\n onOverflow: () => {\n this.sdkDebug(\"log queue overflow, dropping oldest item\");\n },\n });\n\n this.sdkDebug(`initialized (endpoint=${resolved.endpoint}, batch=${resolved.batchSize}, flush=${resolved.flushInterval}ms)`);\n }\n\n // --- Super Properties ---\n\n register(properties: Properties): void {\n Object.assign(this.superProperties, properties);\n }\n\n unregister(key: string): void {\n delete this.superProperties[key];\n }\n\n // --- Disabled ---\n\n disable(): void {\n this._disabled = true;\n }\n\n enable(): void {\n this._disabled = false;\n }\n\n // --- Events ---\n\n track(userId: string, eventName: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n validateEventName(eventName);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: eventName,\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n identify(userId: string, traits?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"identify\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n traits,\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n group(userId: string, groupId: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (!groupId) throw new ValidationError(\"groupId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"group\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n group_id: groupId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n revenue(\n userId: string,\n amount: number,\n currency: string,\n orderId: string,\n properties?: Properties\n ): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (amount <= 0) throw new ValidationError(\"amount\", \"must be positive\");\n if (!currency) throw new ValidationError(\"currency\", \"is required\");\n if (!orderId) throw new ValidationError(\"orderId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: \"Order Completed\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: {\n ...this.superProperties,\n ...properties,\n order_id: orderId,\n amount,\n currency,\n },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n alias(previousId: string, userId: string): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n if (!previousId) throw new ValidationError(\"previousId\", \"is required\");\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"alias\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { previous_id: previousId },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n resetSession(): void {\n this.sessionId = uuid();\n }\n\n // --- Logging ---\n\n log(level: LogLevel, message: string, service?: string, data?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateLogMessage(message);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let logEntry: JsonLog | null = {\n level,\n message,\n source: this.source,\n service: service ?? \"app\",\n session_id: this.sessionId,\n timestamp: Date.now(),\n data,\n };\n\n if (this.beforeSendLog) {\n logEntry = runBeforeSend(logEntry, this.beforeSendLog);\n if (logEntry === null) return;\n }\n\n this.logBatcher.add(logEntry);\n }\n\n logEmergency(message: string, service?: string, data?: Properties): void {\n this.log(\"emergency\", message, service, data);\n }\n logAlert(message: string, service?: string, data?: Properties): void {\n this.log(\"alert\", message, service, data);\n }\n logCritical(message: string, service?: string, data?: Properties): void {\n this.log(\"critical\", message, service, data);\n }\n logError(message: string, service?: string, data?: Properties): void {\n this.log(\"error\", message, service, data);\n }\n logWarning(message: string, service?: string, data?: Properties): void {\n this.log(\"warning\", message, service, data);\n }\n logNotice(message: string, service?: string, data?: Properties): void {\n this.log(\"notice\", message, service, data);\n }\n logInfo(message: string, service?: string, data?: Properties): void {\n this.log(\"info\", message, service, data);\n }\n logDebug(message: string, service?: string, data?: Properties): void {\n this.log(\"debug\", message, service, data);\n }\n logTrace(message: string, service?: string, data?: Properties): void {\n this.log(\"trace\", message, service, data);\n }\n\n // --- Lifecycle ---\n\n async flush(): Promise<void> {\n await Promise.all([this.eventBatcher.flush(), this.logBatcher.flush()]);\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.sdkDebug(\"closing...\");\n const work = Promise.all([this.eventBatcher.close(), this.logBatcher.close()]);\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"close timed out\")), this.closeTimeout)\n );\n try {\n await Promise.race([work, timeout]);\n } catch (err) {\n this.reportError(err);\n }\n }\n\n // --- Internal ---\n\n private reportError(err: unknown): void {\n if (this.onError && err instanceof Error) {\n this.onError(err);\n }\n }\n\n private sdkDebug(msg: string): void {\n if (this.sdkLogLevel >= LOG_LEVELS.debug) {\n console.debug(`[Tell] ${msg}`);\n }\n }\n}\n","import type { TellError } from \"@tell-rs/core\";\nimport type { BeforeSendFn } from \"@tell-rs/core\";\nimport type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { hostname } from \"node:os\";\n\nexport interface TellConfig {\n apiKey: string;\n endpoint?: string;\n batchSize?: number;\n flushInterval?: number;\n maxRetries?: number;\n closeTimeout?: number;\n networkTimeout?: number;\n logLevel?: \"error\" | \"warn\" | \"info\" | \"debug\";\n source?: string;\n onError?: (error: TellError) => void;\n disabled?: boolean;\n maxQueueSize?: number;\n gzip?: boolean;\n beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n}\n\nexport const DEFAULTS = {\n endpoint: \"https://collect.tell.app\",\n batchSize: 100,\n flushInterval: 10_000,\n maxRetries: 3,\n closeTimeout: 5_000,\n networkTimeout: 30_000,\n logLevel: \"info\" as const,\n source: hostname(),\n disabled: false,\n maxQueueSize: 1000,\n gzip: false,\n} as const;\n\nexport type ResolvedConfig = Required<\n Omit<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">\n> &\n Pick<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">;\n\nexport function resolveConfig(config: TellConfig): ResolvedConfig {\n return { ...DEFAULTS, ...config } as ResolvedConfig;\n}\n\n/** Development preset: localhost, small batches, fast flush, debug logging. */\nexport function development(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n endpoint: \"http://localhost:8080\",\n batchSize: 10,\n flushInterval: 2_000,\n logLevel: \"debug\",\n ...overrides,\n apiKey,\n };\n}\n\n/** Production preset: default endpoint, default batching, error-only logging. */\nexport function production(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n logLevel: \"error\",\n ...overrides,\n apiKey,\n };\n}\n","// Standard event names — typed constants matching the spec appendix A\n\nexport const Events = {\n // User Lifecycle\n UserSignedUp: \"User Signed Up\",\n UserSignedIn: \"User Signed In\",\n UserSignedOut: \"User Signed Out\",\n UserInvited: \"User Invited\",\n UserOnboarded: \"User Onboarded\",\n AuthenticationFailed: \"Authentication Failed\",\n PasswordReset: \"Password Reset\",\n TwoFactorEnabled: \"Two Factor Enabled\",\n TwoFactorDisabled: \"Two Factor Disabled\",\n\n // Revenue & Billing\n OrderCompleted: \"Order Completed\",\n OrderRefunded: \"Order Refunded\",\n OrderCanceled: \"Order Canceled\",\n PaymentFailed: \"Payment Failed\",\n PaymentMethodAdded: \"Payment Method Added\",\n PaymentMethodUpdated: \"Payment Method Updated\",\n PaymentMethodRemoved: \"Payment Method Removed\",\n\n // Subscription\n SubscriptionStarted: \"Subscription Started\",\n SubscriptionRenewed: \"Subscription Renewed\",\n SubscriptionPaused: \"Subscription Paused\",\n SubscriptionResumed: \"Subscription Resumed\",\n SubscriptionChanged: \"Subscription Changed\",\n SubscriptionCanceled: \"Subscription Canceled\",\n\n // Trial\n TrialStarted: \"Trial Started\",\n TrialEndingSoon: \"Trial Ending Soon\",\n TrialEnded: \"Trial Ended\",\n TrialConverted: \"Trial Converted\",\n\n // Shopping\n CartViewed: \"Cart Viewed\",\n CartUpdated: \"Cart Updated\",\n CartAbandoned: \"Cart Abandoned\",\n CheckoutStarted: \"Checkout Started\",\n CheckoutCompleted: \"Checkout Completed\",\n\n // Engagement\n PageViewed: \"Page Viewed\",\n FeatureUsed: \"Feature Used\",\n SearchPerformed: \"Search Performed\",\n FileUploaded: \"File Uploaded\",\n NotificationSent: \"Notification Sent\",\n NotificationClicked: \"Notification Clicked\",\n\n // Communication\n EmailSent: \"Email Sent\",\n EmailOpened: \"Email Opened\",\n EmailClicked: \"Email Clicked\",\n EmailBounced: \"Email Bounced\",\n EmailUnsubscribed: \"Email Unsubscribed\",\n SupportTicketCreated: \"Support Ticket Created\",\n SupportTicketResolved: \"Support Ticket Resolved\",\n} as const;\n\nexport type EventName = (typeof Events)[keyof typeof Events];\n","export class TellError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TellError\";\n }\n}\n\nexport class ConfigurationError extends TellError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class ValidationError extends TellError {\n public readonly field: string;\n\n constructor(field: string, message: string) {\n super(`${field}: ${message}`);\n this.name = \"ValidationError\";\n this.field = field;\n }\n}\n\nexport class NetworkError extends TellError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = \"NetworkError\";\n this.statusCode = statusCode;\n }\n}\n\nexport class ClosedError extends TellError {\n constructor() {\n super(\"Client is closed\");\n this.name = \"ClosedError\";\n }\n}\n\nexport class SerializationError extends TellError {\n constructor(message: string) {\n super(message);\n this.name = \"SerializationError\";\n }\n}\n","import { ConfigurationError, ValidationError } from \"./errors.js\";\n\nconst HEX_RE = /^[0-9a-fA-F]{32}$/;\nconst MAX_EVENT_NAME = 256;\nconst MAX_LOG_MESSAGE = 65_536;\n\nexport function validateApiKey(key: string): void {\n if (!key) {\n throw new ConfigurationError(\"apiKey is required\");\n }\n if (!HEX_RE.test(key)) {\n throw new ConfigurationError(\n \"apiKey must be exactly 32 hex characters\"\n );\n }\n}\n\nexport function validateEventName(name: unknown): void {\n if (typeof name !== \"string\" || name.length === 0) {\n throw new ValidationError(\"eventName\", \"must be a non-empty string\");\n }\n if (name.length > MAX_EVENT_NAME) {\n throw new ValidationError(\n \"eventName\",\n `must be at most ${MAX_EVENT_NAME} characters, got ${name.length}`\n );\n }\n}\n\nexport function validateLogMessage(message: unknown): void {\n if (typeof message !== \"string\" || message.length === 0) {\n throw new ValidationError(\"message\", \"must be a non-empty string\");\n }\n if (message.length > MAX_LOG_MESSAGE) {\n throw new ValidationError(\n \"message\",\n `must be at most ${MAX_LOG_MESSAGE} characters, got ${message.length}`\n );\n }\n}\n\nexport function validateUserId(id: unknown): void {\n if (typeof id !== \"string\" || id.length === 0) {\n throw new ValidationError(\"userId\", \"must be a non-empty string\");\n }\n}\n","export interface BatcherConfig<T> {\n size: number;\n interval: number; // ms\n maxQueueSize: number;\n send: (items: T[]) => Promise<void>;\n onOverflow?: () => void;\n}\n\nexport class Batcher<T> {\n private queue: T[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private closed = false;\n private flushing: Promise<void> | null = null;\n private config: BatcherConfig<T>;\n\n constructor(config: BatcherConfig<T>) {\n this.config = config;\n this.timer = setInterval(() => {\n if (this.queue.length > 0) {\n this.flush().catch(() => {});\n }\n }, config.interval);\n // Don't keep Node.js process alive just for flush timer\n if (this.timer && typeof (this.timer as any).unref === \"function\") {\n (this.timer as any).unref();\n }\n }\n\n add(item: T): void {\n if (this.closed) return;\n\n if (this.queue.length >= this.config.maxQueueSize) {\n this.queue.shift(); // drop oldest\n if (this.config.onOverflow) {\n this.config.onOverflow();\n }\n }\n\n this.queue.push(item);\n\n if (this.queue.length >= this.config.size) {\n this.flush().catch(() => {});\n }\n }\n\n async flush(): Promise<void> {\n // Prevent concurrent flushes\n if (this.flushing) {\n return this.flushing;\n }\n this.flushing = this.doFlush();\n try {\n await this.flushing;\n } finally {\n this.flushing = null;\n }\n }\n\n async close(): Promise<void> {\n this.closed = true;\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n drain(): T[] {\n const items = this.queue;\n this.queue = [];\n return items;\n }\n\n halveBatchSize(): void {\n this.config.size = Math.max(1, Math.floor(this.config.size / 2));\n }\n\n private async doFlush(): Promise<void> {\n while (this.queue.length > 0) {\n const batch = this.queue.slice(0, this.config.size);\n try {\n await this.config.send(batch);\n this.queue.splice(0, batch.length); // remove only on success\n } catch {\n return; // items stay in queue (e.g. 413 — batch size already halved)\n }\n }\n }\n}\n","/**\n * A function that transforms or drops an item before it is queued.\n * Return the (possibly modified) item, or null to drop it.\n */\nexport type BeforeSendFn<T> = (item: T) => T | null;\n\n/**\n * Run an item through a pipeline of beforeSend functions.\n * Returns the transformed item, or null if any function in the chain drops it.\n */\nexport function runBeforeSend<T>(\n item: T,\n fns: BeforeSendFn<T> | BeforeSendFn<T>[]\n): T | null {\n const pipeline = Array.isArray(fns) ? fns : [fns];\n let current: T | null = item;\n\n for (const fn of pipeline) {\n if (current === null) return null;\n current = fn(current);\n }\n\n return current;\n}\n","import type { BeforeSendFn } from \"./before-send.js\";\nimport type { JsonEvent, JsonLog, Properties } from \"./types.js\";\n\n/**\n * Common query-parameter names that often carry secrets or tokens.\n * Pass these (or a subset) to `stripParams` for quick sanitization.\n */\nexport const SENSITIVE_PARAMS: readonly string[] = [\n \"token\",\n \"api_key\",\n \"key\",\n \"secret\",\n \"password\",\n \"access_token\",\n \"refresh_token\",\n \"authorization\",\n] as const;\n\nexport interface RedactOptions {\n /** Query-parameter names to strip from URLs (context.url and URL-shaped property values). */\n stripParams?: string[];\n /** Property/trait keys whose values should be replaced with \"[REDACTED]\". */\n redactKeys?: string[];\n /** URL pathname prefixes — events whose context.url matches are dropped entirely. */\n dropRoutes?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction stripUrlParams(url: string, params: string[]): string {\n try {\n const u = new URL(url);\n for (const p of params) u.searchParams.delete(p);\n return u.toString();\n } catch {\n return url; // not a valid URL — leave as-is\n }\n}\n\nfunction stripParamsInProperties(\n props: Properties | undefined,\n params: string[],\n): Properties | undefined {\n if (!props) return props;\n const out: Properties = {};\n for (const [k, v] of Object.entries(props)) {\n if (typeof v === \"string\" && v.startsWith(\"http\")) {\n out[k] = stripUrlParams(v, params);\n } else {\n out[k] = v;\n }\n }\n return out;\n}\n\nfunction redactKeysInProperties(\n props: Properties | undefined,\n keys: string[],\n): Properties | undefined {\n if (!props) return props;\n const out: Properties = {};\n for (const [k, v] of Object.entries(props)) {\n out[k] = keys.includes(k) ? \"[REDACTED]\" : v;\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Factory that returns a `beforeSend` hook for events.\n *\n * - `dropRoutes` — drops events whose `context.url` pathname starts with a prefix.\n * - `stripParams` — removes query params from `context.url` and URL-shaped values\n * in `properties` and `traits`.\n * - `redactKeys` — replaces matching keys in `properties` and `traits` with `\"[REDACTED]\"`.\n *\n * The returned function never mutates the input event.\n */\nexport function redact(options: RedactOptions): BeforeSendFn<JsonEvent> {\n const { stripParams, redactKeys, dropRoutes } = options;\n\n return (event: JsonEvent): JsonEvent | null => {\n // --- dropRoutes ---\n if (dropRoutes && dropRoutes.length > 0 && event.context?.url) {\n try {\n const pathname = new URL(String(event.context.url)).pathname;\n for (const prefix of dropRoutes) {\n if (pathname.startsWith(prefix)) return null;\n }\n } catch {\n // not a valid URL — skip drop check\n }\n }\n\n let ctx = event.context;\n let props = event.properties;\n let traits = event.traits;\n\n // --- stripParams ---\n if (stripParams && stripParams.length > 0) {\n if (ctx?.url && typeof ctx.url === \"string\") {\n ctx = { ...ctx, url: stripUrlParams(ctx.url, stripParams) };\n }\n props = stripParamsInProperties(props, stripParams);\n traits = stripParamsInProperties(traits, stripParams);\n }\n\n // --- redactKeys ---\n if (redactKeys && redactKeys.length > 0) {\n props = redactKeysInProperties(props, redactKeys);\n traits = redactKeysInProperties(traits, redactKeys);\n }\n\n // Return a shallow copy if anything changed\n if (ctx !== event.context || props !== event.properties || traits !== event.traits) {\n return { ...event, context: ctx, properties: props, traits: traits };\n }\n\n return event;\n };\n}\n\n/**\n * Factory that returns a `beforeSend` hook for log entries.\n *\n * - `redactKeys` — replaces matching keys in `log.data` with `\"[REDACTED]\"`.\n *\n * The returned function never mutates the input log.\n */\nexport function redactLog(\n options: Pick<RedactOptions, \"redactKeys\">,\n): BeforeSendFn<JsonLog> {\n const { redactKeys } = options;\n\n return (log: JsonLog): JsonLog | null => {\n if (redactKeys && redactKeys.length > 0 && log.data) {\n const data = redactKeysInProperties(log.data, redactKeys);\n if (data !== log.data) {\n return { ...log, data };\n }\n }\n return log;\n };\n}\n","import type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { NetworkError } from \"@tell-rs/core\";\nimport { gzipSync } from \"node:zlib\";\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n networkTimeout: number;\n gzip: boolean;\n onError?: (error: Error) => void;\n onPayloadTooLarge?: () => void;\n}\n\nexport class HttpTransport {\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly maxRetries: number;\n private readonly networkTimeout: number;\n private readonly gzip: boolean;\n private readonly onError?: (error: Error) => void;\n private readonly onPayloadTooLarge?: () => void;\n\n constructor(config: TransportConfig) {\n this.endpoint = config.endpoint;\n this.apiKey = config.apiKey;\n this.maxRetries = config.maxRetries;\n this.networkTimeout = config.networkTimeout;\n this.gzip = config.gzip;\n this.onError = config.onError;\n this.onPayloadTooLarge = config.onPayloadTooLarge;\n }\n\n async sendEvents(events: JsonEvent[]): Promise<void> {\n if (events.length === 0) return;\n const body = events.map((e) => JSON.stringify(e)).join(\"\\n\");\n await this.send(\"/v1/events\", body);\n }\n\n async sendLogs(logs: JsonLog[]): Promise<void> {\n if (logs.length === 0) return;\n const body = logs.map((l) => JSON.stringify(l)).join(\"\\n\");\n await this.send(\"/v1/logs\", body);\n }\n\n private async send(path: string, body: string): Promise<void> {\n const url = `${this.endpoint}${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-ndjson\",\n Authorization: `Bearer ${this.apiKey}`,\n };\n\n let payload: string | Buffer = body;\n if (this.gzip) {\n payload = gzipSync(body);\n headers[\"Content-Encoding\"] = \"gzip\";\n }\n\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n await this.backoff(attempt);\n }\n\n try {\n const response = await globalThis.fetch(url, {\n method: \"POST\",\n headers,\n body: payload,\n signal: AbortSignal.timeout(this.networkTimeout),\n });\n\n if (response.status === 202) {\n return;\n }\n\n if (response.status === 207) {\n if (this.onError) {\n const data = (await response.json().catch(() => null)) as Record<string, unknown> | null;\n this.onError(\n new NetworkError(\n `Partial success: ${data?.rejected ?? \"unknown\"} items rejected`,\n 207\n )\n );\n }\n return;\n }\n\n if (response.status === 413) {\n if (this.onPayloadTooLarge) {\n this.onPayloadTooLarge();\n }\n throw new NetworkError(\"Payload too large\", 413);\n }\n\n if (response.status === 401) {\n throw new NetworkError(\"Invalid API key\", 401);\n }\n\n if (response.status >= 400 && response.status < 500) {\n throw new NetworkError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status\n );\n }\n\n lastError = new NetworkError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status\n );\n } catch (err) {\n if (err instanceof NetworkError && err.statusCode === 413) {\n throw err;\n }\n\n if (err instanceof NetworkError && err.statusCode && err.statusCode < 500) {\n if (this.onError) this.onError(err);\n return;\n }\n\n // DNS failures surface as TypeError from fetch.\n // These won't resolve by retrying — bail immediately.\n if (err instanceof TypeError) {\n if (this.onError) this.onError(new NetworkError(err.message));\n return;\n }\n\n lastError =\n err instanceof Error ? err : new NetworkError(String(err));\n }\n }\n\n if (lastError && this.onError) {\n this.onError(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const base = 1000 * Math.pow(1.5, attempt - 1);\n const jitter = base * 0.2 * Math.random();\n const delay = Math.min(base + jitter, 30_000);\n return new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGA,qBAAyB;AAoBlB,IAAM,WAAW;AAAA,EACtB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,YAAQ,yBAAS;AAAA,EACjB,UAAU;AAAA,EACV,cAAc;AAAA,EACd,MAAM;AACR;AAOO,SAAS,cAAc,QAAoC;AAChE,SAAO,EAAE,GAAG,UAAU,GAAG,OAAO;AAClC;AAGO,SAAS,YACd,QACA,WACY;AACZ,SAAO;AAAA,IACL,UAAU;AAAA,IACV,WAAW;AAAA,IACX,eAAe;AAAA,IACf,UAAU;AAAA,IACV,GAAG;AAAA,IACH;AAAA,EACF;AACF;AAGO,SAAS,WACd,QACA,WACY;AACZ,SAAO;AAAA,IACL,UAAU;AAAA,IACV,GAAG;AAAA,IACH;AAAA,EACF;AACF;;;ACrEO,IAAM,SAAS;AAAA;AAAA,EAEpB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,eAAe;AAAA,EACf,aAAa;AAAA,EACb,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,mBAAmB;AAAA;AAAA,EAGnB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,sBAAsB;AAAA;AAAA,EAGtB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA;AAAA,EAGtB,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,gBAAgB;AAAA;AAAA,EAGhB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,mBAAmB;AAAA;AAAA,EAGnB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,qBAAqB;AAAA;AAAA,EAGrB,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,uBAAuB;AACzB;;;AC5DO,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,qBAAN,cAAiC,UAAU;AAAA,EAChD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,kBAAN,cAA8B,UAAU;AAAA,EAC7B;AAAA,EAEhB,YAAY,OAAe,SAAiB;AAC1C,UAAM,GAAG,KAAK,KAAK,OAAO,EAAE;AAC5B,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AACF;AAEO,IAAM,eAAN,cAA2B,UAAU;AAAA,EAC1B;AAAA,EAEhB,YAAY,SAAiB,YAAqB;AAChD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,aAAa;AAAA,EACpB;AACF;AAEO,IAAM,cAAN,cAA0B,UAAU;AAAA,EACzC,cAAc;AACZ,UAAM,kBAAkB;AACxB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,qBAAN,cAAiC,UAAU;AAAA,EAChD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;AC5CA,IAAM,SAAS;AACf,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AAEjB,SAAS,eAAe,KAAmB;AAChD,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,mBAAmB,oBAAoB;AAAA,EACnD;AACA,MAAI,CAAC,OAAO,KAAK,GAAG,GAAG;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,kBAAkB,MAAqB;AACrD,MAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAAG;AACjD,UAAM,IAAI,gBAAgB,aAAa,4BAA4B;AAAA,EACrE;AACA,MAAI,KAAK,SAAS,gBAAgB;AAChC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,mBAAmB,cAAc,oBAAoB,KAAK,MAAM;AAAA,IAClE;AAAA,EACF;AACF;AAEO,SAAS,mBAAmB,SAAwB;AACzD,MAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG;AACvD,UAAM,IAAI,gBAAgB,WAAW,4BAA4B;AAAA,EACnE;AACA,MAAI,QAAQ,SAAS,iBAAiB;AACpC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,mBAAmB,eAAe,oBAAoB,QAAQ,MAAM;AAAA,IACtE;AAAA,EACF;AACF;AAEO,SAAS,eAAe,IAAmB;AAChD,MAAI,OAAO,OAAO,YAAY,GAAG,WAAW,GAAG;AAC7C,UAAM,IAAI,gBAAgB,UAAU,4BAA4B;AAAA,EAClE;AACF;;;ACrCO,IAAM,UAAN,MAAiB;AAAA,EACd,QAAa,CAAC;AAAA,EACd,QAA+C;AAAA,EAC/C,SAAS;AAAA,EACT,WAAiC;AAAA,EACjC;AAAA,EAER,YAAY,QAA0B;AACpC,SAAK,SAAS;AACd,SAAK,QAAQ,YAAY,MAAM;AAC7B,UAAI,KAAK,MAAM,SAAS,GAAG;AACzB,aAAK,MAAM,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAC7B;AAAA,IACF,GAAG,OAAO,QAAQ;AAElB,QAAI,KAAK,SAAS,OAAQ,KAAK,MAAc,UAAU,YAAY;AACjE,MAAC,KAAK,MAAc,MAAM;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,IAAI,MAAe;AACjB,QAAI,KAAK,OAAQ;AAEjB,QAAI,KAAK,MAAM,UAAU,KAAK,OAAO,cAAc;AACjD,WAAK,MAAM,MAAM;AACjB,UAAI,KAAK,OAAO,YAAY;AAC1B,aAAK,OAAO,WAAW;AAAA,MACzB;AAAA,IACF;AAEA,SAAK,MAAM,KAAK,IAAI;AAEpB,QAAI,KAAK,MAAM,UAAU,KAAK,OAAO,MAAM;AACzC,WAAK,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAE3B,QAAI,KAAK,UAAU;AACjB,aAAO,KAAK;AAAA,IACd;AACA,SAAK,WAAW,KAAK,QAAQ;AAC7B,QAAI;AACF,YAAM,KAAK;AAAA,IACb,UAAE;AACA,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,SAAS;AACd,QAAI,KAAK,UAAU,MAAM;AACvB,oBAAc,KAAK,KAAK;AACxB,WAAK,QAAQ;AAAA,IACf;AACA,UAAM,KAAK,MAAM;AAAA,EACnB;AAAA,EAEA,IAAI,UAAkB;AACpB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,QAAa;AACX,UAAM,QAAQ,KAAK;AACnB,SAAK,QAAQ,CAAC;AACd,WAAO;AAAA,EACT;AAAA,EAEA,iBAAuB;AACrB,SAAK,OAAO,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC;AAAA,EACjE;AAAA,EAEA,MAAc,UAAyB;AACrC,WAAO,KAAK,MAAM,SAAS,GAAG;AAC5B,YAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,KAAK,OAAO,IAAI;AAClD,UAAI;AACF,cAAM,KAAK,OAAO,KAAK,KAAK;AAC5B,aAAK,MAAM,OAAO,GAAG,MAAM,MAAM;AAAA,MACnC,QAAQ;AACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AClFO,SAAS,cACd,MACA,KACU;AACV,QAAM,WAAW,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG;AAChD,MAAI,UAAoB;AAExB,aAAW,MAAM,UAAU;AACzB,QAAI,YAAY,KAAM,QAAO;AAC7B,cAAU,GAAG,OAAO;AAAA,EACtB;AAEA,SAAO;AACT;;;AChBO,IAAM,mBAAsC;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeA,SAAS,eAAe,KAAa,QAA0B;AAC7D,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,eAAW,KAAK,OAAQ,GAAE,aAAa,OAAO,CAAC;AAC/C,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,wBACP,OACA,QACwB;AACxB,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAkB,CAAC;AACzB,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,OAAO,MAAM,YAAY,EAAE,WAAW,MAAM,GAAG;AACjD,UAAI,CAAC,IAAI,eAAe,GAAG,MAAM;AAAA,IACnC,OAAO;AACL,UAAI,CAAC,IAAI;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,uBACP,OACA,MACwB;AACxB,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAkB,CAAC;AACzB,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,eAAe;AAAA,EAC7C;AACA,SAAO;AACT;AAgBO,SAAS,OAAO,SAAiD;AACtE,QAAM,EAAE,aAAa,YAAY,WAAW,IAAI;AAEhD,SAAO,CAAC,UAAuC;AAE7C,QAAI,cAAc,WAAW,SAAS,KAAK,MAAM,SAAS,KAAK;AAC7D,UAAI;AACF,cAAM,WAAW,IAAI,IAAI,OAAO,MAAM,QAAQ,GAAG,CAAC,EAAE;AACpD,mBAAW,UAAU,YAAY;AAC/B,cAAI,SAAS,WAAW,MAAM,EAAG,QAAO;AAAA,QAC1C;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,QAAI,MAAM,MAAM;AAChB,QAAI,QAAQ,MAAM;AAClB,QAAI,SAAS,MAAM;AAGnB,QAAI,eAAe,YAAY,SAAS,GAAG;AACzC,UAAI,KAAK,OAAO,OAAO,IAAI,QAAQ,UAAU;AAC3C,cAAM,EAAE,GAAG,KAAK,KAAK,eAAe,IAAI,KAAK,WAAW,EAAE;AAAA,MAC5D;AACA,cAAQ,wBAAwB,OAAO,WAAW;AAClD,eAAS,wBAAwB,QAAQ,WAAW;AAAA,IACtD;AAGA,QAAI,cAAc,WAAW,SAAS,GAAG;AACvC,cAAQ,uBAAuB,OAAO,UAAU;AAChD,eAAS,uBAAuB,QAAQ,UAAU;AAAA,IACpD;AAGA,QAAI,QAAQ,MAAM,WAAW,UAAU,MAAM,cAAc,WAAW,MAAM,QAAQ;AAClF,aAAO,EAAE,GAAG,OAAO,SAAS,KAAK,YAAY,OAAO,OAAe;AAAA,IACrE;AAEA,WAAO;AAAA,EACT;AACF;AASO,SAAS,UACd,SACuB;AACvB,QAAM,EAAE,WAAW,IAAI;AAEvB,SAAO,CAAC,QAAiC;AACvC,QAAI,cAAc,WAAW,SAAS,KAAK,IAAI,MAAM;AACnD,YAAM,OAAO,uBAAuB,IAAI,MAAM,UAAU;AACxD,UAAI,SAAS,IAAI,MAAM;AACrB,eAAO,EAAE,GAAG,KAAK,KAAK;AAAA,MACxB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;;;AClJA,uBAAyB;AAYlB,IAAM,gBAAN,MAAoB;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,QAAyB;AACnC,SAAK,WAAW,OAAO;AACvB,SAAK,SAAS,OAAO;AACrB,SAAK,aAAa,OAAO;AACzB,SAAK,iBAAiB,OAAO;AAC7B,SAAK,OAAO,OAAO;AACnB,SAAK,UAAU,OAAO;AACtB,SAAK,oBAAoB,OAAO;AAAA,EAClC;AAAA,EAEA,MAAM,WAAW,QAAoC;AACnD,QAAI,OAAO,WAAW,EAAG;AACzB,UAAM,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,EAAE,KAAK,IAAI;AAC3D,UAAM,KAAK,KAAK,cAAc,IAAI;AAAA,EACpC;AAAA,EAEA,MAAM,SAAS,MAAgC;AAC7C,QAAI,KAAK,WAAW,EAAG;AACvB,UAAM,OAAO,KAAK,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,EAAE,KAAK,IAAI;AACzD,UAAM,KAAK,KAAK,YAAY,IAAI;AAAA,EAClC;AAAA,EAEA,MAAc,KAAK,MAAc,MAA6B;AAC5D,UAAM,MAAM,GAAG,KAAK,QAAQ,GAAG,IAAI;AACnC,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,eAAe,UAAU,KAAK,MAAM;AAAA,IACtC;AAEA,QAAI,UAA2B;AAC/B,QAAI,KAAK,MAAM;AACb,oBAAU,2BAAS,IAAI;AACvB,cAAQ,kBAAkB,IAAI;AAAA,IAChC;AAEA,QAAI;AAEJ,aAAS,UAAU,GAAG,WAAW,KAAK,YAAY,WAAW;AAC3D,UAAI,UAAU,GAAG;AACf,cAAM,KAAK,QAAQ,OAAO;AAAA,MAC5B;AAEA,UAAI;AACF,cAAM,WAAW,MAAM,WAAW,MAAM,KAAK;AAAA,UAC3C,QAAQ;AAAA,UACR;AAAA,UACA,MAAM;AAAA,UACN,QAAQ,YAAY,QAAQ,KAAK,cAAc;AAAA,QACjD,CAAC;AAED,YAAI,SAAS,WAAW,KAAK;AAC3B;AAAA,QACF;AAEA,YAAI,SAAS,WAAW,KAAK;AAC3B,cAAI,KAAK,SAAS;AAChB,kBAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,IAAI;AACpD,iBAAK;AAAA,cACH,IAAI;AAAA,gBACF,oBAAoB,MAAM,YAAY,SAAS;AAAA,gBAC/C;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACA;AAAA,QACF;AAEA,YAAI,SAAS,WAAW,KAAK;AAC3B,cAAI,KAAK,mBAAmB;AAC1B,iBAAK,kBAAkB;AAAA,UACzB;AACA,gBAAM,IAAI,aAAa,qBAAqB,GAAG;AAAA,QACjD;AAEA,YAAI,SAAS,WAAW,KAAK;AAC3B,gBAAM,IAAI,aAAa,mBAAmB,GAAG;AAAA,QAC/C;AAEA,YAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AACnD,gBAAM,IAAI;AAAA,YACR,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU;AAAA,YAC/C,SAAS;AAAA,UACX;AAAA,QACF;AAEA,oBAAY,IAAI;AAAA,UACd,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU;AAAA,UAC/C,SAAS;AAAA,QACX;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,eAAe,gBAAgB,IAAI,eAAe,KAAK;AACzD,gBAAM;AAAA,QACR;AAEA,YAAI,eAAe,gBAAgB,IAAI,cAAc,IAAI,aAAa,KAAK;AACzE,cAAI,KAAK,QAAS,MAAK,QAAQ,GAAG;AAClC;AAAA,QACF;AAIA,YAAI,eAAe,WAAW;AAC5B,cAAI,KAAK,QAAS,MAAK,QAAQ,IAAI,aAAa,IAAI,OAAO,CAAC;AAC5D;AAAA,QACF;AAEA,oBACE,eAAe,QAAQ,MAAM,IAAI,aAAa,OAAO,GAAG,CAAC;AAAA,MAC7D;AAAA,IACF;AAEA,QAAI,aAAa,KAAK,SAAS;AAC7B,WAAK,QAAQ,SAAS;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,QAAQ,SAAgC;AAC9C,UAAM,OAAO,MAAO,KAAK,IAAI,KAAK,UAAU,CAAC;AAC7C,UAAM,SAAS,OAAO,MAAM,KAAK,OAAO;AACxC,UAAM,QAAQ,KAAK,IAAI,OAAO,QAAQ,GAAM;AAC5C,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,EAC5D;AACF;;;ARjIA,IAAM,aAAqC;AAAA,EACzC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,SAAS,OAAe;AACtB,SAAO,OAAO,WAAW;AAC3B;AAEO,IAAM,OAAN,MAAW;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,kBAA8B,CAAC;AAAA,EAC/B,SAAS;AAAA,EACT;AAAA,EAER,YAAY,QAAoB;AAC9B,mBAAe,OAAO,MAAM;AAE5B,UAAM,WAAW,cAAc,MAAM;AACrC,SAAK,UAAU,SAAS;AACxB,SAAK,SAAS,SAAS;AACvB,SAAK,eAAe,SAAS;AAC7B,SAAK,cAAc,WAAW,SAAS,QAAQ,KAAK;AACpD,SAAK,YAAY,SAAS;AAC1B,SAAK,aAAa,SAAS;AAC3B,SAAK,gBAAgB,SAAS;AAC9B,SAAK,WAAW,KAAK;AACrB,SAAK,YAAY,KAAK;AAEtB,SAAK,YAAY,IAAI,cAAc;AAAA,MACjC,UAAU,SAAS;AAAA,MACnB,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,MACrB,gBAAgB,SAAS;AAAA,MACzB,MAAM,SAAS;AAAA,MACf,SAAS,KAAK;AAAA,MACd,mBAAmB,MAAM;AACvB,aAAK,aAAa,eAAe;AACjC,aAAK,WAAW,eAAe;AAC/B,aAAK,SAAS,iCAAiC;AAAA,MACjD;AAAA,IACF,CAAC;AAED,SAAK,eAAe,IAAI,QAAmB;AAAA,MACzC,MAAM,SAAS;AAAA,MACf,UAAU,SAAS;AAAA,MACnB,cAAc,SAAS;AAAA,MACvB,MAAM,CAAC,UAAU,KAAK,UAAU,WAAW,KAAK;AAAA,MAChD,YAAY,MAAM;AAChB,aAAK,SAAS,4CAA4C;AAAA,MAC5D;AAAA,IACF,CAAC;AAED,SAAK,aAAa,IAAI,QAAiB;AAAA,MACrC,MAAM,SAAS;AAAA,MACf,UAAU,SAAS;AAAA,MACnB,cAAc,SAAS;AAAA,MACvB,MAAM,CAAC,UAAU,KAAK,UAAU,SAAS,KAAK;AAAA,MAC9C,YAAY,MAAM;AAChB,aAAK,SAAS,0CAA0C;AAAA,MAC1D;AAAA,IACF,CAAC;AAED,SAAK,SAAS,yBAAyB,SAAS,QAAQ,WAAW,SAAS,SAAS,WAAW,SAAS,aAAa,KAAK;AAAA,EAC7H;AAAA;AAAA,EAIA,SAAS,YAA8B;AACrC,WAAO,OAAO,KAAK,iBAAiB,UAAU;AAAA,EAChD;AAAA,EAEA,WAAW,KAAmB;AAC5B,WAAO,KAAK,gBAAgB,GAAG;AAAA,EACjC;AAAA;AAAA,EAIA,UAAgB;AACd,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,SAAe;AACb,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA,EAIA,MAAM,QAAgB,WAAmB,YAA+B;AACtE,QAAI,KAAK,UAAW;AACpB,QAAI,KAAK,QAAQ;AAAE,WAAK,YAAY,IAAI,YAAY,CAAC;AAAG;AAAA,IAAQ;AAChE,QAAI;AACF,qBAAe,MAAM;AACrB,wBAAkB,SAAS;AAAA,IAC7B,SAAS,KAAK;AACZ,WAAK,YAAY,GAAG;AACpB;AAAA,IACF;AAEA,QAAI,QAA0B;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,MACpB,YAAY,EAAE,GAAG,KAAK,iBAAiB,GAAG,WAAW;AAAA,IACvD;AAEA,QAAI,KAAK,YAAY;AACnB,cAAQ,cAAc,OAAO,KAAK,UAAU;AAC5C,UAAI,UAAU,KAAM;AAAA,IACtB;AAEA,SAAK,aAAa,IAAI,KAAK;AAAA,EAC7B;AAAA,EAEA,SAAS,QAAgB,QAA2B;AAClD,QAAI,KAAK,UAAW;AACpB,QAAI,KAAK,QAAQ;AAAE,WAAK,YAAY,IAAI,YAAY,CAAC;AAAG;AAAA,IAAQ;AAChE,QAAI;AACF,qBAAe,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,WAAK,YAAY,GAAG;AACpB;AAAA,IACF;AAEA,QAAI,QAA0B;AAAA,MAC5B,MAAM;AAAA,MACN,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,MACpB;AAAA,IACF;AAEA,QAAI,KAAK,YAAY;AACnB,cAAQ,cAAc,OAAO,KAAK,UAAU;AAC5C,UAAI,UAAU,KAAM;AAAA,IACtB;AAEA,SAAK,aAAa,IAAI,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAM,QAAgB,SAAiB,YAA+B;AACpE,QAAI,KAAK,UAAW;AACpB,QAAI,KAAK,QAAQ;AAAE,WAAK,YAAY,IAAI,YAAY,CAAC;AAAG;AAAA,IAAQ;AAChE,QAAI;AACF,qBAAe,MAAM;AACrB,UAAI,CAAC,QAAS,OAAM,IAAI,gBAAgB,WAAW,aAAa;AAAA,IAClE,SAAS,KAAK;AACZ,WAAK,YAAY,GAAG;AACpB;AAAA,IACF;AAEA,QAAI,QAA0B;AAAA,MAC5B,MAAM;AAAA,MACN,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW,KAAK,IAAI;AAAA,MACpB,YAAY,EAAE,GAAG,KAAK,iBAAiB,GAAG,WAAW;AAAA,IACvD;AAEA,QAAI,KAAK,YAAY;AACnB,cAAQ,cAAc,OAAO,KAAK,UAAU;AAC5C,UAAI,UAAU,KAAM;AAAA,IACtB;AAEA,SAAK,aAAa,IAAI,KAAK;AAAA,EAC7B;AAAA,EAEA,QACE,QACA,QACA,UACA,SACA,YACM;AACN,QAAI,KAAK,UAAW;AACpB,QAAI,KAAK,QAAQ;AAAE,WAAK,YAAY,IAAI,YAAY,CAAC;AAAG;AAAA,IAAQ;AAChE,QAAI;AACF,qBAAe,MAAM;AACrB,UAAI,UAAU,EAAG,OAAM,IAAI,gBAAgB,UAAU,kBAAkB;AACvE,UAAI,CAAC,SAAU,OAAM,IAAI,gBAAgB,YAAY,aAAa;AAClE,UAAI,CAAC,QAAS,OAAM,IAAI,gBAAgB,WAAW,aAAa;AAAA,IAClE,SAAS,KAAK;AACZ,WAAK,YAAY,GAAG;AACpB;AAAA,IACF;AAEA,QAAI,QAA0B;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,MACpB,YAAY;AAAA,QACV,GAAG,KAAK;AAAA,QACR,GAAG;AAAA,QACH,UAAU;AAAA,QACV;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,YAAY;AACnB,cAAQ,cAAc,OAAO,KAAK,UAAU;AAC5C,UAAI,UAAU,KAAM;AAAA,IACtB;AAEA,SAAK,aAAa,IAAI,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAM,YAAoB,QAAsB;AAC9C,QAAI,KAAK,UAAW;AACpB,QAAI,KAAK,QAAQ;AAAE,WAAK,YAAY,IAAI,YAAY,CAAC;AAAG;AAAA,IAAQ;AAChE,QAAI;AACF,UAAI,CAAC,WAAY,OAAM,IAAI,gBAAgB,cAAc,aAAa;AACtE,qBAAe,MAAM;AAAA,IACvB,SAAS,KAAK;AACZ,WAAK,YAAY,GAAG;AACpB;AAAA,IACF;AAEA,QAAI,QAA0B;AAAA,MAC5B,MAAM;AAAA,MACN,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,MACpB,YAAY,EAAE,aAAa,WAAW;AAAA,IACxC;AAEA,QAAI,KAAK,YAAY;AACnB,cAAQ,cAAc,OAAO,KAAK,UAAU;AAC5C,UAAI,UAAU,KAAM;AAAA,IACtB;AAEA,SAAK,aAAa,IAAI,KAAK;AAAA,EAC7B;AAAA,EAEA,eAAqB;AACnB,SAAK,YAAY,KAAK;AAAA,EACxB;AAAA;AAAA,EAIA,IAAI,OAAiB,SAAiB,SAAkB,MAAyB;AAC/E,QAAI,KAAK,UAAW;AACpB,QAAI,KAAK,QAAQ;AAAE,WAAK,YAAY,IAAI,YAAY,CAAC;AAAG;AAAA,IAAQ;AAChE,QAAI;AACF,yBAAmB,OAAO;AAAA,IAC5B,SAAS,KAAK;AACZ,WAAK,YAAY,GAAG;AACpB;AAAA,IACF;AAEA,QAAI,WAA2B;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,QAAQ,KAAK;AAAA,MACb,SAAS,WAAW;AAAA,MACpB,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK,IAAI;AAAA,MACpB;AAAA,IACF;AAEA,QAAI,KAAK,eAAe;AACtB,iBAAW,cAAc,UAAU,KAAK,aAAa;AACrD,UAAI,aAAa,KAAM;AAAA,IACzB;AAEA,SAAK,WAAW,IAAI,QAAQ;AAAA,EAC9B;AAAA,EAEA,aAAa,SAAiB,SAAkB,MAAyB;AACvE,SAAK,IAAI,aAAa,SAAS,SAAS,IAAI;AAAA,EAC9C;AAAA,EACA,SAAS,SAAiB,SAAkB,MAAyB;AACnE,SAAK,IAAI,SAAS,SAAS,SAAS,IAAI;AAAA,EAC1C;AAAA,EACA,YAAY,SAAiB,SAAkB,MAAyB;AACtE,SAAK,IAAI,YAAY,SAAS,SAAS,IAAI;AAAA,EAC7C;AAAA,EACA,SAAS,SAAiB,SAAkB,MAAyB;AACnE,SAAK,IAAI,SAAS,SAAS,SAAS,IAAI;AAAA,EAC1C;AAAA,EACA,WAAW,SAAiB,SAAkB,MAAyB;AACrE,SAAK,IAAI,WAAW,SAAS,SAAS,IAAI;AAAA,EAC5C;AAAA,EACA,UAAU,SAAiB,SAAkB,MAAyB;AACpE,SAAK,IAAI,UAAU,SAAS,SAAS,IAAI;AAAA,EAC3C;AAAA,EACA,QAAQ,SAAiB,SAAkB,MAAyB;AAClE,SAAK,IAAI,QAAQ,SAAS,SAAS,IAAI;AAAA,EACzC;AAAA,EACA,SAAS,SAAiB,SAAkB,MAAyB;AACnE,SAAK,IAAI,SAAS,SAAS,SAAS,IAAI;AAAA,EAC1C;AAAA,EACA,SAAS,SAAiB,SAAkB,MAAyB;AACnE,SAAK,IAAI,SAAS,SAAS,SAAS,IAAI;AAAA,EAC1C;AAAA;AAAA,EAIA,MAAM,QAAuB;AAC3B,UAAM,QAAQ,IAAI,CAAC,KAAK,aAAa,MAAM,GAAG,KAAK,WAAW,MAAM,CAAC,CAAC;AAAA,EACxE;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,OAAQ;AACjB,SAAK,SAAS;AACd,SAAK,SAAS,YAAY;AAC1B,UAAM,OAAO,QAAQ,IAAI,CAAC,KAAK,aAAa,MAAM,GAAG,KAAK,WAAW,MAAM,CAAC,CAAC;AAC7E,UAAM,UAAU,IAAI;AAAA,MAAe,CAAC,GAAG,WACrC,WAAW,MAAM,OAAO,IAAI,MAAM,iBAAiB,CAAC,GAAG,KAAK,YAAY;AAAA,IAC1E;AACA,QAAI;AACF,YAAM,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC;AAAA,IACpC,SAAS,KAAK;AACZ,WAAK,YAAY,GAAG;AAAA,IACtB;AAAA,EACF;AAAA;AAAA,EAIQ,YAAY,KAAoB;AACtC,QAAI,KAAK,WAAW,eAAe,OAAO;AACxC,WAAK,QAAQ,GAAG;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ,SAAS,KAAmB;AAClC,QAAI,KAAK,eAAe,WAAW,OAAO;AACxC,cAAQ,MAAM,UAAU,GAAG,EAAE;AAAA,IAC/B;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../../core/src/constants.ts","../../core/src/errors.ts","../../core/src/validation.ts","../../core/src/batcher.ts","../../core/src/before-send.ts","../../core/src/redact.ts","../src/transport.ts"],"sourcesContent":["import type { TellConfig } from \"./config.js\";\nimport type { JsonEvent, JsonLog, LogLevel, Properties, BeforeSendFn } from \"@tell-rs/core\";\nimport { resolveConfig } from \"./config.js\";\nimport { ClosedError, ValidationError, validateApiKey, validateEventName, validateLogMessage, validateUserId, Batcher, runBeforeSend } from \"@tell-rs/core\";\nimport { HttpTransport } from \"./transport.js\";\n\n// Re-export core types and values\nexport { Events, type EventName } from \"@tell-rs/core\";\nexport type { Properties, LogLevel, JsonEvent, JsonLog, BeforeSendFn } from \"@tell-rs/core\";\nexport { redact, redactLog, SENSITIVE_PARAMS, type RedactOptions } from \"@tell-rs/core\";\nexport { TellError, ConfigurationError, ValidationError, NetworkError, ClosedError, SerializationError } from \"@tell-rs/core\";\n\n// Re-export node-specific config\nexport type { TellConfig } from \"./config.js\";\nexport { development, production } from \"./config.js\";\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n};\n\nfunction uuid(): string {\n return crypto.randomUUID();\n}\n\nexport class Tell {\n private readonly transport: HttpTransport;\n private readonly eventBatcher: Batcher<JsonEvent>;\n private readonly logBatcher: Batcher<JsonLog>;\n private readonly deviceId: string;\n private sessionId: string;\n private readonly onError?: (error: Error) => void;\n private readonly source: string;\n private readonly closeTimeout: number;\n private readonly sdkLogLevel: number;\n private readonly beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n private readonly beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n private superProperties: Properties = {};\n private closed = false;\n private _disabled: boolean;\n\n constructor(config: TellConfig) {\n validateApiKey(config.apiKey);\n\n const resolved = resolveConfig(config);\n this.onError = resolved.onError;\n this.source = resolved.source;\n this.closeTimeout = resolved.closeTimeout;\n this.sdkLogLevel = LOG_LEVELS[resolved.logLevel] ?? 2;\n this._disabled = resolved.disabled;\n this.beforeSend = resolved.beforeSend;\n this.beforeSendLog = resolved.beforeSendLog;\n this.deviceId = uuid();\n this.sessionId = uuid();\n\n this.transport = new HttpTransport({\n endpoint: resolved.endpoint,\n apiKey: resolved.apiKey,\n maxRetries: resolved.maxRetries,\n networkTimeout: resolved.networkTimeout,\n gzip: resolved.gzip,\n onError: this.onError,\n onPayloadTooLarge: () => {\n this.eventBatcher.halveBatchSize();\n this.logBatcher.halveBatchSize();\n this.sdkDebug(\"413 received, halved batch size\");\n },\n });\n\n this.eventBatcher = new Batcher<JsonEvent>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendEvents(items),\n onOverflow: () => {\n this.sdkDebug(\"event queue overflow, dropping oldest item\");\n },\n });\n\n this.logBatcher = new Batcher<JsonLog>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendLogs(items),\n onOverflow: () => {\n this.sdkDebug(\"log queue overflow, dropping oldest item\");\n },\n });\n\n this.sdkDebug(`initialized (endpoint=${resolved.endpoint}, batch=${resolved.batchSize}, flush=${resolved.flushInterval}ms)`);\n }\n\n // --- Super Properties ---\n\n register(properties: Properties): void {\n Object.assign(this.superProperties, properties);\n }\n\n unregister(key: string): void {\n delete this.superProperties[key];\n }\n\n // --- Disabled ---\n\n disable(): void {\n this._disabled = true;\n }\n\n enable(): void {\n this._disabled = false;\n }\n\n // --- Events ---\n\n track(userId: string, eventName: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n validateEventName(eventName);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: eventName,\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n identify(userId: string, traits?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"identify\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n traits,\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n group(userId: string, groupId: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (!groupId) throw new ValidationError(\"groupId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"group\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n group_id: groupId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n revenue(\n userId: string,\n amount: number,\n currency: string,\n orderId: string,\n properties?: Properties\n ): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (amount <= 0) throw new ValidationError(\"amount\", \"must be positive\");\n if (!currency) throw new ValidationError(\"currency\", \"is required\");\n if (!orderId) throw new ValidationError(\"orderId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: \"Order Completed\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: {\n ...this.superProperties,\n ...properties,\n order_id: orderId,\n amount,\n currency,\n },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n alias(previousId: string, userId: string): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n if (!previousId) throw new ValidationError(\"previousId\", \"is required\");\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"alias\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { previous_id: previousId },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n resetSession(): void {\n this.sessionId = uuid();\n }\n\n // --- Logging ---\n\n log(level: LogLevel, message: string, service?: string, data?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateLogMessage(message);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let logEntry: JsonLog | null = {\n level,\n message,\n source: this.source,\n service: service ?? \"app\",\n session_id: this.sessionId,\n timestamp: Date.now(),\n data,\n };\n\n if (this.beforeSendLog) {\n logEntry = runBeforeSend(logEntry, this.beforeSendLog);\n if (logEntry === null) return;\n }\n\n this.logBatcher.add(logEntry);\n }\n\n logEmergency(message: string, service?: string, data?: Properties): void {\n this.log(\"emergency\", message, service, data);\n }\n logAlert(message: string, service?: string, data?: Properties): void {\n this.log(\"alert\", message, service, data);\n }\n logCritical(message: string, service?: string, data?: Properties): void {\n this.log(\"critical\", message, service, data);\n }\n logError(message: string, service?: string, data?: Properties): void {\n this.log(\"error\", message, service, data);\n }\n logWarning(message: string, service?: string, data?: Properties): void {\n this.log(\"warning\", message, service, data);\n }\n logNotice(message: string, service?: string, data?: Properties): void {\n this.log(\"notice\", message, service, data);\n }\n logInfo(message: string, service?: string, data?: Properties): void {\n this.log(\"info\", message, service, data);\n }\n logDebug(message: string, service?: string, data?: Properties): void {\n this.log(\"debug\", message, service, data);\n }\n logTrace(message: string, service?: string, data?: Properties): void {\n this.log(\"trace\", message, service, data);\n }\n\n // --- Lifecycle ---\n\n async flush(): Promise<void> {\n await Promise.all([this.eventBatcher.flush(), this.logBatcher.flush()]);\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.sdkDebug(\"closing...\");\n const work = Promise.all([this.eventBatcher.close(), this.logBatcher.close()]);\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"close timed out\")), this.closeTimeout)\n );\n try {\n await Promise.race([work, timeout]);\n } catch (err) {\n this.reportError(err);\n }\n }\n\n // --- Internal ---\n\n private reportError(err: unknown): void {\n if (this.onError && err instanceof Error) {\n this.onError(err);\n }\n }\n\n private sdkDebug(msg: string): void {\n if (this.sdkLogLevel >= LOG_LEVELS.debug) {\n console.debug(`[Tell] ${msg}`);\n }\n }\n}\n","import type { TellError } from \"@tell-rs/core\";\nimport type { BeforeSendFn } from \"@tell-rs/core\";\nimport type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { hostname } from \"node:os\";\n\nexport interface TellConfig {\n apiKey: string;\n endpoint?: string;\n batchSize?: number;\n flushInterval?: number;\n maxRetries?: number;\n closeTimeout?: number;\n networkTimeout?: number;\n logLevel?: \"error\" | \"warn\" | \"info\" | \"debug\";\n source?: string;\n onError?: (error: TellError) => void;\n disabled?: boolean;\n maxQueueSize?: number;\n gzip?: boolean;\n beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n}\n\nexport const DEFAULTS = {\n endpoint: \"https://collect.tell.app\",\n batchSize: 100,\n flushInterval: 10_000,\n maxRetries: 3,\n closeTimeout: 5_000,\n networkTimeout: 30_000,\n logLevel: \"info\" as const,\n source: hostname(),\n disabled: false,\n maxQueueSize: 1000,\n gzip: false,\n} as const;\n\nexport type ResolvedConfig = Required<\n Omit<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">\n> &\n Pick<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">;\n\nexport function resolveConfig(config: TellConfig): ResolvedConfig {\n return { ...DEFAULTS, ...config } as ResolvedConfig;\n}\n\n/** Development preset: localhost, small batches, fast flush, debug logging. */\nexport function development(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n endpoint: \"http://localhost:8080\",\n batchSize: 10,\n flushInterval: 2_000,\n logLevel: \"debug\",\n ...overrides,\n apiKey,\n };\n}\n\n/** Production preset: default endpoint, default batching, error-only logging. */\nexport function production(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n logLevel: \"error\",\n ...overrides,\n apiKey,\n };\n}\n","// Standard event names — typed constants matching the spec appendix A\n\nexport const Events = {\n // User Lifecycle\n UserSignedUp: \"User Signed Up\",\n UserSignedIn: \"User Signed In\",\n UserSignedOut: \"User Signed Out\",\n UserInvited: \"User Invited\",\n UserOnboarded: \"User Onboarded\",\n AuthenticationFailed: \"Authentication Failed\",\n PasswordReset: \"Password Reset\",\n TwoFactorEnabled: \"Two Factor Enabled\",\n TwoFactorDisabled: \"Two Factor Disabled\",\n\n // Revenue & Billing\n OrderCompleted: \"Order Completed\",\n OrderRefunded: \"Order Refunded\",\n OrderCanceled: \"Order Canceled\",\n PaymentFailed: \"Payment Failed\",\n PaymentMethodAdded: \"Payment Method Added\",\n PaymentMethodUpdated: \"Payment Method Updated\",\n PaymentMethodRemoved: \"Payment Method Removed\",\n\n // Subscription\n SubscriptionStarted: \"Subscription Started\",\n SubscriptionRenewed: \"Subscription Renewed\",\n SubscriptionPaused: \"Subscription Paused\",\n SubscriptionResumed: \"Subscription Resumed\",\n SubscriptionChanged: \"Subscription Changed\",\n SubscriptionCanceled: \"Subscription Canceled\",\n\n // Trial\n TrialStarted: \"Trial Started\",\n TrialEndingSoon: \"Trial Ending Soon\",\n TrialEnded: \"Trial Ended\",\n TrialConverted: \"Trial Converted\",\n\n // Shopping\n CartViewed: \"Cart Viewed\",\n CartUpdated: \"Cart Updated\",\n CartAbandoned: \"Cart Abandoned\",\n CheckoutStarted: \"Checkout Started\",\n CheckoutCompleted: \"Checkout Completed\",\n\n // Engagement\n PageViewed: \"Page Viewed\",\n FeatureUsed: \"Feature Used\",\n SearchPerformed: \"Search Performed\",\n FileUploaded: \"File Uploaded\",\n NotificationSent: \"Notification Sent\",\n NotificationClicked: \"Notification Clicked\",\n\n // Communication\n EmailSent: \"Email Sent\",\n EmailOpened: \"Email Opened\",\n EmailClicked: \"Email Clicked\",\n EmailBounced: \"Email Bounced\",\n EmailUnsubscribed: \"Email Unsubscribed\",\n SupportTicketCreated: \"Support Ticket Created\",\n SupportTicketResolved: \"Support Ticket Resolved\",\n} as const;\n\nexport type EventName = (typeof Events)[keyof typeof Events];\n","export class TellError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TellError\";\n }\n}\n\nexport class ConfigurationError extends TellError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class ValidationError extends TellError {\n public readonly field: string;\n\n constructor(field: string, message: string) {\n super(`${field}: ${message}`);\n this.name = \"ValidationError\";\n this.field = field;\n }\n}\n\nexport class NetworkError extends TellError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = \"NetworkError\";\n this.statusCode = statusCode;\n }\n}\n\nexport class ClosedError extends TellError {\n constructor() {\n super(\"Client is closed\");\n this.name = \"ClosedError\";\n }\n}\n\nexport class SerializationError extends TellError {\n constructor(message: string) {\n super(message);\n this.name = \"SerializationError\";\n }\n}\n","import { ConfigurationError, ValidationError } from \"./errors.js\";\n\nconst HEX_RE = /^[0-9a-fA-F]{32}$/;\nconst MAX_EVENT_NAME = 256;\nconst MAX_LOG_MESSAGE = 65_536;\n\nexport function validateApiKey(key: string): void {\n if (!key) {\n throw new ConfigurationError(\"apiKey is required\");\n }\n if (!HEX_RE.test(key)) {\n throw new ConfigurationError(\n \"apiKey must be exactly 32 hex characters\"\n );\n }\n}\n\nexport function validateEventName(name: unknown): void {\n if (typeof name !== \"string\" || name.length === 0) {\n throw new ValidationError(\"eventName\", \"must be a non-empty string\");\n }\n if (name.length > MAX_EVENT_NAME) {\n throw new ValidationError(\n \"eventName\",\n `must be at most ${MAX_EVENT_NAME} characters, got ${name.length}`\n );\n }\n}\n\nexport function validateLogMessage(message: unknown): void {\n if (typeof message !== \"string\" || message.length === 0) {\n throw new ValidationError(\"message\", \"must be a non-empty string\");\n }\n if (message.length > MAX_LOG_MESSAGE) {\n throw new ValidationError(\n \"message\",\n `must be at most ${MAX_LOG_MESSAGE} characters, got ${message.length}`\n );\n }\n}\n\nexport function validateUserId(id: unknown): void {\n if (typeof id !== \"string\" || id.length === 0) {\n throw new ValidationError(\"userId\", \"must be a non-empty string\");\n }\n}\n","export interface BatcherConfig<T> {\n size: number;\n interval: number; // ms\n maxQueueSize: number;\n send: (items: T[]) => Promise<void>;\n onOverflow?: () => void;\n}\n\nexport class Batcher<T> {\n private queue: T[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private closed = false;\n private flushing: Promise<void> | null = null;\n private config: BatcherConfig<T>;\n\n constructor(config: BatcherConfig<T>) {\n this.config = config;\n this.timer = setInterval(() => {\n if (this.queue.length > 0) {\n this.flush().catch(() => {});\n }\n }, config.interval);\n // Don't keep Node.js process alive just for flush timer\n if (this.timer && typeof (this.timer as any).unref === \"function\") {\n (this.timer as any).unref();\n }\n }\n\n add(item: T): void {\n if (this.closed) return;\n\n if (this.queue.length >= this.config.maxQueueSize) {\n this.queue.shift(); // drop oldest\n if (this.config.onOverflow) {\n this.config.onOverflow();\n }\n }\n\n this.queue.push(item);\n\n if (this.queue.length >= this.config.size) {\n this.flush().catch(() => {});\n }\n }\n\n async flush(): Promise<void> {\n // Prevent concurrent flushes\n if (this.flushing) {\n return this.flushing;\n }\n this.flushing = this.doFlush();\n try {\n await this.flushing;\n } finally {\n this.flushing = null;\n }\n }\n\n async close(): Promise<void> {\n this.closed = true;\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n drain(): T[] {\n const items = this.queue;\n this.queue = [];\n return items;\n }\n\n halveBatchSize(): void {\n this.config.size = Math.max(1, Math.floor(this.config.size / 2));\n }\n\n private async doFlush(): Promise<void> {\n while (this.queue.length > 0) {\n const batch = this.queue.slice(0, this.config.size);\n try {\n await this.config.send(batch);\n this.queue.splice(0, batch.length); // remove only on success\n } catch {\n return; // items stay in queue (e.g. 413 — batch size already halved)\n }\n }\n }\n}\n","/**\n * A function that transforms or drops an item before it is queued.\n * Return the (possibly modified) item, or null to drop it.\n */\nexport type BeforeSendFn<T> = (item: T) => T | null;\n\n/**\n * Run an item through a pipeline of beforeSend functions.\n * Returns the transformed item, or null if any function in the chain drops it.\n */\nexport function runBeforeSend<T>(\n item: T,\n fns: BeforeSendFn<T> | BeforeSendFn<T>[]\n): T | null {\n const pipeline = Array.isArray(fns) ? fns : [fns];\n let current: T | null = item;\n\n for (const fn of pipeline) {\n if (current === null) return null;\n current = fn(current);\n }\n\n return current;\n}\n","import type { BeforeSendFn } from \"./before-send.js\";\nimport type { JsonEvent, JsonLog, Properties } from \"./types.js\";\n\n/**\n * Common query-parameter names that often carry secrets or tokens.\n * Pass these (or a subset) to `stripParams` for quick sanitization.\n */\nexport const SENSITIVE_PARAMS: readonly string[] = [\n \"token\",\n \"api_key\",\n \"key\",\n \"secret\",\n \"password\",\n \"access_token\",\n \"refresh_token\",\n \"authorization\",\n] as const;\n\nexport interface RedactOptions {\n /** Query-parameter names to strip from URLs (context.url and URL-shaped property values). */\n stripParams?: string[];\n /** Property/trait keys whose values should be replaced with \"[REDACTED]\". */\n redactKeys?: string[];\n /** URL pathname prefixes — events whose context.url matches are dropped entirely. */\n dropRoutes?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction stripUrlParams(url: string, params: string[]): string {\n try {\n const u = new URL(url);\n for (const p of params) u.searchParams.delete(p);\n return u.toString();\n } catch {\n return url; // not a valid URL — leave as-is\n }\n}\n\nfunction stripParamsInProperties(\n props: Properties | undefined,\n params: string[],\n): Properties | undefined {\n if (!props) return props;\n const out: Properties = {};\n for (const [k, v] of Object.entries(props)) {\n if (typeof v === \"string\" && v.startsWith(\"http\")) {\n out[k] = stripUrlParams(v, params);\n } else {\n out[k] = v;\n }\n }\n return out;\n}\n\nfunction redactKeysInProperties(\n props: Properties | undefined,\n keys: string[],\n): Properties | undefined {\n if (!props) return props;\n const out: Properties = {};\n for (const [k, v] of Object.entries(props)) {\n out[k] = keys.includes(k) ? \"[REDACTED]\" : v;\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Factory that returns a `beforeSend` hook for events.\n *\n * - `dropRoutes` — drops events whose `context.url` pathname starts with a prefix.\n * - `stripParams` — removes query params from `context.url` and URL-shaped values\n * in `properties` and `traits`.\n * - `redactKeys` — replaces matching keys in `properties` and `traits` with `\"[REDACTED]\"`.\n *\n * The returned function never mutates the input event.\n */\nexport function redact(options: RedactOptions): BeforeSendFn<JsonEvent> {\n const { stripParams, redactKeys, dropRoutes } = options;\n\n return (event: JsonEvent): JsonEvent | null => {\n // --- dropRoutes ---\n if (dropRoutes && dropRoutes.length > 0 && event.context?.url) {\n try {\n const pathname = new URL(String(event.context.url)).pathname;\n for (const prefix of dropRoutes) {\n if (pathname.startsWith(prefix)) return null;\n }\n } catch {\n // not a valid URL — skip drop check\n }\n }\n\n let ctx = event.context;\n let props = event.properties;\n let traits = event.traits;\n\n // --- stripParams ---\n if (stripParams && stripParams.length > 0) {\n if (ctx?.url && typeof ctx.url === \"string\") {\n ctx = { ...ctx, url: stripUrlParams(ctx.url, stripParams) };\n }\n props = stripParamsInProperties(props, stripParams);\n traits = stripParamsInProperties(traits, stripParams);\n }\n\n // --- redactKeys ---\n if (redactKeys && redactKeys.length > 0) {\n props = redactKeysInProperties(props, redactKeys);\n traits = redactKeysInProperties(traits, redactKeys);\n }\n\n // Return a shallow copy if anything changed\n if (ctx !== event.context || props !== event.properties || traits !== event.traits) {\n return { ...event, context: ctx, properties: props, traits: traits };\n }\n\n return event;\n };\n}\n\n/**\n * Factory that returns a `beforeSend` hook for log entries.\n *\n * - `redactKeys` — replaces matching keys in `log.data` with `\"[REDACTED]\"`.\n *\n * The returned function never mutates the input log.\n */\nexport function redactLog(\n options: Pick<RedactOptions, \"redactKeys\">,\n): BeforeSendFn<JsonLog> {\n const { redactKeys } = options;\n\n return (log: JsonLog): JsonLog | null => {\n if (redactKeys && redactKeys.length > 0 && log.data) {\n const data = redactKeysInProperties(log.data, redactKeys);\n if (data !== log.data) {\n return { ...log, data };\n }\n }\n return log;\n };\n}\n","import type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { NetworkError } from \"@tell-rs/core\";\nimport { gzipSync } from \"node:zlib\";\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n networkTimeout: number;\n gzip: boolean;\n onError?: (error: Error) => void;\n onPayloadTooLarge?: () => void;\n}\n\nexport class HttpTransport {\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly maxRetries: number;\n private readonly networkTimeout: number;\n private readonly gzip: boolean;\n private readonly onError?: (error: Error) => void;\n private readonly onPayloadTooLarge?: () => void;\n\n constructor(config: TransportConfig) {\n this.endpoint = config.endpoint;\n this.apiKey = config.apiKey;\n this.maxRetries = config.maxRetries;\n this.networkTimeout = config.networkTimeout;\n this.gzip = config.gzip;\n this.onError = config.onError;\n this.onPayloadTooLarge = config.onPayloadTooLarge;\n }\n\n async sendEvents(events: JsonEvent[]): Promise<void> {\n if (events.length === 0) return;\n const body = events.map((e) => JSON.stringify(e)).join(\"\\n\");\n await this.send(\"/v1/events\", body);\n }\n\n async sendLogs(logs: JsonLog[]): Promise<void> {\n if (logs.length === 0) return;\n const body = logs.map((l) => JSON.stringify(l)).join(\"\\n\");\n await this.send(\"/v1/logs\", body);\n }\n\n private resolvePort(): string {\n try {\n const u = new URL(this.endpoint);\n if (u.port) return u.port;\n return u.protocol === \"https:\" ? \"443\" : \"80\";\n } catch {\n return \"unknown\";\n }\n }\n\n private async send(path: string, body: string): Promise<void> {\n const url = `${this.endpoint}${path}`;\n const port = this.resolvePort();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-ndjson\",\n Authorization: `Bearer ${this.apiKey}`,\n };\n\n let payload: string | Buffer = body;\n if (this.gzip) {\n payload = gzipSync(body);\n headers[\"Content-Encoding\"] = \"gzip\";\n }\n\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n await this.backoff(attempt);\n }\n\n try {\n const response = await globalThis.fetch(url, {\n method: \"POST\",\n headers,\n body: payload,\n signal: AbortSignal.timeout(this.networkTimeout),\n });\n\n if (response.status === 202) {\n return;\n }\n\n if (response.status === 207) {\n if (this.onError) {\n const data = (await response.json().catch(() => null)) as Record<string, unknown> | null;\n this.onError(\n new NetworkError(\n `Partial success: ${data?.rejected ?? \"unknown\"} items rejected`,\n 207\n )\n );\n }\n return;\n }\n\n if (response.status === 413) {\n if (this.onPayloadTooLarge) {\n this.onPayloadTooLarge();\n }\n throw new NetworkError(\"Payload too large\", 413);\n }\n\n if (response.status === 401) {\n throw new NetworkError(\"Invalid API key\", 401);\n }\n\n if (response.status >= 400 && response.status < 500) {\n throw new NetworkError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status\n );\n }\n\n lastError = new NetworkError(\n `HTTP ${response.status} from ${url} (port ${port}): ${response.statusText}`,\n response.status\n );\n } catch (err) {\n if (err instanceof NetworkError && err.statusCode === 413) {\n throw err;\n }\n\n if (err instanceof NetworkError && err.statusCode && err.statusCode < 500) {\n if (this.onError) this.onError(err);\n return;\n }\n\n // DNS failures and connection refused surface as TypeError from\n // fetch. Include the full URL so the developer can verify the\n // endpoint and port. These won't resolve by retrying.\n if (err instanceof TypeError) {\n if (this.onError)\n this.onError(\n new NetworkError(\n `Failed to connect to ${url} (port ${port}): ${err.message}`\n )\n );\n return;\n }\n\n lastError =\n err instanceof Error ? err : new NetworkError(String(err));\n }\n }\n\n if (lastError && this.onError) {\n this.onError(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const base = 1000 * Math.pow(1.5, attempt - 1);\n const jitter = base * 0.2 * Math.random();\n const delay = Math.min(base + jitter, 30_000);\n return new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -82,8 +82,18 @@ var HttpTransport = class {
|
|
|
82
82
|
const body = logs.map((l) => JSON.stringify(l)).join("\n");
|
|
83
83
|
await this.send("/v1/logs", body);
|
|
84
84
|
}
|
|
85
|
+
resolvePort() {
|
|
86
|
+
try {
|
|
87
|
+
const u = new URL(this.endpoint);
|
|
88
|
+
if (u.port) return u.port;
|
|
89
|
+
return u.protocol === "https:" ? "443" : "80";
|
|
90
|
+
} catch {
|
|
91
|
+
return "unknown";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
85
94
|
async send(path, body) {
|
|
86
95
|
const url = `${this.endpoint}${path}`;
|
|
96
|
+
const port = this.resolvePort();
|
|
87
97
|
const headers = {
|
|
88
98
|
"Content-Type": "application/x-ndjson",
|
|
89
99
|
Authorization: `Bearer ${this.apiKey}`
|
|
@@ -136,7 +146,7 @@ var HttpTransport = class {
|
|
|
136
146
|
);
|
|
137
147
|
}
|
|
138
148
|
lastError = new NetworkError(
|
|
139
|
-
`HTTP ${response.status}: ${response.statusText}`,
|
|
149
|
+
`HTTP ${response.status} from ${url} (port ${port}): ${response.statusText}`,
|
|
140
150
|
response.status
|
|
141
151
|
);
|
|
142
152
|
} catch (err) {
|
|
@@ -148,7 +158,12 @@ var HttpTransport = class {
|
|
|
148
158
|
return;
|
|
149
159
|
}
|
|
150
160
|
if (err instanceof TypeError) {
|
|
151
|
-
if (this.onError)
|
|
161
|
+
if (this.onError)
|
|
162
|
+
this.onError(
|
|
163
|
+
new NetworkError(
|
|
164
|
+
`Failed to connect to ${url} (port ${port}): ${err.message}`
|
|
165
|
+
)
|
|
166
|
+
);
|
|
152
167
|
return;
|
|
153
168
|
}
|
|
154
169
|
lastError = err instanceof Error ? err : new NetworkError(String(err));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/transport.ts","../src/index.ts"],"sourcesContent":["import type { TellError } from \"@tell-rs/core\";\nimport type { BeforeSendFn } from \"@tell-rs/core\";\nimport type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { hostname } from \"node:os\";\n\nexport interface TellConfig {\n apiKey: string;\n endpoint?: string;\n batchSize?: number;\n flushInterval?: number;\n maxRetries?: number;\n closeTimeout?: number;\n networkTimeout?: number;\n logLevel?: \"error\" | \"warn\" | \"info\" | \"debug\";\n source?: string;\n onError?: (error: TellError) => void;\n disabled?: boolean;\n maxQueueSize?: number;\n gzip?: boolean;\n beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n}\n\nexport const DEFAULTS = {\n endpoint: \"https://collect.tell.app\",\n batchSize: 100,\n flushInterval: 10_000,\n maxRetries: 3,\n closeTimeout: 5_000,\n networkTimeout: 30_000,\n logLevel: \"info\" as const,\n source: hostname(),\n disabled: false,\n maxQueueSize: 1000,\n gzip: false,\n} as const;\n\nexport type ResolvedConfig = Required<\n Omit<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">\n> &\n Pick<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">;\n\nexport function resolveConfig(config: TellConfig): ResolvedConfig {\n return { ...DEFAULTS, ...config } as ResolvedConfig;\n}\n\n/** Development preset: localhost, small batches, fast flush, debug logging. */\nexport function development(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n endpoint: \"http://localhost:8080\",\n batchSize: 10,\n flushInterval: 2_000,\n logLevel: \"debug\",\n ...overrides,\n apiKey,\n };\n}\n\n/** Production preset: default endpoint, default batching, error-only logging. */\nexport function production(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n logLevel: \"error\",\n ...overrides,\n apiKey,\n };\n}\n","import type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { NetworkError } from \"@tell-rs/core\";\nimport { gzipSync } from \"node:zlib\";\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n networkTimeout: number;\n gzip: boolean;\n onError?: (error: Error) => void;\n onPayloadTooLarge?: () => void;\n}\n\nexport class HttpTransport {\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly maxRetries: number;\n private readonly networkTimeout: number;\n private readonly gzip: boolean;\n private readonly onError?: (error: Error) => void;\n private readonly onPayloadTooLarge?: () => void;\n\n constructor(config: TransportConfig) {\n this.endpoint = config.endpoint;\n this.apiKey = config.apiKey;\n this.maxRetries = config.maxRetries;\n this.networkTimeout = config.networkTimeout;\n this.gzip = config.gzip;\n this.onError = config.onError;\n this.onPayloadTooLarge = config.onPayloadTooLarge;\n }\n\n async sendEvents(events: JsonEvent[]): Promise<void> {\n if (events.length === 0) return;\n const body = events.map((e) => JSON.stringify(e)).join(\"\\n\");\n await this.send(\"/v1/events\", body);\n }\n\n async sendLogs(logs: JsonLog[]): Promise<void> {\n if (logs.length === 0) return;\n const body = logs.map((l) => JSON.stringify(l)).join(\"\\n\");\n await this.send(\"/v1/logs\", body);\n }\n\n private async send(path: string, body: string): Promise<void> {\n const url = `${this.endpoint}${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-ndjson\",\n Authorization: `Bearer ${this.apiKey}`,\n };\n\n let payload: string | Buffer = body;\n if (this.gzip) {\n payload = gzipSync(body);\n headers[\"Content-Encoding\"] = \"gzip\";\n }\n\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n await this.backoff(attempt);\n }\n\n try {\n const response = await globalThis.fetch(url, {\n method: \"POST\",\n headers,\n body: payload,\n signal: AbortSignal.timeout(this.networkTimeout),\n });\n\n if (response.status === 202) {\n return;\n }\n\n if (response.status === 207) {\n if (this.onError) {\n const data = (await response.json().catch(() => null)) as Record<string, unknown> | null;\n this.onError(\n new NetworkError(\n `Partial success: ${data?.rejected ?? \"unknown\"} items rejected`,\n 207\n )\n );\n }\n return;\n }\n\n if (response.status === 413) {\n if (this.onPayloadTooLarge) {\n this.onPayloadTooLarge();\n }\n throw new NetworkError(\"Payload too large\", 413);\n }\n\n if (response.status === 401) {\n throw new NetworkError(\"Invalid API key\", 401);\n }\n\n if (response.status >= 400 && response.status < 500) {\n throw new NetworkError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status\n );\n }\n\n lastError = new NetworkError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status\n );\n } catch (err) {\n if (err instanceof NetworkError && err.statusCode === 413) {\n throw err;\n }\n\n if (err instanceof NetworkError && err.statusCode && err.statusCode < 500) {\n if (this.onError) this.onError(err);\n return;\n }\n\n // DNS failures surface as TypeError from fetch.\n // These won't resolve by retrying — bail immediately.\n if (err instanceof TypeError) {\n if (this.onError) this.onError(new NetworkError(err.message));\n return;\n }\n\n lastError =\n err instanceof Error ? err : new NetworkError(String(err));\n }\n }\n\n if (lastError && this.onError) {\n this.onError(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const base = 1000 * Math.pow(1.5, attempt - 1);\n const jitter = base * 0.2 * Math.random();\n const delay = Math.min(base + jitter, 30_000);\n return new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n","import type { TellConfig } from \"./config.js\";\nimport type { JsonEvent, JsonLog, LogLevel, Properties, BeforeSendFn } from \"@tell-rs/core\";\nimport { resolveConfig } from \"./config.js\";\nimport { ClosedError, ValidationError, validateApiKey, validateEventName, validateLogMessage, validateUserId, Batcher, runBeforeSend } from \"@tell-rs/core\";\nimport { HttpTransport } from \"./transport.js\";\n\n// Re-export core types and values\nexport { Events, type EventName } from \"@tell-rs/core\";\nexport type { Properties, LogLevel, JsonEvent, JsonLog, BeforeSendFn } from \"@tell-rs/core\";\nexport { redact, redactLog, SENSITIVE_PARAMS, type RedactOptions } from \"@tell-rs/core\";\nexport { TellError, ConfigurationError, ValidationError, NetworkError, ClosedError, SerializationError } from \"@tell-rs/core\";\n\n// Re-export node-specific config\nexport type { TellConfig } from \"./config.js\";\nexport { development, production } from \"./config.js\";\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n};\n\nfunction uuid(): string {\n return crypto.randomUUID();\n}\n\nexport class Tell {\n private readonly transport: HttpTransport;\n private readonly eventBatcher: Batcher<JsonEvent>;\n private readonly logBatcher: Batcher<JsonLog>;\n private readonly deviceId: string;\n private sessionId: string;\n private readonly onError?: (error: Error) => void;\n private readonly source: string;\n private readonly closeTimeout: number;\n private readonly sdkLogLevel: number;\n private readonly beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n private readonly beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n private superProperties: Properties = {};\n private closed = false;\n private _disabled: boolean;\n\n constructor(config: TellConfig) {\n validateApiKey(config.apiKey);\n\n const resolved = resolveConfig(config);\n this.onError = resolved.onError;\n this.source = resolved.source;\n this.closeTimeout = resolved.closeTimeout;\n this.sdkLogLevel = LOG_LEVELS[resolved.logLevel] ?? 2;\n this._disabled = resolved.disabled;\n this.beforeSend = resolved.beforeSend;\n this.beforeSendLog = resolved.beforeSendLog;\n this.deviceId = uuid();\n this.sessionId = uuid();\n\n this.transport = new HttpTransport({\n endpoint: resolved.endpoint,\n apiKey: resolved.apiKey,\n maxRetries: resolved.maxRetries,\n networkTimeout: resolved.networkTimeout,\n gzip: resolved.gzip,\n onError: this.onError,\n onPayloadTooLarge: () => {\n this.eventBatcher.halveBatchSize();\n this.logBatcher.halveBatchSize();\n this.sdkDebug(\"413 received, halved batch size\");\n },\n });\n\n this.eventBatcher = new Batcher<JsonEvent>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendEvents(items),\n onOverflow: () => {\n this.sdkDebug(\"event queue overflow, dropping oldest item\");\n },\n });\n\n this.logBatcher = new Batcher<JsonLog>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendLogs(items),\n onOverflow: () => {\n this.sdkDebug(\"log queue overflow, dropping oldest item\");\n },\n });\n\n this.sdkDebug(`initialized (endpoint=${resolved.endpoint}, batch=${resolved.batchSize}, flush=${resolved.flushInterval}ms)`);\n }\n\n // --- Super Properties ---\n\n register(properties: Properties): void {\n Object.assign(this.superProperties, properties);\n }\n\n unregister(key: string): void {\n delete this.superProperties[key];\n }\n\n // --- Disabled ---\n\n disable(): void {\n this._disabled = true;\n }\n\n enable(): void {\n this._disabled = false;\n }\n\n // --- Events ---\n\n track(userId: string, eventName: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n validateEventName(eventName);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: eventName,\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n identify(userId: string, traits?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"identify\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n traits,\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n group(userId: string, groupId: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (!groupId) throw new ValidationError(\"groupId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"group\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n group_id: groupId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n revenue(\n userId: string,\n amount: number,\n currency: string,\n orderId: string,\n properties?: Properties\n ): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (amount <= 0) throw new ValidationError(\"amount\", \"must be positive\");\n if (!currency) throw new ValidationError(\"currency\", \"is required\");\n if (!orderId) throw new ValidationError(\"orderId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: \"Order Completed\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: {\n ...this.superProperties,\n ...properties,\n order_id: orderId,\n amount,\n currency,\n },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n alias(previousId: string, userId: string): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n if (!previousId) throw new ValidationError(\"previousId\", \"is required\");\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"alias\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { previous_id: previousId },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n resetSession(): void {\n this.sessionId = uuid();\n }\n\n // --- Logging ---\n\n log(level: LogLevel, message: string, service?: string, data?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateLogMessage(message);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let logEntry: JsonLog | null = {\n level,\n message,\n source: this.source,\n service: service ?? \"app\",\n session_id: this.sessionId,\n timestamp: Date.now(),\n data,\n };\n\n if (this.beforeSendLog) {\n logEntry = runBeforeSend(logEntry, this.beforeSendLog);\n if (logEntry === null) return;\n }\n\n this.logBatcher.add(logEntry);\n }\n\n logEmergency(message: string, service?: string, data?: Properties): void {\n this.log(\"emergency\", message, service, data);\n }\n logAlert(message: string, service?: string, data?: Properties): void {\n this.log(\"alert\", message, service, data);\n }\n logCritical(message: string, service?: string, data?: Properties): void {\n this.log(\"critical\", message, service, data);\n }\n logError(message: string, service?: string, data?: Properties): void {\n this.log(\"error\", message, service, data);\n }\n logWarning(message: string, service?: string, data?: Properties): void {\n this.log(\"warning\", message, service, data);\n }\n logNotice(message: string, service?: string, data?: Properties): void {\n this.log(\"notice\", message, service, data);\n }\n logInfo(message: string, service?: string, data?: Properties): void {\n this.log(\"info\", message, service, data);\n }\n logDebug(message: string, service?: string, data?: Properties): void {\n this.log(\"debug\", message, service, data);\n }\n logTrace(message: string, service?: string, data?: Properties): void {\n this.log(\"trace\", message, service, data);\n }\n\n // --- Lifecycle ---\n\n async flush(): Promise<void> {\n await Promise.all([this.eventBatcher.flush(), this.logBatcher.flush()]);\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.sdkDebug(\"closing...\");\n const work = Promise.all([this.eventBatcher.close(), this.logBatcher.close()]);\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"close timed out\")), this.closeTimeout)\n );\n try {\n await Promise.race([work, timeout]);\n } catch (err) {\n this.reportError(err);\n }\n }\n\n // --- Internal ---\n\n private reportError(err: unknown): void {\n if (this.onError && err instanceof Error) {\n this.onError(err);\n }\n }\n\n private sdkDebug(msg: string): void {\n if (this.sdkLogLevel >= LOG_LEVELS.debug) {\n console.debug(`[Tell] ${msg}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/transport.ts","../src/index.ts"],"sourcesContent":["import type { TellError } from \"@tell-rs/core\";\nimport type { BeforeSendFn } from \"@tell-rs/core\";\nimport type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { hostname } from \"node:os\";\n\nexport interface TellConfig {\n apiKey: string;\n endpoint?: string;\n batchSize?: number;\n flushInterval?: number;\n maxRetries?: number;\n closeTimeout?: number;\n networkTimeout?: number;\n logLevel?: \"error\" | \"warn\" | \"info\" | \"debug\";\n source?: string;\n onError?: (error: TellError) => void;\n disabled?: boolean;\n maxQueueSize?: number;\n gzip?: boolean;\n beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n}\n\nexport const DEFAULTS = {\n endpoint: \"https://collect.tell.app\",\n batchSize: 100,\n flushInterval: 10_000,\n maxRetries: 3,\n closeTimeout: 5_000,\n networkTimeout: 30_000,\n logLevel: \"info\" as const,\n source: hostname(),\n disabled: false,\n maxQueueSize: 1000,\n gzip: false,\n} as const;\n\nexport type ResolvedConfig = Required<\n Omit<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">\n> &\n Pick<TellConfig, \"onError\" | \"beforeSend\" | \"beforeSendLog\">;\n\nexport function resolveConfig(config: TellConfig): ResolvedConfig {\n return { ...DEFAULTS, ...config } as ResolvedConfig;\n}\n\n/** Development preset: localhost, small batches, fast flush, debug logging. */\nexport function development(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n endpoint: \"http://localhost:8080\",\n batchSize: 10,\n flushInterval: 2_000,\n logLevel: \"debug\",\n ...overrides,\n apiKey,\n };\n}\n\n/** Production preset: default endpoint, default batching, error-only logging. */\nexport function production(\n apiKey: string,\n overrides?: Partial<TellConfig>\n): TellConfig {\n return {\n logLevel: \"error\",\n ...overrides,\n apiKey,\n };\n}\n","import type { JsonEvent, JsonLog } from \"@tell-rs/core\";\nimport { NetworkError } from \"@tell-rs/core\";\nimport { gzipSync } from \"node:zlib\";\n\nexport interface TransportConfig {\n endpoint: string;\n apiKey: string;\n maxRetries: number;\n networkTimeout: number;\n gzip: boolean;\n onError?: (error: Error) => void;\n onPayloadTooLarge?: () => void;\n}\n\nexport class HttpTransport {\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly maxRetries: number;\n private readonly networkTimeout: number;\n private readonly gzip: boolean;\n private readonly onError?: (error: Error) => void;\n private readonly onPayloadTooLarge?: () => void;\n\n constructor(config: TransportConfig) {\n this.endpoint = config.endpoint;\n this.apiKey = config.apiKey;\n this.maxRetries = config.maxRetries;\n this.networkTimeout = config.networkTimeout;\n this.gzip = config.gzip;\n this.onError = config.onError;\n this.onPayloadTooLarge = config.onPayloadTooLarge;\n }\n\n async sendEvents(events: JsonEvent[]): Promise<void> {\n if (events.length === 0) return;\n const body = events.map((e) => JSON.stringify(e)).join(\"\\n\");\n await this.send(\"/v1/events\", body);\n }\n\n async sendLogs(logs: JsonLog[]): Promise<void> {\n if (logs.length === 0) return;\n const body = logs.map((l) => JSON.stringify(l)).join(\"\\n\");\n await this.send(\"/v1/logs\", body);\n }\n\n private resolvePort(): string {\n try {\n const u = new URL(this.endpoint);\n if (u.port) return u.port;\n return u.protocol === \"https:\" ? \"443\" : \"80\";\n } catch {\n return \"unknown\";\n }\n }\n\n private async send(path: string, body: string): Promise<void> {\n const url = `${this.endpoint}${path}`;\n const port = this.resolvePort();\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-ndjson\",\n Authorization: `Bearer ${this.apiKey}`,\n };\n\n let payload: string | Buffer = body;\n if (this.gzip) {\n payload = gzipSync(body);\n headers[\"Content-Encoding\"] = \"gzip\";\n }\n\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n await this.backoff(attempt);\n }\n\n try {\n const response = await globalThis.fetch(url, {\n method: \"POST\",\n headers,\n body: payload,\n signal: AbortSignal.timeout(this.networkTimeout),\n });\n\n if (response.status === 202) {\n return;\n }\n\n if (response.status === 207) {\n if (this.onError) {\n const data = (await response.json().catch(() => null)) as Record<string, unknown> | null;\n this.onError(\n new NetworkError(\n `Partial success: ${data?.rejected ?? \"unknown\"} items rejected`,\n 207\n )\n );\n }\n return;\n }\n\n if (response.status === 413) {\n if (this.onPayloadTooLarge) {\n this.onPayloadTooLarge();\n }\n throw new NetworkError(\"Payload too large\", 413);\n }\n\n if (response.status === 401) {\n throw new NetworkError(\"Invalid API key\", 401);\n }\n\n if (response.status >= 400 && response.status < 500) {\n throw new NetworkError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status\n );\n }\n\n lastError = new NetworkError(\n `HTTP ${response.status} from ${url} (port ${port}): ${response.statusText}`,\n response.status\n );\n } catch (err) {\n if (err instanceof NetworkError && err.statusCode === 413) {\n throw err;\n }\n\n if (err instanceof NetworkError && err.statusCode && err.statusCode < 500) {\n if (this.onError) this.onError(err);\n return;\n }\n\n // DNS failures and connection refused surface as TypeError from\n // fetch. Include the full URL so the developer can verify the\n // endpoint and port. These won't resolve by retrying.\n if (err instanceof TypeError) {\n if (this.onError)\n this.onError(\n new NetworkError(\n `Failed to connect to ${url} (port ${port}): ${err.message}`\n )\n );\n return;\n }\n\n lastError =\n err instanceof Error ? err : new NetworkError(String(err));\n }\n }\n\n if (lastError && this.onError) {\n this.onError(lastError);\n }\n }\n\n private backoff(attempt: number): Promise<void> {\n const base = 1000 * Math.pow(1.5, attempt - 1);\n const jitter = base * 0.2 * Math.random();\n const delay = Math.min(base + jitter, 30_000);\n return new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n","import type { TellConfig } from \"./config.js\";\nimport type { JsonEvent, JsonLog, LogLevel, Properties, BeforeSendFn } from \"@tell-rs/core\";\nimport { resolveConfig } from \"./config.js\";\nimport { ClosedError, ValidationError, validateApiKey, validateEventName, validateLogMessage, validateUserId, Batcher, runBeforeSend } from \"@tell-rs/core\";\nimport { HttpTransport } from \"./transport.js\";\n\n// Re-export core types and values\nexport { Events, type EventName } from \"@tell-rs/core\";\nexport type { Properties, LogLevel, JsonEvent, JsonLog, BeforeSendFn } from \"@tell-rs/core\";\nexport { redact, redactLog, SENSITIVE_PARAMS, type RedactOptions } from \"@tell-rs/core\";\nexport { TellError, ConfigurationError, ValidationError, NetworkError, ClosedError, SerializationError } from \"@tell-rs/core\";\n\n// Re-export node-specific config\nexport type { TellConfig } from \"./config.js\";\nexport { development, production } from \"./config.js\";\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n};\n\nfunction uuid(): string {\n return crypto.randomUUID();\n}\n\nexport class Tell {\n private readonly transport: HttpTransport;\n private readonly eventBatcher: Batcher<JsonEvent>;\n private readonly logBatcher: Batcher<JsonLog>;\n private readonly deviceId: string;\n private sessionId: string;\n private readonly onError?: (error: Error) => void;\n private readonly source: string;\n private readonly closeTimeout: number;\n private readonly sdkLogLevel: number;\n private readonly beforeSend?: BeforeSendFn<JsonEvent> | BeforeSendFn<JsonEvent>[];\n private readonly beforeSendLog?: BeforeSendFn<JsonLog> | BeforeSendFn<JsonLog>[];\n private superProperties: Properties = {};\n private closed = false;\n private _disabled: boolean;\n\n constructor(config: TellConfig) {\n validateApiKey(config.apiKey);\n\n const resolved = resolveConfig(config);\n this.onError = resolved.onError;\n this.source = resolved.source;\n this.closeTimeout = resolved.closeTimeout;\n this.sdkLogLevel = LOG_LEVELS[resolved.logLevel] ?? 2;\n this._disabled = resolved.disabled;\n this.beforeSend = resolved.beforeSend;\n this.beforeSendLog = resolved.beforeSendLog;\n this.deviceId = uuid();\n this.sessionId = uuid();\n\n this.transport = new HttpTransport({\n endpoint: resolved.endpoint,\n apiKey: resolved.apiKey,\n maxRetries: resolved.maxRetries,\n networkTimeout: resolved.networkTimeout,\n gzip: resolved.gzip,\n onError: this.onError,\n onPayloadTooLarge: () => {\n this.eventBatcher.halveBatchSize();\n this.logBatcher.halveBatchSize();\n this.sdkDebug(\"413 received, halved batch size\");\n },\n });\n\n this.eventBatcher = new Batcher<JsonEvent>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendEvents(items),\n onOverflow: () => {\n this.sdkDebug(\"event queue overflow, dropping oldest item\");\n },\n });\n\n this.logBatcher = new Batcher<JsonLog>({\n size: resolved.batchSize,\n interval: resolved.flushInterval,\n maxQueueSize: resolved.maxQueueSize,\n send: (items) => this.transport.sendLogs(items),\n onOverflow: () => {\n this.sdkDebug(\"log queue overflow, dropping oldest item\");\n },\n });\n\n this.sdkDebug(`initialized (endpoint=${resolved.endpoint}, batch=${resolved.batchSize}, flush=${resolved.flushInterval}ms)`);\n }\n\n // --- Super Properties ---\n\n register(properties: Properties): void {\n Object.assign(this.superProperties, properties);\n }\n\n unregister(key: string): void {\n delete this.superProperties[key];\n }\n\n // --- Disabled ---\n\n disable(): void {\n this._disabled = true;\n }\n\n enable(): void {\n this._disabled = false;\n }\n\n // --- Events ---\n\n track(userId: string, eventName: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n validateEventName(eventName);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: eventName,\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n identify(userId: string, traits?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"identify\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n traits,\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n group(userId: string, groupId: string, properties?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (!groupId) throw new ValidationError(\"groupId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"group\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n group_id: groupId,\n timestamp: Date.now(),\n properties: { ...this.superProperties, ...properties },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n revenue(\n userId: string,\n amount: number,\n currency: string,\n orderId: string,\n properties?: Properties\n ): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateUserId(userId);\n if (amount <= 0) throw new ValidationError(\"amount\", \"must be positive\");\n if (!currency) throw new ValidationError(\"currency\", \"is required\");\n if (!orderId) throw new ValidationError(\"orderId\", \"is required\");\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"track\",\n event: \"Order Completed\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: {\n ...this.superProperties,\n ...properties,\n order_id: orderId,\n amount,\n currency,\n },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n alias(previousId: string, userId: string): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n if (!previousId) throw new ValidationError(\"previousId\", \"is required\");\n validateUserId(userId);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let event: JsonEvent | null = {\n type: \"alias\",\n device_id: this.deviceId,\n session_id: this.sessionId,\n user_id: userId,\n timestamp: Date.now(),\n properties: { previous_id: previousId },\n };\n\n if (this.beforeSend) {\n event = runBeforeSend(event, this.beforeSend);\n if (event === null) return;\n }\n\n this.eventBatcher.add(event);\n }\n\n resetSession(): void {\n this.sessionId = uuid();\n }\n\n // --- Logging ---\n\n log(level: LogLevel, message: string, service?: string, data?: Properties): void {\n if (this._disabled) return;\n if (this.closed) { this.reportError(new ClosedError()); return; }\n try {\n validateLogMessage(message);\n } catch (err) {\n this.reportError(err);\n return;\n }\n\n let logEntry: JsonLog | null = {\n level,\n message,\n source: this.source,\n service: service ?? \"app\",\n session_id: this.sessionId,\n timestamp: Date.now(),\n data,\n };\n\n if (this.beforeSendLog) {\n logEntry = runBeforeSend(logEntry, this.beforeSendLog);\n if (logEntry === null) return;\n }\n\n this.logBatcher.add(logEntry);\n }\n\n logEmergency(message: string, service?: string, data?: Properties): void {\n this.log(\"emergency\", message, service, data);\n }\n logAlert(message: string, service?: string, data?: Properties): void {\n this.log(\"alert\", message, service, data);\n }\n logCritical(message: string, service?: string, data?: Properties): void {\n this.log(\"critical\", message, service, data);\n }\n logError(message: string, service?: string, data?: Properties): void {\n this.log(\"error\", message, service, data);\n }\n logWarning(message: string, service?: string, data?: Properties): void {\n this.log(\"warning\", message, service, data);\n }\n logNotice(message: string, service?: string, data?: Properties): void {\n this.log(\"notice\", message, service, data);\n }\n logInfo(message: string, service?: string, data?: Properties): void {\n this.log(\"info\", message, service, data);\n }\n logDebug(message: string, service?: string, data?: Properties): void {\n this.log(\"debug\", message, service, data);\n }\n logTrace(message: string, service?: string, data?: Properties): void {\n this.log(\"trace\", message, service, data);\n }\n\n // --- Lifecycle ---\n\n async flush(): Promise<void> {\n await Promise.all([this.eventBatcher.flush(), this.logBatcher.flush()]);\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.sdkDebug(\"closing...\");\n const work = Promise.all([this.eventBatcher.close(), this.logBatcher.close()]);\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"close timed out\")), this.closeTimeout)\n );\n try {\n await Promise.race([work, timeout]);\n } catch (err) {\n this.reportError(err);\n }\n }\n\n // --- Internal ---\n\n private reportError(err: unknown): void {\n if (this.onError && err instanceof Error) {\n this.onError(err);\n }\n }\n\n private sdkDebug(msg: string): void {\n if (this.sdkLogLevel >= LOG_LEVELS.debug) {\n console.debug(`[Tell] ${msg}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|