@koderlabs/tasks-sdk 0.1.0
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/LICENSE +179 -0
- package/README.md +9 -0
- package/dist/index.cjs +908 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +187 -0
- package/dist/index.d.ts +187 -0
- package/dist/index.js +876 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transport.ts","../src/scrubber.ts","../src/internal-logger.ts","../src/spans.ts","../src/validate.ts","../src/client.ts","../src/web-vitals.ts","../src/index.ts"],"sourcesContent":["import type { AnyEvent } from '@koderlabs/tasks-sdk-types';\n\nexport interface TransportResult { id: string; ticketKey?: string }\n\n/**\n * Two ingest paths:\n *\n * • `/sdk/events` — JSON body. Validated by SubmitEventDto via\n * NestJS ValidationPipe. Used for plain events\n * (error, breadcrumb) with no attachments.\n *\n * • `/sdk/events/multipart` — multipart/form-data. The whole event lives in\n * a JSON string field named `event`; the\n * screenshot (and any other attachment) lives\n * in its own named field. Used for bug_report\n * with screenshot.\n */\nexport interface SpanRecord {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n kind?: 'internal' | 'server' | 'client' | 'producer' | 'consumer';\n status?: 'ok' | 'error' | 'unset';\n startTime: string;\n endTime: string;\n durationMs: number;\n attrs?: Record<string, unknown>;\n}\n\n/** Per-request timeout — aborts hung connections so they don't stall the queue. */\nconst REQUEST_TIMEOUT_MS = 10_000;\n\n/**\n * Soft cap on serialized event size. Anything larger is almost always a runaway\n * customData blob or a 1MB+ stack trace — both flood ingest and rarely contain\n * actionable info. Defensive limit at the SDK boundary; the ingest also enforces.\n */\nconst MAX_EVENT_BYTES = 500 * 1024;\n\nclass PayloadTooLargeError extends Error {\n constructor(public readonly bytes: number) {\n super(`InstantTasks SDK payload too large: ${bytes} bytes (max ${MAX_EVENT_BYTES})`);\n this.name = 'PayloadTooLargeError';\n }\n}\n\n/** AbortSignal.timeout polyfill — older RN/Hermes runtimes lack it. */\nfunction timeoutSignal(ms: number): AbortSignal {\n if (typeof AbortSignal !== 'undefined' && typeof (AbortSignal as unknown as { timeout?: (ms: number) => AbortSignal }).timeout === 'function') {\n return (AbortSignal as unknown as { timeout: (ms: number) => AbortSignal }).timeout(ms);\n }\n const ctrl = new AbortController();\n setTimeout(() => ctrl.abort(), ms);\n return ctrl.signal;\n}\n\nexport interface TransportOptions {\n /** Custom fetch implementation (e.g. TLS-pinned fetch on RN). */\n fetch?: typeof fetch;\n /** Optional HMAC secret for signed requests. */\n signingSecret?: string;\n}\n\nfunction pickFetch(opts?: TransportOptions): typeof fetch {\n return opts?.fetch ?? (globalThis as { fetch: typeof fetch }).fetch;\n}\n\n/**\n * Compute HMAC-SHA256 signature over `${ts}.${nonce}.${bodyHash}`. Returns\n * the headers to attach. Uses WebCrypto when available (browsers, modern\n * Node, RN with polyfill); silently skips when neither WebCrypto nor Node\n * `crypto` is reachable — the backend will reject if the project requires\n * signatures, surfacing a clear error to the caller.\n */\nexport async function signRequest(\n body: string,\n secret: string,\n): Promise<Record<string, string>> {\n const ts = String(Date.now());\n const nonce = (typeof crypto !== 'undefined' && 'randomUUID' in crypto)\n ? (crypto as { randomUUID: () => string }).randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\n try {\n const subtle = (globalThis as { crypto?: { subtle?: SubtleCrypto } }).crypto?.subtle;\n if (!subtle) return {};\n const enc = new TextEncoder();\n const hashBuf = await subtle.digest('SHA-256', enc.encode(body));\n const bodyHash = bufToHex(hashBuf);\n const key = await subtle.importKey('raw', enc.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);\n const sigBuf = await subtle.sign('HMAC', key, enc.encode(`${ts}.${nonce}.${bodyHash}`));\n return {\n 'X-IT-Timestamp': ts,\n 'X-IT-Nonce': nonce,\n 'X-IT-Signature': bufToHex(sigBuf),\n };\n } catch {\n return {};\n }\n}\n\nfunction bufToHex(buf: ArrayBuffer): string {\n const bytes = new Uint8Array(buf);\n let hex = '';\n for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, '0');\n return hex;\n}\n\nexport async function postSpans(\n endpoint: string,\n projectId: string,\n accessKey: string,\n spans: SpanRecord[],\n opts?: TransportOptions,\n): Promise<{ accepted: number }> {\n if (!spans.length) return { accepted: 0 };\n const url = `${endpoint}/api/v1/sdk/v1/spans`;\n const body = JSON.stringify({ spans });\n const headers: Record<string, string> = {\n Authorization: `Bearer ${accessKey}`,\n 'X-Project-Id': projectId,\n 'Content-Type': 'application/json',\n };\n if (opts?.signingSecret) Object.assign(headers, await signRequest(body, opts.signingSecret));\n const f = pickFetch(opts);\n const res = await f(url, { method: 'POST', headers, body, signal: timeoutSignal(REQUEST_TIMEOUT_MS) });\n if (!res.ok) {\n // Cap response body — an attacker-controlled endpoint could return a huge body.\n const text = (await res.text().catch(() => '')).slice(0, 512);\n throw new Error(`InstantTasks SDK spans ingest failed: ${res.status} ${text}`);\n }\n return (await res.json()) as { accepted: number };\n}\n\nexport async function postEvent(\n endpoint: string,\n projectId: string,\n accessKey: string,\n event: AnyEvent,\n attachments?: Map<string, Blob>,\n opts?: TransportOptions,\n): Promise<TransportResult> {\n const hasAttachments = !!attachments && attachments.size > 0;\n const url = `${endpoint}/api/v1/sdk/events${hasAttachments ? '/multipart' : ''}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${accessKey}`,\n 'X-Project-Id': projectId,\n };\n\n let body: BodyInit;\n let signedBody: string | null = null;\n if (hasAttachments) {\n const form = new FormData();\n const eventJson = JSON.stringify(event);\n if (eventJson.length > MAX_EVENT_BYTES) throw new PayloadTooLargeError(eventJson.length);\n form.append('event', eventJson);\n for (const [name, blob] of attachments!) form.append(name, blob, name);\n body = form;\n // Signing not applied to multipart bodies — boundary makes the hash unstable.\n } else {\n headers['Content-Type'] = 'application/json';\n const json = JSON.stringify(event);\n if (json.length > MAX_EVENT_BYTES) throw new PayloadTooLargeError(json.length);\n signedBody = json;\n body = json;\n }\n\n if (opts?.signingSecret && signedBody !== null) {\n Object.assign(headers, await signRequest(signedBody, opts.signingSecret));\n }\n\n const f = pickFetch(opts);\n const res = await f(url, { method: 'POST', headers, body, signal: timeoutSignal(REQUEST_TIMEOUT_MS) });\n if (!res.ok) {\n const text = (await res.text().catch(() => '')).slice(0, 512);\n const err = new TransportHttpError(res.status, text, res.headers.get('retry-after'));\n throw err;\n }\n return (await res.json()) as TransportResult;\n}\n\nexport class TransportHttpError extends Error {\n constructor(public readonly status: number, public readonly body: string, public readonly retryAfter: string | null) {\n super(`InstantTasks SDK ingest failed: ${status} ${body}`);\n this.name = 'TransportHttpError';\n }\n}\n\nexport { PayloadTooLargeError };\n","/**\n * Default PII scrubber.\n *\n * Redacts common secret-bearing fields (headers, body keys, URL query\n * params) from any event before it leaves the SDK. Always applied unless\n * `init({ scrub: false })` is set. Users can also supply a custom\n * `scrub: (event) => event` function to extend or override the defaults.\n *\n * Design notes:\n * - Deep clones via structuredClone where available, falls back to a\n * manual recursive clone. Original event is never mutated.\n * - Recursion depth capped at 5 to avoid pathological payloads stalling\n * the main thread.\n * - WeakSet cycle guard prevents infinite loops on circular refs.\n * - Bails (returns input as-is) if the serialized payload is over 50 KB\n * — at that size scrubbing is too expensive and the transport layer\n * would reject it anyway.\n */\nimport type { AnyEvent } from '@koderlabs/tasks-sdk-types';\n\nconst REDACTED = '[REDACTED]';\nconst MAX_DEPTH = 5;\nconst MAX_BYTES = 50 * 1024;\n\nconst SECRET_HEADER_NAMES = new Set([\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'proxy-authorization',\n]);\n\nconst SECRET_KEY_NAMES = new Set([\n 'password',\n 'secret',\n 'token',\n 'apikey',\n 'api_key',\n 'auth',\n 'session',\n]);\n\nconst SECRET_QUERY_PARAMS = new Set([\n 'token',\n 'access_token',\n 'refresh_token',\n 'password',\n 'api_key',\n 'apikey',\n 'secret',\n 'key',\n 'auth',\n 'session',\n 'code',\n 'state',\n]);\n\nfunction isSecretHeaderName(name: string): boolean {\n return SECRET_HEADER_NAMES.has(name.toLowerCase());\n}\n\nfunction isSecretKeyName(name: string): boolean {\n return SECRET_KEY_NAMES.has(name.toLowerCase());\n}\n\nfunction redactUrl(input: unknown): unknown {\n if (typeof input !== 'string') return input;\n // Only attempt URL parse if it looks URL-ish (has ? or starts with proto/path)\n if (!input.includes('?')) return input;\n try {\n // Use a base so relative paths parse too.\n const u = new URL(input, 'http://_scrub_base_/');\n let changed = false;\n const params = u.searchParams;\n const keys: string[] = [];\n params.forEach((_v, k) => { keys.push(k); });\n for (const k of keys) {\n if (SECRET_QUERY_PARAMS.has(k.toLowerCase())) {\n params.set(k, REDACTED);\n changed = true;\n }\n }\n if (!changed) return input;\n // Reconstruct: preserve original prefix when relative\n if (input.startsWith('http://') || input.startsWith('https://')) return u.toString();\n return u.pathname + (u.search ? u.search : '') + (u.hash || '');\n } catch {\n return input;\n }\n}\n\nfunction cloneAndScrub(\n value: unknown,\n depth: number,\n seen: WeakSet<object>,\n parentKey?: string,\n): unknown {\n if (depth > MAX_DEPTH) return value;\n if (value === null || value === undefined) return value;\n if (typeof value !== 'object') {\n // primitive — redact strings that are URL-shaped\n if (typeof value === 'string') return redactUrl(value);\n return value;\n }\n if (seen.has(value as object)) return '[Circular]';\n seen.add(value as object);\n\n if (Array.isArray(value)) {\n return value.map((item) => cloneAndScrub(item, depth + 1, seen, parentKey));\n }\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (isSecretKeyName(k)) {\n out[k] = REDACTED;\n continue;\n }\n // Special-case: if parent is a \"headers\" object, redact known header names\n if (parentKey && parentKey.toLowerCase() === 'headers' && isSecretHeaderName(k)) {\n out[k] = REDACTED;\n continue;\n }\n // url-ish keys: scrub query params\n if (typeof v === 'string' && (k === 'url' || k === 'href' || k === 'location')) {\n out[k] = redactUrl(v);\n continue;\n }\n out[k] = cloneAndScrub(v, depth + 1, seen, k);\n }\n return out;\n}\n\nfunction deepClone<T>(value: T): T {\n if (typeof (globalThis as any).structuredClone === 'function') {\n try { return (globalThis as any).structuredClone(value); } catch { /* fall through */ }\n }\n // Manual fallback for environments without structuredClone\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nexport function defaultScrubEvent(event: AnyEvent): AnyEvent {\n // Bail on oversized payloads — scrubbing cost not worth it; transport\n // size cap will reject downstream anyway.\n try {\n const approxSize = JSON.stringify(event).length;\n if (approxSize > MAX_BYTES) return event;\n } catch {\n return event;\n }\n\n // Clone first so callers see a fresh object (and we don't mutate event refs\n // stored in listener buffers).\n const cloned = deepClone(event);\n const scrubbed = cloneAndScrub(cloned, 0, new WeakSet());\n // Always redact top-level url\n if (scrubbed && typeof scrubbed === 'object' && (scrubbed as any).url) {\n (scrubbed as any).url = redactUrl((scrubbed as any).url);\n }\n return scrubbed as AnyEvent;\n}\n","/**\n * Internal logger for the InstantTasks SDK.\n *\n * Two suppression layers:\n * - `debug` must be true (per-client opt-in).\n * - `NODE_ENV !== 'production'` — bare `debug: true` shipped to production by\n * accident must not leak event payloads, user PII, or URLs to end-user\n * consoles.\n *\n * Errors raised inside the SDK itself (listener throws, programming bugs)\n * are routed to `error()` which logs once even in production but never\n * interpolates user data.\n */\n\ntype Level = 'log' | 'warn' | 'error';\n\nfunction isProd(): boolean {\n try {\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n return proc?.env?.NODE_ENV === 'production';\n } catch {\n return false;\n }\n}\n\nfunction emit(level: Level, debug: boolean, args: unknown[]): void {\n if (!debug) return;\n if (isProd()) return;\n // eslint-disable-next-line no-console\n const fn = (console as Record<Level, (...a: unknown[]) => void>)[level];\n if (typeof fn === 'function') fn('[InstantTasks]', ...args);\n}\n\nexport function debugLog(enabled: boolean, ...args: unknown[]): void {\n emit('log', enabled, args);\n}\n\nexport function debugWarn(enabled: boolean, ...args: unknown[]): void {\n emit('warn', enabled, args);\n}\n\n/**\n * Logs a programming/SDK error. Always emits (even in production) but never\n * accepts caller-supplied user data — only Error objects and SDK-internal\n * messages. Use sparingly; prefer emitting an event for the host app.\n */\nexport function internalError(message: string, err?: unknown): void {\n try {\n // eslint-disable-next-line no-console\n console.error('[InstantTasks]', message, err);\n } catch {\n /* console may be replaced in restricted runtimes */\n }\n}\n","import { postSpans, type SpanRecord, type TransportOptions } from './transport';\nimport { debugWarn } from './internal-logger';\n\nfunction randomHex(bytes: number): string {\n const arr = new Uint8Array(bytes);\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\n crypto.getRandomValues(arr);\n } else {\n for (let i = 0; i < bytes; i++) arr[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(arr, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport function newTraceId(): string { return randomHex(16); } // 32 hex\nexport function newSpanId(): string { return randomHex(8); } // 16 hex\n\nexport interface SpanOptions {\n name: string;\n traceId?: string;\n parentSpanId?: string;\n kind?: SpanRecord['kind'];\n attrs?: Record<string, unknown>;\n}\n\nexport interface ActiveSpan {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n end(opts?: { status?: 'ok' | 'error' | 'unset'; attrs?: Record<string, unknown> }): void;\n setAttr(key: string, value: unknown): void;\n}\n\n/**\n * Buffered span exporter. Spans accumulate in memory and flush every 5s or\n * when 50 spans are queued, whichever comes first. SDK lifecycle owners\n * should call `flush()` on shutdown to avoid losing buffered spans.\n */\nexport class SpanExporter {\n private queue: SpanRecord[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly FLUSH_MS = 5_000;\n private readonly MAX_QUEUE = 50;\n\n constructor(\n private readonly endpoint: string,\n private readonly projectId: string,\n private readonly accessKey: string,\n private readonly debug = false,\n private readonly transportOpts: TransportOptions = {},\n ) {}\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => { void this.flush(); }, this.FLUSH_MS);\n }\n\n stop(): void {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n }\n\n enqueue(span: SpanRecord): void {\n this.queue.push(span);\n if (this.queue.length >= this.MAX_QUEUE) void this.flush();\n }\n\n async flush(): Promise<void> {\n if (!this.queue.length) return;\n const batch = this.queue.splice(0, this.queue.length);\n try {\n await postSpans(this.endpoint, this.projectId, this.accessKey, batch, this.transportOpts);\n } catch (err) {\n debugWarn(this.debug, 'span flush failed', err);\n // Drop on failure — never re-queue (avoids memory leak on persistent failure).\n }\n }\n}\n\n/**\n * Mints a span and returns a handle. Caller MUST call `.end()` or span is\n * dropped (handle goes out of scope; nothing buffered).\n */\nexport function startSpan(exporter: SpanExporter, opts: SpanOptions): ActiveSpan {\n const traceId = opts.traceId ?? newTraceId();\n const spanId = newSpanId();\n const startedAt = Date.now();\n let attrs: Record<string, unknown> = { ...(opts.attrs ?? {}) };\n let ended = false;\n\n return {\n traceId,\n spanId,\n parentSpanId: opts.parentSpanId,\n setAttr(key, value) { attrs[key] = value; },\n end(closeOpts) {\n if (ended) return;\n ended = true;\n const endedAt = Date.now();\n if (closeOpts?.attrs) attrs = { ...attrs, ...closeOpts.attrs };\n exporter.enqueue({\n traceId,\n spanId,\n parentSpanId: opts.parentSpanId,\n name: opts.name,\n kind: opts.kind ?? 'internal',\n status: closeOpts?.status ?? 'ok',\n startTime: new Date(startedAt).toISOString(),\n endTime: new Date(endedAt).toISOString(),\n durationMs: endedAt - startedAt,\n attrs,\n });\n },\n };\n}\n","/**\n * Input validation for InstantTasks SDK init options.\n *\n * Defends against:\n * - SSRF via attacker-controlled endpoint (must be https; http allowed only for localhost)\n * - HTTP header injection via CR/LF or non-ASCII in projectId / accessKey\n * - Silent misconfiguration where a typo in endpoint exfiltrates the access key\n */\n\nconst ID_RE = /^[A-Za-z0-9_.:\\-]+$/;\nconst MAX_ID_LEN = 256;\n\nexport function validateEndpoint(endpoint: string): void {\n if (typeof endpoint !== 'string' || endpoint.length === 0) {\n throw new Error('[InstantTasks] endpoint is required');\n }\n let url: URL;\n try {\n url = new URL(endpoint);\n } catch {\n throw new Error(`[InstantTasks] endpoint must be a valid URL, got: ${endpoint.slice(0, 80)}`);\n }\n const isLocalhost =\n url.hostname === 'localhost' ||\n url.hostname === '127.0.0.1' ||\n url.hostname === '::1' ||\n url.hostname.endsWith('.localhost');\n if (url.protocol === 'http:' && !isLocalhost) {\n throw new Error('[InstantTasks] endpoint must use https:// (http:// only allowed for localhost)');\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error(`[InstantTasks] endpoint protocol must be http(s), got: ${url.protocol}`);\n }\n}\n\nexport function validateIdentifier(name: string, value: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`[InstantTasks] ${name} is required`);\n }\n if (value.length > MAX_ID_LEN) {\n throw new Error(`[InstantTasks] ${name} exceeds ${MAX_ID_LEN} chars`);\n }\n if (!ID_RE.test(value)) {\n // Reject CR/LF and any character that would corrupt an HTTP header.\n throw new Error(`[InstantTasks] ${name} contains invalid characters`);\n }\n}\n","import type { AnyEvent, Serializable } from '@koderlabs/tasks-sdk-types';\nimport {\n postEvent,\n TransportHttpError,\n PayloadTooLargeError,\n type TransportOptions,\n} from './transport';\nimport { defaultScrubEvent } from './scrubber';\nimport type { ClientInterface, InitOptions } from './types';\nimport { SpanExporter, startSpan, type ActiveSpan, type SpanOptions } from './spans';\nimport { validateEndpoint, validateIdentifier } from './validate';\nimport { debugLog, debugWarn, internalError } from './internal-logger';\n\nexport class Client implements ClientInterface {\n options: ClientInterface['options'];\n private listeners = new Map<string, Array<(...args: any[]) => void>>();\n private spanExporter: SpanExporter;\n private transportOpts: TransportOptions;\n\n constructor(opts: InitOptions) {\n const endpoint = opts.endpoint ?? 'https://tasks.koderlabs.net';\n if (!opts.endpoint) warnDefaultEndpoint();\n validateEndpoint(endpoint);\n validateIdentifier('projectId', String(opts.projectId));\n validateIdentifier('accessKey', String(opts.accessKey));\n this.options = { ...opts, endpoint };\n this.transportOpts = {\n fetch: this.options.fetch,\n signingSecret: this.options.signingSecret,\n };\n this.spanExporter = new SpanExporter(\n this.options.endpoint,\n this.options.projectId,\n this.options.accessKey,\n !!this.options.debug,\n this.transportOpts,\n );\n this.spanExporter.start();\n }\n\n /** Start a span. Caller MUST call .end() on the returned handle. */\n startSpan(opts: SpanOptions): ActiveSpan {\n return startSpan(this.spanExporter, opts);\n }\n\n /** Flush any buffered spans. Call on app shutdown. */\n flushSpans(): Promise<void> { return this.spanExporter.flush(); }\n\n /** Stop background timers (span exporter interval). Called by init() on replace. */\n stop(): void { this.spanExporter.stop(); }\n\n /** Apply configured scrubber. Returns the event (possibly transformed). */\n private applyScrub(event: AnyEvent): AnyEvent {\n const scrub = this.options.scrub;\n if (scrub === false) return event;\n if (typeof scrub === 'function') {\n try { return scrub(event); }\n catch (err) {\n internalError('custom scrub threw', err);\n return event;\n }\n }\n try { return defaultScrubEvent(event); }\n catch (err) {\n internalError('default scrub threw', err);\n return event;\n }\n }\n\n async send(event: AnyEvent, attachments?: Map<string, Blob>) {\n const debug = !!this.options.debug;\n debugLog(debug, 'send', event.kind);\n\n // Scrub PII BEFORE beforeSend — beforeSend sees the scrubbed event and\n // can further redact or override (but cannot un-redact secrets).\n let outgoing: AnyEvent | null = this.applyScrub(event);\n\n if (this.options.beforeSend) {\n let threw = false;\n try {\n outgoing = await this.options.beforeSend(outgoing);\n } catch (err) {\n threw = true;\n // Fail-closed: a buggy beforeSend MUST NOT silently leak unscrubbed\n // events. Drop the event, surface via listener event, and always log\n // once (even in prod) so the bug is visible to operators.\n internalError('beforeSend threw — dropping event', err);\n outgoing = null;\n }\n if (!outgoing) {\n if (!threw) debugLog(debug, 'event dropped by beforeSend');\n const dropped = { id: 'dropped', dropped: true as const };\n this.emit(threw ? 'beforesend_error' : 'send_dropped', { event });\n return dropped as any;\n }\n }\n\n if (this.options.dryRun) {\n debugLog(debug, 'dryRun — not sending', outgoing.kind);\n const result = { id: 'dryrun', dryRun: true as const };\n this.emit('send_dryrun', { event: outgoing, result });\n return result as any;\n }\n\n // Honor a backoff window set by a prior 429 — drop instead of sending so we\n // don't get banned by the ingest.\n if (Date.now() < this.rateLimitedUntil) {\n const result = { id: 'rate-limited', dropped: true as const };\n this.emit('send_rate_limited', { event: outgoing });\n return result as any;\n }\n\n try {\n const result = await this.sendWithBackoff(outgoing, attachments, debug);\n this.emit('send_success', { event: outgoing, result });\n return result;\n } catch (err) {\n this.emit('send_error', { event: outgoing, error: err });\n throw err;\n }\n }\n\n private rateLimitedUntil = 0;\n private static readonly MAX_RETRIES = 2;\n private static readonly BASE_BACKOFF_MS = 1_000;\n\n private async sendWithBackoff(\n event: AnyEvent,\n attachments: Map<string, Blob> | undefined,\n debug: boolean,\n ) {\n let attempt = 0;\n let lastErr: unknown;\n while (attempt <= Client.MAX_RETRIES) {\n try {\n return await postEvent(\n this.options.endpoint,\n this.options.projectId,\n this.options.accessKey,\n event,\n attachments,\n this.transportOpts,\n );\n } catch (err) {\n lastErr = err;\n if (err instanceof PayloadTooLargeError) {\n // Never retry — payload won't shrink. Drop loudly.\n debugWarn(debug, err.message);\n throw err;\n }\n if (err instanceof TransportHttpError) {\n if (err.status === 429) {\n const cooldown = parseRetryAfter(err.retryAfter) ?? 30_000;\n this.rateLimitedUntil = Date.now() + cooldown;\n throw err; // honor immediately, no retry\n }\n // Retry only transient 5xx; do not retry 4xx (validation, auth).\n if (err.status < 500 || err.status >= 600) throw err;\n }\n attempt++;\n if (attempt > Client.MAX_RETRIES) break;\n const wait = Client.BASE_BACKOFF_MS * Math.pow(2, attempt - 1);\n await new Promise((r) => setTimeout(r, wait));\n }\n }\n throw lastErr;\n }\n\n on(event: string, listener: (...args: any[]) => void) {\n const arr = this.listeners.get(event) ?? [];\n arr.push(listener);\n this.listeners.set(event, arr);\n }\n\n emit(event: string, ...args: any[]) {\n for (const l of this.listeners.get(event) ?? []) {\n try { l(...args); } catch (e) { internalError('listener threw', e); }\n }\n }\n\n setUser(user: InitOptions['user']) { this.options.user = user; }\n setCustomData(data: Record<string, Serializable>) {\n this.options.customData = { ...this.options.customData, ...data };\n }\n}\n\n// One-time deprecation banner — fires per-process the first time a client is\n// constructed without an explicit endpoint. Will become a thrown error in the\n// next major version (M8). Suppressed in tests via INSTANTTASKS_QUIET=1.\nlet warnedDefaultEndpoint = false;\nfunction warnDefaultEndpoint(): void {\n if (warnedDefaultEndpoint) return;\n warnedDefaultEndpoint = true;\n try {\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n if (proc?.env?.INSTANTTASKS_QUIET) return;\n } catch { /* no process */ }\n internalError(\n 'init() called without an explicit `endpoint`. Defaulting to https://tasks.koderlabs.net is deprecated and will throw in the next major release. ' +\n 'Set `endpoint: process.env.INSTANTTASKS_ENDPOINT` (or your self-hosted URL).',\n );\n}\n\n/**\n * Parse `Retry-After` header. Supports both delta-seconds and HTTP-date forms.\n * Returns ms to wait, or null if unparseable.\n */\nfunction parseRetryAfter(header: string | null): number | null {\n if (!header) return null;\n const sec = Number(header);\n if (Number.isFinite(sec) && sec >= 0) return Math.min(sec * 1000, 5 * 60_000);\n const date = Date.parse(header);\n if (Number.isFinite(date)) {\n const ms = date - Date.now();\n if (ms > 0) return Math.min(ms, 5 * 60_000);\n }\n return null;\n}\n","import type { Client } from './client';\nimport type { WebVitalName } from '@koderlabs/tasks-sdk-types';\n\n/**\n * Captures Web Vitals (LCP/INP/CLS/FCP/TTFB) via the standard PerformanceObserver\n * APIs and posts each measurement as an event with kind='web_vital'. No\n * external dep — uses the same observer entries that the `web-vitals` lib\n * wraps. Good enough for v1; swap to web-vitals lib for stricter attribution.\n *\n * Reporting model: each metric is reported AT MOST ONCE per page lifecycle —\n * either on visibility-change (default) or on a debounced timer when\n * `reportOnHidden=false`. Without this the prior implementation fired one\n * event per observer entry which for INP/CLS meant dozens of POSTs per page.\n */\nexport interface WebVitalsOptions {\n /** Send final value only when document becomes hidden. Default true. */\n reportOnHidden?: boolean;\n /** Which vitals to capture. Default all five. */\n metrics?: WebVitalName[];\n /** Debounce interval (ms) for live reporting when reportOnHidden=false. Default 2000. */\n debounceMs?: number;\n}\n\nconst RATING_THRESHOLDS: Record<WebVitalName, [number, number]> = {\n // [good, poor] — between = needs-improvement\n LCP: [2500, 4000],\n INP: [200, 500],\n CLS: [0.1, 0.25],\n FCP: [1800, 3000],\n TTFB: [800, 1800],\n};\n\nfunction rate(name: WebVitalName, value: number): 'good' | 'needs-improvement' | 'poor' {\n const [good, poor] = RATING_THRESHOLDS[name];\n if (value <= good) return 'good';\n if (value >= poor) return 'poor';\n return 'needs-improvement';\n}\n\nfunction randomHexShort(): string {\n if (typeof crypto !== 'undefined' && (crypto as Crypto).getRandomValues) {\n const a = new Uint8Array(4);\n (crypto as Crypto).getRandomValues(a);\n return Array.from(a, (b) => b.toString(16).padStart(2, '0')).join('');\n }\n return Math.random().toString(36).slice(2, 10);\n}\n\nfunction buildReport(client: Client, name: WebVitalName, value: number) {\n const env = client.options;\n return client.send({\n kind: 'web_vital',\n ts: new Date().toISOString(),\n release: env.release,\n environment: env.environment,\n user: env.user,\n url: typeof location !== 'undefined' ? location.href : '',\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n viewport: typeof window !== 'undefined'\n ? { width: window.innerWidth, height: window.innerHeight }\n : { width: 0, height: 0 },\n metric: name,\n value: Math.round(value * 1000) / 1000,\n rating: rate(name, value),\n measurementId: `${name}-${Date.now()}-${randomHexShort()}`,\n navigationType: (performance.getEntriesByType?.('navigation')?.[0] as PerformanceNavigationTiming | undefined)?.type,\n } as any);\n}\n\n/**\n * Per-metric reporter that coalesces multiple observer entries into a single\n * outgoing event. Sends at most once per metric per page (or on visibility\n * hide), preventing the prior fetch-storm behaviour where INP/CLS could fire\n * 20+ events per page.\n */\nclass MetricReporter {\n private value = 0;\n private hasValue = false;\n private sent = false;\n private timer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n private readonly client: Client,\n private readonly name: WebVitalName,\n private readonly debounceMs: number,\n private readonly reportOnHidden: boolean,\n ) {}\n\n setValue(v: number): void {\n this.value = v;\n this.hasValue = true;\n if (this.reportOnHidden) return;\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => this.flush(), this.debounceMs);\n }\n\n flush(): void {\n if (this.sent || !this.hasValue) return;\n this.sent = true;\n if (this.timer) { clearTimeout(this.timer); this.timer = null; }\n void buildReport(this.client, this.name, this.value);\n }\n}\n\nexport function captureWebVitals(client: Client, opts: WebVitalsOptions = {}): void {\n if (typeof PerformanceObserver === 'undefined') return;\n const wanted = new Set<WebVitalName>(opts.metrics ?? ['LCP', 'INP', 'CLS', 'FCP', 'TTFB']);\n const reportOnHidden = opts.reportOnHidden !== false; // default true\n const debounceMs = opts.debounceMs ?? 2000;\n\n const reporters: MetricReporter[] = [];\n const make = (name: WebVitalName) => {\n const r = new MetricReporter(client, name, debounceMs, reportOnHidden);\n reporters.push(r);\n return r;\n };\n\n // Single visibilitychange listener flushes every reporter — replaces N per-metric\n // listeners that the prior version added (each leaking).\n if (typeof document !== 'undefined') {\n const onHide = () => {\n if (document.visibilityState === 'hidden') {\n for (const r of reporters) r.flush();\n }\n };\n document.addEventListener('visibilitychange', onHide);\n }\n\n if (wanted.has('LCP')) {\n safeObserve('largest-contentful-paint', (entries) => {\n const r = lcp ?? (lcp = make('LCP'));\n const last = entries[entries.length - 1] as PerformanceEntry & { startTime: number };\n if (last) r.setValue(last.startTime ?? 0);\n });\n }\n\n let lcp: MetricReporter | null = null;\n\n if (wanted.has('FCP')) {\n const r = make('FCP');\n safeObserve('paint', (entries) => {\n for (const e of entries) {\n if (e.name === 'first-contentful-paint') {\n r.setValue((e as PerformanceEntry & { startTime: number }).startTime ?? 0);\n }\n }\n });\n }\n\n if (wanted.has('CLS')) {\n const r = make('CLS');\n let cls = 0;\n safeObserve('layout-shift', (entries) => {\n for (const e of entries as Array<PerformanceEntry & { value: number; hadRecentInput: boolean }>) {\n if (!e.hadRecentInput) cls += e.value;\n }\n r.setValue(cls);\n });\n }\n\n if (wanted.has('INP')) {\n const r = make('INP');\n let maxInp = 0;\n safeObserve('event', (entries) => {\n for (const e of entries as Array<PerformanceEntry & { duration: number }>) {\n if (e.duration > maxInp) maxInp = e.duration;\n }\n r.setValue(maxInp);\n }, { durationThreshold: 16 });\n }\n\n if (wanted.has('TTFB')) {\n try {\n const nav = performance.getEntriesByType?.('navigation')?.[0] as PerformanceNavigationTiming | undefined;\n if (nav && typeof nav.responseStart === 'number') {\n const r = make('TTFB');\n r.setValue(nav.responseStart);\n // TTFB is single-shot — flush immediately, no need to wait for hide.\n r.flush();\n }\n } catch { /* unsupported */ }\n }\n}\n\nfunction safeObserve(\n type: string,\n cb: (entries: PerformanceEntry[]) => void,\n extra: Record<string, unknown> = {},\n): void {\n try {\n const po = new PerformanceObserver((list) => cb(list.getEntries()));\n po.observe({ type, buffered: true, ...extra } as PerformanceObserverInit);\n } catch { /* unsupported in this browser */ }\n}\n","import { Client } from './client';\nimport type { InitOptions } from './types';\nimport { internalError } from './internal-logger';\n\nexport { Client };\n\nlet currentClient: Client | null = null;\nlet currentIntegrations: Array<{ name: string; teardown?: () => void }> = [];\n\nexport function init(opts: InitOptions): Client {\n // Tear down the prior client synchronously — otherwise span exporter timers,\n // integration listeners, and breadcrumb sources leak across re-init (common\n // in dev / hot reload / tests).\n if (currentClient) {\n currentClient.emit('replaced');\n try { void currentClient.flushSpans?.(); } catch { /* best-effort */ }\n try { currentClient.stop?.(); } catch { /* best-effort */ }\n for (const integration of currentIntegrations) {\n try { integration.teardown?.(); }\n catch (e) { internalError(`integration ${integration.name} teardown failed`, e); }\n }\n currentIntegrations = [];\n }\n const client = new Client(opts);\n currentClient = client;\n const integrations = opts.integrations ?? [];\n for (const integration of integrations) integration.setup(client);\n currentIntegrations = integrations;\n return client;\n}\n\nexport function getClient(): Client | null { return currentClient; }\n\nexport type { InitOptions, Integration, ClientInterface } from './types';\nexport type * from '@koderlabs/tasks-sdk-types';\nexport { newTraceId, newSpanId } from './spans';\nexport { captureWebVitals } from './web-vitals';\nexport type { WebVitalsOptions } from './web-vitals';\nexport type { ActiveSpan, SpanOptions } from './spans';\nexport type { SpanRecord, TransportOptions } from './transport';\nexport { signRequest } from './transport';\nexport { defaultScrubEvent } from './scrubber';\n"],"mappings":"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","names":["REQUEST_TIMEOUT_MS","MAX_EVENT_BYTES","PayloadTooLargeError","Error","bytes","name","timeoutSignal","ms","AbortSignal","timeout","ctrl","AbortController","setTimeout","abort","signal","pickFetch","opts","fetch","globalThis","signRequest","body","secret","ts","String","Date","now","nonce","crypto","randomUUID","Math","random","toString","slice","subtle","enc","TextEncoder","hashBuf","digest","encode","bodyHash","bufToHex","key","importKey","hash","sigBuf","sign","buf","Uint8Array","hex","i","length","padStart","postSpans","endpoint","projectId","accessKey","spans","accepted","url","JSON","stringify","headers","Authorization","signingSecret","Object","assign","f","res","method","ok","text","catch","status","json","postEvent","event","attachments","hasAttachments","size","signedBody","form","FormData","eventJson","append","blob","err","TransportHttpError","get","retryAfter","REDACTED","MAX_DEPTH","MAX_BYTES","SECRET_HEADER_NAMES","Set","SECRET_KEY_NAMES","SECRET_QUERY_PARAMS","isSecretHeaderName","name","has","toLowerCase","isSecretKeyName","redactUrl","input","includes","u","URL","changed","params","searchParams","keys","forEach","_v","k","push","set","startsWith","toString","pathname","search","hash","cloneAndScrub","value","depth","seen","parentKey","undefined","add","Array","isArray","map","item","out","v","Object","entries","deepClone","globalThis","structuredClone","JSON","parse","stringify","defaultScrubEvent","event","approxSize","length","cloned","scrubbed","WeakSet","url","isProd","proc","globalThis","process","env","NODE_ENV","emit","level","debug","args","fn","console","debugLog","enabled","debugWarn","internalError","message","err","error","randomHex","bytes","arr","Uint8Array","crypto","getRandomValues","i","Math","floor","random","Array","from","b","toString","padStart","join","newTraceId","newSpanId","SpanExporter","queue","timer","FLUSH_MS","MAX_QUEUE","endpoint","projectId","accessKey","debug","transportOpts","start","setInterval","flush","stop","clearInterval","enqueue","span","push","length","batch","splice","postSpans","err","debugWarn","startSpan","exporter","opts","traceId","spanId","startedAt","Date","now","attrs","ended","parentSpanId","setAttr","key","value","end","closeOpts","endedAt","name","kind","status","startTime","toISOString","endTime","durationMs","ID_RE","MAX_ID_LEN","validateEndpoint","endpoint","length","Error","url","URL","slice","isLocalhost","hostname","endsWith","protocol","validateIdentifier","name","value","test","Client","options","listeners","Map","spanExporter","transportOpts","opts","endpoint","warnDefaultEndpoint","validateEndpoint","validateIdentifier","String","projectId","accessKey","fetch","signingSecret","SpanExporter","debug","start","startSpan","flushSpans","flush","stop","applyScrub","event","scrub","err","internalError","defaultScrubEvent","send","attachments","debugLog","kind","outgoing","beforeSend","threw","dropped","id","emit","dryRun","result","Date","now","rateLimitedUntil","sendWithBackoff","error","MAX_RETRIES","BASE_BACKOFF_MS","attempt","lastErr","postEvent","PayloadTooLargeError","debugWarn","message","TransportHttpError","status","cooldown","parseRetryAfter","retryAfter","wait","Math","pow","Promise","r","setTimeout","on","listener","arr","get","push","set","args","l","e","setUser","user","setCustomData","data","customData","warnedDefaultEndpoint","proc","globalThis","process","env","INSTANTTASKS_QUIET","header","sec","Number","isFinite","min","date","parse","ms","RATING_THRESHOLDS","LCP","INP","CLS","FCP","TTFB","rate","name","value","good","poor","randomHexShort","crypto","getRandomValues","a","Uint8Array","Array","from","b","toString","padStart","join","Math","random","slice","buildReport","client","env","options","send","kind","ts","Date","toISOString","release","environment","user","url","location","href","userAgent","navigator","viewport","window","width","innerWidth","height","innerHeight","metric","round","rating","measurementId","now","navigationType","performance","getEntriesByType","type","MetricReporter","hasValue","sent","timer","debounceMs","reportOnHidden","setValue","v","clearTimeout","setTimeout","flush","captureWebVitals","opts","PerformanceObserver","wanted","Set","metrics","reporters","make","r","push","document","onHide","visibilityState","addEventListener","has","safeObserve","entries","lcp","last","length","startTime","e","cls","hadRecentInput","maxInp","duration","durationThreshold","nav","responseStart","cb","extra","po","list","getEntries","observe","buffered","currentClient","currentIntegrations","init","opts","emit","flushSpans","stop","integration","teardown","e","internalError","name","client","Client","integrations","setup","getClient"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@koderlabs/tasks-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "InstantTasks SDK — platform-agnostic event + span client.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"instanttasks",
|
|
7
|
+
"sdk",
|
|
8
|
+
"tracing",
|
|
9
|
+
"errors"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/jawaidgadiwala/instant-tasks/tree/main/packages/sdk#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/jawaidgadiwala/instant-tasks/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/jawaidgadiwala/instant-tasks.git",
|
|
18
|
+
"directory": "packages/sdk"
|
|
19
|
+
},
|
|
20
|
+
"license": "UNLICENSED",
|
|
21
|
+
"author": {
|
|
22
|
+
"name": "Jawaid Gadiwala",
|
|
23
|
+
"email": "jawaidgadiwala@gmail.com",
|
|
24
|
+
"url": "https://koderlabs.com"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.cjs",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js",
|
|
34
|
+
"require": "./dist/index.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"sideEffects": false,
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@koderlabs/tasks-sdk-types": "0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"tsup": "^8.3.0",
|
|
47
|
+
"typescript": "^5.5.0",
|
|
48
|
+
"vitest": "^2.1.0"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "restricted"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup",
|
|
58
|
+
"dev": "tsup --watch",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:watch": "vitest"
|
|
61
|
+
}
|
|
62
|
+
}
|