@kenkaiiii/gg-pixel 4.3.65 → 4.3.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +7 -3
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +48 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +48 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/browser.js
CHANGED
|
@@ -149,9 +149,12 @@ var EventQueue = class {
|
|
|
149
149
|
await this.sink.emit(event);
|
|
150
150
|
this.buffer.shift();
|
|
151
151
|
attempt = 0;
|
|
152
|
-
} catch {
|
|
152
|
+
} catch (err) {
|
|
153
153
|
attempt++;
|
|
154
154
|
if (attempt >= 5) {
|
|
155
|
+
console.warn(
|
|
156
|
+
`[gg-pixel] dropping event after 5 failed deliveries: ${err instanceof Error ? err.message : String(err)}`
|
|
157
|
+
);
|
|
155
158
|
this.buffer.shift();
|
|
156
159
|
attempt = 0;
|
|
157
160
|
continue;
|
|
@@ -313,9 +316,10 @@ function uuid() {
|
|
|
313
316
|
|
|
314
317
|
// src/core/sinks/http.ts
|
|
315
318
|
var HttpSink = class {
|
|
316
|
-
constructor(ingestUrl, fetchFn
|
|
319
|
+
constructor(ingestUrl, fetchFn) {
|
|
317
320
|
this.ingestUrl = ingestUrl;
|
|
318
|
-
this
|
|
321
|
+
__publicField(this, "fetchFn");
|
|
322
|
+
this.fetchFn = fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
319
323
|
}
|
|
320
324
|
async emit(event) {
|
|
321
325
|
const body = JSON.stringify(event);
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/stack-web.ts","../src/core/fingerprint-web.ts","../src/core/queue.ts","../src/adapters/browser.ts","../src/core/sinks/http.ts","../src/browser.ts"],"sourcesContent":["import type { StackFrame } from \"./types.js\";\n\n/**\n * Cross-browser stack-trace parser.\n *\n * Browser stack formats differ wildly. We support two — that covers\n * Chrome/Edge/Safari (V8-shaped) and Firefox (Gecko-shaped). Real-world\n * coverage cited by Sentry's parsers in `packages/browser/src/stack-parsers.ts`.\n */\n\n// Chrome / V8 / Edge / modern Safari. Examples:\n// \" at fnName (https://app.com/main.js:42:13)\"\n// \" at https://app.com/main.js:42:13\"\n// \" at fnName (eval at <anonymous> (https://x/y.js:1:1), <anonymous>:1:5)\"\nconst CHROME_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+))(?:\\))?\\s*$/;\n\n// Firefox / Gecko. Examples:\n// \"fnName@https://app.com/main.js:42:13\"\n// \"@https://app.com/main.js:42:13\"\nconst GECKO_FRAME = /^\\s*(.*?)@(.+?):(\\d+)(?::(\\d+))?\\s*$/;\n\nexport function parseBrowserStack(stack: string | undefined, sameOrigin?: string): StackFrame[] {\n if (!stack) return [];\n const frames: StackFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n // Skip the leading \"TypeError: x\" header line — no `at` prefix and no `@`.\n if (!/^(?:at\\s|.*@)/.test(trimmed)) continue;\n\n const chrome = CHROME_FRAME.exec(line);\n if (chrome) {\n const fn = (chrome[1] ?? \"\").trim() || \"<anon>\";\n const file = chrome[2];\n if (!file) continue;\n frames.push({\n fn,\n file,\n line: Number(chrome[3]),\n col: Number(chrome[4]),\n in_app: isInApp(file, sameOrigin),\n });\n continue;\n }\n\n const gecko = GECKO_FRAME.exec(line);\n if (gecko) {\n const fn = (gecko[1] ?? \"\").trim() || \"<anon>\";\n const file = gecko[2];\n if (!file) continue;\n frames.push({\n fn,\n file,\n line: Number(gecko[3]),\n col: gecko[4] ? Number(gecko[4]) : 0,\n in_app: isInApp(file, sameOrigin),\n });\n }\n }\n return frames;\n}\n\n/**\n * Mark a frame as in-app when its URL matches the page's origin (or other\n * provided origin). Cross-origin scripts (CDN bundles, third-party widgets,\n * browser extensions) are framework/library noise — not the user's code.\n */\nfunction isInApp(file: string, sameOrigin?: string): boolean {\n if (!file) return false;\n // Browser-extension and inline-eval frames — never user code.\n if (/^chrome-extension:\\/\\//.test(file)) return false;\n if (/^moz-extension:\\/\\//.test(file)) return false;\n if (/^safari-extension:\\/\\//.test(file)) return false;\n if (/^webkit-masked-url:\\/\\//.test(file)) return false;\n if (file === \"<anonymous>\" || file === \"[native code]\") return false;\n\n if (!sameOrigin) {\n // No origin context — best-effort: any http(s) URL counts as in_app\n // unless we can prove otherwise.\n return /^https?:\\/\\//.test(file) || /^[a-z]+:\\/\\//.test(file) === false;\n }\n\n try {\n const url = new URL(file, sameOrigin);\n return url.origin === sameOrigin;\n } catch {\n return false;\n }\n}\n","import type { StackFrame } from \"./types.js\";\n\n/**\n * Browser-safe synchronous fingerprint.\n *\n * `node:crypto` doesn't exist in browsers, and Web Crypto's `subtle.digest`\n * is async — making the queue async would break the fast-path. Sentry's\n * browser SDK uses simple sync hashing for the same reason. Our fingerprint\n * just needs to be stable for the same inputs; cryptographic strength isn't\n * required.\n *\n * Implementation: FNV-1a 64-bit. Fast, sync, ~1KB. Output as 16-char hex.\n */\nexport function fingerprintWeb(type: string, stack: StackFrame[]): string {\n const top = stack[0];\n const normalized = top\n ? `${type}|${normalizeFile(top.file)}|${top.fn || \"<anon>\"}|${top.line}`\n : `${type}|<no-stack>`;\n return fnv1a64(normalized);\n}\n\n/** FNV-1a 64-bit hash. Returns 16-char lowercase hex. */\nexport function fnv1a64(input: string): string {\n // 64-bit math via two 32-bit halves, since JS doesn't have native u64.\n // Constants from the FNV-1a spec.\n let hHi = 0xcbf29ce4;\n let hLo = 0x84222325;\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n hLo ^= code & 0xff;\n if (input.charCodeAt(i) > 0xff) hHi ^= (code >>> 8) & 0xff;\n\n // h = h * 0x100000001b3 (FNV prime), as 64-bit math:\n // The prime split into hi/lo 32-bit parts is { 0x100, 0x000001b3 }.\n const lo16 = hLo & 0xffff;\n const lo32 = (hLo >>> 16) & 0xffff;\n const hi16 = hHi & 0xffff;\n const hi32 = (hHi >>> 16) & 0xffff;\n\n let nLo = lo16 * 0x1b3;\n let nMid = lo32 * 0x1b3 + ((nLo >>> 16) & 0xffff);\n let nHi = hi16 * 0x1b3 + ((nMid >>> 16) & 0xffff);\n let nTop = hi32 * 0x1b3 + ((nHi >>> 16) & 0xffff);\n\n nLo += lo16 * 0; // *= 0x100... carry from low parts\n nMid += lo32 * 0;\n nHi += hi16 * 0;\n nTop += hi32 * 0;\n\n // Add the * 0x1_00000000_00 portion (lo16 << 32).\n nHi += lo16;\n nTop += lo32 + ((nHi >>> 16) & 0xffff);\n\n hLo = (((nMid & 0xffff) << 16) | (nLo & 0xffff)) >>> 0;\n hHi = (((nTop & 0xffff) << 16) | (nHi & 0xffff)) >>> 0;\n }\n\n return toHex32(hHi) + toHex32(hLo);\n}\n\nfunction toHex32(n: number): string {\n return (n >>> 0).toString(16).padStart(8, \"0\");\n}\n\nfunction normalizeFile(file: string): string {\n return file.replace(/\\?.*$/, \"\").replace(/#.*$/, \"\");\n}\n","import type { Sink, WireEvent } from \"./types.js\";\n\nconst MAX_BUFFER = 100;\nconst BASE_DELAY_MS = 200;\nconst MAX_DELAY_MS = 5_000;\n\nexport class EventQueue {\n private readonly buffer: WireEvent[] = [];\n private draining = false;\n private closed = false;\n\n constructor(private readonly sink: Sink) {}\n\n enqueue(event: WireEvent): void {\n if (this.closed) return;\n if (this.buffer.length >= MAX_BUFFER) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n void this.drain();\n }\n\n enqueueSync(event: WireEvent): void {\n if (this.closed) return;\n if (this.sink.emitSync) {\n try {\n this.sink.emitSync(event);\n return;\n } catch {\n // fall through to async path\n }\n }\n this.enqueue(event);\n }\n\n async flush(): Promise<void> {\n while (this.buffer.length > 0 || this.draining) {\n await new Promise((r) => setTimeout(r, 10));\n }\n }\n\n async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n if (this.sink.close) await this.sink.close();\n }\n\n private async drain(): Promise<void> {\n if (this.draining) return;\n this.draining = true;\n let attempt = 0;\n while (this.buffer.length > 0) {\n const event = this.buffer[0];\n try {\n await this.sink.emit(event);\n this.buffer.shift();\n attempt = 0;\n } catch {\n attempt++;\n if (attempt >= 5) {\n this.buffer.shift();\n attempt = 0;\n continue;\n }\n const delay = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n this.draining = false;\n }\n}\n","import { parseBrowserStack } from \"../core/stack-web.js\";\nimport { fingerprintWeb } from \"../core/fingerprint-web.js\";\nimport { EventQueue } from \"../core/queue.js\";\nimport type { Level, ReportInput, Sink, WireEvent } from \"../core/types.js\";\n\ndeclare global {\n interface Window {\n onerror:\n | ((\n message: string | Event,\n source?: string,\n lineno?: number,\n colno?: number,\n error?: Error,\n ) => boolean | void)\n | null;\n onunhandledrejection: ((event: PromiseRejectionEvent) => boolean | void) | null;\n }\n}\n\nexport interface BrowserAdapterOptions {\n projectKey: string;\n runtime: string;\n sink: Sink;\n captureConsoleErrors: boolean;\n captureConsoleWarnings: boolean;\n captureUnhandledRejections: boolean;\n captureUncaughtExceptions: boolean;\n}\n\nexport interface BrowserAdapter {\n report(input: ReportInput): void;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\n/**\n * Wire global browser error handlers.\n *\n * Patterned after Sentry's `globalError.ts` / `globalUnhandledRejection.ts`:\n * we patch `window.onerror` / `window.onunhandledrejection` (the property,\n * not addEventListener) so that errors fired before our listener registered\n * — e.g. via a deferred loader — are still observed. Any previous handler\n * is preserved and called after we capture.\n */\nexport function installBrowserAdapter(opts: BrowserAdapterOptions): BrowserAdapter {\n const queue = new EventQueue(opts.sink);\n const detach: Array<() => void> = [];\n\n const enqueueError = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n if (opts.captureUncaughtExceptions) {\n const previous = window.onerror;\n const handler: typeof window.onerror = (message, source, lineno, colno, error) => {\n // Cross-origin script errors give us no useful info. Bugsnag's filter:\n // `lineno === 0` plus a \"Script error.\" message is the canonical signal.\n const msgStr = typeof message === \"string\" ? message : \"\";\n if (lineno === 0 && /^Script error\\.?$/i.test(msgStr)) {\n return previous ? previous.call(window, message, source, lineno, colno, error) : false;\n }\n // Prefer the actual Error object if present (modern browsers pass it\n // as the 5th arg). Fall back to constructing one from the message.\n if (error instanceof Error) {\n enqueueError(error, \"error\", false);\n } else if (msgStr) {\n const synthetic = new Error(msgStr);\n if (source) synthetic.stack = `${msgStr}\\n at ${source}:${lineno ?? 0}:${colno ?? 0}`;\n enqueueError(synthetic, \"error\", false);\n }\n return previous ? previous.call(window, message, source, lineno, colno, error) : false;\n };\n window.onerror = handler;\n detach.push(() => {\n if (window.onerror === handler) window.onerror = previous;\n });\n }\n\n if (opts.captureUnhandledRejections) {\n const previous = window.onunhandledrejection;\n const handler: typeof window.onunhandledrejection = (event) => {\n const reason = (event as PromiseRejectionEvent).reason;\n enqueueError(reason, \"error\", false);\n if (previous) return previous.call(window, event);\n return undefined;\n };\n window.onunhandledrejection = handler;\n detach.push(() => {\n if (window.onunhandledrejection === handler) window.onunhandledrejection = previous;\n });\n }\n\n if (opts.captureConsoleErrors) {\n detach.push(patchConsole(\"error\", (args) => enqueueError(consoleError(args), \"error\", false)));\n }\n\n if (opts.captureConsoleWarnings) {\n detach.push(patchConsole(\"warn\", (args) => enqueueError(consoleError(args), \"warning\", false)));\n }\n\n return {\n report(input: ReportInput) {\n const level = input.level ?? \"error\";\n if (input.error !== undefined) {\n try {\n const event = buildEvent(input.error, level, true, opts.projectKey, opts.runtime);\n if (input.message) event.message = input.message;\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n return;\n }\n const err = new Error(input.message);\n err.name = \"ManualReport\";\n enqueueError(err, level, true);\n },\n flush: () => queue.flush(),\n close: async () => {\n for (const fn of detach) fn();\n await queue.close();\n },\n };\n}\n\nfunction buildEvent(\n err: unknown,\n level: Level,\n manual: boolean,\n projectKey: string,\n runtime: string,\n): WireEvent {\n const { type, message, stackString } = normalize(err);\n const sameOrigin = typeof window !== \"undefined\" ? window.location.origin : undefined;\n const stack = parseBrowserStack(stackString, sameOrigin);\n return {\n event_id: uuid(),\n project_key: projectKey,\n fingerprint: fingerprintWeb(type, stack),\n type,\n message,\n stack,\n code_context: null, // browsers can't read source files synchronously\n runtime,\n manual_report: manual,\n level,\n occurred_at: new Date().toISOString(),\n };\n}\n\nfunction normalize(err: unknown): { type: string; message: string; stackString?: string } {\n if (err instanceof Error) {\n return { type: err.name || \"Error\", message: err.message, stackString: err.stack };\n }\n if (typeof err === \"string\") {\n return { type: \"StringError\", message: err };\n }\n try {\n return { type: \"UnknownError\", message: JSON.stringify(err) };\n } catch {\n return { type: \"UnknownError\", message: String(err) };\n }\n}\n\nfunction consoleError(args: unknown[]): unknown {\n for (const a of args) if (a instanceof Error) return a;\n return new Error(args.map(stringify).join(\" \"));\n}\n\nfunction stringify(x: unknown): string {\n if (typeof x === \"string\") return x;\n try {\n return JSON.stringify(x);\n } catch {\n return String(x);\n }\n}\n\ntype ConsoleMethod = \"error\" | \"warn\";\n\nfunction patchConsole(method: ConsoleMethod, onCall: (args: unknown[]) => void): () => void {\n const original = console[method];\n console[method] = (...args: unknown[]) => {\n try {\n onCall(args);\n } catch {\n // never let pixel break the host program\n }\n original.apply(console, args);\n };\n return () => {\n console[method] = original;\n };\n}\n\n/**\n * RFC4122 v4 UUID using `crypto.randomUUID()` when available,\n * falling back to `crypto.getRandomValues()`-based generation.\n */\nfunction uuid(): string {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n // Fallback: build manually from 16 random bytes.\n const bytes = new Uint8Array(16);\n if (c?.getRandomValues) {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n bytes[6] = (bytes[6]! & 0x0f) | 0x40; // version 4\n bytes[8] = (bytes[8]! & 0x3f) | 0x80; // variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n","import type { Sink, WireEvent } from \"../types.js\";\n\nexport class HttpSink implements Sink {\n constructor(\n private readonly ingestUrl: string,\n private readonly fetchFn: typeof fetch = fetch,\n ) {}\n\n async emit(event: WireEvent): Promise<void> {\n const body = JSON.stringify(event);\n // `keepalive: true` lets the request survive page unload (browser).\n // `mode: \"cors\"` is the explicit default but stating it makes the\n // intent clear and avoids surprises on stricter contexts.\n const res = await this.fetchFn(this.ingestUrl, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-pixel-key\": event.project_key,\n },\n body,\n keepalive: typeof window !== \"undefined\",\n mode: typeof window !== \"undefined\" ? \"cors\" : undefined,\n });\n if (!res.ok) {\n throw new Error(`pixel ingest failed: ${res.status}`);\n }\n }\n}\n","import { installBrowserAdapter, type BrowserAdapter } from \"./adapters/browser.js\";\nimport { HttpSink } from \"./core/sinks/http.js\";\nimport type { Sink } from \"./core/types.js\";\n\nexport const DEFAULT_INGEST_URL = \"https://gg-pixel-server.buzzbeamaustralia.workers.dev\";\n\nexport interface BrowserPixelOptions {\n projectKey: string;\n /** Backend ingest URL. Defaults to the public gg-pixel server. */\n ingestUrl?: string;\n /** Override the runtime label. Default: `browser-<UA short>`. */\n runtime?: string;\n /** Inject a custom sink — overrides ingestUrl. */\n sink?: Sink;\n captureConsoleErrors?: boolean;\n captureConsoleWarnings?: boolean;\n captureUnhandledRejections?: boolean;\n captureUncaughtExceptions?: boolean;\n}\n\nlet active: BrowserAdapter | null = null;\n\nexport function initPixel(options: BrowserPixelOptions): BrowserAdapter {\n if (active) {\n throw new Error(\"gg-pixel is already initialized; call closePixel() first\");\n }\n const sink: Sink = options.sink ?? new HttpSink(buildIngestUrl(options.ingestUrl));\n active = installBrowserAdapter({\n projectKey: options.projectKey,\n runtime: options.runtime ?? defaultRuntime(),\n sink,\n captureConsoleErrors: options.captureConsoleErrors ?? false,\n captureConsoleWarnings: options.captureConsoleWarnings ?? false,\n captureUnhandledRejections: options.captureUnhandledRejections ?? true,\n captureUncaughtExceptions: options.captureUncaughtExceptions ?? true,\n });\n return active;\n}\n\nexport function reportPixel(input: {\n message: string;\n error?: unknown;\n level?: \"error\" | \"warning\" | \"fatal\";\n}): void {\n if (!active) return;\n active.report(input);\n}\n\nexport async function flushPixel(): Promise<void> {\n if (!active) return;\n await active.flush();\n}\n\nexport async function closePixel(): Promise<void> {\n if (!active) return;\n await active.close();\n active = null;\n}\n\nfunction buildIngestUrl(base?: string): string {\n const url = (base ?? DEFAULT_INGEST_URL).replace(/\\/+$/, \"\");\n return `${url}/ingest`;\n}\n\nfunction defaultRuntime(): string {\n if (typeof navigator === \"undefined\") return \"browser-unknown\";\n const ua = navigator.userAgent;\n if (/Chrome\\/(\\d+)/.test(ua)) return `chrome-${RegExp.$1}`;\n if (/Firefox\\/(\\d+)/.test(ua)) return `firefox-${RegExp.$1}`;\n if (/Version\\/(\\d+).*Safari/.test(ua)) return `safari-${RegExp.$1}`;\n if (/Edg\\/(\\d+)/.test(ua)) return `edge-${RegExp.$1}`;\n return \"browser\";\n}\n\nexport type { Level, ReportInput, StackFrame, WireEvent } from \"./core/types.js\";\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core/stack-web.ts","../src/core/fingerprint-web.ts","../src/core/queue.ts","../src/adapters/browser.ts","../src/core/sinks/http.ts","../src/browser.ts"],"sourcesContent":["import type { StackFrame } from \"./types.js\";\n\n/**\n * Cross-browser stack-trace parser.\n *\n * Browser stack formats differ wildly. We support two — that covers\n * Chrome/Edge/Safari (V8-shaped) and Firefox (Gecko-shaped). Real-world\n * coverage cited by Sentry's parsers in `packages/browser/src/stack-parsers.ts`.\n */\n\n// Chrome / V8 / Edge / modern Safari. Examples:\n// \" at fnName (https://app.com/main.js:42:13)\"\n// \" at https://app.com/main.js:42:13\"\n// \" at fnName (eval at <anonymous> (https://x/y.js:1:1), <anonymous>:1:5)\"\nconst CHROME_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+))(?:\\))?\\s*$/;\n\n// Firefox / Gecko. Examples:\n// \"fnName@https://app.com/main.js:42:13\"\n// \"@https://app.com/main.js:42:13\"\nconst GECKO_FRAME = /^\\s*(.*?)@(.+?):(\\d+)(?::(\\d+))?\\s*$/;\n\nexport function parseBrowserStack(stack: string | undefined, sameOrigin?: string): StackFrame[] {\n if (!stack) return [];\n const frames: StackFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n // Skip the leading \"TypeError: x\" header line — no `at` prefix and no `@`.\n if (!/^(?:at\\s|.*@)/.test(trimmed)) continue;\n\n const chrome = CHROME_FRAME.exec(line);\n if (chrome) {\n const fn = (chrome[1] ?? \"\").trim() || \"<anon>\";\n const file = chrome[2];\n if (!file) continue;\n frames.push({\n fn,\n file,\n line: Number(chrome[3]),\n col: Number(chrome[4]),\n in_app: isInApp(file, sameOrigin),\n });\n continue;\n }\n\n const gecko = GECKO_FRAME.exec(line);\n if (gecko) {\n const fn = (gecko[1] ?? \"\").trim() || \"<anon>\";\n const file = gecko[2];\n if (!file) continue;\n frames.push({\n fn,\n file,\n line: Number(gecko[3]),\n col: gecko[4] ? Number(gecko[4]) : 0,\n in_app: isInApp(file, sameOrigin),\n });\n }\n }\n return frames;\n}\n\n/**\n * Mark a frame as in-app when its URL matches the page's origin (or other\n * provided origin). Cross-origin scripts (CDN bundles, third-party widgets,\n * browser extensions) are framework/library noise — not the user's code.\n */\nfunction isInApp(file: string, sameOrigin?: string): boolean {\n if (!file) return false;\n // Browser-extension and inline-eval frames — never user code.\n if (/^chrome-extension:\\/\\//.test(file)) return false;\n if (/^moz-extension:\\/\\//.test(file)) return false;\n if (/^safari-extension:\\/\\//.test(file)) return false;\n if (/^webkit-masked-url:\\/\\//.test(file)) return false;\n if (file === \"<anonymous>\" || file === \"[native code]\") return false;\n\n if (!sameOrigin) {\n // No origin context — best-effort: any http(s) URL counts as in_app\n // unless we can prove otherwise.\n return /^https?:\\/\\//.test(file) || /^[a-z]+:\\/\\//.test(file) === false;\n }\n\n try {\n const url = new URL(file, sameOrigin);\n return url.origin === sameOrigin;\n } catch {\n return false;\n }\n}\n","import type { StackFrame } from \"./types.js\";\n\n/**\n * Browser-safe synchronous fingerprint.\n *\n * `node:crypto` doesn't exist in browsers, and Web Crypto's `subtle.digest`\n * is async — making the queue async would break the fast-path. Sentry's\n * browser SDK uses simple sync hashing for the same reason. Our fingerprint\n * just needs to be stable for the same inputs; cryptographic strength isn't\n * required.\n *\n * Implementation: FNV-1a 64-bit. Fast, sync, ~1KB. Output as 16-char hex.\n */\nexport function fingerprintWeb(type: string, stack: StackFrame[]): string {\n const top = stack[0];\n const normalized = top\n ? `${type}|${normalizeFile(top.file)}|${top.fn || \"<anon>\"}|${top.line}`\n : `${type}|<no-stack>`;\n return fnv1a64(normalized);\n}\n\n/** FNV-1a 64-bit hash. Returns 16-char lowercase hex. */\nexport function fnv1a64(input: string): string {\n // 64-bit math via two 32-bit halves, since JS doesn't have native u64.\n // Constants from the FNV-1a spec.\n let hHi = 0xcbf29ce4;\n let hLo = 0x84222325;\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n hLo ^= code & 0xff;\n if (input.charCodeAt(i) > 0xff) hHi ^= (code >>> 8) & 0xff;\n\n // h = h * 0x100000001b3 (FNV prime), as 64-bit math:\n // The prime split into hi/lo 32-bit parts is { 0x100, 0x000001b3 }.\n const lo16 = hLo & 0xffff;\n const lo32 = (hLo >>> 16) & 0xffff;\n const hi16 = hHi & 0xffff;\n const hi32 = (hHi >>> 16) & 0xffff;\n\n let nLo = lo16 * 0x1b3;\n let nMid = lo32 * 0x1b3 + ((nLo >>> 16) & 0xffff);\n let nHi = hi16 * 0x1b3 + ((nMid >>> 16) & 0xffff);\n let nTop = hi32 * 0x1b3 + ((nHi >>> 16) & 0xffff);\n\n nLo += lo16 * 0; // *= 0x100... carry from low parts\n nMid += lo32 * 0;\n nHi += hi16 * 0;\n nTop += hi32 * 0;\n\n // Add the * 0x1_00000000_00 portion (lo16 << 32).\n nHi += lo16;\n nTop += lo32 + ((nHi >>> 16) & 0xffff);\n\n hLo = (((nMid & 0xffff) << 16) | (nLo & 0xffff)) >>> 0;\n hHi = (((nTop & 0xffff) << 16) | (nHi & 0xffff)) >>> 0;\n }\n\n return toHex32(hHi) + toHex32(hLo);\n}\n\nfunction toHex32(n: number): string {\n return (n >>> 0).toString(16).padStart(8, \"0\");\n}\n\nfunction normalizeFile(file: string): string {\n return file.replace(/\\?.*$/, \"\").replace(/#.*$/, \"\");\n}\n","import type { Sink, WireEvent } from \"./types.js\";\n\nconst MAX_BUFFER = 100;\nconst BASE_DELAY_MS = 200;\nconst MAX_DELAY_MS = 5_000;\n\nexport class EventQueue {\n private readonly buffer: WireEvent[] = [];\n private draining = false;\n private closed = false;\n\n constructor(private readonly sink: Sink) {}\n\n enqueue(event: WireEvent): void {\n if (this.closed) return;\n if (this.buffer.length >= MAX_BUFFER) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n void this.drain();\n }\n\n enqueueSync(event: WireEvent): void {\n if (this.closed) return;\n if (this.sink.emitSync) {\n try {\n this.sink.emitSync(event);\n return;\n } catch {\n // fall through to async path\n }\n }\n this.enqueue(event);\n }\n\n async flush(): Promise<void> {\n while (this.buffer.length > 0 || this.draining) {\n await new Promise((r) => setTimeout(r, 10));\n }\n }\n\n async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n if (this.sink.close) await this.sink.close();\n }\n\n private async drain(): Promise<void> {\n if (this.draining) return;\n this.draining = true;\n let attempt = 0;\n while (this.buffer.length > 0) {\n const event = this.buffer[0];\n try {\n await this.sink.emit(event);\n this.buffer.shift();\n attempt = 0;\n } catch (err) {\n attempt++;\n if (attempt >= 5) {\n // Drop the event but make the loss observable — silent data loss\n // from the error tracker is the worst possible failure mode.\n console.warn(\n `[gg-pixel] dropping event after 5 failed deliveries: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n this.buffer.shift();\n attempt = 0;\n continue;\n }\n const delay = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n this.draining = false;\n }\n}\n","import { parseBrowserStack } from \"../core/stack-web.js\";\nimport { fingerprintWeb } from \"../core/fingerprint-web.js\";\nimport { EventQueue } from \"../core/queue.js\";\nimport type { Level, ReportInput, Sink, WireEvent } from \"../core/types.js\";\n\ndeclare global {\n interface Window {\n onerror:\n | ((\n message: string | Event,\n source?: string,\n lineno?: number,\n colno?: number,\n error?: Error,\n ) => boolean | void)\n | null;\n onunhandledrejection: ((event: PromiseRejectionEvent) => boolean | void) | null;\n }\n}\n\nexport interface BrowserAdapterOptions {\n projectKey: string;\n runtime: string;\n sink: Sink;\n captureConsoleErrors: boolean;\n captureConsoleWarnings: boolean;\n captureUnhandledRejections: boolean;\n captureUncaughtExceptions: boolean;\n}\n\nexport interface BrowserAdapter {\n report(input: ReportInput): void;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\n/**\n * Wire global browser error handlers.\n *\n * Patterned after Sentry's `globalError.ts` / `globalUnhandledRejection.ts`:\n * we patch `window.onerror` / `window.onunhandledrejection` (the property,\n * not addEventListener) so that errors fired before our listener registered\n * — e.g. via a deferred loader — are still observed. Any previous handler\n * is preserved and called after we capture.\n */\nexport function installBrowserAdapter(opts: BrowserAdapterOptions): BrowserAdapter {\n const queue = new EventQueue(opts.sink);\n const detach: Array<() => void> = [];\n\n const enqueueError = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n if (opts.captureUncaughtExceptions) {\n const previous = window.onerror;\n const handler: typeof window.onerror = (message, source, lineno, colno, error) => {\n // Cross-origin script errors give us no useful info. Bugsnag's filter:\n // `lineno === 0` plus a \"Script error.\" message is the canonical signal.\n const msgStr = typeof message === \"string\" ? message : \"\";\n if (lineno === 0 && /^Script error\\.?$/i.test(msgStr)) {\n return previous ? previous.call(window, message, source, lineno, colno, error) : false;\n }\n // Prefer the actual Error object if present (modern browsers pass it\n // as the 5th arg). Fall back to constructing one from the message.\n if (error instanceof Error) {\n enqueueError(error, \"error\", false);\n } else if (msgStr) {\n const synthetic = new Error(msgStr);\n if (source) synthetic.stack = `${msgStr}\\n at ${source}:${lineno ?? 0}:${colno ?? 0}`;\n enqueueError(synthetic, \"error\", false);\n }\n return previous ? previous.call(window, message, source, lineno, colno, error) : false;\n };\n window.onerror = handler;\n detach.push(() => {\n if (window.onerror === handler) window.onerror = previous;\n });\n }\n\n if (opts.captureUnhandledRejections) {\n const previous = window.onunhandledrejection;\n const handler: typeof window.onunhandledrejection = (event) => {\n const reason = (event as PromiseRejectionEvent).reason;\n enqueueError(reason, \"error\", false);\n if (previous) return previous.call(window, event);\n return undefined;\n };\n window.onunhandledrejection = handler;\n detach.push(() => {\n if (window.onunhandledrejection === handler) window.onunhandledrejection = previous;\n });\n }\n\n if (opts.captureConsoleErrors) {\n detach.push(patchConsole(\"error\", (args) => enqueueError(consoleError(args), \"error\", false)));\n }\n\n if (opts.captureConsoleWarnings) {\n detach.push(patchConsole(\"warn\", (args) => enqueueError(consoleError(args), \"warning\", false)));\n }\n\n return {\n report(input: ReportInput) {\n const level = input.level ?? \"error\";\n if (input.error !== undefined) {\n try {\n const event = buildEvent(input.error, level, true, opts.projectKey, opts.runtime);\n if (input.message) event.message = input.message;\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n return;\n }\n const err = new Error(input.message);\n err.name = \"ManualReport\";\n enqueueError(err, level, true);\n },\n flush: () => queue.flush(),\n close: async () => {\n for (const fn of detach) fn();\n await queue.close();\n },\n };\n}\n\nfunction buildEvent(\n err: unknown,\n level: Level,\n manual: boolean,\n projectKey: string,\n runtime: string,\n): WireEvent {\n const { type, message, stackString } = normalize(err);\n const sameOrigin = typeof window !== \"undefined\" ? window.location.origin : undefined;\n const stack = parseBrowserStack(stackString, sameOrigin);\n return {\n event_id: uuid(),\n project_key: projectKey,\n fingerprint: fingerprintWeb(type, stack),\n type,\n message,\n stack,\n code_context: null, // browsers can't read source files synchronously\n runtime,\n manual_report: manual,\n level,\n occurred_at: new Date().toISOString(),\n };\n}\n\nfunction normalize(err: unknown): { type: string; message: string; stackString?: string } {\n if (err instanceof Error) {\n return { type: err.name || \"Error\", message: err.message, stackString: err.stack };\n }\n if (typeof err === \"string\") {\n return { type: \"StringError\", message: err };\n }\n try {\n return { type: \"UnknownError\", message: JSON.stringify(err) };\n } catch {\n return { type: \"UnknownError\", message: String(err) };\n }\n}\n\nfunction consoleError(args: unknown[]): unknown {\n for (const a of args) if (a instanceof Error) return a;\n return new Error(args.map(stringify).join(\" \"));\n}\n\nfunction stringify(x: unknown): string {\n if (typeof x === \"string\") return x;\n try {\n return JSON.stringify(x);\n } catch {\n return String(x);\n }\n}\n\ntype ConsoleMethod = \"error\" | \"warn\";\n\nfunction patchConsole(method: ConsoleMethod, onCall: (args: unknown[]) => void): () => void {\n const original = console[method];\n console[method] = (...args: unknown[]) => {\n try {\n onCall(args);\n } catch {\n // never let pixel break the host program\n }\n original.apply(console, args);\n };\n return () => {\n console[method] = original;\n };\n}\n\n/**\n * RFC4122 v4 UUID using `crypto.randomUUID()` when available,\n * falling back to `crypto.getRandomValues()`-based generation.\n */\nfunction uuid(): string {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n // Fallback: build manually from 16 random bytes.\n const bytes = new Uint8Array(16);\n if (c?.getRandomValues) {\n c.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n bytes[6] = (bytes[6]! & 0x0f) | 0x40; // version 4\n bytes[8] = (bytes[8]! & 0x3f) | 0x80; // variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n","import type { Sink, WireEvent } from \"../types.js\";\n\nexport class HttpSink implements Sink {\n private readonly fetchFn: typeof fetch;\n\n constructor(\n private readonly ingestUrl: string,\n fetchFn?: typeof fetch,\n ) {\n // CRITICAL: in browsers `fetch` is `window.fetch` and requires `this === window`.\n // Storing it as a property and calling via `this.fetchFn(...)` strips that\n // binding and throws \"Illegal invocation\". Bind to globalThis on assignment.\n // Tests can still inject a custom fetchFn (no binding needed for plain fns).\n this.fetchFn = fetchFn ?? globalThis.fetch.bind(globalThis);\n }\n\n async emit(event: WireEvent): Promise<void> {\n const body = JSON.stringify(event);\n // `keepalive: true` lets the request survive page unload (browser).\n // `mode: \"cors\"` is the explicit default but stating it makes the\n // intent clear and avoids surprises on stricter contexts.\n const res = await this.fetchFn(this.ingestUrl, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-pixel-key\": event.project_key,\n },\n body,\n keepalive: typeof window !== \"undefined\",\n mode: typeof window !== \"undefined\" ? \"cors\" : undefined,\n });\n if (!res.ok) {\n throw new Error(`pixel ingest failed: ${res.status}`);\n }\n }\n}\n","import { installBrowserAdapter, type BrowserAdapter } from \"./adapters/browser.js\";\nimport { HttpSink } from \"./core/sinks/http.js\";\nimport type { Sink } from \"./core/types.js\";\n\nexport const DEFAULT_INGEST_URL = \"https://gg-pixel-server.buzzbeamaustralia.workers.dev\";\n\nexport interface BrowserPixelOptions {\n projectKey: string;\n /** Backend ingest URL. Defaults to the public gg-pixel server. */\n ingestUrl?: string;\n /** Override the runtime label. Default: `browser-<UA short>`. */\n runtime?: string;\n /** Inject a custom sink — overrides ingestUrl. */\n sink?: Sink;\n captureConsoleErrors?: boolean;\n captureConsoleWarnings?: boolean;\n captureUnhandledRejections?: boolean;\n captureUncaughtExceptions?: boolean;\n}\n\nlet active: BrowserAdapter | null = null;\n\nexport function initPixel(options: BrowserPixelOptions): BrowserAdapter {\n if (active) {\n throw new Error(\"gg-pixel is already initialized; call closePixel() first\");\n }\n const sink: Sink = options.sink ?? new HttpSink(buildIngestUrl(options.ingestUrl));\n active = installBrowserAdapter({\n projectKey: options.projectKey,\n runtime: options.runtime ?? defaultRuntime(),\n sink,\n captureConsoleErrors: options.captureConsoleErrors ?? false,\n captureConsoleWarnings: options.captureConsoleWarnings ?? false,\n captureUnhandledRejections: options.captureUnhandledRejections ?? true,\n captureUncaughtExceptions: options.captureUncaughtExceptions ?? true,\n });\n return active;\n}\n\nexport function reportPixel(input: {\n message: string;\n error?: unknown;\n level?: \"error\" | \"warning\" | \"fatal\";\n}): void {\n if (!active) return;\n active.report(input);\n}\n\nexport async function flushPixel(): Promise<void> {\n if (!active) return;\n await active.flush();\n}\n\nexport async function closePixel(): Promise<void> {\n if (!active) return;\n await active.close();\n active = null;\n}\n\nfunction buildIngestUrl(base?: string): string {\n const url = (base ?? DEFAULT_INGEST_URL).replace(/\\/+$/, \"\");\n return `${url}/ingest`;\n}\n\nfunction defaultRuntime(): string {\n if (typeof navigator === \"undefined\") return \"browser-unknown\";\n const ua = navigator.userAgent;\n if (/Chrome\\/(\\d+)/.test(ua)) return `chrome-${RegExp.$1}`;\n if (/Firefox\\/(\\d+)/.test(ua)) return `firefox-${RegExp.$1}`;\n if (/Version\\/(\\d+).*Safari/.test(ua)) return `safari-${RegExp.$1}`;\n if (/Edg\\/(\\d+)/.test(ua)) return `edge-${RegExp.$1}`;\n return \"browser\";\n}\n\nexport type { Level, ReportInput, StackFrame, WireEvent } from \"./core/types.js\";\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -183,9 +183,12 @@ var EventQueue = class {
|
|
|
183
183
|
await this.sink.emit(event);
|
|
184
184
|
this.buffer.shift();
|
|
185
185
|
attempt = 0;
|
|
186
|
-
} catch {
|
|
186
|
+
} catch (err) {
|
|
187
187
|
attempt++;
|
|
188
188
|
if (attempt >= 5) {
|
|
189
|
+
console.warn(
|
|
190
|
+
`[gg-pixel] dropping event after 5 failed deliveries: ${err instanceof Error ? err.message : String(err)}`
|
|
191
|
+
);
|
|
189
192
|
this.buffer.shift();
|
|
190
193
|
attempt = 0;
|
|
191
194
|
continue;
|
|
@@ -316,12 +319,16 @@ function patchConsole(method, onCall) {
|
|
|
316
319
|
};
|
|
317
320
|
}
|
|
318
321
|
|
|
322
|
+
// src/core/sinks/node-http.ts
|
|
323
|
+
var import_node_child_process = require("child_process");
|
|
324
|
+
|
|
319
325
|
// src/core/sinks/http.ts
|
|
320
326
|
var HttpSink = class {
|
|
321
|
-
constructor(ingestUrl, fetchFn
|
|
327
|
+
constructor(ingestUrl, fetchFn) {
|
|
322
328
|
this.ingestUrl = ingestUrl;
|
|
323
|
-
this.fetchFn = fetchFn;
|
|
329
|
+
this.fetchFn = fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
324
330
|
}
|
|
331
|
+
fetchFn;
|
|
325
332
|
async emit(event) {
|
|
326
333
|
const body = JSON.stringify(event);
|
|
327
334
|
const res = await this.fetchFn(this.ingestUrl, {
|
|
@@ -340,6 +347,41 @@ var HttpSink = class {
|
|
|
340
347
|
}
|
|
341
348
|
};
|
|
342
349
|
|
|
350
|
+
// src/core/sinks/node-http.ts
|
|
351
|
+
var NodeHttpSink = class extends HttpSink {
|
|
352
|
+
constructor(url, fetchFn) {
|
|
353
|
+
super(url, fetchFn);
|
|
354
|
+
this.url = url;
|
|
355
|
+
}
|
|
356
|
+
emitSync(event) {
|
|
357
|
+
const body = JSON.stringify(event);
|
|
358
|
+
const result = (0, import_node_child_process.spawnSync)(
|
|
359
|
+
"curl",
|
|
360
|
+
[
|
|
361
|
+
"--silent",
|
|
362
|
+
"--show-error",
|
|
363
|
+
"-X",
|
|
364
|
+
"POST",
|
|
365
|
+
"-H",
|
|
366
|
+
"content-type: application/json",
|
|
367
|
+
"-H",
|
|
368
|
+
`x-pixel-key: ${event.project_key}`,
|
|
369
|
+
"--data-binary",
|
|
370
|
+
"@-",
|
|
371
|
+
"--max-time",
|
|
372
|
+
"3",
|
|
373
|
+
this.url
|
|
374
|
+
],
|
|
375
|
+
{ input: body, encoding: "utf8" }
|
|
376
|
+
);
|
|
377
|
+
if (result.error || result.status !== 0) {
|
|
378
|
+
console.warn(
|
|
379
|
+
`[gg-pixel] sync emit failed: ${result.error?.message ?? result.stderr ?? "unknown"}`
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
343
385
|
// src/core/sinks/local-sqlite.ts
|
|
344
386
|
var import_node_os = require("os");
|
|
345
387
|
var import_node_fs2 = require("fs");
|
|
@@ -410,7 +452,7 @@ var LocalSqliteSink = class {
|
|
|
410
452
|
var import_node_fs3 = require("fs");
|
|
411
453
|
var import_node_os2 = require("os");
|
|
412
454
|
var import_node_path2 = require("path");
|
|
413
|
-
var
|
|
455
|
+
var import_node_child_process2 = require("child_process");
|
|
414
456
|
var DEFAULT_INGEST_URL = "https://gg-pixel-server.buzzbeamaustralia.workers.dev";
|
|
415
457
|
async function install(opts = {}) {
|
|
416
458
|
const cwd = (0, import_node_path2.resolve)(opts.cwd ?? process.cwd());
|
|
@@ -518,7 +560,7 @@ function detectPackageManager(projectRoot) {
|
|
|
518
560
|
function runInstall(projectRoot, pm, pkg) {
|
|
519
561
|
const cmd = pm;
|
|
520
562
|
const args = pm === "npm" ? ["install", pkg, "--no-audit", "--no-fund"] : ["add", pkg];
|
|
521
|
-
const result = (0,
|
|
563
|
+
const result = (0, import_node_child_process2.spawnSync)(cmd, args, { cwd: projectRoot, stdio: "inherit" });
|
|
522
564
|
return result.status === 0;
|
|
523
565
|
}
|
|
524
566
|
function renderInitFile(ingestUrl) {
|
|
@@ -691,7 +733,7 @@ async function closePixel() {
|
|
|
691
733
|
function buildSink(config) {
|
|
692
734
|
switch (config.kind) {
|
|
693
735
|
case "http":
|
|
694
|
-
return new
|
|
736
|
+
return new NodeHttpSink(config.ingestUrl, config.fetchFn);
|
|
695
737
|
case "local":
|
|
696
738
|
return new LocalSqliteSink(config.path);
|
|
697
739
|
case "custom":
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/adapters/node.ts","../src/core/stack.ts","../src/core/fingerprint.ts","../src/code-context.ts","../src/core/queue.ts","../src/core/sinks/http.ts","../src/core/sinks/local-sqlite.ts","../src/install.ts"],"sourcesContent":["import { installNodeAdapter, type NodeAdapter } from \"./adapters/node.js\";\nimport { HttpSink } from \"./core/sinks/http.js\";\nimport { LocalSqliteSink } from \"./core/sinks/local-sqlite.js\";\nimport type { PixelOptions, ReportInput, Sink, SinkConfig } from \"./core/types.js\";\n\nlet active: NodeAdapter | null = null;\n\nexport function initPixel(options: PixelOptions): NodeAdapter {\n if (active) {\n throw new Error(\"gg-pixel is already initialized; call closePixel() first\");\n }\n const sink = buildSink(options.sink);\n active = installNodeAdapter({\n projectKey: options.projectKey,\n runtime: options.runtime ?? defaultRuntime(),\n sink,\n captureConsoleErrors: options.captureConsoleErrors ?? true,\n captureConsoleWarnings: options.captureConsoleWarnings ?? false,\n captureUnhandledRejections: options.captureUnhandledRejections ?? true,\n captureUncaughtExceptions: options.captureUncaughtExceptions ?? true,\n });\n return active;\n}\n\nexport function reportPixel(input: ReportInput): void {\n if (!active) return;\n active.report(input);\n}\n\nexport async function flushPixel(): Promise<void> {\n if (!active) return;\n await active.flush();\n}\n\nexport async function closePixel(): Promise<void> {\n if (!active) return;\n await active.close();\n active = null;\n}\n\nfunction buildSink(config: SinkConfig): Sink {\n switch (config.kind) {\n case \"http\":\n return new HttpSink(config.ingestUrl, config.fetchFn);\n case \"local\":\n return new LocalSqliteSink(config.path);\n case \"custom\":\n return config.sink;\n }\n}\n\nfunction defaultRuntime(): string {\n const v = process.versions.node;\n return `node-${v}`;\n}\n\nexport type {\n Level,\n PixelOptions,\n ReportInput,\n Sink,\n SinkConfig,\n StackFrame,\n CodeContext,\n WireEvent,\n} from \"./core/types.js\";\n\nexport { install, DEFAULT_INGEST_URL } from \"./install.js\";\nexport type { InstallOptions, InstallResult, PackageManager } from \"./install.js\";\n","import { randomUUID } from \"node:crypto\";\nimport { parseStack } from \"../core/stack.js\";\nimport { fingerprint } from \"../core/fingerprint.js\";\nimport { captureCodeContext } from \"../code-context.js\";\nimport { EventQueue } from \"../core/queue.js\";\nimport type { Level, ReportInput, Sink, WireEvent } from \"../core/types.js\";\n\nexport interface NodeAdapterOptions {\n projectKey: string;\n runtime: string;\n sink: Sink;\n captureConsoleErrors: boolean;\n captureConsoleWarnings: boolean;\n captureUnhandledRejections: boolean;\n captureUncaughtExceptions: boolean;\n}\n\nexport interface NodeAdapter {\n report(input: ReportInput): void;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport function installNodeAdapter(opts: NodeAdapterOptions): NodeAdapter {\n const queue = new EventQueue(opts.sink);\n const detach: Array<() => void> = [];\n\n const enqueueError = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n const enqueueErrorSync = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueueSync(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n if (opts.captureUncaughtExceptions) {\n const handler = (err: Error) => enqueueErrorSync(err, \"fatal\", false);\n process.on(\"uncaughtExceptionMonitor\", handler);\n detach.push(() => process.off(\"uncaughtExceptionMonitor\", handler));\n }\n\n if (opts.captureUnhandledRejections) {\n const handler = (reason: unknown) => enqueueErrorSync(reason, \"error\", false);\n process.on(\"unhandledRejection\", handler);\n detach.push(() => process.off(\"unhandledRejection\", handler));\n }\n\n if (opts.captureConsoleErrors) {\n detach.push(patchConsole(\"error\", (args) => enqueueError(consoleError(args), \"error\", false)));\n }\n\n if (opts.captureConsoleWarnings) {\n detach.push(patchConsole(\"warn\", (args) => enqueueError(consoleError(args), \"warning\", false)));\n }\n\n const onBeforeExit = () => {\n void queue.flush();\n };\n process.on(\"beforeExit\", onBeforeExit);\n detach.push(() => process.off(\"beforeExit\", onBeforeExit));\n\n return {\n report(input: ReportInput) {\n const level = input.level ?? \"error\";\n if (input.error !== undefined) {\n try {\n const event = buildEvent(input.error, level, true, opts.projectKey, opts.runtime);\n if (input.message) event.message = input.message;\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n return;\n }\n const err = new Error(input.message);\n err.name = \"ManualReport\";\n enqueueError(err, level, true);\n },\n flush: () => queue.flush(),\n close: async () => {\n for (const fn of detach) fn();\n await queue.close();\n },\n };\n}\n\nfunction buildEvent(\n err: unknown,\n level: Level,\n manual: boolean,\n projectKey: string,\n runtime: string,\n): WireEvent {\n const { type, message, stackString } = normalize(err);\n const stack = parseStack(stackString);\n return {\n event_id: randomUUID(),\n project_key: projectKey,\n fingerprint: fingerprint(type, stack),\n type,\n message,\n stack,\n code_context: captureCodeContext(stack),\n runtime,\n manual_report: manual,\n level,\n occurred_at: new Date().toISOString(),\n };\n}\n\nfunction normalize(err: unknown): { type: string; message: string; stackString?: string } {\n if (err instanceof Error) {\n return { type: err.name || \"Error\", message: err.message, stackString: err.stack };\n }\n if (typeof err === \"string\") {\n return { type: \"StringError\", message: err };\n }\n try {\n return { type: \"UnknownError\", message: JSON.stringify(err) };\n } catch {\n return { type: \"UnknownError\", message: String(err) };\n }\n}\n\nfunction consoleError(args: unknown[]): unknown {\n for (const a of args) if (a instanceof Error) return a;\n return new Error(args.map(stringify).join(\" \"));\n}\n\nfunction stringify(x: unknown): string {\n if (typeof x === \"string\") return x;\n try {\n return JSON.stringify(x);\n } catch {\n return String(x);\n }\n}\n\ntype ConsoleMethod = \"error\" | \"warn\";\n\nfunction patchConsole(method: ConsoleMethod, onCall: (args: unknown[]) => void): () => void {\n const original = console[method];\n console[method] = (...args: unknown[]) => {\n try {\n onCall(args);\n } catch {\n // never let pixel break the host program\n }\n original.apply(console, args);\n };\n return () => {\n console[method] = original;\n };\n}\n","import type { StackFrame } from \"./types.js\";\n\nconst FRAME_WITH_FN = /^\\s*at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)\\s*$/;\nconst FRAME_NO_FN = /^\\s*at\\s+(.+?):(\\d+):(\\d+)\\s*$/;\n\nexport function parseStack(stack: string | undefined): StackFrame[] {\n if (!stack) return [];\n const frames: StackFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n const withFn = FRAME_WITH_FN.exec(line);\n if (withFn) {\n const file = withFn[2];\n frames.push({\n fn: withFn[1],\n file,\n line: Number(withFn[3]),\n col: Number(withFn[4]),\n in_app: isInApp(file),\n });\n continue;\n }\n const noFn = FRAME_NO_FN.exec(line);\n if (noFn) {\n const file = noFn[1];\n frames.push({\n fn: \"<anon>\",\n file,\n line: Number(noFn[2]),\n col: Number(noFn[3]),\n in_app: isInApp(file),\n });\n }\n }\n return frames;\n}\n\nfunction isInApp(file: string): boolean {\n if (!file) return false;\n if (file.startsWith(\"node:\")) return false;\n if (file.startsWith(\"internal/\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return true;\n}\n","import { createHash } from \"node:crypto\";\nimport type { StackFrame } from \"./types.js\";\n\nexport function fingerprint(type: string, stack: StackFrame[]): string {\n const top = stack[0];\n const normalized = top\n ? `${type}|${normalizeFile(top.file)}|${top.fn || \"<anon>\"}|${top.line}`\n : `${type}|<no-stack>`;\n return createHash(\"sha256\").update(normalized).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeFile(file: string): string {\n return file\n .replace(/^file:\\/\\//, \"\")\n .replace(/^.*\\/node_modules\\//, \"node_modules/\")\n .replace(/\\?.*$/, \"\");\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport type { CodeContext, StackFrame } from \"./core/types.js\";\n\nconst WINDOW = 2;\nconst cache = new Map<string, string[] | null>();\n\nexport function captureCodeContext(stack: StackFrame[]): CodeContext | null {\n const top = stack.find((f) => isReadable(f.file));\n if (!top) return null;\n const lines = loadLines(top.file);\n if (!lines) return null;\n const start = Math.max(0, top.line - 1 - WINDOW);\n const end = Math.min(lines.length, top.line + WINDOW);\n return {\n file: top.file,\n error_line: top.line,\n lines: lines.slice(start, end),\n };\n}\n\nfunction isReadable(file: string): boolean {\n if (!file || file.startsWith(\"node:\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return file.startsWith(\"/\") || file.startsWith(\"file://\");\n}\n\nfunction loadLines(file: string): string[] | null {\n const path = file.replace(/^file:\\/\\//, \"\");\n if (cache.has(path)) return cache.get(path) ?? null;\n if (!existsSync(path)) {\n cache.set(path, null);\n return null;\n }\n try {\n const lines = readFileSync(path, \"utf8\").split(\"\\n\");\n cache.set(path, lines);\n return lines;\n } catch {\n cache.set(path, null);\n return null;\n }\n}\n","import type { Sink, WireEvent } from \"./types.js\";\n\nconst MAX_BUFFER = 100;\nconst BASE_DELAY_MS = 200;\nconst MAX_DELAY_MS = 5_000;\n\nexport class EventQueue {\n private readonly buffer: WireEvent[] = [];\n private draining = false;\n private closed = false;\n\n constructor(private readonly sink: Sink) {}\n\n enqueue(event: WireEvent): void {\n if (this.closed) return;\n if (this.buffer.length >= MAX_BUFFER) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n void this.drain();\n }\n\n enqueueSync(event: WireEvent): void {\n if (this.closed) return;\n if (this.sink.emitSync) {\n try {\n this.sink.emitSync(event);\n return;\n } catch {\n // fall through to async path\n }\n }\n this.enqueue(event);\n }\n\n async flush(): Promise<void> {\n while (this.buffer.length > 0 || this.draining) {\n await new Promise((r) => setTimeout(r, 10));\n }\n }\n\n async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n if (this.sink.close) await this.sink.close();\n }\n\n private async drain(): Promise<void> {\n if (this.draining) return;\n this.draining = true;\n let attempt = 0;\n while (this.buffer.length > 0) {\n const event = this.buffer[0];\n try {\n await this.sink.emit(event);\n this.buffer.shift();\n attempt = 0;\n } catch {\n attempt++;\n if (attempt >= 5) {\n this.buffer.shift();\n attempt = 0;\n continue;\n }\n const delay = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n this.draining = false;\n }\n}\n","import type { Sink, WireEvent } from \"../types.js\";\n\nexport class HttpSink implements Sink {\n constructor(\n private readonly ingestUrl: string,\n private readonly fetchFn: typeof fetch = fetch,\n ) {}\n\n async emit(event: WireEvent): Promise<void> {\n const body = JSON.stringify(event);\n // `keepalive: true` lets the request survive page unload (browser).\n // `mode: \"cors\"` is the explicit default but stating it makes the\n // intent clear and avoids surprises on stricter contexts.\n const res = await this.fetchFn(this.ingestUrl, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-pixel-key\": event.project_key,\n },\n body,\n keepalive: typeof window !== \"undefined\",\n mode: typeof window !== \"undefined\" ? \"cors\" : undefined,\n });\n if (!res.ok) {\n throw new Error(`pixel ingest failed: ${res.status}`);\n }\n }\n}\n","import { homedir } from \"node:os\";\nimport { mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { Sink, WireEvent } from \"../types.js\";\n\nconst SCHEMA = `\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n event_id TEXT NOT NULL UNIQUE,\n project_key TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n type TEXT NOT NULL,\n message TEXT NOT NULL,\n stack TEXT NOT NULL,\n code_context TEXT,\n runtime TEXT NOT NULL,\n manual_report INTEGER NOT NULL DEFAULT 0,\n level TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n ingested_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS events_fingerprint ON events(project_key, fingerprint);\n CREATE INDEX IF NOT EXISTS events_occurred ON events(occurred_at);\n`;\n\nexport class LocalSqliteSink implements Sink {\n private readonly db: Database.Database;\n private readonly insert: Database.Statement;\n\n constructor(path?: string) {\n const resolved = path ?? join(homedir(), \".gg\", \"errors.db\");\n mkdirSync(dirname(resolved), { recursive: true });\n this.db = new Database(resolved);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.exec(SCHEMA);\n this.insert = this.db.prepare(`\n INSERT INTO events (\n event_id, project_key, fingerprint, type, message, stack, code_context,\n runtime, manual_report, level, occurred_at\n ) VALUES (\n @event_id, @project_key, @fingerprint, @type, @message, @stack, @code_context,\n @runtime, @manual_report, @level, @occurred_at\n )\n `);\n }\n\n emitSync(event: WireEvent): void {\n this.insert.run({\n event_id: event.event_id,\n project_key: event.project_key,\n fingerprint: event.fingerprint,\n type: event.type,\n message: event.message,\n stack: JSON.stringify(event.stack),\n code_context: event.code_context ? JSON.stringify(event.code_context) : null,\n runtime: event.runtime,\n manual_report: event.manual_report ? 1 : 0,\n level: event.level,\n occurred_at: event.occurred_at,\n });\n }\n\n async emit(event: WireEvent): Promise<void> {\n this.emitSync(event);\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n}\n","import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\n\nexport const DEFAULT_INGEST_URL = \"https://gg-pixel-server.buzzbeamaustralia.workers.dev\";\n\nexport interface InstallOptions {\n cwd?: string;\n ingestUrl?: string;\n projectName?: string;\n fetchFn?: typeof fetch;\n skipPackageInstall?: boolean;\n homeDir?: string;\n}\n\nexport interface InstallResult {\n projectId: string;\n projectKey: string;\n projectName: string;\n initFilePath: string;\n envFilePath: string;\n projectsJsonPath: string;\n packageManager: PackageManager;\n packageInstalled: boolean;\n entryWiring: EntryWiringResult;\n /** True when an existing project mapping was reused instead of minting a fresh one. */\n reused: boolean;\n}\n\nexport type EntryWiringResult =\n | { kind: \"injected\"; entryPath: string }\n | { kind: \"already_present\"; entryPath: string }\n | { kind: \"no_entry_found\" }\n | { kind: \"skipped\"; reason: string };\n\ninterface PackageJson {\n name?: string;\n type?: string;\n main?: string;\n module?: string;\n bin?: string | Record<string, string>;\n}\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport async function install(opts: InstallOptions = {}): Promise<InstallResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const ingestUrl = (opts.ingestUrl ?? DEFAULT_INGEST_URL).replace(/\\/+$/, \"\");\n const fetchFn = opts.fetchFn ?? fetch;\n\n const projectRoot = findProjectRoot(cwd);\n if (!projectRoot) {\n throw new Error(`No package.json found in ${cwd} or any parent directory.`);\n }\n\n const pkgPath = join(projectRoot, \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as PackageJson;\n const projectName = opts.projectName ?? pkg.name ?? projectRoot.split(\"/\").pop() ?? \"unnamed\";\n\n const home = opts.homeDir ?? homedir();\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(projectRoot, \".env\");\n\n // Idempotency: if we already have a mapping for this directory AND the .env\n // still has its key, reuse it instead of minting a fresh project.\n const existing = findMappingByPath(projectsJsonPath, projectRoot);\n const existingKey = readEnvKey(envFilePath, \"GG_PIXEL_KEY\");\n let created: { id: string; key: string };\n let reused = false;\n if (existing && existingKey) {\n created = { id: existing.id, key: existingKey };\n reused = true;\n } else {\n created = await createProject(fetchFn, ingestUrl, projectName);\n }\n\n const pm = detectPackageManager(projectRoot);\n const packageInstalled = opts.skipPackageInstall\n ? false\n : runInstall(projectRoot, pm, \"@kenkaiiii/gg-pixel\");\n\n const initFilePath = join(projectRoot, \"gg-pixel.init.mjs\");\n writeFileSync(initFilePath, renderInitFile(ingestUrl), \"utf8\");\n\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n\n writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);\n\n const entryWiring = wireEntryFile(projectRoot, initFilePath, pkg);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n initFilePath,\n envFilePath,\n projectsJsonPath,\n packageManager: pm,\n packageInstalled,\n entryWiring,\n reused,\n };\n}\n\nfunction findMappingByPath(\n projectsJsonPath: string,\n projectRoot: string,\n): { id: string; name: string; path: string } | null {\n if (!existsSync(projectsJsonPath)) return null;\n let map: Record<string, { name: string; path: string }>;\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n return null;\n }\n for (const [id, entry] of Object.entries(map)) {\n if (entry.path === projectRoot) return { id, ...entry };\n }\n return null;\n}\n\nfunction readEnvKey(envPath: string, key: string): string | null {\n if (!existsSync(envPath)) return null;\n try {\n const content = readFileSync(envPath, \"utf8\");\n const match = new RegExp(`^${key}=(.+)$`, \"m\").exec(content);\n return match?.[1]?.trim() ?? null;\n } catch {\n return null;\n }\n}\n\nfunction findProjectRoot(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n return null;\n}\n\nasync function createProject(\n fetchFn: typeof fetch,\n ingestUrl: string,\n name: string,\n): Promise<{ id: string; key: string }> {\n const res = await fetchFn(`${ingestUrl}/api/projects`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ name }),\n });\n if (!res.ok) {\n throw new Error(`POST /api/projects failed: ${res.status} ${await safeText(res)}`);\n }\n const body = (await res.json()) as { id: string; key: string };\n if (!body.id || !body.key) throw new Error(\"response missing id/key\");\n return { id: body.id, key: body.key };\n}\n\nasync function safeText(r: Response): Promise<string> {\n try {\n return await r.text();\n } catch {\n return \"\";\n }\n}\n\nexport function detectPackageManager(projectRoot: string): PackageManager {\n if (existsSync(join(projectRoot, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(projectRoot, \"bun.lockb\"))) return \"bun\";\n if (existsSync(join(projectRoot, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nfunction runInstall(projectRoot: string, pm: PackageManager, pkg: string): boolean {\n const cmd = pm;\n // npm prints `npm audit` warnings + `npm fund` solicitations on every install.\n // That output is about the user's *existing* project — irrelevant to pixel.\n // The other package managers don't show this noise by default.\n const args = pm === \"npm\" ? [\"install\", pkg, \"--no-audit\", \"--no-fund\"] : [\"add\", pkg];\n const result = spawnSync(cmd, args, { cwd: projectRoot, stdio: \"inherit\" });\n return result.status === 0;\n}\n\nexport function renderInitFile(ingestUrl: string): string {\n return `import { initPixel } from \"@kenkaiiii/gg-pixel\";\n\nconst key = process.env.GG_PIXEL_KEY;\nif (key) {\n initPixel({\n projectKey: key,\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\n });\n}\n`;\n}\n\nexport function writeEnvKey(envPath: string, key: string, value: string): void {\n if (existsSync(envPath)) {\n const current = readFileSync(envPath, \"utf8\");\n const lineRegex = new RegExp(`^${key}=.*$`, \"m\");\n if (lineRegex.test(current)) {\n writeFileSync(envPath, current.replace(lineRegex, `${key}=${value}`), \"utf8\");\n return;\n }\n const sep = current.endsWith(\"\\n\") || current.length === 0 ? \"\" : \"\\n\";\n appendFileSync(envPath, `${sep}${key}=${value}\\n`, \"utf8\");\n return;\n }\n writeFileSync(envPath, `${key}=${value}\\n`, \"utf8\");\n}\n\nexport function wireEntryFile(\n projectRoot: string,\n initFilePath: string,\n pkg: PackageJson,\n): EntryWiringResult {\n const entryPath = findEntryFile(projectRoot, pkg);\n if (!entryPath) return { kind: \"no_entry_found\" };\n\n let content: string;\n try {\n content = readFileSync(entryPath, \"utf8\");\n } catch (err) {\n return { kind: \"skipped\", reason: `unreadable: ${(err as Error).message}` };\n }\n\n if (content.includes(\"gg-pixel.init\")) {\n return { kind: \"already_present\", entryPath };\n }\n\n // Compute import specifier relative to the entry file.\n const fromDir = dirname(entryPath);\n let spec = relative(fromDir, initFilePath).split(sep).join(\"/\");\n if (!spec.startsWith(\".\")) spec = \"./\" + spec;\n\n const isCjs = isCommonJsEntry(entryPath, pkg);\n const importLine = isCjs\n ? `require(${JSON.stringify(spec)});`\n : `import ${JSON.stringify(spec)};`;\n\n // Inject at the top — after a shebang line and any leading \"use strict\",\n // but before all other code, so pixel hooks run before anything else.\n const lines = content.split(\"\\n\");\n let insertAt = 0;\n if (lines[0]?.startsWith(\"#!\")) insertAt = 1;\n while (\n insertAt < lines.length &&\n /^\\s*(?:[\"']use strict[\"']|\\/\\/|\\/\\*)/.test(lines[insertAt] ?? \"\")\n ) {\n insertAt++;\n }\n\n const updated = [...lines.slice(0, insertAt), importLine, ...lines.slice(insertAt)].join(\"\\n\");\n writeFileSync(entryPath, updated, \"utf8\");\n return { kind: \"injected\", entryPath };\n}\n\nfunction findEntryFile(projectRoot: string, pkg: PackageJson): string | null {\n const tryPath = (rel: string): string | null => {\n const p = join(projectRoot, rel);\n if (existsSync(p)) return p;\n // If user pointed `main` at .js but only the .ts source exists (common in TS projects).\n if (rel.endsWith(\".js\")) {\n const ts = join(projectRoot, rel.replace(/\\.js$/, \".ts\"));\n if (existsSync(ts)) return ts;\n }\n return null;\n };\n\n if (typeof pkg.bin === \"string\") {\n const found = tryPath(pkg.bin);\n if (found) return found;\n }\n if (pkg.bin && typeof pkg.bin === \"object\") {\n for (const value of Object.values(pkg.bin)) {\n if (typeof value === \"string\") {\n const found = tryPath(value);\n if (found) return found;\n }\n }\n }\n if (pkg.main) {\n const found = tryPath(pkg.main);\n if (found) return found;\n }\n if (pkg.module) {\n const found = tryPath(pkg.module);\n if (found) return found;\n }\n\n // Fall back to common conventions.\n const candidates = [\n \"src/index.ts\",\n \"src/index.tsx\",\n \"src/index.js\",\n \"src/index.mjs\",\n \"src/main.ts\",\n \"src/main.tsx\",\n \"src/main.js\",\n \"src/server.ts\",\n \"src/server.js\",\n \"src/app.ts\",\n \"src/app.js\",\n \"src/cli.ts\",\n \"src/cli.js\",\n \"index.ts\",\n \"index.tsx\",\n \"index.js\",\n \"index.mjs\",\n \"main.ts\",\n \"main.js\",\n \"server.ts\",\n \"server.js\",\n \"app.ts\",\n \"app.js\",\n ];\n for (const c of candidates) {\n const found = tryPath(c);\n if (found) return found;\n }\n return null;\n}\n\nfunction isCommonJsEntry(entryPath: string, pkg: PackageJson): boolean {\n if (entryPath.endsWith(\".cjs\")) return true;\n if (entryPath.endsWith(\".mjs\")) return false;\n if (entryPath.endsWith(\".ts\") || entryPath.endsWith(\".tsx\")) return false;\n // .js → governed by package.json type (default is \"commonjs\")\n return pkg.type !== \"module\";\n}\n\nexport function writeProjectsMapping(\n projectsJsonPath: string,\n projectId: string,\n name: string,\n path: string,\n): void {\n mkdirSync(dirname(projectsJsonPath), { recursive: true });\n let map: Record<string, { name: string; path: string }> = {};\n if (existsSync(projectsJsonPath)) {\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n // start fresh on corrupt file\n }\n }\n map[projectId] = { name, path };\n writeFileSync(projectsJsonPath, `${JSON.stringify(map, null, 2)}\\n`, \"utf8\");\n}\n"],"mappings":"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","names":["import_node_crypto","import_node_fs","Database","import_node_fs","import_node_os","import_node_path","sep"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapters/node.ts","../src/core/stack.ts","../src/core/fingerprint.ts","../src/code-context.ts","../src/core/queue.ts","../src/core/sinks/node-http.ts","../src/core/sinks/http.ts","../src/core/sinks/local-sqlite.ts","../src/install.ts"],"sourcesContent":["import { installNodeAdapter, type NodeAdapter } from \"./adapters/node.js\";\nimport { NodeHttpSink } from \"./core/sinks/node-http.js\";\nimport { LocalSqliteSink } from \"./core/sinks/local-sqlite.js\";\nimport type { PixelOptions, ReportInput, Sink, SinkConfig } from \"./core/types.js\";\n\nlet active: NodeAdapter | null = null;\n\nexport function initPixel(options: PixelOptions): NodeAdapter {\n if (active) {\n throw new Error(\"gg-pixel is already initialized; call closePixel() first\");\n }\n const sink = buildSink(options.sink);\n active = installNodeAdapter({\n projectKey: options.projectKey,\n runtime: options.runtime ?? defaultRuntime(),\n sink,\n captureConsoleErrors: options.captureConsoleErrors ?? true,\n captureConsoleWarnings: options.captureConsoleWarnings ?? false,\n captureUnhandledRejections: options.captureUnhandledRejections ?? true,\n captureUncaughtExceptions: options.captureUncaughtExceptions ?? true,\n });\n return active;\n}\n\nexport function reportPixel(input: ReportInput): void {\n if (!active) return;\n active.report(input);\n}\n\nexport async function flushPixel(): Promise<void> {\n if (!active) return;\n await active.flush();\n}\n\nexport async function closePixel(): Promise<void> {\n if (!active) return;\n await active.close();\n active = null;\n}\n\nfunction buildSink(config: SinkConfig): Sink {\n switch (config.kind) {\n case \"http\":\n return new NodeHttpSink(config.ingestUrl, config.fetchFn);\n case \"local\":\n return new LocalSqliteSink(config.path);\n case \"custom\":\n return config.sink;\n }\n}\n\nfunction defaultRuntime(): string {\n const v = process.versions.node;\n return `node-${v}`;\n}\n\nexport type {\n Level,\n PixelOptions,\n ReportInput,\n Sink,\n SinkConfig,\n StackFrame,\n CodeContext,\n WireEvent,\n} from \"./core/types.js\";\n\nexport { install, DEFAULT_INGEST_URL } from \"./install.js\";\nexport type { InstallOptions, InstallResult, PackageManager } from \"./install.js\";\n","import { randomUUID } from \"node:crypto\";\nimport { parseStack } from \"../core/stack.js\";\nimport { fingerprint } from \"../core/fingerprint.js\";\nimport { captureCodeContext } from \"../code-context.js\";\nimport { EventQueue } from \"../core/queue.js\";\nimport type { Level, ReportInput, Sink, WireEvent } from \"../core/types.js\";\n\nexport interface NodeAdapterOptions {\n projectKey: string;\n runtime: string;\n sink: Sink;\n captureConsoleErrors: boolean;\n captureConsoleWarnings: boolean;\n captureUnhandledRejections: boolean;\n captureUncaughtExceptions: boolean;\n}\n\nexport interface NodeAdapter {\n report(input: ReportInput): void;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport function installNodeAdapter(opts: NodeAdapterOptions): NodeAdapter {\n const queue = new EventQueue(opts.sink);\n const detach: Array<() => void> = [];\n\n const enqueueError = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n const enqueueErrorSync = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueueSync(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n if (opts.captureUncaughtExceptions) {\n const handler = (err: Error) => enqueueErrorSync(err, \"fatal\", false);\n process.on(\"uncaughtExceptionMonitor\", handler);\n detach.push(() => process.off(\"uncaughtExceptionMonitor\", handler));\n }\n\n if (opts.captureUnhandledRejections) {\n const handler = (reason: unknown) => enqueueErrorSync(reason, \"error\", false);\n process.on(\"unhandledRejection\", handler);\n detach.push(() => process.off(\"unhandledRejection\", handler));\n }\n\n if (opts.captureConsoleErrors) {\n detach.push(patchConsole(\"error\", (args) => enqueueError(consoleError(args), \"error\", false)));\n }\n\n if (opts.captureConsoleWarnings) {\n detach.push(patchConsole(\"warn\", (args) => enqueueError(consoleError(args), \"warning\", false)));\n }\n\n const onBeforeExit = () => {\n void queue.flush();\n };\n process.on(\"beforeExit\", onBeforeExit);\n detach.push(() => process.off(\"beforeExit\", onBeforeExit));\n\n return {\n report(input: ReportInput) {\n const level = input.level ?? \"error\";\n if (input.error !== undefined) {\n try {\n const event = buildEvent(input.error, level, true, opts.projectKey, opts.runtime);\n if (input.message) event.message = input.message;\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n return;\n }\n const err = new Error(input.message);\n err.name = \"ManualReport\";\n enqueueError(err, level, true);\n },\n flush: () => queue.flush(),\n close: async () => {\n for (const fn of detach) fn();\n await queue.close();\n },\n };\n}\n\nfunction buildEvent(\n err: unknown,\n level: Level,\n manual: boolean,\n projectKey: string,\n runtime: string,\n): WireEvent {\n const { type, message, stackString } = normalize(err);\n const stack = parseStack(stackString);\n return {\n event_id: randomUUID(),\n project_key: projectKey,\n fingerprint: fingerprint(type, stack),\n type,\n message,\n stack,\n code_context: captureCodeContext(stack),\n runtime,\n manual_report: manual,\n level,\n occurred_at: new Date().toISOString(),\n };\n}\n\nfunction normalize(err: unknown): { type: string; message: string; stackString?: string } {\n if (err instanceof Error) {\n return { type: err.name || \"Error\", message: err.message, stackString: err.stack };\n }\n if (typeof err === \"string\") {\n return { type: \"StringError\", message: err };\n }\n try {\n return { type: \"UnknownError\", message: JSON.stringify(err) };\n } catch {\n return { type: \"UnknownError\", message: String(err) };\n }\n}\n\nfunction consoleError(args: unknown[]): unknown {\n for (const a of args) if (a instanceof Error) return a;\n return new Error(args.map(stringify).join(\" \"));\n}\n\nfunction stringify(x: unknown): string {\n if (typeof x === \"string\") return x;\n try {\n return JSON.stringify(x);\n } catch {\n return String(x);\n }\n}\n\ntype ConsoleMethod = \"error\" | \"warn\";\n\nfunction patchConsole(method: ConsoleMethod, onCall: (args: unknown[]) => void): () => void {\n const original = console[method];\n console[method] = (...args: unknown[]) => {\n try {\n onCall(args);\n } catch {\n // never let pixel break the host program\n }\n original.apply(console, args);\n };\n return () => {\n console[method] = original;\n };\n}\n","import type { StackFrame } from \"./types.js\";\n\nconst FRAME_WITH_FN = /^\\s*at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)\\s*$/;\nconst FRAME_NO_FN = /^\\s*at\\s+(.+?):(\\d+):(\\d+)\\s*$/;\n\nexport function parseStack(stack: string | undefined): StackFrame[] {\n if (!stack) return [];\n const frames: StackFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n const withFn = FRAME_WITH_FN.exec(line);\n if (withFn) {\n const file = withFn[2];\n frames.push({\n fn: withFn[1],\n file,\n line: Number(withFn[3]),\n col: Number(withFn[4]),\n in_app: isInApp(file),\n });\n continue;\n }\n const noFn = FRAME_NO_FN.exec(line);\n if (noFn) {\n const file = noFn[1];\n frames.push({\n fn: \"<anon>\",\n file,\n line: Number(noFn[2]),\n col: Number(noFn[3]),\n in_app: isInApp(file),\n });\n }\n }\n return frames;\n}\n\nfunction isInApp(file: string): boolean {\n if (!file) return false;\n if (file.startsWith(\"node:\")) return false;\n if (file.startsWith(\"internal/\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return true;\n}\n","import { createHash } from \"node:crypto\";\nimport type { StackFrame } from \"./types.js\";\n\nexport function fingerprint(type: string, stack: StackFrame[]): string {\n const top = stack[0];\n const normalized = top\n ? `${type}|${normalizeFile(top.file)}|${top.fn || \"<anon>\"}|${top.line}`\n : `${type}|<no-stack>`;\n return createHash(\"sha256\").update(normalized).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeFile(file: string): string {\n return file\n .replace(/^file:\\/\\//, \"\")\n .replace(/^.*\\/node_modules\\//, \"node_modules/\")\n .replace(/\\?.*$/, \"\");\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport type { CodeContext, StackFrame } from \"./core/types.js\";\n\nconst WINDOW = 2;\nconst cache = new Map<string, string[] | null>();\n\nexport function captureCodeContext(stack: StackFrame[]): CodeContext | null {\n const top = stack.find((f) => isReadable(f.file));\n if (!top) return null;\n const lines = loadLines(top.file);\n if (!lines) return null;\n const start = Math.max(0, top.line - 1 - WINDOW);\n const end = Math.min(lines.length, top.line + WINDOW);\n return {\n file: top.file,\n error_line: top.line,\n lines: lines.slice(start, end),\n };\n}\n\nfunction isReadable(file: string): boolean {\n if (!file || file.startsWith(\"node:\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return file.startsWith(\"/\") || file.startsWith(\"file://\");\n}\n\nfunction loadLines(file: string): string[] | null {\n const path = file.replace(/^file:\\/\\//, \"\");\n if (cache.has(path)) return cache.get(path) ?? null;\n if (!existsSync(path)) {\n cache.set(path, null);\n return null;\n }\n try {\n const lines = readFileSync(path, \"utf8\").split(\"\\n\");\n cache.set(path, lines);\n return lines;\n } catch {\n cache.set(path, null);\n return null;\n }\n}\n","import type { Sink, WireEvent } from \"./types.js\";\n\nconst MAX_BUFFER = 100;\nconst BASE_DELAY_MS = 200;\nconst MAX_DELAY_MS = 5_000;\n\nexport class EventQueue {\n private readonly buffer: WireEvent[] = [];\n private draining = false;\n private closed = false;\n\n constructor(private readonly sink: Sink) {}\n\n enqueue(event: WireEvent): void {\n if (this.closed) return;\n if (this.buffer.length >= MAX_BUFFER) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n void this.drain();\n }\n\n enqueueSync(event: WireEvent): void {\n if (this.closed) return;\n if (this.sink.emitSync) {\n try {\n this.sink.emitSync(event);\n return;\n } catch {\n // fall through to async path\n }\n }\n this.enqueue(event);\n }\n\n async flush(): Promise<void> {\n while (this.buffer.length > 0 || this.draining) {\n await new Promise((r) => setTimeout(r, 10));\n }\n }\n\n async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n if (this.sink.close) await this.sink.close();\n }\n\n private async drain(): Promise<void> {\n if (this.draining) return;\n this.draining = true;\n let attempt = 0;\n while (this.buffer.length > 0) {\n const event = this.buffer[0];\n try {\n await this.sink.emit(event);\n this.buffer.shift();\n attempt = 0;\n } catch (err) {\n attempt++;\n if (attempt >= 5) {\n // Drop the event but make the loss observable — silent data loss\n // from the error tracker is the worst possible failure mode.\n console.warn(\n `[gg-pixel] dropping event after 5 failed deliveries: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n this.buffer.shift();\n attempt = 0;\n continue;\n }\n const delay = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n this.draining = false;\n }\n}\n","import { spawnSync } from \"node:child_process\";\nimport { HttpSink } from \"./http.js\";\nimport type { WireEvent } from \"../types.js\";\n\n/**\n * Node-only HTTP sink that adds a synchronous `emitSync` path for fatal\n * events.\n *\n * Why: when `uncaughtExceptionMonitor` fires, Node tears the process down\n * before any pending async work can complete — meaning a normal `fetch()` to\n * the ingest endpoint loses the most important event (the fatal one).\n * Sentry's Node SDK solves this for serverless environments by spawning\n * an external HTTP client synchronously. We do the same with `curl`, which\n * ships with macOS, every modern Linux distro, and Windows 10 1803+.\n *\n * Tradeoff: ~100ms latency per fatal event (curl process spin-up). Fatal\n * events are rare so this is acceptable. Pending non-fatal events still in\n * the async queue at crash time may be lost — flushing them sync would\n * block the fatal handler for seconds in the worst case.\n */\nexport class NodeHttpSink extends HttpSink {\n constructor(\n private readonly url: string,\n fetchFn?: typeof fetch,\n ) {\n super(url, fetchFn);\n }\n\n emitSync(event: WireEvent): void {\n const body = JSON.stringify(event);\n const result = spawnSync(\n \"curl\",\n [\n \"--silent\",\n \"--show-error\",\n \"-X\",\n \"POST\",\n \"-H\",\n \"content-type: application/json\",\n \"-H\",\n `x-pixel-key: ${event.project_key}`,\n \"--data-binary\",\n \"@-\",\n \"--max-time\",\n \"3\",\n this.url,\n ],\n { input: body, encoding: \"utf8\" },\n );\n if (result.error || result.status !== 0) {\n // Best-effort. We're already in a fatal handler; can't retry async.\n console.warn(\n `[gg-pixel] sync emit failed: ${result.error?.message ?? result.stderr ?? \"unknown\"}`,\n );\n }\n }\n}\n","import type { Sink, WireEvent } from \"../types.js\";\n\nexport class HttpSink implements Sink {\n private readonly fetchFn: typeof fetch;\n\n constructor(\n private readonly ingestUrl: string,\n fetchFn?: typeof fetch,\n ) {\n // CRITICAL: in browsers `fetch` is `window.fetch` and requires `this === window`.\n // Storing it as a property and calling via `this.fetchFn(...)` strips that\n // binding and throws \"Illegal invocation\". Bind to globalThis on assignment.\n // Tests can still inject a custom fetchFn (no binding needed for plain fns).\n this.fetchFn = fetchFn ?? globalThis.fetch.bind(globalThis);\n }\n\n async emit(event: WireEvent): Promise<void> {\n const body = JSON.stringify(event);\n // `keepalive: true` lets the request survive page unload (browser).\n // `mode: \"cors\"` is the explicit default but stating it makes the\n // intent clear and avoids surprises on stricter contexts.\n const res = await this.fetchFn(this.ingestUrl, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-pixel-key\": event.project_key,\n },\n body,\n keepalive: typeof window !== \"undefined\",\n mode: typeof window !== \"undefined\" ? \"cors\" : undefined,\n });\n if (!res.ok) {\n throw new Error(`pixel ingest failed: ${res.status}`);\n }\n }\n}\n","import { homedir } from \"node:os\";\nimport { mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { Sink, WireEvent } from \"../types.js\";\n\nconst SCHEMA = `\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n event_id TEXT NOT NULL UNIQUE,\n project_key TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n type TEXT NOT NULL,\n message TEXT NOT NULL,\n stack TEXT NOT NULL,\n code_context TEXT,\n runtime TEXT NOT NULL,\n manual_report INTEGER NOT NULL DEFAULT 0,\n level TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n ingested_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS events_fingerprint ON events(project_key, fingerprint);\n CREATE INDEX IF NOT EXISTS events_occurred ON events(occurred_at);\n`;\n\nexport class LocalSqliteSink implements Sink {\n private readonly db: Database.Database;\n private readonly insert: Database.Statement;\n\n constructor(path?: string) {\n const resolved = path ?? join(homedir(), \".gg\", \"errors.db\");\n mkdirSync(dirname(resolved), { recursive: true });\n this.db = new Database(resolved);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.exec(SCHEMA);\n this.insert = this.db.prepare(`\n INSERT INTO events (\n event_id, project_key, fingerprint, type, message, stack, code_context,\n runtime, manual_report, level, occurred_at\n ) VALUES (\n @event_id, @project_key, @fingerprint, @type, @message, @stack, @code_context,\n @runtime, @manual_report, @level, @occurred_at\n )\n `);\n }\n\n emitSync(event: WireEvent): void {\n this.insert.run({\n event_id: event.event_id,\n project_key: event.project_key,\n fingerprint: event.fingerprint,\n type: event.type,\n message: event.message,\n stack: JSON.stringify(event.stack),\n code_context: event.code_context ? JSON.stringify(event.code_context) : null,\n runtime: event.runtime,\n manual_report: event.manual_report ? 1 : 0,\n level: event.level,\n occurred_at: event.occurred_at,\n });\n }\n\n async emit(event: WireEvent): Promise<void> {\n this.emitSync(event);\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n}\n","import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\n\nexport const DEFAULT_INGEST_URL = \"https://gg-pixel-server.buzzbeamaustralia.workers.dev\";\n\nexport interface InstallOptions {\n cwd?: string;\n ingestUrl?: string;\n projectName?: string;\n fetchFn?: typeof fetch;\n skipPackageInstall?: boolean;\n homeDir?: string;\n}\n\nexport interface InstallResult {\n projectId: string;\n projectKey: string;\n projectName: string;\n initFilePath: string;\n envFilePath: string;\n projectsJsonPath: string;\n packageManager: PackageManager;\n packageInstalled: boolean;\n entryWiring: EntryWiringResult;\n /** True when an existing project mapping was reused instead of minting a fresh one. */\n reused: boolean;\n}\n\nexport type EntryWiringResult =\n | { kind: \"injected\"; entryPath: string }\n | { kind: \"already_present\"; entryPath: string }\n | { kind: \"no_entry_found\" }\n | { kind: \"skipped\"; reason: string };\n\ninterface PackageJson {\n name?: string;\n type?: string;\n main?: string;\n module?: string;\n bin?: string | Record<string, string>;\n}\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport async function install(opts: InstallOptions = {}): Promise<InstallResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const ingestUrl = (opts.ingestUrl ?? DEFAULT_INGEST_URL).replace(/\\/+$/, \"\");\n const fetchFn = opts.fetchFn ?? fetch;\n\n const projectRoot = findProjectRoot(cwd);\n if (!projectRoot) {\n throw new Error(`No package.json found in ${cwd} or any parent directory.`);\n }\n\n const pkgPath = join(projectRoot, \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as PackageJson;\n const projectName = opts.projectName ?? pkg.name ?? projectRoot.split(\"/\").pop() ?? \"unnamed\";\n\n const home = opts.homeDir ?? homedir();\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(projectRoot, \".env\");\n\n // Idempotency: if we already have a mapping for this directory AND the .env\n // still has its key, reuse it instead of minting a fresh project.\n const existing = findMappingByPath(projectsJsonPath, projectRoot);\n const existingKey = readEnvKey(envFilePath, \"GG_PIXEL_KEY\");\n let created: { id: string; key: string };\n let reused = false;\n if (existing && existingKey) {\n created = { id: existing.id, key: existingKey };\n reused = true;\n } else {\n created = await createProject(fetchFn, ingestUrl, projectName);\n }\n\n const pm = detectPackageManager(projectRoot);\n const packageInstalled = opts.skipPackageInstall\n ? false\n : runInstall(projectRoot, pm, \"@kenkaiiii/gg-pixel\");\n\n const initFilePath = join(projectRoot, \"gg-pixel.init.mjs\");\n writeFileSync(initFilePath, renderInitFile(ingestUrl), \"utf8\");\n\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n\n writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);\n\n const entryWiring = wireEntryFile(projectRoot, initFilePath, pkg);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n initFilePath,\n envFilePath,\n projectsJsonPath,\n packageManager: pm,\n packageInstalled,\n entryWiring,\n reused,\n };\n}\n\nfunction findMappingByPath(\n projectsJsonPath: string,\n projectRoot: string,\n): { id: string; name: string; path: string } | null {\n if (!existsSync(projectsJsonPath)) return null;\n let map: Record<string, { name: string; path: string }>;\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n return null;\n }\n for (const [id, entry] of Object.entries(map)) {\n if (entry.path === projectRoot) return { id, ...entry };\n }\n return null;\n}\n\nfunction readEnvKey(envPath: string, key: string): string | null {\n if (!existsSync(envPath)) return null;\n try {\n const content = readFileSync(envPath, \"utf8\");\n const match = new RegExp(`^${key}=(.+)$`, \"m\").exec(content);\n return match?.[1]?.trim() ?? null;\n } catch {\n return null;\n }\n}\n\nfunction findProjectRoot(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n return null;\n}\n\nasync function createProject(\n fetchFn: typeof fetch,\n ingestUrl: string,\n name: string,\n): Promise<{ id: string; key: string }> {\n const res = await fetchFn(`${ingestUrl}/api/projects`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ name }),\n });\n if (!res.ok) {\n throw new Error(`POST /api/projects failed: ${res.status} ${await safeText(res)}`);\n }\n const body = (await res.json()) as { id: string; key: string };\n if (!body.id || !body.key) throw new Error(\"response missing id/key\");\n return { id: body.id, key: body.key };\n}\n\nasync function safeText(r: Response): Promise<string> {\n try {\n return await r.text();\n } catch {\n return \"\";\n }\n}\n\nexport function detectPackageManager(projectRoot: string): PackageManager {\n if (existsSync(join(projectRoot, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(projectRoot, \"bun.lockb\"))) return \"bun\";\n if (existsSync(join(projectRoot, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nfunction runInstall(projectRoot: string, pm: PackageManager, pkg: string): boolean {\n const cmd = pm;\n // npm prints `npm audit` warnings + `npm fund` solicitations on every install.\n // That output is about the user's *existing* project — irrelevant to pixel.\n // The other package managers don't show this noise by default.\n const args = pm === \"npm\" ? [\"install\", pkg, \"--no-audit\", \"--no-fund\"] : [\"add\", pkg];\n const result = spawnSync(cmd, args, { cwd: projectRoot, stdio: \"inherit\" });\n return result.status === 0;\n}\n\nexport function renderInitFile(ingestUrl: string): string {\n return `import { initPixel } from \"@kenkaiiii/gg-pixel\";\n\nconst key = process.env.GG_PIXEL_KEY;\nif (key) {\n initPixel({\n projectKey: key,\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\n });\n}\n`;\n}\n\nexport function writeEnvKey(envPath: string, key: string, value: string): void {\n if (existsSync(envPath)) {\n const current = readFileSync(envPath, \"utf8\");\n const lineRegex = new RegExp(`^${key}=.*$`, \"m\");\n if (lineRegex.test(current)) {\n writeFileSync(envPath, current.replace(lineRegex, `${key}=${value}`), \"utf8\");\n return;\n }\n const sep = current.endsWith(\"\\n\") || current.length === 0 ? \"\" : \"\\n\";\n appendFileSync(envPath, `${sep}${key}=${value}\\n`, \"utf8\");\n return;\n }\n writeFileSync(envPath, `${key}=${value}\\n`, \"utf8\");\n}\n\nexport function wireEntryFile(\n projectRoot: string,\n initFilePath: string,\n pkg: PackageJson,\n): EntryWiringResult {\n const entryPath = findEntryFile(projectRoot, pkg);\n if (!entryPath) return { kind: \"no_entry_found\" };\n\n let content: string;\n try {\n content = readFileSync(entryPath, \"utf8\");\n } catch (err) {\n return { kind: \"skipped\", reason: `unreadable: ${(err as Error).message}` };\n }\n\n if (content.includes(\"gg-pixel.init\")) {\n return { kind: \"already_present\", entryPath };\n }\n\n // Compute import specifier relative to the entry file.\n const fromDir = dirname(entryPath);\n let spec = relative(fromDir, initFilePath).split(sep).join(\"/\");\n if (!spec.startsWith(\".\")) spec = \"./\" + spec;\n\n const isCjs = isCommonJsEntry(entryPath, pkg);\n const importLine = isCjs\n ? `require(${JSON.stringify(spec)});`\n : `import ${JSON.stringify(spec)};`;\n\n // Inject at the top — after a shebang line and any leading \"use strict\",\n // but before all other code, so pixel hooks run before anything else.\n const lines = content.split(\"\\n\");\n let insertAt = 0;\n if (lines[0]?.startsWith(\"#!\")) insertAt = 1;\n while (\n insertAt < lines.length &&\n /^\\s*(?:[\"']use strict[\"']|\\/\\/|\\/\\*)/.test(lines[insertAt] ?? \"\")\n ) {\n insertAt++;\n }\n\n const updated = [...lines.slice(0, insertAt), importLine, ...lines.slice(insertAt)].join(\"\\n\");\n writeFileSync(entryPath, updated, \"utf8\");\n return { kind: \"injected\", entryPath };\n}\n\nfunction findEntryFile(projectRoot: string, pkg: PackageJson): string | null {\n const tryPath = (rel: string): string | null => {\n const p = join(projectRoot, rel);\n if (existsSync(p)) return p;\n // If user pointed `main` at .js but only the .ts source exists (common in TS projects).\n if (rel.endsWith(\".js\")) {\n const ts = join(projectRoot, rel.replace(/\\.js$/, \".ts\"));\n if (existsSync(ts)) return ts;\n }\n return null;\n };\n\n if (typeof pkg.bin === \"string\") {\n const found = tryPath(pkg.bin);\n if (found) return found;\n }\n if (pkg.bin && typeof pkg.bin === \"object\") {\n for (const value of Object.values(pkg.bin)) {\n if (typeof value === \"string\") {\n const found = tryPath(value);\n if (found) return found;\n }\n }\n }\n if (pkg.main) {\n const found = tryPath(pkg.main);\n if (found) return found;\n }\n if (pkg.module) {\n const found = tryPath(pkg.module);\n if (found) return found;\n }\n\n // Fall back to common conventions.\n const candidates = [\n \"src/index.ts\",\n \"src/index.tsx\",\n \"src/index.js\",\n \"src/index.mjs\",\n \"src/main.ts\",\n \"src/main.tsx\",\n \"src/main.js\",\n \"src/server.ts\",\n \"src/server.js\",\n \"src/app.ts\",\n \"src/app.js\",\n \"src/cli.ts\",\n \"src/cli.js\",\n \"index.ts\",\n \"index.tsx\",\n \"index.js\",\n \"index.mjs\",\n \"main.ts\",\n \"main.js\",\n \"server.ts\",\n \"server.js\",\n \"app.ts\",\n \"app.js\",\n ];\n for (const c of candidates) {\n const found = tryPath(c);\n if (found) return found;\n }\n return null;\n}\n\nfunction isCommonJsEntry(entryPath: string, pkg: PackageJson): boolean {\n if (entryPath.endsWith(\".cjs\")) return true;\n if (entryPath.endsWith(\".mjs\")) return false;\n if (entryPath.endsWith(\".ts\") || entryPath.endsWith(\".tsx\")) return false;\n // .js → governed by package.json type (default is \"commonjs\")\n return pkg.type !== \"module\";\n}\n\nexport function writeProjectsMapping(\n projectsJsonPath: string,\n projectId: string,\n name: string,\n path: string,\n): void {\n mkdirSync(dirname(projectsJsonPath), { recursive: true });\n let map: Record<string, { name: string; path: string }> = {};\n if (existsSync(projectsJsonPath)) {\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n // start fresh on corrupt file\n }\n }\n map[projectId] = { name, path };\n writeFileSync(projectsJsonPath, `${JSON.stringify(map, null, 2)}\\n`, \"utf8\");\n}\n"],"mappings":"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","names":["import_node_crypto","import_node_fs","Database","import_node_fs","import_node_os","import_node_path","import_node_child_process","sep"]}
|
package/dist/index.js
CHANGED
|
@@ -142,9 +142,12 @@ var EventQueue = class {
|
|
|
142
142
|
await this.sink.emit(event);
|
|
143
143
|
this.buffer.shift();
|
|
144
144
|
attempt = 0;
|
|
145
|
-
} catch {
|
|
145
|
+
} catch (err) {
|
|
146
146
|
attempt++;
|
|
147
147
|
if (attempt >= 5) {
|
|
148
|
+
console.warn(
|
|
149
|
+
`[gg-pixel] dropping event after 5 failed deliveries: ${err instanceof Error ? err.message : String(err)}`
|
|
150
|
+
);
|
|
148
151
|
this.buffer.shift();
|
|
149
152
|
attempt = 0;
|
|
150
153
|
continue;
|
|
@@ -275,12 +278,16 @@ function patchConsole(method, onCall) {
|
|
|
275
278
|
};
|
|
276
279
|
}
|
|
277
280
|
|
|
281
|
+
// src/core/sinks/node-http.ts
|
|
282
|
+
import { spawnSync } from "child_process";
|
|
283
|
+
|
|
278
284
|
// src/core/sinks/http.ts
|
|
279
285
|
var HttpSink = class {
|
|
280
|
-
constructor(ingestUrl, fetchFn
|
|
286
|
+
constructor(ingestUrl, fetchFn) {
|
|
281
287
|
this.ingestUrl = ingestUrl;
|
|
282
|
-
this.fetchFn = fetchFn;
|
|
288
|
+
this.fetchFn = fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
283
289
|
}
|
|
290
|
+
fetchFn;
|
|
284
291
|
async emit(event) {
|
|
285
292
|
const body = JSON.stringify(event);
|
|
286
293
|
const res = await this.fetchFn(this.ingestUrl, {
|
|
@@ -299,6 +306,41 @@ var HttpSink = class {
|
|
|
299
306
|
}
|
|
300
307
|
};
|
|
301
308
|
|
|
309
|
+
// src/core/sinks/node-http.ts
|
|
310
|
+
var NodeHttpSink = class extends HttpSink {
|
|
311
|
+
constructor(url, fetchFn) {
|
|
312
|
+
super(url, fetchFn);
|
|
313
|
+
this.url = url;
|
|
314
|
+
}
|
|
315
|
+
emitSync(event) {
|
|
316
|
+
const body = JSON.stringify(event);
|
|
317
|
+
const result = spawnSync(
|
|
318
|
+
"curl",
|
|
319
|
+
[
|
|
320
|
+
"--silent",
|
|
321
|
+
"--show-error",
|
|
322
|
+
"-X",
|
|
323
|
+
"POST",
|
|
324
|
+
"-H",
|
|
325
|
+
"content-type: application/json",
|
|
326
|
+
"-H",
|
|
327
|
+
`x-pixel-key: ${event.project_key}`,
|
|
328
|
+
"--data-binary",
|
|
329
|
+
"@-",
|
|
330
|
+
"--max-time",
|
|
331
|
+
"3",
|
|
332
|
+
this.url
|
|
333
|
+
],
|
|
334
|
+
{ input: body, encoding: "utf8" }
|
|
335
|
+
);
|
|
336
|
+
if (result.error || result.status !== 0) {
|
|
337
|
+
console.warn(
|
|
338
|
+
`[gg-pixel] sync emit failed: ${result.error?.message ?? result.stderr ?? "unknown"}`
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
302
344
|
// src/core/sinks/local-sqlite.ts
|
|
303
345
|
import { homedir } from "os";
|
|
304
346
|
import { mkdirSync } from "fs";
|
|
@@ -369,7 +411,7 @@ var LocalSqliteSink = class {
|
|
|
369
411
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
370
412
|
import { homedir as homedir2 } from "os";
|
|
371
413
|
import { dirname as dirname2, join as join2, relative, resolve, sep } from "path";
|
|
372
|
-
import { spawnSync } from "child_process";
|
|
414
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
373
415
|
var DEFAULT_INGEST_URL = "https://gg-pixel-server.buzzbeamaustralia.workers.dev";
|
|
374
416
|
async function install(opts = {}) {
|
|
375
417
|
const cwd = resolve(opts.cwd ?? process.cwd());
|
|
@@ -477,7 +519,7 @@ function detectPackageManager(projectRoot) {
|
|
|
477
519
|
function runInstall(projectRoot, pm, pkg) {
|
|
478
520
|
const cmd = pm;
|
|
479
521
|
const args = pm === "npm" ? ["install", pkg, "--no-audit", "--no-fund"] : ["add", pkg];
|
|
480
|
-
const result =
|
|
522
|
+
const result = spawnSync2(cmd, args, { cwd: projectRoot, stdio: "inherit" });
|
|
481
523
|
return result.status === 0;
|
|
482
524
|
}
|
|
483
525
|
function renderInitFile(ingestUrl) {
|
|
@@ -650,7 +692,7 @@ async function closePixel() {
|
|
|
650
692
|
function buildSink(config) {
|
|
651
693
|
switch (config.kind) {
|
|
652
694
|
case "http":
|
|
653
|
-
return new
|
|
695
|
+
return new NodeHttpSink(config.ingestUrl, config.fetchFn);
|
|
654
696
|
case "local":
|
|
655
697
|
return new LocalSqliteSink(config.path);
|
|
656
698
|
case "custom":
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/node.ts","../src/core/stack.ts","../src/core/fingerprint.ts","../src/code-context.ts","../src/core/queue.ts","../src/core/sinks/http.ts","../src/core/sinks/local-sqlite.ts","../src/install.ts","../src/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { parseStack } from \"../core/stack.js\";\nimport { fingerprint } from \"../core/fingerprint.js\";\nimport { captureCodeContext } from \"../code-context.js\";\nimport { EventQueue } from \"../core/queue.js\";\nimport type { Level, ReportInput, Sink, WireEvent } from \"../core/types.js\";\n\nexport interface NodeAdapterOptions {\n projectKey: string;\n runtime: string;\n sink: Sink;\n captureConsoleErrors: boolean;\n captureConsoleWarnings: boolean;\n captureUnhandledRejections: boolean;\n captureUncaughtExceptions: boolean;\n}\n\nexport interface NodeAdapter {\n report(input: ReportInput): void;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport function installNodeAdapter(opts: NodeAdapterOptions): NodeAdapter {\n const queue = new EventQueue(opts.sink);\n const detach: Array<() => void> = [];\n\n const enqueueError = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n const enqueueErrorSync = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueueSync(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n if (opts.captureUncaughtExceptions) {\n const handler = (err: Error) => enqueueErrorSync(err, \"fatal\", false);\n process.on(\"uncaughtExceptionMonitor\", handler);\n detach.push(() => process.off(\"uncaughtExceptionMonitor\", handler));\n }\n\n if (opts.captureUnhandledRejections) {\n const handler = (reason: unknown) => enqueueErrorSync(reason, \"error\", false);\n process.on(\"unhandledRejection\", handler);\n detach.push(() => process.off(\"unhandledRejection\", handler));\n }\n\n if (opts.captureConsoleErrors) {\n detach.push(patchConsole(\"error\", (args) => enqueueError(consoleError(args), \"error\", false)));\n }\n\n if (opts.captureConsoleWarnings) {\n detach.push(patchConsole(\"warn\", (args) => enqueueError(consoleError(args), \"warning\", false)));\n }\n\n const onBeforeExit = () => {\n void queue.flush();\n };\n process.on(\"beforeExit\", onBeforeExit);\n detach.push(() => process.off(\"beforeExit\", onBeforeExit));\n\n return {\n report(input: ReportInput) {\n const level = input.level ?? \"error\";\n if (input.error !== undefined) {\n try {\n const event = buildEvent(input.error, level, true, opts.projectKey, opts.runtime);\n if (input.message) event.message = input.message;\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n return;\n }\n const err = new Error(input.message);\n err.name = \"ManualReport\";\n enqueueError(err, level, true);\n },\n flush: () => queue.flush(),\n close: async () => {\n for (const fn of detach) fn();\n await queue.close();\n },\n };\n}\n\nfunction buildEvent(\n err: unknown,\n level: Level,\n manual: boolean,\n projectKey: string,\n runtime: string,\n): WireEvent {\n const { type, message, stackString } = normalize(err);\n const stack = parseStack(stackString);\n return {\n event_id: randomUUID(),\n project_key: projectKey,\n fingerprint: fingerprint(type, stack),\n type,\n message,\n stack,\n code_context: captureCodeContext(stack),\n runtime,\n manual_report: manual,\n level,\n occurred_at: new Date().toISOString(),\n };\n}\n\nfunction normalize(err: unknown): { type: string; message: string; stackString?: string } {\n if (err instanceof Error) {\n return { type: err.name || \"Error\", message: err.message, stackString: err.stack };\n }\n if (typeof err === \"string\") {\n return { type: \"StringError\", message: err };\n }\n try {\n return { type: \"UnknownError\", message: JSON.stringify(err) };\n } catch {\n return { type: \"UnknownError\", message: String(err) };\n }\n}\n\nfunction consoleError(args: unknown[]): unknown {\n for (const a of args) if (a instanceof Error) return a;\n return new Error(args.map(stringify).join(\" \"));\n}\n\nfunction stringify(x: unknown): string {\n if (typeof x === \"string\") return x;\n try {\n return JSON.stringify(x);\n } catch {\n return String(x);\n }\n}\n\ntype ConsoleMethod = \"error\" | \"warn\";\n\nfunction patchConsole(method: ConsoleMethod, onCall: (args: unknown[]) => void): () => void {\n const original = console[method];\n console[method] = (...args: unknown[]) => {\n try {\n onCall(args);\n } catch {\n // never let pixel break the host program\n }\n original.apply(console, args);\n };\n return () => {\n console[method] = original;\n };\n}\n","import type { StackFrame } from \"./types.js\";\n\nconst FRAME_WITH_FN = /^\\s*at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)\\s*$/;\nconst FRAME_NO_FN = /^\\s*at\\s+(.+?):(\\d+):(\\d+)\\s*$/;\n\nexport function parseStack(stack: string | undefined): StackFrame[] {\n if (!stack) return [];\n const frames: StackFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n const withFn = FRAME_WITH_FN.exec(line);\n if (withFn) {\n const file = withFn[2];\n frames.push({\n fn: withFn[1],\n file,\n line: Number(withFn[3]),\n col: Number(withFn[4]),\n in_app: isInApp(file),\n });\n continue;\n }\n const noFn = FRAME_NO_FN.exec(line);\n if (noFn) {\n const file = noFn[1];\n frames.push({\n fn: \"<anon>\",\n file,\n line: Number(noFn[2]),\n col: Number(noFn[3]),\n in_app: isInApp(file),\n });\n }\n }\n return frames;\n}\n\nfunction isInApp(file: string): boolean {\n if (!file) return false;\n if (file.startsWith(\"node:\")) return false;\n if (file.startsWith(\"internal/\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return true;\n}\n","import { createHash } from \"node:crypto\";\nimport type { StackFrame } from \"./types.js\";\n\nexport function fingerprint(type: string, stack: StackFrame[]): string {\n const top = stack[0];\n const normalized = top\n ? `${type}|${normalizeFile(top.file)}|${top.fn || \"<anon>\"}|${top.line}`\n : `${type}|<no-stack>`;\n return createHash(\"sha256\").update(normalized).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeFile(file: string): string {\n return file\n .replace(/^file:\\/\\//, \"\")\n .replace(/^.*\\/node_modules\\//, \"node_modules/\")\n .replace(/\\?.*$/, \"\");\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport type { CodeContext, StackFrame } from \"./core/types.js\";\n\nconst WINDOW = 2;\nconst cache = new Map<string, string[] | null>();\n\nexport function captureCodeContext(stack: StackFrame[]): CodeContext | null {\n const top = stack.find((f) => isReadable(f.file));\n if (!top) return null;\n const lines = loadLines(top.file);\n if (!lines) return null;\n const start = Math.max(0, top.line - 1 - WINDOW);\n const end = Math.min(lines.length, top.line + WINDOW);\n return {\n file: top.file,\n error_line: top.line,\n lines: lines.slice(start, end),\n };\n}\n\nfunction isReadable(file: string): boolean {\n if (!file || file.startsWith(\"node:\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return file.startsWith(\"/\") || file.startsWith(\"file://\");\n}\n\nfunction loadLines(file: string): string[] | null {\n const path = file.replace(/^file:\\/\\//, \"\");\n if (cache.has(path)) return cache.get(path) ?? null;\n if (!existsSync(path)) {\n cache.set(path, null);\n return null;\n }\n try {\n const lines = readFileSync(path, \"utf8\").split(\"\\n\");\n cache.set(path, lines);\n return lines;\n } catch {\n cache.set(path, null);\n return null;\n }\n}\n","import type { Sink, WireEvent } from \"./types.js\";\n\nconst MAX_BUFFER = 100;\nconst BASE_DELAY_MS = 200;\nconst MAX_DELAY_MS = 5_000;\n\nexport class EventQueue {\n private readonly buffer: WireEvent[] = [];\n private draining = false;\n private closed = false;\n\n constructor(private readonly sink: Sink) {}\n\n enqueue(event: WireEvent): void {\n if (this.closed) return;\n if (this.buffer.length >= MAX_BUFFER) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n void this.drain();\n }\n\n enqueueSync(event: WireEvent): void {\n if (this.closed) return;\n if (this.sink.emitSync) {\n try {\n this.sink.emitSync(event);\n return;\n } catch {\n // fall through to async path\n }\n }\n this.enqueue(event);\n }\n\n async flush(): Promise<void> {\n while (this.buffer.length > 0 || this.draining) {\n await new Promise((r) => setTimeout(r, 10));\n }\n }\n\n async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n if (this.sink.close) await this.sink.close();\n }\n\n private async drain(): Promise<void> {\n if (this.draining) return;\n this.draining = true;\n let attempt = 0;\n while (this.buffer.length > 0) {\n const event = this.buffer[0];\n try {\n await this.sink.emit(event);\n this.buffer.shift();\n attempt = 0;\n } catch {\n attempt++;\n if (attempt >= 5) {\n this.buffer.shift();\n attempt = 0;\n continue;\n }\n const delay = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n this.draining = false;\n }\n}\n","import type { Sink, WireEvent } from \"../types.js\";\n\nexport class HttpSink implements Sink {\n constructor(\n private readonly ingestUrl: string,\n private readonly fetchFn: typeof fetch = fetch,\n ) {}\n\n async emit(event: WireEvent): Promise<void> {\n const body = JSON.stringify(event);\n // `keepalive: true` lets the request survive page unload (browser).\n // `mode: \"cors\"` is the explicit default but stating it makes the\n // intent clear and avoids surprises on stricter contexts.\n const res = await this.fetchFn(this.ingestUrl, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-pixel-key\": event.project_key,\n },\n body,\n keepalive: typeof window !== \"undefined\",\n mode: typeof window !== \"undefined\" ? \"cors\" : undefined,\n });\n if (!res.ok) {\n throw new Error(`pixel ingest failed: ${res.status}`);\n }\n }\n}\n","import { homedir } from \"node:os\";\nimport { mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { Sink, WireEvent } from \"../types.js\";\n\nconst SCHEMA = `\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n event_id TEXT NOT NULL UNIQUE,\n project_key TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n type TEXT NOT NULL,\n message TEXT NOT NULL,\n stack TEXT NOT NULL,\n code_context TEXT,\n runtime TEXT NOT NULL,\n manual_report INTEGER NOT NULL DEFAULT 0,\n level TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n ingested_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS events_fingerprint ON events(project_key, fingerprint);\n CREATE INDEX IF NOT EXISTS events_occurred ON events(occurred_at);\n`;\n\nexport class LocalSqliteSink implements Sink {\n private readonly db: Database.Database;\n private readonly insert: Database.Statement;\n\n constructor(path?: string) {\n const resolved = path ?? join(homedir(), \".gg\", \"errors.db\");\n mkdirSync(dirname(resolved), { recursive: true });\n this.db = new Database(resolved);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.exec(SCHEMA);\n this.insert = this.db.prepare(`\n INSERT INTO events (\n event_id, project_key, fingerprint, type, message, stack, code_context,\n runtime, manual_report, level, occurred_at\n ) VALUES (\n @event_id, @project_key, @fingerprint, @type, @message, @stack, @code_context,\n @runtime, @manual_report, @level, @occurred_at\n )\n `);\n }\n\n emitSync(event: WireEvent): void {\n this.insert.run({\n event_id: event.event_id,\n project_key: event.project_key,\n fingerprint: event.fingerprint,\n type: event.type,\n message: event.message,\n stack: JSON.stringify(event.stack),\n code_context: event.code_context ? JSON.stringify(event.code_context) : null,\n runtime: event.runtime,\n manual_report: event.manual_report ? 1 : 0,\n level: event.level,\n occurred_at: event.occurred_at,\n });\n }\n\n async emit(event: WireEvent): Promise<void> {\n this.emitSync(event);\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n}\n","import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\n\nexport const DEFAULT_INGEST_URL = \"https://gg-pixel-server.buzzbeamaustralia.workers.dev\";\n\nexport interface InstallOptions {\n cwd?: string;\n ingestUrl?: string;\n projectName?: string;\n fetchFn?: typeof fetch;\n skipPackageInstall?: boolean;\n homeDir?: string;\n}\n\nexport interface InstallResult {\n projectId: string;\n projectKey: string;\n projectName: string;\n initFilePath: string;\n envFilePath: string;\n projectsJsonPath: string;\n packageManager: PackageManager;\n packageInstalled: boolean;\n entryWiring: EntryWiringResult;\n /** True when an existing project mapping was reused instead of minting a fresh one. */\n reused: boolean;\n}\n\nexport type EntryWiringResult =\n | { kind: \"injected\"; entryPath: string }\n | { kind: \"already_present\"; entryPath: string }\n | { kind: \"no_entry_found\" }\n | { kind: \"skipped\"; reason: string };\n\ninterface PackageJson {\n name?: string;\n type?: string;\n main?: string;\n module?: string;\n bin?: string | Record<string, string>;\n}\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport async function install(opts: InstallOptions = {}): Promise<InstallResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const ingestUrl = (opts.ingestUrl ?? DEFAULT_INGEST_URL).replace(/\\/+$/, \"\");\n const fetchFn = opts.fetchFn ?? fetch;\n\n const projectRoot = findProjectRoot(cwd);\n if (!projectRoot) {\n throw new Error(`No package.json found in ${cwd} or any parent directory.`);\n }\n\n const pkgPath = join(projectRoot, \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as PackageJson;\n const projectName = opts.projectName ?? pkg.name ?? projectRoot.split(\"/\").pop() ?? \"unnamed\";\n\n const home = opts.homeDir ?? homedir();\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(projectRoot, \".env\");\n\n // Idempotency: if we already have a mapping for this directory AND the .env\n // still has its key, reuse it instead of minting a fresh project.\n const existing = findMappingByPath(projectsJsonPath, projectRoot);\n const existingKey = readEnvKey(envFilePath, \"GG_PIXEL_KEY\");\n let created: { id: string; key: string };\n let reused = false;\n if (existing && existingKey) {\n created = { id: existing.id, key: existingKey };\n reused = true;\n } else {\n created = await createProject(fetchFn, ingestUrl, projectName);\n }\n\n const pm = detectPackageManager(projectRoot);\n const packageInstalled = opts.skipPackageInstall\n ? false\n : runInstall(projectRoot, pm, \"@kenkaiiii/gg-pixel\");\n\n const initFilePath = join(projectRoot, \"gg-pixel.init.mjs\");\n writeFileSync(initFilePath, renderInitFile(ingestUrl), \"utf8\");\n\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n\n writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);\n\n const entryWiring = wireEntryFile(projectRoot, initFilePath, pkg);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n initFilePath,\n envFilePath,\n projectsJsonPath,\n packageManager: pm,\n packageInstalled,\n entryWiring,\n reused,\n };\n}\n\nfunction findMappingByPath(\n projectsJsonPath: string,\n projectRoot: string,\n): { id: string; name: string; path: string } | null {\n if (!existsSync(projectsJsonPath)) return null;\n let map: Record<string, { name: string; path: string }>;\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n return null;\n }\n for (const [id, entry] of Object.entries(map)) {\n if (entry.path === projectRoot) return { id, ...entry };\n }\n return null;\n}\n\nfunction readEnvKey(envPath: string, key: string): string | null {\n if (!existsSync(envPath)) return null;\n try {\n const content = readFileSync(envPath, \"utf8\");\n const match = new RegExp(`^${key}=(.+)$`, \"m\").exec(content);\n return match?.[1]?.trim() ?? null;\n } catch {\n return null;\n }\n}\n\nfunction findProjectRoot(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n return null;\n}\n\nasync function createProject(\n fetchFn: typeof fetch,\n ingestUrl: string,\n name: string,\n): Promise<{ id: string; key: string }> {\n const res = await fetchFn(`${ingestUrl}/api/projects`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ name }),\n });\n if (!res.ok) {\n throw new Error(`POST /api/projects failed: ${res.status} ${await safeText(res)}`);\n }\n const body = (await res.json()) as { id: string; key: string };\n if (!body.id || !body.key) throw new Error(\"response missing id/key\");\n return { id: body.id, key: body.key };\n}\n\nasync function safeText(r: Response): Promise<string> {\n try {\n return await r.text();\n } catch {\n return \"\";\n }\n}\n\nexport function detectPackageManager(projectRoot: string): PackageManager {\n if (existsSync(join(projectRoot, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(projectRoot, \"bun.lockb\"))) return \"bun\";\n if (existsSync(join(projectRoot, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nfunction runInstall(projectRoot: string, pm: PackageManager, pkg: string): boolean {\n const cmd = pm;\n // npm prints `npm audit` warnings + `npm fund` solicitations on every install.\n // That output is about the user's *existing* project — irrelevant to pixel.\n // The other package managers don't show this noise by default.\n const args = pm === \"npm\" ? [\"install\", pkg, \"--no-audit\", \"--no-fund\"] : [\"add\", pkg];\n const result = spawnSync(cmd, args, { cwd: projectRoot, stdio: \"inherit\" });\n return result.status === 0;\n}\n\nexport function renderInitFile(ingestUrl: string): string {\n return `import { initPixel } from \"@kenkaiiii/gg-pixel\";\n\nconst key = process.env.GG_PIXEL_KEY;\nif (key) {\n initPixel({\n projectKey: key,\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\n });\n}\n`;\n}\n\nexport function writeEnvKey(envPath: string, key: string, value: string): void {\n if (existsSync(envPath)) {\n const current = readFileSync(envPath, \"utf8\");\n const lineRegex = new RegExp(`^${key}=.*$`, \"m\");\n if (lineRegex.test(current)) {\n writeFileSync(envPath, current.replace(lineRegex, `${key}=${value}`), \"utf8\");\n return;\n }\n const sep = current.endsWith(\"\\n\") || current.length === 0 ? \"\" : \"\\n\";\n appendFileSync(envPath, `${sep}${key}=${value}\\n`, \"utf8\");\n return;\n }\n writeFileSync(envPath, `${key}=${value}\\n`, \"utf8\");\n}\n\nexport function wireEntryFile(\n projectRoot: string,\n initFilePath: string,\n pkg: PackageJson,\n): EntryWiringResult {\n const entryPath = findEntryFile(projectRoot, pkg);\n if (!entryPath) return { kind: \"no_entry_found\" };\n\n let content: string;\n try {\n content = readFileSync(entryPath, \"utf8\");\n } catch (err) {\n return { kind: \"skipped\", reason: `unreadable: ${(err as Error).message}` };\n }\n\n if (content.includes(\"gg-pixel.init\")) {\n return { kind: \"already_present\", entryPath };\n }\n\n // Compute import specifier relative to the entry file.\n const fromDir = dirname(entryPath);\n let spec = relative(fromDir, initFilePath).split(sep).join(\"/\");\n if (!spec.startsWith(\".\")) spec = \"./\" + spec;\n\n const isCjs = isCommonJsEntry(entryPath, pkg);\n const importLine = isCjs\n ? `require(${JSON.stringify(spec)});`\n : `import ${JSON.stringify(spec)};`;\n\n // Inject at the top — after a shebang line and any leading \"use strict\",\n // but before all other code, so pixel hooks run before anything else.\n const lines = content.split(\"\\n\");\n let insertAt = 0;\n if (lines[0]?.startsWith(\"#!\")) insertAt = 1;\n while (\n insertAt < lines.length &&\n /^\\s*(?:[\"']use strict[\"']|\\/\\/|\\/\\*)/.test(lines[insertAt] ?? \"\")\n ) {\n insertAt++;\n }\n\n const updated = [...lines.slice(0, insertAt), importLine, ...lines.slice(insertAt)].join(\"\\n\");\n writeFileSync(entryPath, updated, \"utf8\");\n return { kind: \"injected\", entryPath };\n}\n\nfunction findEntryFile(projectRoot: string, pkg: PackageJson): string | null {\n const tryPath = (rel: string): string | null => {\n const p = join(projectRoot, rel);\n if (existsSync(p)) return p;\n // If user pointed `main` at .js but only the .ts source exists (common in TS projects).\n if (rel.endsWith(\".js\")) {\n const ts = join(projectRoot, rel.replace(/\\.js$/, \".ts\"));\n if (existsSync(ts)) return ts;\n }\n return null;\n };\n\n if (typeof pkg.bin === \"string\") {\n const found = tryPath(pkg.bin);\n if (found) return found;\n }\n if (pkg.bin && typeof pkg.bin === \"object\") {\n for (const value of Object.values(pkg.bin)) {\n if (typeof value === \"string\") {\n const found = tryPath(value);\n if (found) return found;\n }\n }\n }\n if (pkg.main) {\n const found = tryPath(pkg.main);\n if (found) return found;\n }\n if (pkg.module) {\n const found = tryPath(pkg.module);\n if (found) return found;\n }\n\n // Fall back to common conventions.\n const candidates = [\n \"src/index.ts\",\n \"src/index.tsx\",\n \"src/index.js\",\n \"src/index.mjs\",\n \"src/main.ts\",\n \"src/main.tsx\",\n \"src/main.js\",\n \"src/server.ts\",\n \"src/server.js\",\n \"src/app.ts\",\n \"src/app.js\",\n \"src/cli.ts\",\n \"src/cli.js\",\n \"index.ts\",\n \"index.tsx\",\n \"index.js\",\n \"index.mjs\",\n \"main.ts\",\n \"main.js\",\n \"server.ts\",\n \"server.js\",\n \"app.ts\",\n \"app.js\",\n ];\n for (const c of candidates) {\n const found = tryPath(c);\n if (found) return found;\n }\n return null;\n}\n\nfunction isCommonJsEntry(entryPath: string, pkg: PackageJson): boolean {\n if (entryPath.endsWith(\".cjs\")) return true;\n if (entryPath.endsWith(\".mjs\")) return false;\n if (entryPath.endsWith(\".ts\") || entryPath.endsWith(\".tsx\")) return false;\n // .js → governed by package.json type (default is \"commonjs\")\n return pkg.type !== \"module\";\n}\n\nexport function writeProjectsMapping(\n projectsJsonPath: string,\n projectId: string,\n name: string,\n path: string,\n): void {\n mkdirSync(dirname(projectsJsonPath), { recursive: true });\n let map: Record<string, { name: string; path: string }> = {};\n if (existsSync(projectsJsonPath)) {\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n // start fresh on corrupt file\n }\n }\n map[projectId] = { name, path };\n writeFileSync(projectsJsonPath, `${JSON.stringify(map, null, 2)}\\n`, \"utf8\");\n}\n","import { installNodeAdapter, type NodeAdapter } from \"./adapters/node.js\";\nimport { HttpSink } from \"./core/sinks/http.js\";\nimport { LocalSqliteSink } from \"./core/sinks/local-sqlite.js\";\nimport type { PixelOptions, ReportInput, Sink, SinkConfig } from \"./core/types.js\";\n\nlet active: NodeAdapter | null = null;\n\nexport function initPixel(options: PixelOptions): NodeAdapter {\n if (active) {\n throw new Error(\"gg-pixel is already initialized; call closePixel() first\");\n }\n const sink = buildSink(options.sink);\n active = installNodeAdapter({\n projectKey: options.projectKey,\n runtime: options.runtime ?? defaultRuntime(),\n sink,\n captureConsoleErrors: options.captureConsoleErrors ?? true,\n captureConsoleWarnings: options.captureConsoleWarnings ?? false,\n captureUnhandledRejections: options.captureUnhandledRejections ?? true,\n captureUncaughtExceptions: options.captureUncaughtExceptions ?? true,\n });\n return active;\n}\n\nexport function reportPixel(input: ReportInput): void {\n if (!active) return;\n active.report(input);\n}\n\nexport async function flushPixel(): Promise<void> {\n if (!active) return;\n await active.flush();\n}\n\nexport async function closePixel(): Promise<void> {\n if (!active) return;\n await active.close();\n active = null;\n}\n\nfunction buildSink(config: SinkConfig): Sink {\n switch (config.kind) {\n case \"http\":\n return new HttpSink(config.ingestUrl, config.fetchFn);\n case \"local\":\n return new LocalSqliteSink(config.path);\n case \"custom\":\n return config.sink;\n }\n}\n\nfunction defaultRuntime(): string {\n const v = process.versions.node;\n return `node-${v}`;\n}\n\nexport type {\n Level,\n PixelOptions,\n ReportInput,\n Sink,\n SinkConfig,\n StackFrame,\n CodeContext,\n WireEvent,\n} from \"./core/types.js\";\n\nexport { install, DEFAULT_INGEST_URL } from \"./install.js\";\nexport type { InstallOptions, InstallResult, PackageManager } from \"./install.js\";\n"],"mappings":"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","names":["existsSync","readFileSync","mkdirSync","homedir","dirname","join","sep"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapters/node.ts","../src/core/stack.ts","../src/core/fingerprint.ts","../src/code-context.ts","../src/core/queue.ts","../src/core/sinks/node-http.ts","../src/core/sinks/http.ts","../src/core/sinks/local-sqlite.ts","../src/install.ts","../src/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { parseStack } from \"../core/stack.js\";\nimport { fingerprint } from \"../core/fingerprint.js\";\nimport { captureCodeContext } from \"../code-context.js\";\nimport { EventQueue } from \"../core/queue.js\";\nimport type { Level, ReportInput, Sink, WireEvent } from \"../core/types.js\";\n\nexport interface NodeAdapterOptions {\n projectKey: string;\n runtime: string;\n sink: Sink;\n captureConsoleErrors: boolean;\n captureConsoleWarnings: boolean;\n captureUnhandledRejections: boolean;\n captureUncaughtExceptions: boolean;\n}\n\nexport interface NodeAdapter {\n report(input: ReportInput): void;\n flush(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport function installNodeAdapter(opts: NodeAdapterOptions): NodeAdapter {\n const queue = new EventQueue(opts.sink);\n const detach: Array<() => void> = [];\n\n const enqueueError = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n const enqueueErrorSync = (err: unknown, level: Level, manual: boolean) => {\n try {\n const event = buildEvent(err, level, manual, opts.projectKey, opts.runtime);\n queue.enqueueSync(event);\n } catch {\n // never let pixel break the host program\n }\n };\n\n if (opts.captureUncaughtExceptions) {\n const handler = (err: Error) => enqueueErrorSync(err, \"fatal\", false);\n process.on(\"uncaughtExceptionMonitor\", handler);\n detach.push(() => process.off(\"uncaughtExceptionMonitor\", handler));\n }\n\n if (opts.captureUnhandledRejections) {\n const handler = (reason: unknown) => enqueueErrorSync(reason, \"error\", false);\n process.on(\"unhandledRejection\", handler);\n detach.push(() => process.off(\"unhandledRejection\", handler));\n }\n\n if (opts.captureConsoleErrors) {\n detach.push(patchConsole(\"error\", (args) => enqueueError(consoleError(args), \"error\", false)));\n }\n\n if (opts.captureConsoleWarnings) {\n detach.push(patchConsole(\"warn\", (args) => enqueueError(consoleError(args), \"warning\", false)));\n }\n\n const onBeforeExit = () => {\n void queue.flush();\n };\n process.on(\"beforeExit\", onBeforeExit);\n detach.push(() => process.off(\"beforeExit\", onBeforeExit));\n\n return {\n report(input: ReportInput) {\n const level = input.level ?? \"error\";\n if (input.error !== undefined) {\n try {\n const event = buildEvent(input.error, level, true, opts.projectKey, opts.runtime);\n if (input.message) event.message = input.message;\n queue.enqueue(event);\n } catch {\n // never let pixel break the host program\n }\n return;\n }\n const err = new Error(input.message);\n err.name = \"ManualReport\";\n enqueueError(err, level, true);\n },\n flush: () => queue.flush(),\n close: async () => {\n for (const fn of detach) fn();\n await queue.close();\n },\n };\n}\n\nfunction buildEvent(\n err: unknown,\n level: Level,\n manual: boolean,\n projectKey: string,\n runtime: string,\n): WireEvent {\n const { type, message, stackString } = normalize(err);\n const stack = parseStack(stackString);\n return {\n event_id: randomUUID(),\n project_key: projectKey,\n fingerprint: fingerprint(type, stack),\n type,\n message,\n stack,\n code_context: captureCodeContext(stack),\n runtime,\n manual_report: manual,\n level,\n occurred_at: new Date().toISOString(),\n };\n}\n\nfunction normalize(err: unknown): { type: string; message: string; stackString?: string } {\n if (err instanceof Error) {\n return { type: err.name || \"Error\", message: err.message, stackString: err.stack };\n }\n if (typeof err === \"string\") {\n return { type: \"StringError\", message: err };\n }\n try {\n return { type: \"UnknownError\", message: JSON.stringify(err) };\n } catch {\n return { type: \"UnknownError\", message: String(err) };\n }\n}\n\nfunction consoleError(args: unknown[]): unknown {\n for (const a of args) if (a instanceof Error) return a;\n return new Error(args.map(stringify).join(\" \"));\n}\n\nfunction stringify(x: unknown): string {\n if (typeof x === \"string\") return x;\n try {\n return JSON.stringify(x);\n } catch {\n return String(x);\n }\n}\n\ntype ConsoleMethod = \"error\" | \"warn\";\n\nfunction patchConsole(method: ConsoleMethod, onCall: (args: unknown[]) => void): () => void {\n const original = console[method];\n console[method] = (...args: unknown[]) => {\n try {\n onCall(args);\n } catch {\n // never let pixel break the host program\n }\n original.apply(console, args);\n };\n return () => {\n console[method] = original;\n };\n}\n","import type { StackFrame } from \"./types.js\";\n\nconst FRAME_WITH_FN = /^\\s*at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)\\s*$/;\nconst FRAME_NO_FN = /^\\s*at\\s+(.+?):(\\d+):(\\d+)\\s*$/;\n\nexport function parseStack(stack: string | undefined): StackFrame[] {\n if (!stack) return [];\n const frames: StackFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n const withFn = FRAME_WITH_FN.exec(line);\n if (withFn) {\n const file = withFn[2];\n frames.push({\n fn: withFn[1],\n file,\n line: Number(withFn[3]),\n col: Number(withFn[4]),\n in_app: isInApp(file),\n });\n continue;\n }\n const noFn = FRAME_NO_FN.exec(line);\n if (noFn) {\n const file = noFn[1];\n frames.push({\n fn: \"<anon>\",\n file,\n line: Number(noFn[2]),\n col: Number(noFn[3]),\n in_app: isInApp(file),\n });\n }\n }\n return frames;\n}\n\nfunction isInApp(file: string): boolean {\n if (!file) return false;\n if (file.startsWith(\"node:\")) return false;\n if (file.startsWith(\"internal/\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return true;\n}\n","import { createHash } from \"node:crypto\";\nimport type { StackFrame } from \"./types.js\";\n\nexport function fingerprint(type: string, stack: StackFrame[]): string {\n const top = stack[0];\n const normalized = top\n ? `${type}|${normalizeFile(top.file)}|${top.fn || \"<anon>\"}|${top.line}`\n : `${type}|<no-stack>`;\n return createHash(\"sha256\").update(normalized).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeFile(file: string): string {\n return file\n .replace(/^file:\\/\\//, \"\")\n .replace(/^.*\\/node_modules\\//, \"node_modules/\")\n .replace(/\\?.*$/, \"\");\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport type { CodeContext, StackFrame } from \"./core/types.js\";\n\nconst WINDOW = 2;\nconst cache = new Map<string, string[] | null>();\n\nexport function captureCodeContext(stack: StackFrame[]): CodeContext | null {\n const top = stack.find((f) => isReadable(f.file));\n if (!top) return null;\n const lines = loadLines(top.file);\n if (!lines) return null;\n const start = Math.max(0, top.line - 1 - WINDOW);\n const end = Math.min(lines.length, top.line + WINDOW);\n return {\n file: top.file,\n error_line: top.line,\n lines: lines.slice(start, end),\n };\n}\n\nfunction isReadable(file: string): boolean {\n if (!file || file.startsWith(\"node:\")) return false;\n if (file.includes(\"/node_modules/\")) return false;\n return file.startsWith(\"/\") || file.startsWith(\"file://\");\n}\n\nfunction loadLines(file: string): string[] | null {\n const path = file.replace(/^file:\\/\\//, \"\");\n if (cache.has(path)) return cache.get(path) ?? null;\n if (!existsSync(path)) {\n cache.set(path, null);\n return null;\n }\n try {\n const lines = readFileSync(path, \"utf8\").split(\"\\n\");\n cache.set(path, lines);\n return lines;\n } catch {\n cache.set(path, null);\n return null;\n }\n}\n","import type { Sink, WireEvent } from \"./types.js\";\n\nconst MAX_BUFFER = 100;\nconst BASE_DELAY_MS = 200;\nconst MAX_DELAY_MS = 5_000;\n\nexport class EventQueue {\n private readonly buffer: WireEvent[] = [];\n private draining = false;\n private closed = false;\n\n constructor(private readonly sink: Sink) {}\n\n enqueue(event: WireEvent): void {\n if (this.closed) return;\n if (this.buffer.length >= MAX_BUFFER) {\n this.buffer.shift();\n }\n this.buffer.push(event);\n void this.drain();\n }\n\n enqueueSync(event: WireEvent): void {\n if (this.closed) return;\n if (this.sink.emitSync) {\n try {\n this.sink.emitSync(event);\n return;\n } catch {\n // fall through to async path\n }\n }\n this.enqueue(event);\n }\n\n async flush(): Promise<void> {\n while (this.buffer.length > 0 || this.draining) {\n await new Promise((r) => setTimeout(r, 10));\n }\n }\n\n async close(): Promise<void> {\n await this.flush();\n this.closed = true;\n if (this.sink.close) await this.sink.close();\n }\n\n private async drain(): Promise<void> {\n if (this.draining) return;\n this.draining = true;\n let attempt = 0;\n while (this.buffer.length > 0) {\n const event = this.buffer[0];\n try {\n await this.sink.emit(event);\n this.buffer.shift();\n attempt = 0;\n } catch (err) {\n attempt++;\n if (attempt >= 5) {\n // Drop the event but make the loss observable — silent data loss\n // from the error tracker is the worst possible failure mode.\n console.warn(\n `[gg-pixel] dropping event after 5 failed deliveries: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n this.buffer.shift();\n attempt = 0;\n continue;\n }\n const delay = Math.min(BASE_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n this.draining = false;\n }\n}\n","import { spawnSync } from \"node:child_process\";\nimport { HttpSink } from \"./http.js\";\nimport type { WireEvent } from \"../types.js\";\n\n/**\n * Node-only HTTP sink that adds a synchronous `emitSync` path for fatal\n * events.\n *\n * Why: when `uncaughtExceptionMonitor` fires, Node tears the process down\n * before any pending async work can complete — meaning a normal `fetch()` to\n * the ingest endpoint loses the most important event (the fatal one).\n * Sentry's Node SDK solves this for serverless environments by spawning\n * an external HTTP client synchronously. We do the same with `curl`, which\n * ships with macOS, every modern Linux distro, and Windows 10 1803+.\n *\n * Tradeoff: ~100ms latency per fatal event (curl process spin-up). Fatal\n * events are rare so this is acceptable. Pending non-fatal events still in\n * the async queue at crash time may be lost — flushing them sync would\n * block the fatal handler for seconds in the worst case.\n */\nexport class NodeHttpSink extends HttpSink {\n constructor(\n private readonly url: string,\n fetchFn?: typeof fetch,\n ) {\n super(url, fetchFn);\n }\n\n emitSync(event: WireEvent): void {\n const body = JSON.stringify(event);\n const result = spawnSync(\n \"curl\",\n [\n \"--silent\",\n \"--show-error\",\n \"-X\",\n \"POST\",\n \"-H\",\n \"content-type: application/json\",\n \"-H\",\n `x-pixel-key: ${event.project_key}`,\n \"--data-binary\",\n \"@-\",\n \"--max-time\",\n \"3\",\n this.url,\n ],\n { input: body, encoding: \"utf8\" },\n );\n if (result.error || result.status !== 0) {\n // Best-effort. We're already in a fatal handler; can't retry async.\n console.warn(\n `[gg-pixel] sync emit failed: ${result.error?.message ?? result.stderr ?? \"unknown\"}`,\n );\n }\n }\n}\n","import type { Sink, WireEvent } from \"../types.js\";\n\nexport class HttpSink implements Sink {\n private readonly fetchFn: typeof fetch;\n\n constructor(\n private readonly ingestUrl: string,\n fetchFn?: typeof fetch,\n ) {\n // CRITICAL: in browsers `fetch` is `window.fetch` and requires `this === window`.\n // Storing it as a property and calling via `this.fetchFn(...)` strips that\n // binding and throws \"Illegal invocation\". Bind to globalThis on assignment.\n // Tests can still inject a custom fetchFn (no binding needed for plain fns).\n this.fetchFn = fetchFn ?? globalThis.fetch.bind(globalThis);\n }\n\n async emit(event: WireEvent): Promise<void> {\n const body = JSON.stringify(event);\n // `keepalive: true` lets the request survive page unload (browser).\n // `mode: \"cors\"` is the explicit default but stating it makes the\n // intent clear and avoids surprises on stricter contexts.\n const res = await this.fetchFn(this.ingestUrl, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-pixel-key\": event.project_key,\n },\n body,\n keepalive: typeof window !== \"undefined\",\n mode: typeof window !== \"undefined\" ? \"cors\" : undefined,\n });\n if (!res.ok) {\n throw new Error(`pixel ingest failed: ${res.status}`);\n }\n }\n}\n","import { homedir } from \"node:os\";\nimport { mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { Sink, WireEvent } from \"../types.js\";\n\nconst SCHEMA = `\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n event_id TEXT NOT NULL UNIQUE,\n project_key TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n type TEXT NOT NULL,\n message TEXT NOT NULL,\n stack TEXT NOT NULL,\n code_context TEXT,\n runtime TEXT NOT NULL,\n manual_report INTEGER NOT NULL DEFAULT 0,\n level TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n ingested_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS events_fingerprint ON events(project_key, fingerprint);\n CREATE INDEX IF NOT EXISTS events_occurred ON events(occurred_at);\n`;\n\nexport class LocalSqliteSink implements Sink {\n private readonly db: Database.Database;\n private readonly insert: Database.Statement;\n\n constructor(path?: string) {\n const resolved = path ?? join(homedir(), \".gg\", \"errors.db\");\n mkdirSync(dirname(resolved), { recursive: true });\n this.db = new Database(resolved);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.exec(SCHEMA);\n this.insert = this.db.prepare(`\n INSERT INTO events (\n event_id, project_key, fingerprint, type, message, stack, code_context,\n runtime, manual_report, level, occurred_at\n ) VALUES (\n @event_id, @project_key, @fingerprint, @type, @message, @stack, @code_context,\n @runtime, @manual_report, @level, @occurred_at\n )\n `);\n }\n\n emitSync(event: WireEvent): void {\n this.insert.run({\n event_id: event.event_id,\n project_key: event.project_key,\n fingerprint: event.fingerprint,\n type: event.type,\n message: event.message,\n stack: JSON.stringify(event.stack),\n code_context: event.code_context ? JSON.stringify(event.code_context) : null,\n runtime: event.runtime,\n manual_report: event.manual_report ? 1 : 0,\n level: event.level,\n occurred_at: event.occurred_at,\n });\n }\n\n async emit(event: WireEvent): Promise<void> {\n this.emitSync(event);\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n}\n","import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\n\nexport const DEFAULT_INGEST_URL = \"https://gg-pixel-server.buzzbeamaustralia.workers.dev\";\n\nexport interface InstallOptions {\n cwd?: string;\n ingestUrl?: string;\n projectName?: string;\n fetchFn?: typeof fetch;\n skipPackageInstall?: boolean;\n homeDir?: string;\n}\n\nexport interface InstallResult {\n projectId: string;\n projectKey: string;\n projectName: string;\n initFilePath: string;\n envFilePath: string;\n projectsJsonPath: string;\n packageManager: PackageManager;\n packageInstalled: boolean;\n entryWiring: EntryWiringResult;\n /** True when an existing project mapping was reused instead of minting a fresh one. */\n reused: boolean;\n}\n\nexport type EntryWiringResult =\n | { kind: \"injected\"; entryPath: string }\n | { kind: \"already_present\"; entryPath: string }\n | { kind: \"no_entry_found\" }\n | { kind: \"skipped\"; reason: string };\n\ninterface PackageJson {\n name?: string;\n type?: string;\n main?: string;\n module?: string;\n bin?: string | Record<string, string>;\n}\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport async function install(opts: InstallOptions = {}): Promise<InstallResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const ingestUrl = (opts.ingestUrl ?? DEFAULT_INGEST_URL).replace(/\\/+$/, \"\");\n const fetchFn = opts.fetchFn ?? fetch;\n\n const projectRoot = findProjectRoot(cwd);\n if (!projectRoot) {\n throw new Error(`No package.json found in ${cwd} or any parent directory.`);\n }\n\n const pkgPath = join(projectRoot, \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as PackageJson;\n const projectName = opts.projectName ?? pkg.name ?? projectRoot.split(\"/\").pop() ?? \"unnamed\";\n\n const home = opts.homeDir ?? homedir();\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(projectRoot, \".env\");\n\n // Idempotency: if we already have a mapping for this directory AND the .env\n // still has its key, reuse it instead of minting a fresh project.\n const existing = findMappingByPath(projectsJsonPath, projectRoot);\n const existingKey = readEnvKey(envFilePath, \"GG_PIXEL_KEY\");\n let created: { id: string; key: string };\n let reused = false;\n if (existing && existingKey) {\n created = { id: existing.id, key: existingKey };\n reused = true;\n } else {\n created = await createProject(fetchFn, ingestUrl, projectName);\n }\n\n const pm = detectPackageManager(projectRoot);\n const packageInstalled = opts.skipPackageInstall\n ? false\n : runInstall(projectRoot, pm, \"@kenkaiiii/gg-pixel\");\n\n const initFilePath = join(projectRoot, \"gg-pixel.init.mjs\");\n writeFileSync(initFilePath, renderInitFile(ingestUrl), \"utf8\");\n\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n\n writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);\n\n const entryWiring = wireEntryFile(projectRoot, initFilePath, pkg);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n initFilePath,\n envFilePath,\n projectsJsonPath,\n packageManager: pm,\n packageInstalled,\n entryWiring,\n reused,\n };\n}\n\nfunction findMappingByPath(\n projectsJsonPath: string,\n projectRoot: string,\n): { id: string; name: string; path: string } | null {\n if (!existsSync(projectsJsonPath)) return null;\n let map: Record<string, { name: string; path: string }>;\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n return null;\n }\n for (const [id, entry] of Object.entries(map)) {\n if (entry.path === projectRoot) return { id, ...entry };\n }\n return null;\n}\n\nfunction readEnvKey(envPath: string, key: string): string | null {\n if (!existsSync(envPath)) return null;\n try {\n const content = readFileSync(envPath, \"utf8\");\n const match = new RegExp(`^${key}=(.+)$`, \"m\").exec(content);\n return match?.[1]?.trim() ?? null;\n } catch {\n return null;\n }\n}\n\nfunction findProjectRoot(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n return null;\n}\n\nasync function createProject(\n fetchFn: typeof fetch,\n ingestUrl: string,\n name: string,\n): Promise<{ id: string; key: string }> {\n const res = await fetchFn(`${ingestUrl}/api/projects`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ name }),\n });\n if (!res.ok) {\n throw new Error(`POST /api/projects failed: ${res.status} ${await safeText(res)}`);\n }\n const body = (await res.json()) as { id: string; key: string };\n if (!body.id || !body.key) throw new Error(\"response missing id/key\");\n return { id: body.id, key: body.key };\n}\n\nasync function safeText(r: Response): Promise<string> {\n try {\n return await r.text();\n } catch {\n return \"\";\n }\n}\n\nexport function detectPackageManager(projectRoot: string): PackageManager {\n if (existsSync(join(projectRoot, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(projectRoot, \"bun.lockb\"))) return \"bun\";\n if (existsSync(join(projectRoot, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nfunction runInstall(projectRoot: string, pm: PackageManager, pkg: string): boolean {\n const cmd = pm;\n // npm prints `npm audit` warnings + `npm fund` solicitations on every install.\n // That output is about the user's *existing* project — irrelevant to pixel.\n // The other package managers don't show this noise by default.\n const args = pm === \"npm\" ? [\"install\", pkg, \"--no-audit\", \"--no-fund\"] : [\"add\", pkg];\n const result = spawnSync(cmd, args, { cwd: projectRoot, stdio: \"inherit\" });\n return result.status === 0;\n}\n\nexport function renderInitFile(ingestUrl: string): string {\n return `import { initPixel } from \"@kenkaiiii/gg-pixel\";\n\nconst key = process.env.GG_PIXEL_KEY;\nif (key) {\n initPixel({\n projectKey: key,\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\n });\n}\n`;\n}\n\nexport function writeEnvKey(envPath: string, key: string, value: string): void {\n if (existsSync(envPath)) {\n const current = readFileSync(envPath, \"utf8\");\n const lineRegex = new RegExp(`^${key}=.*$`, \"m\");\n if (lineRegex.test(current)) {\n writeFileSync(envPath, current.replace(lineRegex, `${key}=${value}`), \"utf8\");\n return;\n }\n const sep = current.endsWith(\"\\n\") || current.length === 0 ? \"\" : \"\\n\";\n appendFileSync(envPath, `${sep}${key}=${value}\\n`, \"utf8\");\n return;\n }\n writeFileSync(envPath, `${key}=${value}\\n`, \"utf8\");\n}\n\nexport function wireEntryFile(\n projectRoot: string,\n initFilePath: string,\n pkg: PackageJson,\n): EntryWiringResult {\n const entryPath = findEntryFile(projectRoot, pkg);\n if (!entryPath) return { kind: \"no_entry_found\" };\n\n let content: string;\n try {\n content = readFileSync(entryPath, \"utf8\");\n } catch (err) {\n return { kind: \"skipped\", reason: `unreadable: ${(err as Error).message}` };\n }\n\n if (content.includes(\"gg-pixel.init\")) {\n return { kind: \"already_present\", entryPath };\n }\n\n // Compute import specifier relative to the entry file.\n const fromDir = dirname(entryPath);\n let spec = relative(fromDir, initFilePath).split(sep).join(\"/\");\n if (!spec.startsWith(\".\")) spec = \"./\" + spec;\n\n const isCjs = isCommonJsEntry(entryPath, pkg);\n const importLine = isCjs\n ? `require(${JSON.stringify(spec)});`\n : `import ${JSON.stringify(spec)};`;\n\n // Inject at the top — after a shebang line and any leading \"use strict\",\n // but before all other code, so pixel hooks run before anything else.\n const lines = content.split(\"\\n\");\n let insertAt = 0;\n if (lines[0]?.startsWith(\"#!\")) insertAt = 1;\n while (\n insertAt < lines.length &&\n /^\\s*(?:[\"']use strict[\"']|\\/\\/|\\/\\*)/.test(lines[insertAt] ?? \"\")\n ) {\n insertAt++;\n }\n\n const updated = [...lines.slice(0, insertAt), importLine, ...lines.slice(insertAt)].join(\"\\n\");\n writeFileSync(entryPath, updated, \"utf8\");\n return { kind: \"injected\", entryPath };\n}\n\nfunction findEntryFile(projectRoot: string, pkg: PackageJson): string | null {\n const tryPath = (rel: string): string | null => {\n const p = join(projectRoot, rel);\n if (existsSync(p)) return p;\n // If user pointed `main` at .js but only the .ts source exists (common in TS projects).\n if (rel.endsWith(\".js\")) {\n const ts = join(projectRoot, rel.replace(/\\.js$/, \".ts\"));\n if (existsSync(ts)) return ts;\n }\n return null;\n };\n\n if (typeof pkg.bin === \"string\") {\n const found = tryPath(pkg.bin);\n if (found) return found;\n }\n if (pkg.bin && typeof pkg.bin === \"object\") {\n for (const value of Object.values(pkg.bin)) {\n if (typeof value === \"string\") {\n const found = tryPath(value);\n if (found) return found;\n }\n }\n }\n if (pkg.main) {\n const found = tryPath(pkg.main);\n if (found) return found;\n }\n if (pkg.module) {\n const found = tryPath(pkg.module);\n if (found) return found;\n }\n\n // Fall back to common conventions.\n const candidates = [\n \"src/index.ts\",\n \"src/index.tsx\",\n \"src/index.js\",\n \"src/index.mjs\",\n \"src/main.ts\",\n \"src/main.tsx\",\n \"src/main.js\",\n \"src/server.ts\",\n \"src/server.js\",\n \"src/app.ts\",\n \"src/app.js\",\n \"src/cli.ts\",\n \"src/cli.js\",\n \"index.ts\",\n \"index.tsx\",\n \"index.js\",\n \"index.mjs\",\n \"main.ts\",\n \"main.js\",\n \"server.ts\",\n \"server.js\",\n \"app.ts\",\n \"app.js\",\n ];\n for (const c of candidates) {\n const found = tryPath(c);\n if (found) return found;\n }\n return null;\n}\n\nfunction isCommonJsEntry(entryPath: string, pkg: PackageJson): boolean {\n if (entryPath.endsWith(\".cjs\")) return true;\n if (entryPath.endsWith(\".mjs\")) return false;\n if (entryPath.endsWith(\".ts\") || entryPath.endsWith(\".tsx\")) return false;\n // .js → governed by package.json type (default is \"commonjs\")\n return pkg.type !== \"module\";\n}\n\nexport function writeProjectsMapping(\n projectsJsonPath: string,\n projectId: string,\n name: string,\n path: string,\n): void {\n mkdirSync(dirname(projectsJsonPath), { recursive: true });\n let map: Record<string, { name: string; path: string }> = {};\n if (existsSync(projectsJsonPath)) {\n try {\n map = JSON.parse(readFileSync(projectsJsonPath, \"utf8\")) as typeof map;\n } catch {\n // start fresh on corrupt file\n }\n }\n map[projectId] = { name, path };\n writeFileSync(projectsJsonPath, `${JSON.stringify(map, null, 2)}\\n`, \"utf8\");\n}\n","import { installNodeAdapter, type NodeAdapter } from \"./adapters/node.js\";\nimport { NodeHttpSink } from \"./core/sinks/node-http.js\";\nimport { LocalSqliteSink } from \"./core/sinks/local-sqlite.js\";\nimport type { PixelOptions, ReportInput, Sink, SinkConfig } from \"./core/types.js\";\n\nlet active: NodeAdapter | null = null;\n\nexport function initPixel(options: PixelOptions): NodeAdapter {\n if (active) {\n throw new Error(\"gg-pixel is already initialized; call closePixel() first\");\n }\n const sink = buildSink(options.sink);\n active = installNodeAdapter({\n projectKey: options.projectKey,\n runtime: options.runtime ?? defaultRuntime(),\n sink,\n captureConsoleErrors: options.captureConsoleErrors ?? true,\n captureConsoleWarnings: options.captureConsoleWarnings ?? false,\n captureUnhandledRejections: options.captureUnhandledRejections ?? true,\n captureUncaughtExceptions: options.captureUncaughtExceptions ?? true,\n });\n return active;\n}\n\nexport function reportPixel(input: ReportInput): void {\n if (!active) return;\n active.report(input);\n}\n\nexport async function flushPixel(): Promise<void> {\n if (!active) return;\n await active.flush();\n}\n\nexport async function closePixel(): Promise<void> {\n if (!active) return;\n await active.close();\n active = null;\n}\n\nfunction buildSink(config: SinkConfig): Sink {\n switch (config.kind) {\n case \"http\":\n return new NodeHttpSink(config.ingestUrl, config.fetchFn);\n case \"local\":\n return new LocalSqliteSink(config.path);\n case \"custom\":\n return config.sink;\n }\n}\n\nfunction defaultRuntime(): string {\n const v = process.versions.node;\n return `node-${v}`;\n}\n\nexport type {\n Level,\n PixelOptions,\n ReportInput,\n Sink,\n SinkConfig,\n StackFrame,\n CodeContext,\n WireEvent,\n} from \"./core/types.js\";\n\nexport { install, DEFAULT_INGEST_URL } from \"./install.js\";\nexport type { InstallOptions, InstallResult, PackageManager } from \"./install.js\";\n"],"mappings":"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","names":["existsSync","readFileSync","mkdirSync","homedir","dirname","join","spawnSync","sep"]}
|