@kenkaiiii/gg-pixel 4.3.80 → 4.3.81
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.iife.global.js +4 -0
- package/dist/browser.iife.global.js.map +1 -0
- package/dist/cli.js +168 -37
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +168 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +168 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use strict";var GGPixel=(()=>{var h=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var F=(e,n,r)=>n in e?h(e,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[n]=r;var x=(e,n)=>{for(var r in n)h(e,r,{get:n[r],enumerable:!0})},M=(e,n,r,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let t of P(n))!C.call(e,t)&&t!==r&&h(e,t,{get:()=>n[t],enumerable:!(o=_(n,t))||o.enumerable});return e};var B=e=>M(h({},"__esModule",{value:!0}),e);var g=(e,n,r)=>F(e,typeof n!="symbol"?n+"":n,r);var J={};x(J,{default:()=>Y});var y={};x(y,{DEFAULT_INGEST_URL:()=>R,closePixel:()=>G,flushPixel:()=>K,initPixel:()=>N,reportPixel:()=>q});var W=/^\s*at\s+(?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+))(?:\))?\s*$/,L=/^\s*(.*?)@(.+?):(\d+)(?::(\d+))?\s*$/;function v(e,n){if(!e)return[];let r=[];for(let o of e.split(`
|
|
2
|
+
`)){let t=o.trim();if(!t||!/^(?:at\s|.*@)/.test(t))continue;let i=W.exec(o);if(i){let a=(i[1]??"").trim()||"<anon>",f=i[2];if(!f)continue;r.push({fn:a,file:f,line:Number(i[3]),col:Number(i[4]),in_app:k(f,n)});continue}let s=L.exec(o);if(s){let a=(s[1]??"").trim()||"<anon>",f=s[2];if(!f)continue;r.push({fn:a,file:f,line:Number(s[3]),col:s[4]?Number(s[4]):0,in_app:k(f,n)})}}return r}function k(e,n){if(!e||/^chrome-extension:\/\//.test(e)||/^moz-extension:\/\//.test(e)||/^safari-extension:\/\//.test(e)||/^webkit-masked-url:\/\//.test(e)||e==="<anonymous>"||e==="[native code]")return!1;if(!n)return/^https?:\/\//.test(e)||/^[a-z]+:\/\//.test(e)===!1;try{return new URL(e,n).origin===n}catch{return!1}}function b(e,n){let r=n[0],o=r?`${e}|${I(r.file)}|${r.fn||"<anon>"}|${r.line}`:`${e}|<no-stack>`;return T(o)}function T(e){let n=3421674724,r=2216829733;for(let o=0;o<e.length;o++){let t=e.charCodeAt(o);r^=t&255,e.charCodeAt(o)>255&&(n^=t>>>8&255);let i=r&65535,s=r>>>16&65535,a=n&65535,f=n>>>16&65535,c=i*435,p=s*435+(c>>>16&65535),u=a*435+(p>>>16&65535),d=f*435+(u>>>16&65535);c+=i*0,p+=s*0,u+=a*0,d+=f*0,u+=i,d+=s+(u>>>16&65535),r=((p&65535)<<16|c&65535)>>>0,n=((d&65535)<<16|u&65535)>>>0}return E(n)+E(r)}function E(e){return(e>>>0).toString(16).padStart(8,"0")}function I(e){return e.replace(/\?.*$/,"").replace(/#.*$/,"")}var m=class{constructor(n){this.sink=n;g(this,"buffer",[]);g(this,"draining",!1);g(this,"closed",!1)}enqueue(n){this.closed||(this.buffer.length>=100&&this.buffer.shift(),this.buffer.push(n),this.drain())}enqueueSync(n){if(!this.closed){if(this.sink.emitSync)try{this.sink.emitSync(n);return}catch{}this.enqueue(n)}}async flush(){for(;this.buffer.length>0||this.draining;)await new Promise(n=>setTimeout(n,10))}async close(){await this.flush(),this.closed=!0,this.sink.close&&await this.sink.close()}async drain(){if(this.draining)return;this.draining=!0;let n=0;for(;this.buffer.length>0;){let r=this.buffer[0];try{await this.sink.emit(r),this.buffer.shift(),n=0}catch(o){if(n++,n>=5){console.warn(`[gg-pixel] dropping event after 5 failed deliveries: ${o instanceof Error?o.message:String(o)}`),this.buffer.shift(),n=0;continue}let t=Math.min(200*2**(n-1),5e3);await new Promise(i=>setTimeout(i,t))}}this.draining=!1}};function A(e){let n=new m(e.sink),r=[],o=(t,i,s)=>{try{let a=S(t,i,s,e.projectKey,e.runtime);n.enqueue(a)}catch{}};if(e.captureUncaughtExceptions){let t=window.onerror,i=(s,a,f,c,p)=>{let u=typeof s=="string"?s:"";if(f===0&&/^Script error\.?$/i.test(u))return t?t.call(window,s,a,f,c,p):!1;if(p instanceof Error)o(p,"error",!1);else if(u){let d=new Error(u);a&&(d.stack=`${u}
|
|
3
|
+
at ${a}:${f??0}:${c??0}`),o(d,"error",!1)}return t?t.call(window,s,a,f,c,p):!1};window.onerror=i,r.push(()=>{window.onerror===i&&(window.onerror=t)})}if(e.captureUnhandledRejections){let t=window.onunhandledrejection,i=s=>{let a=s.reason;if(o(a,"error",!1),t)return t.call(window,s)};window.onunhandledrejection=i,r.push(()=>{window.onunhandledrejection===i&&(window.onunhandledrejection=t)})}return e.captureConsoleErrors&&r.push($("error",t=>o(j(t),"error",!1))),e.captureConsoleWarnings&&r.push($("warn",t=>o(j(t),"warning",!1))),{report(t){let i=t.level??"error";if(t.error!==void 0){try{let a=S(t.error,i,!0,e.projectKey,e.runtime);t.message&&(a.message=t.message),n.enqueue(a)}catch{}return}let s=new Error(t.message);s.name="ManualReport",o(s,i,!0)},flush:()=>n.flush(),close:async()=>{for(let t of r)t();await n.close()}}}function S(e,n,r,o,t){let{type:i,message:s,stackString:a}=O(e),f=typeof window<"u"?window.location.origin:void 0,c=v(a,f);return{event_id:D(),project_key:o,fingerprint:b(i,c),type:i,message:s,stack:c,code_context:null,runtime:t,manual_report:r,level:n,occurred_at:new Date().toISOString()}}function O(e){if(e instanceof Error)return{type:e.name||"Error",message:e.message,stackString:e.stack};if(typeof e=="string")return{type:"StringError",message:e};try{return{type:"UnknownError",message:JSON.stringify(e)}}catch{return{type:"UnknownError",message:String(e)}}}function j(e){for(let n of e)if(n instanceof Error)return n;return new Error(e.map(z).join(" "))}function z(e){if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}function $(e,n){let r=console[e];return console[e]=(...o)=>{try{n(o)}catch{}r.apply(console,o)},()=>{console[e]=r}}function D(){let e=globalThis.crypto;if(e?.randomUUID)return e.randomUUID();let n=new Uint8Array(16);if(e?.getRandomValues)e.getRandomValues(n);else for(let o=0;o<16;o++)n[o]=Math.floor(Math.random()*256);n[6]=n[6]&15|64,n[8]=n[8]&63|128;let r=Array.from(n,o=>o.toString(16).padStart(2,"0")).join("");return`${r.slice(0,8)}-${r.slice(8,12)}-${r.slice(12,16)}-${r.slice(16,20)}-${r.slice(20)}`}var w=class{constructor(n,r){this.ingestUrl=n;g(this,"fetchFn");this.fetchFn=r??globalThis.fetch.bind(globalThis)}async emit(n){let r=JSON.stringify(n),o=await this.fetchFn(this.ingestUrl,{method:"POST",headers:{"content-type":"application/json","x-pixel-key":n.project_key},body:r,keepalive:typeof window<"u",mode:typeof window<"u"?"cors":void 0});if(!o.ok)throw new Error(`pixel ingest failed: ${o.status}`)}};var R="https://gg-pixel-server.buzzbeamaustralia.workers.dev",l=null;function N(e){if(l)throw new Error("gg-pixel is already initialized; call closePixel() first");let n=e.sink??new w(H(e.ingestUrl));return l=A({projectKey:e.projectKey,runtime:e.runtime??X(),sink:n,captureConsoleErrors:e.captureConsoleErrors??!1,captureConsoleWarnings:e.captureConsoleWarnings??!1,captureUnhandledRejections:e.captureUnhandledRejections??!0,captureUncaughtExceptions:e.captureUncaughtExceptions??!0}),l}function q(e){l&&l.report(e)}async function K(){l&&await l.flush()}async function G(){l&&(await l.close(),l=null)}function H(e){return`${(e??R).replace(/\/+$/,"")}/ingest`}function X(){if(typeof navigator>"u")return"browser-unknown";let e=navigator.userAgent;return/Chrome\/(\d+)/.test(e)?`chrome-${RegExp.$1}`:/Firefox\/(\d+)/.test(e)?`firefox-${RegExp.$1}`:/Version\/(\d+).*Safari/.test(e)?`safari-${RegExp.$1}`:/Edg\/(\d+)/.test(e)?`edge-${RegExp.$1}`:"browser"}var U=typeof globalThis<"u"?globalThis:typeof window<"u"?window:void 0;U&&(U.GGPixel=y);var Y=y;return B(J);})();
|
|
4
|
+
//# sourceMappingURL=browser.iife.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/browser.iife.ts","../src/browser.ts","../src/core/stack-web.ts","../src/core/fingerprint-web.ts","../src/core/queue.ts","../src/adapters/browser.ts","../src/core/sinks/http.ts"],"sourcesContent":["// IIFE entry — for HTML+CDN renderers (Electron multi-window apps,\n// classic websites, anything without a bundler). When loaded via\n// `<script src=\"gg-pixel.browser.iife.js\"></script>`, it exposes the\n// SDK as `globalThis.GGPixel` (and `window.GGPixel`):\n//\n// <script src=\"gg-pixel.browser.iife.js\"></script>\n// <script>\n// GGPixel.initPixel({ projectKey: \"pk_live_...\", ingestUrl: \"...\" });\n// </script>\nimport * as Pixel from \"./browser.js\";\n\nconst target =\n typeof globalThis !== \"undefined\"\n ? globalThis\n : typeof window !== \"undefined\"\n ? (window as unknown as Record<string, unknown>)\n : (undefined as unknown as Record<string, unknown>);\nif (target) (target as Record<string, unknown>).GGPixel = Pixel;\n\nexport default Pixel;\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","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"],"mappings":"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","names":["browser_iife_exports","__export","browser_iife_default","browser_exports","__export","DEFAULT_INGEST_URL","closePixel","flushPixel","initPixel","reportPixel","CHROME_FRAME","GECKO_FRAME","parseBrowserStack","stack","sameOrigin","frames","line","trimmed","chrome","fn","file","isInApp","gecko","fingerprintWeb","type","stack","top","normalized","normalizeFile","fnv1a64","input","hHi","hLo","i","code","lo16","lo32","hi16","hi32","nLo","nMid","nHi","nTop","toHex32","n","file","EventQueue","sink","__publicField","event","r","attempt","err","delay","installBrowserAdapter","opts","queue","EventQueue","detach","enqueueError","err","level","manual","event","buildEvent","previous","handler","message","source","lineno","colno","error","msgStr","synthetic","reason","patchConsole","args","consoleError","input","fn","projectKey","runtime","type","stackString","normalize","sameOrigin","stack","parseBrowserStack","uuid","fingerprintWeb","a","stringify","x","method","onCall","original","c","bytes","i","hex","b","HttpSink","ingestUrl","fetchFn","__publicField","event","body","res","DEFAULT_INGEST_URL","active","initPixel","options","sink","HttpSink","buildIngestUrl","installBrowserAdapter","defaultRuntime","reportPixel","input","flushPixel","closePixel","base","ua","target","browser_exports","browser_iife_default"]}
|
package/dist/cli.js
CHANGED
|
@@ -635,6 +635,7 @@ function wireRemix({ projectRoot, projectKey, ingestUrl }) {
|
|
|
635
635
|
};
|
|
636
636
|
}
|
|
637
637
|
function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
|
|
638
|
+
const warnings = [];
|
|
638
639
|
const isMainEsm = pkg.type === "module";
|
|
639
640
|
const mainInitPath = isMainEsm ? join(projectRoot, "gg-pixel.main.mjs") : join(projectRoot, "gg-pixel.main.cjs");
|
|
640
641
|
writeFileSync(
|
|
@@ -642,50 +643,62 @@ function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
|
|
|
642
643
|
isMainEsm ? renderInitFile(ingestUrl, projectKey) : renderInitFileCjs(ingestUrl, projectKey),
|
|
643
644
|
"utf8"
|
|
644
645
|
);
|
|
645
|
-
const
|
|
646
|
-
writeFileSync(rendererInitPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|
|
647
|
-
const mainEntry = pkg.main ? join(projectRoot, pkg.main) : pickPath(projectRoot, [
|
|
648
|
-
"main.js",
|
|
649
|
-
"main.ts",
|
|
650
|
-
"src/main.js",
|
|
651
|
-
"src/main.ts",
|
|
652
|
-
"electron/main.js",
|
|
653
|
-
"electron/main.ts"
|
|
654
|
-
]);
|
|
646
|
+
const mainEntry = resolveMainEntryFromPkg(projectRoot, pkg);
|
|
655
647
|
let mainWiring = { kind: "no_entry_found" };
|
|
656
648
|
if (mainEntry && existsSync(mainEntry)) {
|
|
657
649
|
mainWiring = injectImport(mainEntry, mainInitPath);
|
|
658
650
|
}
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
"
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
651
|
+
const htmlFiles = findRendererHtmlFiles(projectRoot);
|
|
652
|
+
let rendererInitPath;
|
|
653
|
+
if (htmlFiles.length > 0) {
|
|
654
|
+
const rendererDir = dirname(htmlFiles[0]);
|
|
655
|
+
rendererInitPath = join(rendererDir, "gg-pixel.browser.iife.js");
|
|
656
|
+
if (!copyIifeBundle(projectRoot, rendererInitPath)) {
|
|
657
|
+
warnings.push(
|
|
658
|
+
"Could not copy gg-pixel browser IIFE bundle \u2014 install @kenkaiiii/gg-pixel and re-run."
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
let patchedAny = false;
|
|
662
|
+
for (const html of htmlFiles) {
|
|
663
|
+
if (patchRendererHtml(html, rendererInitPath, projectKey, ingestUrl) === "patched") {
|
|
664
|
+
patchedAny = true;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (!patchedAny) {
|
|
668
|
+
warnings.push(
|
|
669
|
+
`Found HTML files in ${rendererDir} but couldn't patch any \u2014 they may have unusual CSP or no <head>.`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
} else {
|
|
673
|
+
rendererInitPath = join(projectRoot, "gg-pixel.renderer.mjs");
|
|
674
|
+
writeFileSync(rendererInitPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|
|
675
|
+
const rendererEntry = pickPath(projectRoot, [
|
|
676
|
+
"src/renderer/index.ts",
|
|
677
|
+
"src/renderer/index.tsx",
|
|
678
|
+
"src/renderer/index.js",
|
|
679
|
+
"src/renderer/main.ts",
|
|
680
|
+
"src/renderer/main.tsx",
|
|
681
|
+
"src/renderer/main.js",
|
|
682
|
+
"renderer/index.ts",
|
|
683
|
+
"renderer/index.tsx",
|
|
684
|
+
"renderer/index.js",
|
|
685
|
+
"renderer.ts",
|
|
686
|
+
"renderer.tsx",
|
|
687
|
+
"renderer.js",
|
|
688
|
+
"src/index.tsx",
|
|
689
|
+
"src/index.jsx",
|
|
690
|
+
"src/main.tsx",
|
|
691
|
+
"src/main.jsx"
|
|
692
|
+
]);
|
|
693
|
+
if (rendererEntry) injectImport(rendererEntry, rendererInitPath);
|
|
694
|
+
else
|
|
695
|
+
warnings.push(
|
|
696
|
+
'Could not auto-detect the Electron renderer entry. Add `import "./gg-pixel.renderer.mjs";` to the top of your renderer entry file.'
|
|
697
|
+
);
|
|
685
698
|
}
|
|
686
699
|
return {
|
|
687
700
|
primaryInitPath: rendererInitPath,
|
|
688
|
-
entryWiring:
|
|
701
|
+
entryWiring: { kind: "injected", entryPath: rendererInitPath },
|
|
689
702
|
secondaryInit: {
|
|
690
703
|
path: mainInitPath,
|
|
691
704
|
description: "Electron main-process init" + (mainWiring.kind === "injected" ? ` (wired into ${mainEntry})` : "")
|
|
@@ -693,6 +706,124 @@ function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
|
|
|
693
706
|
warnings
|
|
694
707
|
};
|
|
695
708
|
}
|
|
709
|
+
function resolveMainEntryFromPkg(projectRoot, pkg) {
|
|
710
|
+
if (pkg.main) {
|
|
711
|
+
const sourceCandidates = [];
|
|
712
|
+
const main2 = pkg.main;
|
|
713
|
+
if (/^(dist|build|\.next|out)\//.test(main2)) {
|
|
714
|
+
const swap = main2.replace(/^(dist|build|\.next|out)\//, "src/");
|
|
715
|
+
if (swap.endsWith(".js")) {
|
|
716
|
+
sourceCandidates.push(swap.replace(/\.js$/, ".ts"));
|
|
717
|
+
sourceCandidates.push(swap.replace(/\.js$/, ".tsx"));
|
|
718
|
+
}
|
|
719
|
+
sourceCandidates.push(swap);
|
|
720
|
+
}
|
|
721
|
+
if (main2.endsWith(".js")) {
|
|
722
|
+
sourceCandidates.push(main2.replace(/\.js$/, ".ts"));
|
|
723
|
+
sourceCandidates.push(main2.replace(/\.js$/, ".tsx"));
|
|
724
|
+
}
|
|
725
|
+
for (const c of sourceCandidates) {
|
|
726
|
+
const p = join(projectRoot, c);
|
|
727
|
+
if (existsSync(p)) return p;
|
|
728
|
+
}
|
|
729
|
+
const literal = join(projectRoot, main2);
|
|
730
|
+
if (existsSync(literal)) return literal;
|
|
731
|
+
}
|
|
732
|
+
return pickPath(projectRoot, [
|
|
733
|
+
"main.js",
|
|
734
|
+
"main.ts",
|
|
735
|
+
"src/main.js",
|
|
736
|
+
"src/main.ts",
|
|
737
|
+
"src/main/index.ts",
|
|
738
|
+
"src/main/index.js",
|
|
739
|
+
"electron/main.js",
|
|
740
|
+
"electron/main.ts"
|
|
741
|
+
]);
|
|
742
|
+
}
|
|
743
|
+
var RENDERER_HTML_DIRS = ["ui", "renderer", "src/renderer", "public", "static"];
|
|
744
|
+
function findRendererHtmlFiles(projectRoot) {
|
|
745
|
+
for (const dir of RENDERER_HTML_DIRS) {
|
|
746
|
+
const root = join(projectRoot, dir);
|
|
747
|
+
if (!existsSync(root)) continue;
|
|
748
|
+
const html = [];
|
|
749
|
+
let entries;
|
|
750
|
+
try {
|
|
751
|
+
entries = readdirSync(root);
|
|
752
|
+
} catch {
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
for (const e of entries) {
|
|
756
|
+
if (!e.endsWith(".html")) continue;
|
|
757
|
+
const p = join(root, e);
|
|
758
|
+
try {
|
|
759
|
+
const c = readFileSync(p, "utf8");
|
|
760
|
+
if (/<meta[^>]+content-security-policy/i.test(c) || /<script[\s>]/i.test(c)) {
|
|
761
|
+
html.push(p);
|
|
762
|
+
}
|
|
763
|
+
} catch {
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (html.length > 0) return html;
|
|
767
|
+
}
|
|
768
|
+
return [];
|
|
769
|
+
}
|
|
770
|
+
function copyIifeBundle(projectRoot, dest) {
|
|
771
|
+
const candidates = [
|
|
772
|
+
join(projectRoot, "node_modules/@kenkaiiii/gg-pixel/dist/browser.iife.global.js"),
|
|
773
|
+
join(projectRoot, "node_modules/@kenkaiiii/gg-pixel/dist/browser.iife.js")
|
|
774
|
+
];
|
|
775
|
+
for (const c of candidates) {
|
|
776
|
+
if (existsSync(c)) {
|
|
777
|
+
try {
|
|
778
|
+
writeFileSync(dest, readFileSync(c, "utf8"), "utf8");
|
|
779
|
+
return true;
|
|
780
|
+
} catch {
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
function patchRendererHtml(htmlPath, iifePath, projectKey, ingestUrl) {
|
|
787
|
+
let content;
|
|
788
|
+
try {
|
|
789
|
+
content = readFileSync(htmlPath, "utf8");
|
|
790
|
+
} catch {
|
|
791
|
+
return "not-applicable";
|
|
792
|
+
}
|
|
793
|
+
if (content.includes("gg-pixel.browser.iife")) return "already";
|
|
794
|
+
const ingestOrigin = new URL(ingestUrl).origin;
|
|
795
|
+
content = content.replace(
|
|
796
|
+
/(<meta[^>]+http-equiv=["']?content-security-policy["']?[^>]+content=["'])([^"']+)(["'])/i,
|
|
797
|
+
(_match, before, csp, after) => {
|
|
798
|
+
let updated = csp;
|
|
799
|
+
if (/connect-src\s/i.test(csp)) {
|
|
800
|
+
if (!csp.includes(ingestOrigin)) {
|
|
801
|
+
updated = csp.replace(/(connect-src[^;]*)/i, `$1 ${ingestOrigin}`);
|
|
802
|
+
}
|
|
803
|
+
} else {
|
|
804
|
+
updated = csp.trim().replace(/;?$/, `; connect-src 'self' ${ingestOrigin};`);
|
|
805
|
+
}
|
|
806
|
+
return before + updated + after;
|
|
807
|
+
}
|
|
808
|
+
);
|
|
809
|
+
const relScript = relative(dirname(htmlPath), iifePath).split(sep).join("/");
|
|
810
|
+
const inject = `
|
|
811
|
+
<!-- gg-pixel: auto-wired by ggcoder pixel install -->
|
|
812
|
+
<script src="${relScript}"></script>
|
|
813
|
+
<script>
|
|
814
|
+
if (window.GGPixel) GGPixel.initPixel({ projectKey: ${JSON.stringify(projectKey)}, ingestUrl: ${JSON.stringify(ingestUrl)} });
|
|
815
|
+
</script>
|
|
816
|
+
`;
|
|
817
|
+
if (/<head[^>]*>/i.test(content)) {
|
|
818
|
+
content = content.replace(/(<head[^>]*>)/i, `$1${inject}`);
|
|
819
|
+
} else if (/<html[^>]*>/i.test(content)) {
|
|
820
|
+
content = content.replace(/(<html[^>]*>)/i, `$1<head>${inject}</head>`);
|
|
821
|
+
} else {
|
|
822
|
+
return "not-applicable";
|
|
823
|
+
}
|
|
824
|
+
writeFileSync(htmlPath, content, "utf8");
|
|
825
|
+
return "patched";
|
|
826
|
+
}
|
|
696
827
|
function wireTauri({ projectRoot, pkg, projectKey, ingestUrl }) {
|
|
697
828
|
const initPath = join(projectRoot, "gg-pixel.init.mjs");
|
|
698
829
|
writeFileSync(initPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|