@tillstack/electron 0.3.0 → 0.4.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/README.md +8 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +206 -51
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +207 -52
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/scrub.ts","../src/index.ts"],"names":["release"],"mappings":"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","file":"index.mjs","sourcesContent":["// On-device PII scrubbing — mirror of the browser/RN/server scrub. Runs over\n// every event before it is queued, so secrets never leave the machine.\n\nconst SCRUB_RULES: Array<{ pattern: RegExp; replacement: string }> = [\n { pattern: /\\bAKIA[0-9A-Z]{16}\\b/g, replacement: '[aws_key]' },\n { pattern: /(?:aws_secret|secret_access_key|AWS_SECRET)[^A-Za-z0-9+/]*([A-Za-z0-9+/]{40})\\b/gi, replacement: '[aws_secret]' },\n { pattern: /\\bAIza[0-9A-Za-z_-]{35}\\b/g, replacement: '[gcp_key]' },\n { pattern: /\\b(?:ghp|gho|ghs|ghr)_[A-Za-z0-9]{36,}\\b/g, replacement: '[github_token]' },\n { pattern: /\\bgithub_pat_[A-Za-z0-9_]{82}\\b/g, replacement: '[github_token]' },\n { pattern: /\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b/g, replacement: '[slack_token]' },\n { pattern: /\\bxapp-\\d-[A-Za-z0-9-]{10,}\\b/g, replacement: '[slack_token]' },\n { pattern: /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, replacement: '[jwt]' },\n { pattern: /Bearer\\s+[A-Za-z0-9\\-._~+/]+=*/gi, replacement: 'Bearer [token]' },\n { pattern: /\\b(?:sk|pk|ak|rk)_(?:live|test)_[A-Za-z0-9]{16,}\\b/g, replacement: '[apikey]' },\n { pattern: /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g, replacement: '[email]' },\n { pattern: /\\b[A-Z0-9]{10}\\b(?=\\s*confirmed|\\s*transaction|\\s*M-?Pesa)/gi, replacement: '[mpesa_tx]' },\n { pattern: /\\b(?:\\d[ -]*?){13,19}\\b/g, replacement: '[card]' },\n { pattern: /\\b\\d{13}\\b/g, replacement: '[id_number]' },\n { pattern: /\\b\\d{11}\\b/g, replacement: '[id_number]' },\n { pattern: /\\+?\\d{1,3}[\\s.-]?\\(?\\d{2,4}\\)?[\\s.-]?\\d{3,4}[\\s.-]?\\d{3,4}\\b/g, replacement: '[phone]' },\n { pattern: /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g, replacement: '[ip]' },\n]\n\nconst SENSITIVE_KEY =\n /^(?:password|passwd|pwd|secret|client[_-]?secret|token|access[_-]?token|refresh[_-]?token|id[_-]?token|api[_-]?key|apikey|authorization|auth|session|cookie|set[_-]?cookie|private[_-]?key|credit[_-]?card|card[_-]?number|cvv|cvc|ssn|pin|otp|mfa|totp)$/i\n\nconst MAX_REDACT_DEPTH = 24\n\nfunction redactByKey(value: unknown, depth = 0): unknown {\n if (depth > MAX_REDACT_DEPTH || value === null || typeof value !== 'object') return value\n if (Array.isArray(value)) return value.map((v) => redactByKey(v, depth + 1))\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = SENSITIVE_KEY.test(k) ? '[redacted]' : redactByKey(v, depth + 1)\n }\n return out\n}\n\nexport function scrubEvent<T>(event: T): T {\n try {\n let json = JSON.stringify(redactByKey(event))\n for (const { pattern, replacement } of SCRUB_RULES) json = json.replace(pattern, replacement)\n return JSON.parse(json) as T\n } catch {\n return event\n }\n}\n","import type { TillPulseEvent, Severity, DeviceContext, Breadcrumb, BreadcrumbType } from '@tillstack/types'\nimport { classifyIngestResponse } from '@tillstack/types'\nimport { app, crashReporter } from 'electron'\nimport * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { scrubEvent } from './scrub'\n\nconst SDK_NAME = '@tillstack/electron'\ndeclare const __SDK_VERSION__: string | undefined\n// Set from package.json at build.\nconst SDK_VERSION = typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev'\n\nexport interface TillPulseElectronOptions {\n dsn: string\n release: string\n environment?: string\n dist?: string\n /** Start Electron's native crashReporter (writes minidumps for C++/V8 crashes the JS layer can't catch). Default true. */\n enableNativeCrashReporter?: boolean\n /** Upload native minidumps to `<dsn-host>/api/v1/minidump`. Default false (dumps kept locally + a metadata event is sent). */\n uploadMinidumps?: boolean\n /** Capture renderer/GPU/child-process-gone as crashes. Default true. */\n enableProcessMonitoring?: boolean\n /** Treat renderer `unresponsive` as an app-hang event. Default true. */\n enableHangDetection?: boolean\n /** Emit session events for crash-free sessions. Default true. */\n enableSessionTracking?: boolean\n /** Opt in to TillShield desktop threat detection (DevTools-open on renderers). Off by default. */\n enableThreatDetection?: boolean\n disableDefaultPiiScrubbing?: boolean\n beforeSend?: (e: TillPulseEvent) => TillPulseEvent | null | Promise<TillPulseEvent | null>\n initialTags?: Record<string, string>\n flushIntervalMs?: number\n debug?: boolean\n}\n\n// ── DSN ──\nfunction parseDsn(dsn: string): { scheme: string; host: string } {\n const m = dsn.match(/^(https?):\\/\\/([^@]+)@([^/]+)\\/(.+)$/)\n if (!m) throw new Error(`TillPulse: invalid DSN: ${dsn}`)\n const scheme = m[1]!\n const host = m[3]!\n const local = /^(localhost|127\\.0\\.0\\.1|::1)(:\\d+)?$/i.test(host)\n if (scheme !== 'https' && !local) {\n throw new Error('TillPulse: DSN must use https:// (refusing to send telemetry over cleartext http)')\n }\n return { scheme, host }\n}\n\nfunction generateId(): string {\n return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`\n}\n\n// ── File-backed queue (survives an app restart after a crash) ──\ninterface QItem { id: string; event_type: string; payload: string; attempts: number; next: number }\n\nclass FileQueue {\n private items: QItem[] = []\n private file: string\n private max = 500\n\n constructor(dir: string) {\n this.file = path.join(dir, 'tillpulse-queue.json')\n try {\n if (fs.existsSync(this.file)) {\n const parsed = JSON.parse(fs.readFileSync(this.file, 'utf8')) as QItem[]\n if (Array.isArray(parsed)) this.items = parsed\n }\n } catch {\n /* corrupt — start clean */\n }\n }\n private persist(): void {\n try {\n fs.writeFileSync(this.file, JSON.stringify(this.items))\n } catch {\n /* non-fatal */\n }\n }\n enqueue(id: string, eventType: string, obj: unknown): void {\n let payload: string\n try {\n payload = JSON.stringify(obj)\n } catch {\n return\n }\n this.items.push({ id, event_type: eventType, payload, attempts: 0, next: 0 })\n if (this.items.length > this.max) this.items = this.items.slice(this.items.length - this.max)\n this.persist()\n }\n due(limit: number): QItem[] {\n const now = Date.now()\n return this.items.filter((i) => i.next <= now).slice(0, limit)\n }\n ackOk(ids: string[]): void {\n const s = new Set(ids)\n this.items = this.items.filter((i) => !s.has(i.id))\n this.persist()\n }\n ackFail(ids: string[]): void {\n const s = new Set(ids)\n const now = Date.now()\n for (const i of this.items) {\n if (!s.has(i.id)) continue\n i.attempts += 1\n i.next = now + Math.min(2000 * 2 ** (i.attempts - 1), 5 * 60_000)\n }\n this.items = this.items.filter((i) => i.attempts <= 10)\n this.persist()\n }\n size(): number {\n return this.items.length\n }\n}\n\nfunction osName(): DeviceContext['os_name'] {\n if (process.platform === 'darwin') return 'macOS'\n if (process.platform === 'win32') return 'Windows'\n return 'Linux'\n}\n\nclass TillPulseElectronSDK {\n private opts: TillPulseElectronOptions | null = null\n private queue: FileQueue | null = null\n private endpoint = ''\n private sessionId = generateId()\n private timer: ReturnType<typeof setInterval> | null = null\n private initialized = false\n private crumbs: Breadcrumb[] = []\n private tags: Record<string, string> = {}\n private user: { id?: string; segment?: string } | null = null\n private sessionStartedAt = 0\n private sessionEnded = false\n\n init(options: TillPulseElectronOptions): void {\n if (this.initialized) return\n let host: string\n let scheme: string\n try {\n ;({ host, scheme } = parseDsn(options.dsn))\n } catch (err) {\n if (options.debug) console.error('[TillPulse]', err)\n return\n }\n this.initialized = true\n this.opts = options\n this.endpoint = `${scheme}://${host}/api/v1/envelope`\n this.tags = { ...options.initialTags }\n\n let dir = '.'\n try {\n dir = app.getPath('userData')\n } catch {\n /* app not ready yet in some flows — cwd fallback */\n }\n this.queue = new FileQueue(dir)\n\n // 1. Native crash reporter — captures C++/V8 minidumps the JS layer can't.\n if (options.enableNativeCrashReporter !== false) {\n try {\n crashReporter.start({\n productName: (() => {\n try {\n return app.getName()\n } catch {\n return 'app'\n }\n })(),\n submitURL: options.uploadMinidumps ? `${scheme}://${host}/api/v1/minidump` : undefined,\n uploadToServer: options.uploadMinidumps === true,\n compress: true,\n globalExtra: { tp_release: options.release, tp_env: options.environment ?? 'production' },\n })\n } catch (err) {\n if (options.debug) console.warn('[TillPulse] crashReporter.start failed:', err)\n }\n }\n\n // 2. Main-process JS crashes.\n process.on('uncaughtException', (...args: unknown[]) => {\n const err = args[0]\n this._captureError(err, 'critical', 'uncaughtException')\n this._markSession('crashed')\n void this.flush(true)\n })\n process.on('unhandledRejection', (...args: unknown[]) => {\n this._captureError(args[0], 'high', 'unhandledRejection')\n })\n\n // 3. Renderer / GPU / child-process crashes + hangs.\n if (options.enableProcessMonitoring !== false) {\n app.on('render-process-gone', (...a: unknown[]) => {\n const details = (a[2] ?? a[1]) as { reason?: string; exitCode?: number } | undefined\n const reason = details?.reason ?? 'unknown'\n const crashed = reason === 'crashed' || reason === 'oom' || reason === 'abnormal-exit'\n this._captureSynthetic('RenderProcessGone', `Renderer process gone: ${reason}`, crashed ? 'critical' : 'medium', {\n reason,\n exit_code: details?.exitCode,\n })\n if (crashed) this._markSession('crashed')\n })\n app.on('child-process-gone', (...a: unknown[]) => {\n const d = a[1] as { type?: string; reason?: string; exitCode?: number } | undefined\n this._captureSynthetic('ChildProcessGone', `Child process (${d?.type}) gone: ${d?.reason}`, 'medium', {\n type: d?.type,\n reason: d?.reason,\n exit_code: d?.exitCode,\n })\n })\n }\n\n if (options.enableHangDetection !== false) {\n app.on('web-contents-created', (...a: unknown[]) => {\n const contents = a[1] as { on(ev: string, cb: (...x: unknown[]) => void): void } | undefined\n if (!contents || typeof contents.on !== 'function') return\n let hangStart = 0\n contents.on('unresponsive', () => {\n hangStart = Date.now()\n this.addBreadcrumb({ type: 'device', category: 'app.hang', level: 'warning', message: 'renderer unresponsive' })\n })\n contents.on('responsive', () => {\n const dur = hangStart ? Date.now() - hangStart : 0\n if (dur > 0) {\n this._captureSynthetic('AppHang', `Renderer was unresponsive for ${dur}ms`, 'medium', { duration_ms: dur })\n }\n hangStart = 0\n })\n })\n }\n\n // 3b. TillShield threat detection — opt-in. DevTools opening on a renderer\n // is a real tamper/inspection signal for a desktop app (e.g. someone poking\n // at your production build). Reported as a security event.\n if (options.enableThreatDetection) {\n app.on('web-contents-created', (...a: unknown[]) => {\n const contents = a[1] as { on(ev: string, cb: (...x: unknown[]) => void): void; getURL?(): string } | undefined\n if (!contents || typeof contents.on !== 'function') return\n contents.on('devtools-opened', () => {\n this.captureSecurityEvent({\n securityType: 'devtools_open',\n severity: 'low',\n confidence: 0.7,\n message: 'DevTools opened on a renderer',\n evidence: { url: typeof contents.getURL === 'function' ? contents.getURL() : undefined },\n })\n })\n })\n }\n\n // 4. Session lifecycle.\n if (options.enableSessionTracking !== false) {\n const start = () => this._startSession()\n try {\n if (app.isReady()) start()\n else void app.whenReady().then(start)\n } catch {\n start()\n }\n app.on('before-quit', () => {\n this._markSession('exited')\n void this.flush(true)\n })\n app.on('window-all-closed', () => this._markSession('exited'))\n }\n\n // 5. Flush loop.\n const flushMs = options.flushIntervalMs ?? 10_000\n this.timer = setInterval(() => void this.flush(), flushMs)\n if (this.timer.unref) this.timer.unref()\n\n if (options.debug) console.log('[TillPulse] electron SDK initialized', { release: options.release })\n }\n\n // ── Public API ──\n captureException(error: unknown): void {\n this._captureError(error, 'high', 'captureException')\n }\n captureMessage(message: string, level: Severity = 'info'): void {\n this._enqueue(this._base('error', level, { exception: { type: 'Message', value: message } }))\n }\n\n // Report a security signal to TillShield (same shape as the other SDKs).\n captureSecurityEvent(input: {\n securityType: string\n severity?: Severity\n confidence?: number\n evidence?: Record<string, unknown>\n message?: string\n }): void {\n this._enqueue(\n this._base('security', input.severity ?? 'high', {\n security_type: input.securityType,\n security_confidence: input.confidence ?? 0.8,\n security_evidence: input.evidence ?? {},\n exception: { type: `security:${input.securityType}`, value: input.message ?? input.securityType },\n }),\n )\n }\n addBreadcrumb(input: { type: BreadcrumbType; category: string; message: string; level?: Breadcrumb['level']; data?: Record<string, unknown> }): void {\n this.crumbs.push({\n type: input.type,\n category: input.category,\n message: input.message,\n level: input.level ?? 'info',\n data: input.data,\n timestamp: new Date().toISOString(),\n })\n if (this.crumbs.length > 100) this.crumbs = this.crumbs.slice(this.crumbs.length - 100)\n }\n setUser(user: { id?: string; segment?: string } | null): void {\n this.user = user\n }\n setTag(key: string, value: string): void {\n this.tags[key] = value\n }\n getQueueStats(): { size: number } {\n return { size: this.queue?.size() ?? 0 }\n }\n\n async flush(useKeepalive = false): Promise<boolean> {\n void useKeepalive\n if (!this.queue || !this.opts) return false\n const items = this.queue.due(50)\n if (items.length === 0) return true\n const lines: string[] = [\n JSON.stringify({ dsn: this.opts.dsn, sdk: { name: SDK_NAME, version: SDK_VERSION }, sent_at: new Date().toISOString() }),\n ]\n const ids: string[] = []\n for (const it of items) {\n lines.push(JSON.stringify({ type: it.event_type, content_type: 'application/json', length: it.payload.length }))\n lines.push(it.payload)\n ids.push(it.id)\n }\n try {\n const res = await fetch(this.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-sentry-envelope', Authorization: `DSN ${this.opts.dsn}` },\n body: lines.join('\\n'),\n })\n // A 4xx only means \"your request was wrong\" when it came from ingest. An\n // intermediary — CDN, proxy, captive portal — can answer 4xx for reasons\n // the payload had nothing to do with, and clearing the batch on that\n // basis loses the events for good. See classifyIngestResponse.\n const verdict = classifyIngestResponse({\n status: res.status,\n contentType: res.headers.get('content-type'),\n })\n if (verdict.disposition === 'retry') {\n this.queue.ackFail(ids)\n return false\n }\n // 'drop' clears the batch too: retrying a DSN ingest has rejected will\n // never succeed, and an unbounded retry would starve live events.\n this.queue.ackOk(ids)\n return true\n } catch {\n this.queue.ackFail(ids)\n return false\n }\n }\n\n close(): void {\n this._markSession('exited')\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n void this.flush(true)\n this.initialized = false\n }\n\n // ── Internals ──\n private _device(): DeviceContext {\n let total = 0\n let free = 0\n let release = ''\n try {\n total = os.totalmem()\n free = os.freemem()\n release = os.release()\n } catch {\n /* ignore */\n }\n return {\n device_model: `Electron ${process.versions['electron'] ?? ''}`.trim(),\n device_manufacturer: process.platform,\n device_family: 'desktop',\n os_name: osName(),\n os_version: release,\n cpu_architecture: process.arch,\n total_ram_mb: total ? Math.round(total / (1024 * 1024)) : undefined,\n available_ram_mb: free ? Math.round(free / (1024 * 1024)) : undefined,\n locale: process.env['LANG'],\n }\n }\n\n private _base(eventType: TillPulseEvent['event_type'], severity: Severity, extra: Partial<TillPulseEvent>): TillPulseEvent {\n const o = this.opts!\n const now = new Date().toISOString()\n const event: TillPulseEvent = {\n event_id: generateId(),\n project_id: '',\n event_type: eventType,\n severity,\n environment: o.environment ?? 'production',\n release_version: o.release,\n dist: o.dist,\n timestamp: now,\n client_timestamp: now,\n breadcrumbs: this.crumbs.slice(),\n device: this._device(),\n network: { network_type: 'unknown' },\n app_state: { app_foreground: true },\n user: { user_id: this.user?.id, user_segment: this.user?.segment, session_id: this.sessionId },\n sdk: { name: SDK_NAME, version: SDK_VERSION },\n ...extra,\n }\n if (Object.keys(this.tags).length) {\n ;(event as TillPulseEvent & { tags?: Record<string, string> }).tags = { ...this.tags }\n }\n // Runtime versions are always useful desktop context.\n ;(event as TillPulseEvent & { extra?: Record<string, unknown> }).extra = {\n chrome: process.versions['chrome'],\n node: process.versions['node'],\n v8: process.versions['v8'],\n }\n return event\n }\n\n private _captureError(thrown: unknown, severity: Severity, mechanism: string): void {\n if (!this.opts) return\n const err = thrown instanceof Error ? thrown : null\n this._enqueue(\n this._base('error', severity, {\n exception: {\n type: err?.name ?? 'Error',\n value: err?.message ?? String(thrown),\n stacktrace: err?.stack ? { frames: parseNodeStack(err.stack) } : undefined,\n },\n fingerprint: `electron:${mechanism}`,\n }),\n )\n }\n\n private _captureSynthetic(type: string, message: string, severity: Severity, data?: Record<string, unknown>): void {\n if (!this.opts) return\n const ev = this._base('error', severity, { exception: { type, value: message } })\n ;(ev as TillPulseEvent & { extra?: Record<string, unknown> }).extra = {\n ...(ev as TillPulseEvent & { extra?: Record<string, unknown> }).extra,\n ...data,\n }\n this._enqueue(ev)\n }\n\n private _startSession(): void {\n this.sessionStartedAt = Date.now()\n this.sessionEnded = false\n this._emitSession('ok')\n }\n private _markSession(status: 'exited' | 'crashed' | 'errored'): void {\n if (this.sessionEnded || this.sessionStartedAt === 0) return\n this.sessionEnded = true\n this._emitSession(status, Date.now() - this.sessionStartedAt)\n }\n private _emitSession(status: 'ok' | 'exited' | 'crashed' | 'errored', durationMs?: number): void {\n if (!this.opts) return\n this._enqueue(this._base('session', 'info', { session_status: status, ...(durationMs !== undefined ? { session_duration_ms: durationMs } : {}) }))\n }\n\n private async _enqueue(event: TillPulseEvent): Promise<void> {\n const o = this.opts\n if (!o || !this.queue) return\n let final: TillPulseEvent | null = event\n if (o.beforeSend) {\n try {\n final = await o.beforeSend(event)\n } catch {\n /* ignore */\n }\n }\n if (!final) return\n if (!o.disableDefaultPiiScrubbing) final = scrubEvent(final)\n this.queue.enqueue(final.event_id, final.event_type, final)\n }\n}\n\n// Minimal V8 stack parser: \" at fn (/abs/file.js:12:34)\" / \" at /abs/file.js:12:34\".\nfunction parseNodeStack(stack: string): Array<{ filename: string; function: string; lineno?: number; colno?: number; in_app: boolean }> {\n const frames: Array<{ filename: string; function: string; lineno?: number; colno?: number; in_app: boolean }> = []\n for (const raw of stack.split('\\n')) {\n const line = raw.trim()\n const m = line.match(/^at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)$/) || line.match(/^at\\s+()(.+?):(\\d+):(\\d+)$/)\n if (!m) continue\n const file = m[2]!\n frames.push({\n filename: file,\n function: m[1] || '<anonymous>',\n lineno: Number(m[3]),\n colno: Number(m[4]),\n in_app: !file.includes('node_modules') && !file.startsWith('node:'),\n })\n }\n return frames\n}\n\nexport const TillPulse = new TillPulseElectronSDK()\nexport default TillPulse\nexport type { TillPulseEvent } from '@tillstack/types'\n"]}
|
|
1
|
+
{"version":3,"sources":["../../scrub-core/src/rules.ts","../../scrub-core/src/scrub.ts","../src/scrub.ts","../src/queue.ts","../src/index.ts"],"names":["scrubEvent","release"],"mappings":"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","file":"index.mjs","sourcesContent":["// @tillstack/scrub-core — the canonical PII scrub rules for the whole suite.\n//\n// This is the SINGLE SOURCE OF TRUTH. The SDK on-device scrubbers\n// (packages/sdk-*/src/scrub.ts), the server \"second line of defence\"\n// (apps/event-processor), and TillArk's clone masker all key off these rules so\n// they can never drift apart. Import-free on purpose: nothing here touches Node,\n// the DOM, or React Native, so any runtime can consume it.\n//\n// Rule order matters: more-specific patterns must run before more-general ones,\n// otherwise a permissive pattern (e.g. phone) consumes the digits a stricter\n// pattern (e.g. card or NIN) was looking for.\n\nexport interface ScrubRule {\n pattern: RegExp\n replacement: string\n /** Stable label for the class of data this rule neutralises (used by the\n * masking planner to classify columns by the shape of their sample values). */\n label: ScrubLabel\n /** Skips UUIDs and hex ids, which would otherwise read as phone or card digits. */\n outsideIds?: true\n}\n\nexport type ScrubLabel =\n | 'private_key'\n | 'aws_key'\n | 'aws_secret'\n | 'gcp_key'\n | 'github_token'\n | 'gitlab_token'\n | 'slack_token'\n | 'webhook_url'\n | 'jwt'\n | 'bearer'\n | 'apikey'\n | 'package_token'\n | 'ai_key'\n | 'service_token'\n | 'tilldev_token'\n | 'db_url'\n | 'email'\n | 'mpesa_tx'\n | 'card'\n | 'id_number'\n | 'phone'\n | 'ip'\n\n/** The kinds of data a policy can decide about; every label belongs to one. */\nexport const DATA_CLASSES = ['credential', 'contact', 'financial', 'government_id', 'network'] as const\nexport type DataClass = (typeof DATA_CLASSES)[number]\n\nexport const LABEL_CLASS: Record<ScrubLabel, DataClass> = {\n private_key: 'credential',\n aws_key: 'credential',\n aws_secret: 'credential',\n gcp_key: 'credential',\n github_token: 'credential',\n gitlab_token: 'credential',\n slack_token: 'credential',\n webhook_url: 'credential',\n jwt: 'credential',\n bearer: 'credential',\n apikey: 'credential',\n package_token: 'credential',\n ai_key: 'credential',\n service_token: 'credential',\n tilldev_token: 'credential',\n db_url: 'credential',\n email: 'contact',\n phone: 'contact',\n mpesa_tx: 'financial',\n card: 'financial',\n id_number: 'government_id',\n ip: 'network',\n}\n\nexport const SCRUB_RULES: ScrubRule[] = [\n // ── Credentials (highest priority — long, distinctive patterns) ──\n\n { label: 'private_key', pattern: /-----BEGIN [A-Z0-9 ]{0,40}PRIVATE KEY(?: BLOCK)?-----(?:[^-\"\\\\]|\\\\[^\"]|-Type|-Info)*(?:-----END [A-Z0-9 ]{0,40}PRIVATE KEY(?: BLOCK)?-----)?/g, replacement: '[private_key]' },\n { label: 'private_key', pattern: /\\bAGE-SECRET-KEY-1[0-9A-Z]{58}/g, replacement: '[private_key]' },\n\n { label: 'aws_key', pattern: /\\b(?:AKIA|ASIA|ABIA|ACCA)[0-9A-Z]{16}\\b/g, replacement: '[aws_key]' },\n // 40-char base64 following common context words\n { label: 'aws_secret', pattern: /(?:aws_secret|secret_access_key|AWS_SECRET)[^A-Za-z0-9+/]*([A-Za-z0-9+/]{40})\\b/gi, replacement: '[aws_secret]' },\n\n { label: 'gcp_key', pattern: /\\bAIza[0-9A-Za-z_-]{35}\\b/g, replacement: '[gcp_key]' },\n { label: 'gcp_key', pattern: /\\bGOCSPX-[0-9A-Za-z_-]{28}/g, replacement: '[gcp_key]' },\n\n { label: 'github_token', pattern: /\\bgh[pousr]_[A-Za-z0-9]{36,}\\b/g, replacement: '[github_token]' },\n { label: 'github_token', pattern: /\\bgithub_pat_[A-Za-z0-9_]{82}\\b/g, replacement: '[github_token]' },\n { label: 'gitlab_token', pattern: /\\bgl(?:pat|rt|ptt|ft|dt|soat|imt|cbt|agent)-[0-9A-Za-z_-]{20,}/g, replacement: '[gitlab_token]' },\n\n { label: 'slack_token', pattern: /\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b/g, replacement: '[slack_token]' },\n { label: 'slack_token', pattern: /\\bxapp-\\d-[A-Za-z0-9-]{10,}\\b/g, replacement: '[slack_token]' },\n { label: 'webhook_url', pattern: /https:\\/\\/hooks\\.slack\\.com\\/services\\/[0-9A-Za-z_/]+/g, replacement: '[webhook_url]' },\n { label: 'webhook_url', pattern: /https:\\/\\/(?:canary\\.|ptb\\.)?discord(?:app)?\\.com\\/api\\/webhooks\\/[0-9]+\\/[0-9A-Za-z_-]+/g, replacement: '[webhook_url]' },\n\n // Three base64url segments separated by dots (eyJ header is canonical)\n { label: 'jwt', pattern: /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, replacement: '[jwt]' },\n\n { label: 'bearer', pattern: /Bearer\\s+[A-Za-z0-9\\-._~+/]+=*/gi, replacement: 'Bearer [token]' },\n { label: 'apikey', pattern: /\\b(?:sk|pk|ak|rk)_(?:live|test)_[A-Za-z0-9]{16,}\\b/g, replacement: '[apikey]' },\n { label: 'apikey', pattern: /\\bwhsec_[0-9A-Za-z]{24,}/g, replacement: '[apikey]' },\n\n { label: 'package_token', pattern: /\\b(?:npm_[0-9A-Za-z]{36}|pypi-[0-9A-Za-z_-]{50,}|rubygems_[0-9a-f]{48}|dckr_pat_[0-9A-Za-z_-]{20,})/g, replacement: '[package_token]' },\n { label: 'ai_key', pattern: /\\b(?:sk-(?:or-v1-[0-9a-f]{64}|ant-[0-9A-Za-z_-]{32,}|proj-[0-9A-Za-z_-]{32,})|hf_[0-9A-Za-z]{34,})/g, replacement: '[ai_key]' },\n { label: 'ai_key', pattern: /\\bsk-[A-Za-z0-9]{48}\\b/g, replacement: '[ai_key]' },\n { label: 'service_token', pattern: /\\b(?:SG\\.[0-9A-Za-z_-]{22}\\.[0-9A-Za-z_-]{43}|do[oprt]_v1_[0-9a-f]{64}|hv[sb]\\.[A-Za-z0-9_-]{24,}|lin_api_[0-9A-Za-z]{40}|shp(?:at|ss|pa|ca)_[0-9a-fA-F]{32}|sntry[su]_[0-9A-Za-z_-]{40,})/g, replacement: '[service_token]' },\n { label: 'tilldev_token', pattern: /\\b(?:(?:tp|tc|ts|ta|tsc|tse|tark|tnot|tfp|tfd|tfr|tfb)_[0-9a-f]{32}\\b|tfn_[0-9a-f]{64}\\b|tg_secret_[0-9a-f]{40}\\b|(?:tausec|tau_rt|tau_sso|tau_ssg|scim)_[A-Za-z0-9_-]{43}|tau_inv_[A-Za-z0-9_-]{38}|tdr_[A-Za-z0-9_-]{32})/g, replacement: '[tilldev_token]' },\n\n // The user and password of a connection string; the host stays.\n { label: 'db_url', pattern: /\\b(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\\+srv)?|rediss?|amqps?):\\/\\/[^:@/\\s\"']*:[^@/\\s\"']+@/g, replacement: '[db_credentials]@' },\n\n // ── Personal data ──\n\n { label: 'email', pattern: /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g, replacement: '[email]' },\n\n // M-Pesa transaction IDs (10 alphanumeric, common Kenyan format)\n { label: 'mpesa_tx', pattern: /\\b[A-Z0-9]{10}\\b(?=\\s*confirmed|\\s*transaction|\\s*M-?Pesa)/gi, replacement: '[mpesa_tx]' },\n\n // 13–19 digits; before phone, which would eat the first 11 digits.\n { label: 'card', pattern: /\\b(?:\\d[ -]*?){13,19}\\b/g, replacement: '[card]', outsideIds: true },\n\n // South African ID (13) and Nigerian NIN / BVN (11); before phone.\n { label: 'id_number', pattern: /\\b\\d{13}\\b/g, replacement: '[id_number]', outsideIds: true },\n { label: 'id_number', pattern: /\\b\\d{11}\\b/g, replacement: '[id_number]', outsideIds: true },\n\n // E.164-ish, 7–15 digits with optional + and separators\n { label: 'phone', pattern: /\\+?\\d{1,3}[\\s.-]?\\(?\\d{2,4}\\)?[\\s.-]?\\d{3,4}[\\s.-]?\\d{3,4}\\b/g, replacement: '[phone]', outsideIds: true },\n\n // IPv6 with at least three groups, so C++ scopes and clock times stay; then IPv4.\n { label: 'ip', pattern: /\\b(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}\\b|\\b(?:[0-9A-Fa-f]{1,4}:){2,6}:[0-9A-Fa-f]{1,4}\\b|\\b[0-9A-Fa-f]{1,4}::(?:[0-9A-Fa-f]{1,4}:){1,5}[0-9A-Fa-f]{1,4}\\b/g, replacement: '[ip]', outsideIds: true },\n { label: 'ip', pattern: /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g, replacement: '[ip]', outsideIds: true },\n]\n\n// Key-name redaction. The value-pattern rules above catch data that *looks*\n// like a secret, but they miss a secret that carries no distinctive shape —\n// e.g. `\"password\": \"correct horse\"` or `\"authorization\": \"opaque\"`. Any value\n// whose key matches a sensitive name is replaced wholesale, regardless of the\n// value's format. Runs before the pattern pass so redacted values don't get\n// double-processed.\nexport const SENSITIVE_KEY =\n /^(?:password|passwd|pwd|secret|client[_-]?secret|token|access[_-]?token|refresh[_-]?token|id[_-]?token|api[_-]?key|apikey|authorization|auth|session|cookie|set[_-]?cookie|private[_-]?key|credit[_-]?card|card[_-]?number|cvv|cvc|ssn|pin|otp|mfa|totp)$/i\n\nexport const ID_TOKEN = /\\b[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\b|\\b[0-9A-Fa-f]{16,}\\b/g\nconst HEX_LETTER = /[A-Fa-f]/\n\n/** Applies one rule; an `outsideIds` rule leaves UUIDs and hex ids (those with a letter) alone. */\nexport function applyRule(rule: ScrubRule, text: string, onHit?: () => void): string {\n const rep = onHit\n ? () => {\n onHit()\n return rule.replacement\n }\n : () => rule.replacement\n if (!rule.outsideIds) return text.replace(rule.pattern, rep)\n let out = ''\n let last = 0\n for (const m of text.matchAll(ID_TOKEN)) {\n if (!HEX_LETTER.test(m[0])) continue\n out += text.slice(last, m.index).replace(rule.pattern, rep) + m[0]\n last = m.index + m[0].length\n }\n return out + text.slice(last).replace(rule.pattern, rep)\n}\n","// @tillstack/scrub-core — free-text / event scrubbing (import-free, portable).\n//\n// `scrubEvent` is the drop-in the SDKs and the event-processor use: it walks an\n// arbitrary object, redacts sensitive KEYS wholesale, then runs the value-pattern\n// rules over the serialised form. It NEVER throws and NEVER drops the event —\n// scrubbing must not be able to lose data — so on any internal failure it returns\n// the input unchanged (which, for the server, is at worst the SDK-already-scrubbed\n// payload). See rules.ts for the canonical rule set.\n\nimport { SCRUB_RULES, SENSITIVE_KEY, applyRule } from './rules.js'\n\nconst MAX_REDACT_DEPTH = 24\n\nfunction redactByKey(value: unknown, depth = 0): unknown {\n if (depth > MAX_REDACT_DEPTH || value === null || typeof value !== 'object') return value\n if (Array.isArray(value)) return value.map((v) => redactByKey(v, depth + 1))\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = SENSITIVE_KEY.test(k) ? '[redacted]' : redactByKey(v, depth + 1)\n }\n return out\n}\n\n/** Scrub PII/secrets from an arbitrary event object. Never throws, never drops. */\nexport function scrubEvent<T>(event: T): T {\n try {\n let json = JSON.stringify(redactByKey(event))\n for (const rule of SCRUB_RULES) json = applyRule(rule, json)\n return JSON.parse(json) as T\n } catch {\n // Scrubbing can never be the reason an event is lost.\n return event\n }\n}\n\n/** Scrub a single free-text string with the value-pattern rules only (no key\n * redaction — there are no keys). Used to mask free-text columns in a clone. */\nexport function scrubText(text: string): string {\n let out = text\n for (const rule of SCRUB_RULES) out = applyRule(rule, out)\n return out\n}\n","// On-device scrub with the suite's shared rules, bundled in at build time.\nimport { scrubEvent as scrub } from '@tillstack/scrub-core'\n\n/** A scrubbed deep copy of `event`; on any failure the input, so an event is never dropped. */\nexport function scrubEvent<T>(event: T): T {\n return scrub(event)\n}\n","import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nexport interface QItem {\n id: string\n event_type: string\n payload: string\n attempts: number\n next: number\n created: number\n}\n\nexport interface Codec {\n encode(plain: string): Buffer\n decode(data: Buffer): string\n}\n\nexport interface KeyWrap {\n wrap(plain: string): Buffer\n unwrap(data: Buffer): string\n}\n\nconst KEY_FILE = 'tillpulse-queue.key'\nconst AAD = Buffer.from('tillpulse.queue.v1')\nconst VERSION = 1\n\n/** AES-256-GCM over the queue; the OS key store (via `kw`) protects only the data key. */\nexport function gcmCodec(dir: string, kw: KeyWrap): Codec {\n let key: Buffer | null = null\n const keyFile = path.join(dir, KEY_FILE)\n const load = (): Buffer => {\n if (key) return key\n try {\n const k = Buffer.from(kw.unwrap(fs.readFileSync(keyFile)), 'base64')\n if (k.length === 32) return (key = k)\n } catch {}\n const fresh = randomBytes(32)\n const tmp = `${keyFile}.${process.pid}.tmp`\n fs.writeFileSync(tmp, kw.wrap(fresh.toString('base64')), { mode: 0o600 })\n fs.renameSync(tmp, keyFile)\n return (key = fresh)\n }\n return {\n encode(plain) {\n const iv = randomBytes(12)\n const c = createCipheriv('aes-256-gcm', load(), iv)\n c.setAAD(AAD)\n const ct = Buffer.concat([c.update(plain, 'utf8'), c.final()])\n return Buffer.concat([Buffer.from([VERSION]), iv, ct, c.getAuthTag()])\n },\n decode(data) {\n if (data.length < 29 || data[0] !== VERSION) throw new Error('bad blob')\n const d = createDecipheriv('aes-256-gcm', load(), data.subarray(1, 13))\n d.setAAD(AAD)\n d.setAuthTag(data.subarray(data.length - 16))\n return Buffer.concat([d.update(data.subarray(13, data.length - 16)), d.final()]).toString('utf8')\n },\n }\n}\n\nconst FILE = 'tillpulse-queue.bin'\nconst LEGACY_FILE = 'tillpulse-queue.json'\nconst MAX_ITEMS = 500\nconst MAX_AGE_MS = 24 * 60 * 60 * 1000\nconst LEASE_MS = 20_000\n\nexport class FileQueue {\n private items: QItem[] = []\n private codec: Codec | null = null\n private dir: string | null = null\n onTamper: (() => void) | null = null\n\n attach(dir: string, codec: Codec | null): void {\n this.dir = dir\n this.codec = codec\n const now = Date.now()\n const legacy = path.join(dir, LEGACY_FILE)\n try {\n if (fs.existsSync(legacy)) {\n this.adopt(JSON.parse(fs.readFileSync(legacy, 'utf8')), now)\n fs.rmSync(legacy, { force: true })\n }\n } catch {\n fs.rmSync(legacy, { force: true })\n }\n const file = path.join(dir, FILE)\n if (codec && fs.existsSync(file)) {\n try {\n this.adopt(JSON.parse(codec.decode(fs.readFileSync(file))), now)\n } catch {\n fs.rmSync(file, { force: true })\n this.onTamper?.()\n }\n } else if (!codec) {\n fs.rmSync(file, { force: true })\n }\n this.persist()\n }\n\n private adopt(list: unknown, now: number): void {\n if (!Array.isArray(list)) return\n const known = new Set(this.items.map((i) => i.id))\n for (const raw of list as Partial<QItem>[]) {\n if (!raw || typeof raw.id !== 'string' || typeof raw.payload !== 'string' || typeof raw.event_type !== 'string') continue\n if (known.has(raw.id)) continue\n const created = typeof raw.created === 'number' ? raw.created : now\n if (now - created > MAX_AGE_MS) continue\n this.items.push({ id: raw.id, event_type: raw.event_type, payload: raw.payload, attempts: Number(raw.attempts) || 0, next: 0, created })\n }\n if (this.items.length > MAX_ITEMS) this.items = this.items.slice(this.items.length - MAX_ITEMS)\n }\n\n private persist(): void {\n if (!this.dir || !this.codec) return\n const file = path.join(this.dir, FILE)\n try {\n if (this.items.length === 0) {\n fs.rmSync(file, { force: true })\n return\n }\n const tmp = `${file}.${process.pid}.tmp`\n fs.writeFileSync(tmp, this.codec.encode(JSON.stringify(this.items)), { mode: 0o600 })\n fs.renameSync(tmp, file)\n } catch {}\n }\n\n enqueue(id: string, eventType: string, obj: unknown): void {\n let payload: string\n try {\n payload = JSON.stringify(obj)\n } catch {\n return\n }\n const now = Date.now()\n this.items.push({ id, event_type: eventType, payload, attempts: 0, next: 0, created: now })\n if (this.items.length > MAX_ITEMS) this.items = this.items.slice(this.items.length - MAX_ITEMS)\n this.persist()\n }\n\n due(limit: number): QItem[] {\n const now = Date.now()\n this.items = this.items.filter((i) => now - i.created <= MAX_AGE_MS)\n const out = this.items.filter((i) => i.next <= now).slice(0, limit)\n for (const i of out) i.next = now + LEASE_MS\n return out\n }\n\n ackOk(ids: string[]): void {\n const s = new Set(ids)\n this.items = this.items.filter((i) => !s.has(i.id))\n this.persist()\n }\n\n ackFail(ids: string[]): void {\n const s = new Set(ids)\n const now = Date.now()\n for (const i of this.items) {\n if (!s.has(i.id)) continue\n i.attempts += 1\n i.next = now + Math.min(2000 * 2 ** (i.attempts - 1), 5 * 60_000)\n }\n this.items = this.items.filter((i) => i.attempts <= 10)\n this.persist()\n }\n\n clear(): void {\n this.items = []\n if (this.dir) {\n fs.rmSync(path.join(this.dir, FILE), { force: true })\n fs.rmSync(path.join(this.dir, LEGACY_FILE), { force: true })\n }\n }\n\n size(): number {\n return this.items.length\n }\n}\n","import type { TillPulseEvent, Severity, DeviceContext, Breadcrumb, BreadcrumbType } from '@tillstack/types'\nimport { classifyIngestResponse } from '@tillstack/types'\nimport { app, crashReporter, safeStorage } from 'electron'\nimport * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { scrubEvent } from './scrub'\nimport { FileQueue, gcmCodec, type Codec } from './queue'\n\nconst SDK_NAME = '@tillstack/electron'\ndeclare const __SDK_VERSION__: string | undefined\nconst SDK_VERSION = typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev'\n\nexport interface TillPulseElectronOptions {\n dsn: string\n release: string\n environment?: string\n dist?: string\n /** Start Electron's native crashReporter (writes minidumps for C++/V8 crashes the JS layer can't catch). Default true. */\n enableNativeCrashReporter?: boolean\n /** Upload native minidumps to `<dsn-host>/api/v1/minidump`. Default false (dumps kept locally + a metadata event is sent). */\n uploadMinidumps?: boolean\n /** Capture renderer/GPU/child-process-gone as crashes. Default true. */\n enableProcessMonitoring?: boolean\n /** Treat renderer `unresponsive` as an app-hang event. Default true. */\n enableHangDetection?: boolean\n /** Emit session events for crash-free sessions. Default true. */\n enableSessionTracking?: boolean\n /** Opt in to TillShield desktop threat detection (DevTools-open on renderers). Off by default. */\n enableThreatDetection?: boolean\n disableDefaultPiiScrubbing?: boolean\n /** Keep the offline queue on disk unencrypted where the OS offers no keychain (Linux without a secret store). Default false: memory only. */\n allowPlaintextQueue?: boolean\n beforeSend?: (e: TillPulseEvent) => TillPulseEvent | null | Promise<TillPulseEvent | null>\n initialTags?: Record<string, string>\n flushIntervalMs?: number\n debug?: boolean\n}\n\nfunction parseDsn(dsn: string): { scheme: string; host: string } {\n const m = dsn.match(/^(https?):\\/\\/([^@]+)@([^/]+)\\/(.+)$/)\n if (!m) throw new Error(`TillPulse: invalid DSN: ${dsn}`)\n const scheme = m[1]!\n const host = m[3]!\n const local = /^(localhost|127\\.0\\.0\\.1|::1)(:\\d+)?$/i.test(host)\n if (scheme !== 'https' && !local) {\n throw new Error('TillPulse: DSN must use https:// (refusing to send telemetry over cleartext http)')\n }\n return { scheme, host }\n}\n\nfunction generateId(): string {\n return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`\n}\n\nfunction osCodec(dir: string, allowPlaintext: boolean): Codec | null {\n try {\n const backend = process.platform === 'linux' ? safeStorage.getSelectedStorageBackend?.() : undefined\n if (safeStorage.isEncryptionAvailable() && backend !== 'basic_text' && backend !== 'unknown') {\n return gcmCodec(dir, { wrap: (t) => safeStorage.encryptString(t), unwrap: (b) => safeStorage.decryptString(b) })\n }\n } catch {}\n return allowPlaintext ? { encode: (t) => Buffer.from(t, 'utf8'), decode: (b) => b.toString('utf8') } : null\n}\n\nfunction osName(): DeviceContext['os_name'] {\n if (process.platform === 'darwin') return 'macOS'\n if (process.platform === 'win32') return 'Windows'\n return 'Linux'\n}\n\nclass TillPulseElectronSDK {\n private opts: TillPulseElectronOptions | null = null\n private queue: FileQueue | null = null\n private endpoint = ''\n private sessionId = generateId()\n private timer: ReturnType<typeof setInterval> | null = null\n private initialized = false\n private crumbs: Breadcrumb[] = []\n private tags: Record<string, string> = {}\n private user: { id?: string; segment?: string } | null = null\n private sessionStartedAt = 0\n private sessionEnded = false\n\n init(options: TillPulseElectronOptions): void {\n if (this.initialized) return\n let host: string\n let scheme: string\n try {\n ;({ host, scheme } = parseDsn(options.dsn))\n } catch (err) {\n if (options.debug) console.error('[TillPulse]', err)\n return\n }\n this.initialized = true\n this.opts = options\n this.endpoint = `${scheme}://${host}/api/v1/envelope`\n this.tags = { ...options.initialTags }\n\n let dir = '.'\n try {\n dir = app.getPath('userData')\n } catch {\n /* app not ready yet in some flows — cwd fallback */\n }\n this.queue = new FileQueue()\n this.queue.onTamper = () => {\n if (!this.opts?.enableThreatDetection) return\n this.captureSecurityEvent({\n securityType: 'storage_tamper',\n severity: 'medium',\n confidence: 0.6,\n message: 'Stored TillPulse events failed their integrity check and were discarded',\n })\n }\n const attach = () => this.queue?.attach(dir, osCodec(dir, options.allowPlaintextQueue === true))\n if (app.isReady()) attach()\n else void app.whenReady().then(attach)\n\n if (options.enableNativeCrashReporter !== false) {\n try {\n crashReporter.start({\n productName: (() => {\n try {\n return app.getName()\n } catch {\n return 'app'\n }\n })(),\n submitURL: options.uploadMinidumps ? `${scheme}://${host}/api/v1/minidump` : undefined,\n uploadToServer: options.uploadMinidumps === true,\n compress: true,\n globalExtra: { tp_release: options.release, tp_env: options.environment ?? 'production' },\n })\n } catch (err) {\n if (options.debug) console.warn('[TillPulse] crashReporter.start failed:', err)\n }\n }\n\n process.on('uncaughtException', (...args: unknown[]) => {\n const err = args[0]\n this._captureError(err, 'critical', 'uncaughtException')\n this._markSession('crashed')\n void this.flush(true)\n })\n process.on('unhandledRejection', (...args: unknown[]) => {\n this._captureError(args[0], 'high', 'unhandledRejection')\n })\n\n if (options.enableProcessMonitoring !== false) {\n app.on('render-process-gone', (...a: unknown[]) => {\n const details = (a[2] ?? a[1]) as { reason?: string; exitCode?: number } | undefined\n const reason = details?.reason ?? 'unknown'\n const crashed = reason === 'crashed' || reason === 'oom' || reason === 'abnormal-exit'\n this._captureSynthetic('RenderProcessGone', `Renderer process gone: ${reason}`, crashed ? 'critical' : 'medium', {\n reason,\n exit_code: details?.exitCode,\n })\n if (crashed) this._markSession('crashed')\n })\n app.on('child-process-gone', (...a: unknown[]) => {\n const d = a[1] as { type?: string; reason?: string; exitCode?: number } | undefined\n this._captureSynthetic('ChildProcessGone', `Child process (${d?.type}) gone: ${d?.reason}`, 'medium', {\n type: d?.type,\n reason: d?.reason,\n exit_code: d?.exitCode,\n })\n })\n }\n\n if (options.enableHangDetection !== false) {\n app.on('web-contents-created', (...a: unknown[]) => {\n const contents = a[1] as { on(ev: string, cb: (...x: unknown[]) => void): void } | undefined\n if (!contents || typeof contents.on !== 'function') return\n let hangStart = 0\n contents.on('unresponsive', () => {\n hangStart = Date.now()\n this.addBreadcrumb({ type: 'device', category: 'app.hang', level: 'warning', message: 'renderer unresponsive' })\n })\n contents.on('responsive', () => {\n const dur = hangStart ? Date.now() - hangStart : 0\n if (dur > 0) {\n this._captureSynthetic('AppHang', `Renderer was unresponsive for ${dur}ms`, 'medium', { duration_ms: dur })\n }\n hangStart = 0\n })\n })\n }\n\n if (options.enableThreatDetection) {\n app.on('web-contents-created', (...a: unknown[]) => {\n const contents = a[1] as { on(ev: string, cb: (...x: unknown[]) => void): void; getURL?(): string } | undefined\n if (!contents || typeof contents.on !== 'function') return\n contents.on('devtools-opened', () => {\n this.captureSecurityEvent({\n securityType: 'devtools_open',\n severity: 'low',\n confidence: 0.7,\n message: 'DevTools opened on a renderer',\n evidence: { url: typeof contents.getURL === 'function' ? contents.getURL() : undefined },\n })\n })\n })\n }\n\n if (options.enableSessionTracking !== false) {\n const start = () => this._startSession()\n try {\n if (app.isReady()) start()\n else void app.whenReady().then(start)\n } catch {\n start()\n }\n app.on('before-quit', () => {\n this._markSession('exited')\n void this.flush(true)\n })\n app.on('window-all-closed', () => this._markSession('exited'))\n }\n\n const flushMs = options.flushIntervalMs ?? 10_000\n this.timer = setInterval(() => void this.flush(), flushMs)\n if (this.timer.unref) this.timer.unref()\n\n if (options.debug) console.log('[TillPulse] electron SDK initialized', { release: options.release })\n }\n\n captureException(error: unknown): void {\n this._captureError(error, 'high', 'captureException')\n }\n captureMessage(message: string, level: Severity = 'info'): void {\n this._enqueue(this._base('error', level, { exception: { type: 'Message', value: message } }))\n }\n\n captureSecurityEvent(input: {\n securityType: string\n severity?: Severity\n confidence?: number\n evidence?: Record<string, unknown>\n message?: string\n }): void {\n this._enqueue(\n this._base('security', input.severity ?? 'high', {\n security_type: input.securityType,\n security_confidence: input.confidence ?? 0.8,\n security_evidence: input.evidence ?? {},\n exception: { type: `security:${input.securityType}`, value: input.message ?? input.securityType },\n }),\n )\n }\n addBreadcrumb(input: { type: BreadcrumbType; category: string; message: string; level?: Breadcrumb['level']; data?: Record<string, unknown> }): void {\n this.crumbs.push({\n type: input.type,\n category: input.category,\n message: input.message,\n level: input.level ?? 'info',\n data: input.data,\n timestamp: new Date().toISOString(),\n })\n if (this.crumbs.length > 100) this.crumbs = this.crumbs.slice(this.crumbs.length - 100)\n }\n setUser(user: { id?: string; segment?: string } | null): void {\n this.user = user\n }\n setTag(key: string, value: string): void {\n this.tags[key] = value\n }\n getQueueStats(): { size: number } {\n return { size: this.queue?.size() ?? 0 }\n }\n clearQueue(): void {\n this.queue?.clear()\n }\n\n async flush(useKeepalive = false): Promise<boolean> {\n void useKeepalive\n if (!this.queue || !this.opts) return false\n const items = this.queue.due(50)\n if (items.length === 0) return true\n const lines: string[] = [\n JSON.stringify({ dsn: this.opts.dsn, sdk: { name: SDK_NAME, version: SDK_VERSION }, sent_at: new Date().toISOString() }),\n ]\n const ids: string[] = []\n for (const it of items) {\n lines.push(JSON.stringify({ type: it.event_type, content_type: 'application/json', length: it.payload.length }))\n lines.push(it.payload)\n ids.push(it.id)\n }\n try {\n const res = await fetch(this.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-sentry-envelope', Authorization: `DSN ${this.opts.dsn}` },\n body: lines.join('\\n'),\n })\n const verdict = classifyIngestResponse({\n status: res.status,\n contentType: res.headers.get('content-type'),\n })\n if (verdict.disposition === 'retry') {\n this.queue.ackFail(ids)\n return false\n }\n this.queue.ackOk(ids)\n return true\n } catch {\n this.queue.ackFail(ids)\n return false\n }\n }\n\n close(): void {\n this._markSession('exited')\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n void this.flush(true)\n this.initialized = false\n }\n\n private _device(): DeviceContext {\n let total = 0\n let free = 0\n let release = ''\n try {\n total = os.totalmem()\n free = os.freemem()\n release = os.release()\n } catch {\n /* ignore */\n }\n return {\n device_model: `Electron ${process.versions['electron'] ?? ''}`.trim(),\n device_manufacturer: process.platform,\n device_family: 'desktop',\n os_name: osName(),\n os_version: release,\n cpu_architecture: process.arch,\n total_ram_mb: total ? Math.round(total / (1024 * 1024)) : undefined,\n available_ram_mb: free ? Math.round(free / (1024 * 1024)) : undefined,\n locale: process.env['LANG'],\n }\n }\n\n private _base(eventType: TillPulseEvent['event_type'], severity: Severity, extra: Partial<TillPulseEvent>): TillPulseEvent {\n const o = this.opts!\n const now = new Date().toISOString()\n const event: TillPulseEvent = {\n event_id: generateId(),\n project_id: '',\n event_type: eventType,\n severity,\n environment: o.environment ?? 'production',\n release_version: o.release,\n dist: o.dist,\n timestamp: now,\n client_timestamp: now,\n breadcrumbs: this.crumbs.slice(),\n device: this._device(),\n network: { network_type: 'unknown' },\n app_state: { app_foreground: true },\n user: { user_id: this.user?.id, user_segment: this.user?.segment, session_id: this.sessionId },\n sdk: { name: SDK_NAME, version: SDK_VERSION },\n ...extra,\n }\n if (Object.keys(this.tags).length) {\n ;(event as TillPulseEvent & { tags?: Record<string, string> }).tags = { ...this.tags }\n }\n ;(event as TillPulseEvent & { extra?: Record<string, unknown> }).extra = {\n chrome: process.versions['chrome'],\n node: process.versions['node'],\n v8: process.versions['v8'],\n }\n return event\n }\n\n private _captureError(thrown: unknown, severity: Severity, mechanism: string): void {\n if (!this.opts) return\n const err = thrown instanceof Error ? thrown : null\n this._enqueue(\n this._base('error', severity, {\n exception: {\n type: err?.name ?? 'Error',\n value: err?.message ?? String(thrown),\n stacktrace: err?.stack ? { frames: parseNodeStack(err.stack) } : undefined,\n },\n fingerprint: `electron:${mechanism}`,\n }),\n )\n }\n\n private _captureSynthetic(type: string, message: string, severity: Severity, data?: Record<string, unknown>): void {\n if (!this.opts) return\n const ev = this._base('error', severity, { exception: { type, value: message } })\n ;(ev as TillPulseEvent & { extra?: Record<string, unknown> }).extra = {\n ...(ev as TillPulseEvent & { extra?: Record<string, unknown> }).extra,\n ...data,\n }\n this._enqueue(ev)\n }\n\n private _startSession(): void {\n this.sessionStartedAt = Date.now()\n this.sessionEnded = false\n this._emitSession('ok')\n }\n private _markSession(status: 'exited' | 'crashed' | 'errored'): void {\n if (this.sessionEnded || this.sessionStartedAt === 0) return\n this.sessionEnded = true\n this._emitSession(status, Date.now() - this.sessionStartedAt)\n }\n private _emitSession(status: 'ok' | 'exited' | 'crashed' | 'errored', durationMs?: number): void {\n if (!this.opts) return\n this._enqueue(this._base('session', 'info', { session_status: status, ...(durationMs !== undefined ? { session_duration_ms: durationMs } : {}) }))\n }\n\n private async _enqueue(event: TillPulseEvent): Promise<void> {\n const o = this.opts\n if (!o || !this.queue) return\n let final: TillPulseEvent | null = event\n if (o.beforeSend) {\n try {\n final = await o.beforeSend(event)\n } catch {\n /* ignore */\n }\n }\n if (!final) return\n if (!o.disableDefaultPiiScrubbing) final = scrubEvent(final)\n this.queue.enqueue(final.event_id, final.event_type, final)\n }\n}\n\nfunction parseNodeStack(stack: string): Array<{ filename: string; function: string; lineno?: number; colno?: number; in_app: boolean }> {\n const frames: Array<{ filename: string; function: string; lineno?: number; colno?: number; in_app: boolean }> = []\n for (const raw of stack.split('\\n')) {\n const line = raw.trim()\n const m = line.match(/^at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)$/) || line.match(/^at\\s+()(.+?):(\\d+):(\\d+)$/)\n if (!m) continue\n const file = m[2]!\n frames.push({\n filename: file,\n function: m[1] || '<anonymous>',\n lineno: Number(m[3]),\n colno: Number(m[4]),\n in_app: !file.includes('node_modules') && !file.startsWith('node:'),\n })\n }\n return frames\n}\n\nexport const TillPulse = new TillPulseElectronSDK()\nexport default TillPulse\nexport type { TillPulseEvent } from '@tillstack/types'\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tillstack/electron",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "TillPulse observability SDK for Electron — main-process crashes, renderer-gone, hangs, native minidumps, crash-free sessions",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -32,8 +32,10 @@
|
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^20.0.0",
|
|
34
34
|
"electron": "^30.0.0",
|
|
35
|
+
"tsx": "^4.19.2",
|
|
35
36
|
"tsup": "^8.5.1",
|
|
36
|
-
"typescript": "^5.7.3"
|
|
37
|
+
"typescript": "^5.7.3",
|
|
38
|
+
"@tillstack/scrub-core": "0.1.0"
|
|
37
39
|
},
|
|
38
40
|
"license": "Apache-2.0",
|
|
39
41
|
"repository": {
|
|
@@ -59,6 +61,7 @@
|
|
|
59
61
|
"scripts": {
|
|
60
62
|
"build": "tsup",
|
|
61
63
|
"dev": "tsup --watch",
|
|
64
|
+
"test": "node --import tsx --test test/*.test.ts",
|
|
62
65
|
"typecheck": "tsc --noEmit",
|
|
63
66
|
"clean": "rm -rf dist"
|
|
64
67
|
}
|