@kenkaiiii/gg-pixel 4.3.63 → 4.3.64
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/cli.js +39 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +38 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17,15 +17,24 @@ async function install(opts = {}) {
|
|
|
17
17
|
const pkgPath = join(projectRoot, "package.json");
|
|
18
18
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
19
19
|
const projectName = opts.projectName ?? pkg.name ?? projectRoot.split("/").pop() ?? "unnamed";
|
|
20
|
-
const
|
|
20
|
+
const home = opts.homeDir ?? homedir();
|
|
21
|
+
const projectsJsonPath = join(home, ".gg", "projects.json");
|
|
22
|
+
const envFilePath = join(projectRoot, ".env");
|
|
23
|
+
const existing = findMappingByPath(projectsJsonPath, projectRoot);
|
|
24
|
+
const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
|
|
25
|
+
let created;
|
|
26
|
+
let reused = false;
|
|
27
|
+
if (existing && existingKey) {
|
|
28
|
+
created = { id: existing.id, key: existingKey };
|
|
29
|
+
reused = true;
|
|
30
|
+
} else {
|
|
31
|
+
created = await createProject(fetchFn, ingestUrl, projectName);
|
|
32
|
+
}
|
|
21
33
|
const pm = detectPackageManager(projectRoot);
|
|
22
34
|
const packageInstalled = opts.skipPackageInstall ? false : runInstall(projectRoot, pm, "@kenkaiiii/gg-pixel");
|
|
23
35
|
const initFilePath = join(projectRoot, "gg-pixel.init.mjs");
|
|
24
36
|
writeFileSync(initFilePath, renderInitFile(ingestUrl), "utf8");
|
|
25
|
-
const envFilePath = join(projectRoot, ".env");
|
|
26
37
|
writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
|
|
27
|
-
const home = opts.homeDir ?? homedir();
|
|
28
|
-
const projectsJsonPath = join(home, ".gg", "projects.json");
|
|
29
38
|
writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
|
|
30
39
|
const entryWiring = wireEntryFile(projectRoot, initFilePath, pkg);
|
|
31
40
|
return {
|
|
@@ -37,9 +46,33 @@ async function install(opts = {}) {
|
|
|
37
46
|
projectsJsonPath,
|
|
38
47
|
packageManager: pm,
|
|
39
48
|
packageInstalled,
|
|
40
|
-
entryWiring
|
|
49
|
+
entryWiring,
|
|
50
|
+
reused
|
|
41
51
|
};
|
|
42
52
|
}
|
|
53
|
+
function findMappingByPath(projectsJsonPath, projectRoot) {
|
|
54
|
+
if (!existsSync(projectsJsonPath)) return null;
|
|
55
|
+
let map;
|
|
56
|
+
try {
|
|
57
|
+
map = JSON.parse(readFileSync(projectsJsonPath, "utf8"));
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
for (const [id, entry] of Object.entries(map)) {
|
|
62
|
+
if (entry.path === projectRoot) return { id, ...entry };
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function readEnvKey(envPath, key) {
|
|
67
|
+
if (!existsSync(envPath)) return null;
|
|
68
|
+
try {
|
|
69
|
+
const content = readFileSync(envPath, "utf8");
|
|
70
|
+
const match = new RegExp(`^${key}=(.+)$`, "m").exec(content);
|
|
71
|
+
return match?.[1]?.trim() ?? null;
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
43
76
|
function findProjectRoot(start) {
|
|
44
77
|
let dir = start;
|
|
45
78
|
for (let i = 0; i < 20; i++) {
|
|
@@ -260,7 +293,7 @@ async function main(argv) {
|
|
|
260
293
|
skipPackageInstall: args.skipPackageInstall
|
|
261
294
|
});
|
|
262
295
|
console.log("");
|
|
263
|
-
console.log("Pixel installed.");
|
|
296
|
+
console.log(result.reused ? "Pixel re-wired (existing project)." : "Pixel installed.");
|
|
264
297
|
console.log(` Project: ${result.projectName} (${result.projectId})`);
|
|
265
298
|
console.log(` Wrote: ${result.initFilePath}`);
|
|
266
299
|
console.log(` Wrote env: ${result.envFilePath}`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/install.ts","../src/cli.ts"],"sourcesContent":["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}\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 created = await createProject(fetchFn, ingestUrl, projectName);\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 const envFilePath = join(projectRoot, \".env\");\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n\n const home = opts.homeDir ?? homedir();\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\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 };\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 { install, DEFAULT_INGEST_URL } from \"./install.js\";\n\ninterface ParsedArgs {\n command: string;\n ingestUrl?: string;\n name?: string;\n skipPackageInstall: boolean;\n help: boolean;\n}\n\nfunction parse(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { command: argv[0] ?? \"\", skipPackageInstall: false, help: false };\n for (let i = 1; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--ingest-url\") out.ingestUrl = argv[++i];\n else if (a === \"--name\") out.name = argv[++i];\n else if (a === \"--skip-install\") out.skipPackageInstall = true;\n else if (a === \"--help\" || a === \"-h\") out.help = true;\n }\n return out;\n}\n\nfunction printUsage(): void {\n console.log(`gg-pixel install — drop the pixel into the current project\n\nUsage:\n gg-pixel install [--name <project-name>] [--ingest-url <url>] [--skip-install]\n\nOptions:\n --name Project name to register (defaults to package.json name)\n --ingest-url Backend URL (defaults to ${DEFAULT_INGEST_URL})\n --skip-install Skip the package-manager install step (useful for testing)\n`);\n}\n\nasync function main(argv: string[]): Promise<void> {\n const args = parse(argv);\n if (args.help || !args.command) {\n printUsage();\n return;\n }\n if (args.command !== \"install\") {\n console.error(`Unknown command: ${args.command}`);\n printUsage();\n process.exitCode = 1;\n return;\n }\n\n const result = await install({\n ingestUrl: args.ingestUrl,\n projectName: args.name,\n skipPackageInstall: args.skipPackageInstall,\n });\n\n console.log(\"\");\n console.log(\"Pixel installed.\");\n console.log(` Project: ${result.projectName} (${result.projectId})`);\n console.log(` Wrote: ${result.initFilePath}`);\n console.log(` Wrote env: ${result.envFilePath}`);\n console.log(` Mapping saved: ${result.projectsJsonPath}`);\n switch (result.entryWiring.kind) {\n case \"injected\":\n console.log(` Wired entry: ${result.entryWiring.entryPath}`);\n break;\n case \"already_present\":\n console.log(` Entry: ${result.entryWiring.entryPath} (already wired)`);\n break;\n case \"no_entry_found\":\n console.log(` ⚠ Could not auto-detect your entry file.`);\n console.log(` Add this line to the TOP of your entry file manually:`);\n console.log(` import \"./gg-pixel.init.mjs\";`);\n break;\n case \"skipped\":\n console.log(` ⚠ Entry wiring skipped: ${result.entryWiring.reason}`);\n break;\n }\n if (!result.packageInstalled && !args.skipPackageInstall) {\n console.log(` ⚠ Package install failed via ${result.packageManager}. Run it manually.`);\n }\n console.log(\"\");\n}\n\nmain(process.argv.slice(2)).catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n});\n"],"mappings":"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","names":["sep"]}
|
|
1
|
+
{"version":3,"sources":["../src/install.ts","../src/cli.ts"],"sourcesContent":["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 { install, DEFAULT_INGEST_URL } from \"./install.js\";\n\ninterface ParsedArgs {\n command: string;\n ingestUrl?: string;\n name?: string;\n skipPackageInstall: boolean;\n help: boolean;\n}\n\nfunction parse(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { command: argv[0] ?? \"\", skipPackageInstall: false, help: false };\n for (let i = 1; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--ingest-url\") out.ingestUrl = argv[++i];\n else if (a === \"--name\") out.name = argv[++i];\n else if (a === \"--skip-install\") out.skipPackageInstall = true;\n else if (a === \"--help\" || a === \"-h\") out.help = true;\n }\n return out;\n}\n\nfunction printUsage(): void {\n console.log(`gg-pixel install — drop the pixel into the current project\n\nUsage:\n gg-pixel install [--name <project-name>] [--ingest-url <url>] [--skip-install]\n\nOptions:\n --name Project name to register (defaults to package.json name)\n --ingest-url Backend URL (defaults to ${DEFAULT_INGEST_URL})\n --skip-install Skip the package-manager install step (useful for testing)\n`);\n}\n\nasync function main(argv: string[]): Promise<void> {\n const args = parse(argv);\n if (args.help || !args.command) {\n printUsage();\n return;\n }\n if (args.command !== \"install\") {\n console.error(`Unknown command: ${args.command}`);\n printUsage();\n process.exitCode = 1;\n return;\n }\n\n const result = await install({\n ingestUrl: args.ingestUrl,\n projectName: args.name,\n skipPackageInstall: args.skipPackageInstall,\n });\n\n console.log(\"\");\n console.log(result.reused ? \"Pixel re-wired (existing project).\" : \"Pixel installed.\");\n console.log(` Project: ${result.projectName} (${result.projectId})`);\n console.log(` Wrote: ${result.initFilePath}`);\n console.log(` Wrote env: ${result.envFilePath}`);\n console.log(` Mapping saved: ${result.projectsJsonPath}`);\n switch (result.entryWiring.kind) {\n case \"injected\":\n console.log(` Wired entry: ${result.entryWiring.entryPath}`);\n break;\n case \"already_present\":\n console.log(` Entry: ${result.entryWiring.entryPath} (already wired)`);\n break;\n case \"no_entry_found\":\n console.log(` ⚠ Could not auto-detect your entry file.`);\n console.log(` Add this line to the TOP of your entry file manually:`);\n console.log(` import \"./gg-pixel.init.mjs\";`);\n break;\n case \"skipped\":\n console.log(` ⚠ Entry wiring skipped: ${result.entryWiring.reason}`);\n break;\n }\n if (!result.packageInstalled && !args.skipPackageInstall) {\n console.log(` ⚠ Package install failed via ${result.packageManager}. Run it manually.`);\n }\n console.log(\"\");\n}\n\nmain(process.argv.slice(2)).catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n});\n"],"mappings":"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","names":["sep"]}
|
package/dist/index.cjs
CHANGED
|
@@ -420,15 +420,24 @@ async function install(opts = {}) {
|
|
|
420
420
|
const pkgPath = (0, import_node_path2.join)(projectRoot, "package.json");
|
|
421
421
|
const pkg = JSON.parse((0, import_node_fs3.readFileSync)(pkgPath, "utf8"));
|
|
422
422
|
const projectName = opts.projectName ?? pkg.name ?? projectRoot.split("/").pop() ?? "unnamed";
|
|
423
|
-
const
|
|
423
|
+
const home = opts.homeDir ?? (0, import_node_os2.homedir)();
|
|
424
|
+
const projectsJsonPath = (0, import_node_path2.join)(home, ".gg", "projects.json");
|
|
425
|
+
const envFilePath = (0, import_node_path2.join)(projectRoot, ".env");
|
|
426
|
+
const existing = findMappingByPath(projectsJsonPath, projectRoot);
|
|
427
|
+
const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
|
|
428
|
+
let created;
|
|
429
|
+
let reused = false;
|
|
430
|
+
if (existing && existingKey) {
|
|
431
|
+
created = { id: existing.id, key: existingKey };
|
|
432
|
+
reused = true;
|
|
433
|
+
} else {
|
|
434
|
+
created = await createProject(fetchFn, ingestUrl, projectName);
|
|
435
|
+
}
|
|
424
436
|
const pm = detectPackageManager(projectRoot);
|
|
425
437
|
const packageInstalled = opts.skipPackageInstall ? false : runInstall(projectRoot, pm, "@kenkaiiii/gg-pixel");
|
|
426
438
|
const initFilePath = (0, import_node_path2.join)(projectRoot, "gg-pixel.init.mjs");
|
|
427
439
|
(0, import_node_fs3.writeFileSync)(initFilePath, renderInitFile(ingestUrl), "utf8");
|
|
428
|
-
const envFilePath = (0, import_node_path2.join)(projectRoot, ".env");
|
|
429
440
|
writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
|
|
430
|
-
const home = opts.homeDir ?? (0, import_node_os2.homedir)();
|
|
431
|
-
const projectsJsonPath = (0, import_node_path2.join)(home, ".gg", "projects.json");
|
|
432
441
|
writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
|
|
433
442
|
const entryWiring = wireEntryFile(projectRoot, initFilePath, pkg);
|
|
434
443
|
return {
|
|
@@ -440,9 +449,33 @@ async function install(opts = {}) {
|
|
|
440
449
|
projectsJsonPath,
|
|
441
450
|
packageManager: pm,
|
|
442
451
|
packageInstalled,
|
|
443
|
-
entryWiring
|
|
452
|
+
entryWiring,
|
|
453
|
+
reused
|
|
444
454
|
};
|
|
445
455
|
}
|
|
456
|
+
function findMappingByPath(projectsJsonPath, projectRoot) {
|
|
457
|
+
if (!(0, import_node_fs3.existsSync)(projectsJsonPath)) return null;
|
|
458
|
+
let map;
|
|
459
|
+
try {
|
|
460
|
+
map = JSON.parse((0, import_node_fs3.readFileSync)(projectsJsonPath, "utf8"));
|
|
461
|
+
} catch {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
for (const [id, entry] of Object.entries(map)) {
|
|
465
|
+
if (entry.path === projectRoot) return { id, ...entry };
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
function readEnvKey(envPath, key) {
|
|
470
|
+
if (!(0, import_node_fs3.existsSync)(envPath)) return null;
|
|
471
|
+
try {
|
|
472
|
+
const content = (0, import_node_fs3.readFileSync)(envPath, "utf8");
|
|
473
|
+
const match = new RegExp(`^${key}=(.+)$`, "m").exec(content);
|
|
474
|
+
return match?.[1]?.trim() ?? null;
|
|
475
|
+
} catch {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
446
479
|
function findProjectRoot(start) {
|
|
447
480
|
let dir = start;
|
|
448
481
|
for (let i = 0; i < 20; i++) {
|
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 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: JSON.stringify(event),\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}\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 created = await createProject(fetchFn, ingestUrl, projectName);\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 const envFilePath = join(projectRoot, \".env\");\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n\n const home = opts.homeDir ?? homedir();\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\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 };\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,sBAA2B;;;ACE3B,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAEb,SAAS,WAAW,OAAyC;AAClE,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,SAAuB,CAAC;AAC9B,aAAW,QAAQ,MAAM,MAAM,IAAI,GAAG;AACpC,UAAM,SAAS,cAAc,KAAK,IAAI;AACtC,QAAI,QAAQ;AACV,YAAM,OAAO,OAAO,CAAC;AACrB,aAAO,KAAK;AAAA,QACV,IAAI,OAAO,CAAC;AAAA,QACZ;AAAA,QACA,MAAM,OAAO,OAAO,CAAC,CAAC;AAAA,QACtB,KAAK,OAAO,OAAO,CAAC,CAAC;AAAA,QACrB,QAAQ,QAAQ,IAAI;AAAA,MACtB,CAAC;AACD;AAAA,IACF;AACA,UAAM,OAAO,YAAY,KAAK,IAAI;AAClC,QAAI,MAAM;AACR,YAAM,OAAO,KAAK,CAAC;AACnB,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ;AAAA,QACA,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,QACpB,KAAK,OAAO,KAAK,CAAC,CAAC;AAAA,QACnB,QAAQ,QAAQ,IAAI;AAAA,MACtB,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,MAAuB;AACtC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,WAAW,OAAO,EAAG,QAAO;AACrC,MAAI,KAAK,WAAW,WAAW,EAAG,QAAO;AACzC,MAAI,KAAK,SAAS,gBAAgB,EAAG,QAAO;AAC5C,SAAO;AACT;;;AC1CA,yBAA2B;AAGpB,SAAS,YAAY,MAAc,OAA6B;AACrE,QAAM,MAAM,MAAM,CAAC;AACnB,QAAM,aAAa,MACf,GAAG,IAAI,IAAI,cAAc,IAAI,IAAI,CAAC,IAAI,IAAI,MAAM,QAAQ,IAAI,IAAI,IAAI,KACpE,GAAG,IAAI;AACX,aAAO,+BAAW,QAAQ,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAC1E;AAEA,SAAS,cAAc,MAAsB;AAC3C,SAAO,KACJ,QAAQ,cAAc,EAAE,EACxB,QAAQ,uBAAuB,eAAe,EAC9C,QAAQ,SAAS,EAAE;AACxB;;;AChBA,qBAAyC;AAGzC,IAAM,SAAS;AACf,IAAM,QAAQ,oBAAI,IAA6B;AAExC,SAAS,mBAAmB,OAAyC;AAC1E,QAAM,MAAM,MAAM,KAAK,CAAC,MAAM,WAAW,EAAE,IAAI,CAAC;AAChD,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,UAAU,IAAI,IAAI;AAChC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,OAAO,IAAI,MAAM;AAC/C,QAAM,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI,OAAO,MAAM;AACpD,SAAO;AAAA,IACL,MAAM,IAAI;AAAA,IACV,YAAY,IAAI;AAAA,IAChB,OAAO,MAAM,MAAM,OAAO,GAAG;AAAA,EAC/B;AACF;AAEA,SAAS,WAAW,MAAuB;AACzC,MAAI,CAAC,QAAQ,KAAK,WAAW,OAAO,EAAG,QAAO;AAC9C,MAAI,KAAK,SAAS,gBAAgB,EAAG,QAAO;AAC5C,SAAO,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,SAAS;AAC1D;AAEA,SAAS,UAAU,MAA+B;AAChD,QAAM,OAAO,KAAK,QAAQ,cAAc,EAAE;AAC1C,MAAI,MAAM,IAAI,IAAI,EAAG,QAAO,MAAM,IAAI,IAAI,KAAK;AAC/C,MAAI,KAAC,2BAAW,IAAI,GAAG;AACrB,UAAM,IAAI,MAAM,IAAI;AACpB,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,YAAQ,6BAAa,MAAM,MAAM,EAAE,MAAM,IAAI;AACnD,UAAM,IAAI,MAAM,KAAK;AACrB,WAAO;AAAA,EACT,QAAQ;AACN,UAAM,IAAI,MAAM,IAAI;AACpB,WAAO;AAAA,EACT;AACF;;;ACvCA,IAAM,aAAa;AACnB,IAAM,gBAAgB;AACtB,IAAM,eAAe;AAEd,IAAM,aAAN,MAAiB;AAAA,EAKtB,YAA6B,MAAY;AAAZ;AAAA,EAAa;AAAA,EAJzB,SAAsB,CAAC;AAAA,EAChC,WAAW;AAAA,EACX,SAAS;AAAA,EAIjB,QAAQ,OAAwB;AAC9B,QAAI,KAAK,OAAQ;AACjB,QAAI,KAAK,OAAO,UAAU,YAAY;AACpC,WAAK,OAAO,MAAM;AAAA,IACpB;AACA,SAAK,OAAO,KAAK,KAAK;AACtB,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA,EAEA,YAAY,OAAwB;AAClC,QAAI,KAAK,OAAQ;AACjB,QAAI,KAAK,KAAK,UAAU;AACtB,UAAI;AACF,aAAK,KAAK,SAAS,KAAK;AACxB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,QAAQ,KAAK;AAAA,EACpB;AAAA,EAEA,MAAM,QAAuB;AAC3B,WAAO,KAAK,OAAO,SAAS,KAAK,KAAK,UAAU;AAC9C,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,KAAK,MAAM;AACjB,SAAK,SAAS;AACd,QAAI,KAAK,KAAK,MAAO,OAAM,KAAK,KAAK,MAAM;AAAA,EAC7C;AAAA,EAEA,MAAc,QAAuB;AACnC,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,QAAI,UAAU;AACd,WAAO,KAAK,OAAO,SAAS,GAAG;AAC7B,YAAM,QAAQ,KAAK,OAAO,CAAC;AAC3B,UAAI;AACF,cAAM,KAAK,KAAK,KAAK,KAAK;AAC1B,aAAK,OAAO,MAAM;AAClB,kBAAU;AAAA,MACZ,QAAQ;AACN;AACA,YAAI,WAAW,GAAG;AAChB,eAAK,OAAO,MAAM;AAClB,oBAAU;AACV;AAAA,QACF;AACA,cAAM,QAAQ,KAAK,IAAI,gBAAgB,MAAM,UAAU,IAAI,YAAY;AACvE,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AAAA,MAC/C;AAAA,IACF;AACA,SAAK,WAAW;AAAA,EAClB;AACF;;;AJ/CO,SAAS,mBAAmB,MAAuC;AACxE,QAAM,QAAQ,IAAI,WAAW,KAAK,IAAI;AACtC,QAAM,SAA4B,CAAC;AAEnC,QAAM,eAAe,CAAC,KAAc,OAAc,WAAoB;AACpE,QAAI;AACF,YAAM,QAAQ,WAAW,KAAK,OAAO,QAAQ,KAAK,YAAY,KAAK,OAAO;AAC1E,YAAM,QAAQ,KAAK;AAAA,IACrB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,mBAAmB,CAAC,KAAc,OAAc,WAAoB;AACxE,QAAI;AACF,YAAM,QAAQ,WAAW,KAAK,OAAO,QAAQ,KAAK,YAAY,KAAK,OAAO;AAC1E,YAAM,YAAY,KAAK;AAAA,IACzB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,KAAK,2BAA2B;AAClC,UAAM,UAAU,CAAC,QAAe,iBAAiB,KAAK,SAAS,KAAK;AACpE,YAAQ,GAAG,4BAA4B,OAAO;AAC9C,WAAO,KAAK,MAAM,QAAQ,IAAI,4BAA4B,OAAO,CAAC;AAAA,EACpE;AAEA,MAAI,KAAK,4BAA4B;AACnC,UAAM,UAAU,CAAC,WAAoB,iBAAiB,QAAQ,SAAS,KAAK;AAC5E,YAAQ,GAAG,sBAAsB,OAAO;AACxC,WAAO,KAAK,MAAM,QAAQ,IAAI,sBAAsB,OAAO,CAAC;AAAA,EAC9D;AAEA,MAAI,KAAK,sBAAsB;AAC7B,WAAO,KAAK,aAAa,SAAS,CAAC,SAAS,aAAa,aAAa,IAAI,GAAG,SAAS,KAAK,CAAC,CAAC;AAAA,EAC/F;AAEA,MAAI,KAAK,wBAAwB;AAC/B,WAAO,KAAK,aAAa,QAAQ,CAAC,SAAS,aAAa,aAAa,IAAI,GAAG,WAAW,KAAK,CAAC,CAAC;AAAA,EAChG;AAEA,QAAM,eAAe,MAAM;AACzB,SAAK,MAAM,MAAM;AAAA,EACnB;AACA,UAAQ,GAAG,cAAc,YAAY;AACrC,SAAO,KAAK,MAAM,QAAQ,IAAI,cAAc,YAAY,CAAC;AAEzD,SAAO;AAAA,IACL,OAAO,OAAoB;AACzB,YAAM,QAAQ,MAAM,SAAS;AAC7B,UAAI,MAAM,UAAU,QAAW;AAC7B,YAAI;AACF,gBAAM,QAAQ,WAAW,MAAM,OAAO,OAAO,MAAM,KAAK,YAAY,KAAK,OAAO;AAChF,cAAI,MAAM,QAAS,OAAM,UAAU,MAAM;AACzC,gBAAM,QAAQ,KAAK;AAAA,QACrB,QAAQ;AAAA,QAER;AACA;AAAA,MACF;AACA,YAAM,MAAM,IAAI,MAAM,MAAM,OAAO;AACnC,UAAI,OAAO;AACX,mBAAa,KAAK,OAAO,IAAI;AAAA,IAC/B;AAAA,IACA,OAAO,MAAM,MAAM,MAAM;AAAA,IACzB,OAAO,YAAY;AACjB,iBAAW,MAAM,OAAQ,IAAG;AAC5B,YAAM,MAAM,MAAM;AAAA,IACpB;AAAA,EACF;AACF;AAEA,SAAS,WACP,KACA,OACA,QACA,YACA,SACW;AACX,QAAM,EAAE,MAAM,SAAS,YAAY,IAAI,UAAU,GAAG;AACpD,QAAM,QAAQ,WAAW,WAAW;AACpC,SAAO;AAAA,IACL,cAAU,gCAAW;AAAA,IACrB,aAAa;AAAA,IACb,aAAa,YAAY,MAAM,KAAK;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,mBAAmB,KAAK;AAAA,IACtC;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC;AACF;AAEA,SAAS,UAAU,KAAuE;AACxF,MAAI,eAAe,OAAO;AACxB,WAAO,EAAE,MAAM,IAAI,QAAQ,SAAS,SAAS,IAAI,SAAS,aAAa,IAAI,MAAM;AAAA,EACnF;AACA,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,EAAE,MAAM,eAAe,SAAS,IAAI;AAAA,EAC7C;AACA,MAAI;AACF,WAAO,EAAE,MAAM,gBAAgB,SAAS,KAAK,UAAU,GAAG,EAAE;AAAA,EAC9D,QAAQ;AACN,WAAO,EAAE,MAAM,gBAAgB,SAAS,OAAO,GAAG,EAAE;AAAA,EACtD;AACF;AAEA,SAAS,aAAa,MAA0B;AAC9C,aAAW,KAAK,KAAM,KAAI,aAAa,MAAO,QAAO;AACrD,SAAO,IAAI,MAAM,KAAK,IAAI,SAAS,EAAE,KAAK,GAAG,CAAC;AAChD;AAEA,SAAS,UAAU,GAAoB;AACrC,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI;AACF,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB,QAAQ;AACN,WAAO,OAAO,CAAC;AAAA,EACjB;AACF;AAIA,SAAS,aAAa,QAAuB,QAA+C;AAC1F,QAAM,WAAW,QAAQ,MAAM;AAC/B,UAAQ,MAAM,IAAI,IAAI,SAAoB;AACxC,QAAI;AACF,aAAO,IAAI;AAAA,IACb,QAAQ;AAAA,IAER;AACA,aAAS,MAAM,SAAS,IAAI;AAAA,EAC9B;AACA,SAAO,MAAM;AACX,YAAQ,MAAM,IAAI;AAAA,EACpB;AACF;;;AKjKO,IAAM,WAAN,MAA+B;AAAA,EACpC,YACmB,WACA,UAAwB,OACzC;AAFiB;AACA;AAAA,EAChB;AAAA,EAEH,MAAM,KAAK,OAAiC;AAC1C,UAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,MAAM;AAAA,MACvB;AAAA,MACA,MAAM,KAAK,UAAU,KAAK;AAAA,IAC5B,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,MAAM,wBAAwB,IAAI,MAAM,EAAE;AAAA,IACtD;AAAA,EACF;AACF;;;ACrBA,qBAAwB;AACxB,IAAAC,kBAA0B;AAC1B,uBAA8B;AAC9B,4BAAqB;AAGrB,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBR,IAAM,kBAAN,MAAsC;AAAA,EAC1B;AAAA,EACA;AAAA,EAEjB,YAAY,MAAe;AACzB,UAAM,WAAW,YAAQ,2BAAK,wBAAQ,GAAG,OAAO,WAAW;AAC3D,uCAAU,0BAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,SAAK,KAAK,IAAI,sBAAAC,QAAS,QAAQ;AAC/B,SAAK,GAAG,OAAO,oBAAoB;AACnC,SAAK,GAAG,KAAK,MAAM;AACnB,SAAK,SAAS,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAQ7B;AAAA,EACH;AAAA,EAEA,SAAS,OAAwB;AAC/B,SAAK,OAAO,IAAI;AAAA,MACd,UAAU,MAAM;AAAA,MAChB,aAAa,MAAM;AAAA,MACnB,aAAa,MAAM;AAAA,MACnB,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,OAAO,KAAK,UAAU,MAAM,KAAK;AAAA,MACjC,cAAc,MAAM,eAAe,KAAK,UAAU,MAAM,YAAY,IAAI;AAAA,MACxE,SAAS,MAAM;AAAA,MACf,eAAe,MAAM,gBAAgB,IAAI;AAAA,MACzC,OAAO,MAAM;AAAA,MACb,aAAa,MAAM;AAAA,IACrB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,KAAK,OAAiC;AAC1C,SAAK,SAAS,KAAK;AAAA,EACrB;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,GAAG,MAAM;AAAA,EAChB;AACF;;;ACtEA,IAAAC,kBAAmF;AACnF,IAAAC,kBAAwB;AACxB,IAAAC,oBAAsD;AACtD,gCAA0B;AAEnB,IAAM,qBAAqB;AAuClC,eAAsB,QAAQ,OAAuB,CAAC,GAA2B;AAC/E,QAAM,UAAM,2BAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC;AAC7C,QAAM,aAAa,KAAK,aAAa,oBAAoB,QAAQ,QAAQ,EAAE;AAC3E,QAAM,UAAU,KAAK,WAAW;AAEhC,QAAM,cAAc,gBAAgB,GAAG;AACvC,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,4BAA4B,GAAG,2BAA2B;AAAA,EAC5E;AAEA,QAAM,cAAU,wBAAK,aAAa,cAAc;AAChD,QAAM,MAAM,KAAK,UAAM,8BAAa,SAAS,MAAM,CAAC;AACpD,QAAM,cAAc,KAAK,eAAe,IAAI,QAAQ,YAAY,MAAM,GAAG,EAAE,IAAI,KAAK;AAEpF,QAAM,UAAU,MAAM,cAAc,SAAS,WAAW,WAAW;AAEnE,QAAM,KAAK,qBAAqB,WAAW;AAC3C,QAAM,mBAAmB,KAAK,qBAC1B,QACA,WAAW,aAAa,IAAI,qBAAqB;AAErD,QAAM,mBAAe,wBAAK,aAAa,mBAAmB;AAC1D,qCAAc,cAAc,eAAe,SAAS,GAAG,MAAM;AAE7D,QAAM,kBAAc,wBAAK,aAAa,MAAM;AAC5C,cAAY,aAAa,gBAAgB,QAAQ,GAAG;AAEpD,QAAM,OAAO,KAAK,eAAW,yBAAQ;AACrC,QAAM,uBAAmB,wBAAK,MAAM,OAAO,eAAe;AAC1D,uBAAqB,kBAAkB,QAAQ,IAAI,aAAa,WAAW;AAE3E,QAAM,cAAc,cAAc,aAAa,cAAc,GAAG;AAEhE,SAAO;AAAA,IACL,WAAW,QAAQ;AAAA,IACnB,YAAY,QAAQ;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAA8B;AACrD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAI,gCAAW,wBAAK,KAAK,cAAc,CAAC,EAAG,QAAO;AAClD,UAAM,aAAS,2BAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEA,eAAe,cACb,SACA,WACA,MACsC;AACtC,QAAM,MAAM,MAAM,QAAQ,GAAG,SAAS,iBAAiB;AAAA,IACrD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC;AAAA,EAC/B,CAAC;AACD,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,MAAM,8BAA8B,IAAI,MAAM,IAAI,MAAM,SAAS,GAAG,CAAC,EAAE;AAAA,EACnF;AACA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,MAAI,CAAC,KAAK,MAAM,CAAC,KAAK,IAAK,OAAM,IAAI,MAAM,yBAAyB;AACpE,SAAO,EAAE,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI;AACtC;AAEA,eAAe,SAAS,GAA8B;AACpD,MAAI;AACF,WAAO,MAAM,EAAE,KAAK;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,qBAAqB,aAAqC;AACxE,UAAI,gCAAW,wBAAK,aAAa,gBAAgB,CAAC,EAAG,QAAO;AAC5D,UAAI,gCAAW,wBAAK,aAAa,WAAW,CAAC,EAAG,QAAO;AACvD,UAAI,gCAAW,wBAAK,aAAa,WAAW,CAAC,EAAG,QAAO;AACvD,SAAO;AACT;AAEA,SAAS,WAAW,aAAqB,IAAoB,KAAsB;AACjF,QAAM,MAAM;AAIZ,QAAM,OAAO,OAAO,QAAQ,CAAC,WAAW,KAAK,cAAc,WAAW,IAAI,CAAC,OAAO,GAAG;AACrF,QAAM,aAAS,qCAAU,KAAK,MAAM,EAAE,KAAK,aAAa,OAAO,UAAU,CAAC;AAC1E,SAAO,OAAO,WAAW;AAC3B;AAEO,SAAS,eAAe,WAA2B;AACxD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uCAM8B,KAAK,UAAU,GAAG,SAAS,SAAS,CAAC;AAAA;AAAA;AAAA;AAI5E;AAEO,SAAS,YAAY,SAAiB,KAAa,OAAqB;AAC7E,UAAI,4BAAW,OAAO,GAAG;AACvB,UAAM,cAAU,8BAAa,SAAS,MAAM;AAC5C,UAAM,YAAY,IAAI,OAAO,IAAI,GAAG,QAAQ,GAAG;AAC/C,QAAI,UAAU,KAAK,OAAO,GAAG;AAC3B,yCAAc,SAAS,QAAQ,QAAQ,WAAW,GAAG,GAAG,IAAI,KAAK,EAAE,GAAG,MAAM;AAC5E;AAAA,IACF;AACA,UAAMC,OAAM,QAAQ,SAAS,IAAI,KAAK,QAAQ,WAAW,IAAI,KAAK;AAClE,wCAAe,SAAS,GAAGA,IAAG,GAAG,GAAG,IAAI,KAAK;AAAA,GAAM,MAAM;AACzD;AAAA,EACF;AACA,qCAAc,SAAS,GAAG,GAAG,IAAI,KAAK;AAAA,GAAM,MAAM;AACpD;AAEO,SAAS,cACd,aACA,cACA,KACmB;AACnB,QAAM,YAAY,cAAc,aAAa,GAAG;AAChD,MAAI,CAAC,UAAW,QAAO,EAAE,MAAM,iBAAiB;AAEhD,MAAI;AACJ,MAAI;AACF,kBAAU,8BAAa,WAAW,MAAM;AAAA,EAC1C,SAAS,KAAK;AACZ,WAAO,EAAE,MAAM,WAAW,QAAQ,eAAgB,IAAc,OAAO,GAAG;AAAA,EAC5E;AAEA,MAAI,QAAQ,SAAS,eAAe,GAAG;AACrC,WAAO,EAAE,MAAM,mBAAmB,UAAU;AAAA,EAC9C;AAGA,QAAM,cAAU,2BAAQ,SAAS;AACjC,MAAI,WAAO,4BAAS,SAAS,YAAY,EAAE,MAAM,qBAAG,EAAE,KAAK,GAAG;AAC9D,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO,OAAO;AAEzC,QAAM,QAAQ,gBAAgB,WAAW,GAAG;AAC5C,QAAM,aAAa,QACf,WAAW,KAAK,UAAU,IAAI,CAAC,OAC/B,UAAU,KAAK,UAAU,IAAI,CAAC;AAIlC,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,MAAI,WAAW;AACf,MAAI,MAAM,CAAC,GAAG,WAAW,IAAI,EAAG,YAAW;AAC3C,SACE,WAAW,MAAM,UACjB,uCAAuC,KAAK,MAAM,QAAQ,KAAK,EAAE,GACjE;AACA;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,GAAG,MAAM,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,MAAM,QAAQ,CAAC,EAAE,KAAK,IAAI;AAC7F,qCAAc,WAAW,SAAS,MAAM;AACxC,SAAO,EAAE,MAAM,YAAY,UAAU;AACvC;AAEA,SAAS,cAAc,aAAqB,KAAiC;AAC3E,QAAM,UAAU,CAAC,QAA+B;AAC9C,UAAM,QAAI,wBAAK,aAAa,GAAG;AAC/B,YAAI,4BAAW,CAAC,EAAG,QAAO;AAE1B,QAAI,IAAI,SAAS,KAAK,GAAG;AACvB,YAAM,SAAK,wBAAK,aAAa,IAAI,QAAQ,SAAS,KAAK,CAAC;AACxD,cAAI,4BAAW,EAAE,EAAG,QAAO;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,IAAI,QAAQ,UAAU;AAC/B,UAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,MAAI,IAAI,OAAO,OAAO,IAAI,QAAQ,UAAU;AAC1C,eAAW,SAAS,OAAO,OAAO,IAAI,GAAG,GAAG;AAC1C,UAAI,OAAO,UAAU,UAAU;AAC7B,cAAM,QAAQ,QAAQ,KAAK;AAC3B,YAAI,MAAO,QAAO;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACA,MAAI,IAAI,MAAM;AACZ,UAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,MAAI,IAAI,QAAQ;AACd,UAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,QAAI,MAAO,QAAO;AAAA,EACpB;AAGA,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,aAAW,KAAK,YAAY;AAC1B,UAAM,QAAQ,QAAQ,CAAC;AACvB,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,WAAmB,KAA2B;AACrE,MAAI,UAAU,SAAS,MAAM,EAAG,QAAO;AACvC,MAAI,UAAU,SAAS,MAAM,EAAG,QAAO;AACvC,MAAI,UAAU,SAAS,KAAK,KAAK,UAAU,SAAS,MAAM,EAAG,QAAO;AAEpE,SAAO,IAAI,SAAS;AACtB;AAEO,SAAS,qBACd,kBACA,WACA,MACA,MACM;AACN,qCAAU,2BAAQ,gBAAgB,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,MAAI,MAAsD,CAAC;AAC3D,UAAI,4BAAW,gBAAgB,GAAG;AAChC,QAAI;AACF,YAAM,KAAK,UAAM,8BAAa,kBAAkB,MAAM,CAAC;AAAA,IACzD,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI,SAAS,IAAI,EAAE,MAAM,KAAK;AAC9B,qCAAc,kBAAkB,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AAC7E;;;ARhTA,IAAI,SAA6B;AAE1B,SAAS,UAAU,SAAoC;AAC5D,MAAI,QAAQ;AACV,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,QAAM,OAAO,UAAU,QAAQ,IAAI;AACnC,WAAS,mBAAmB;AAAA,IAC1B,YAAY,QAAQ;AAAA,IACpB,SAAS,QAAQ,WAAW,eAAe;AAAA,IAC3C;AAAA,IACA,sBAAsB,QAAQ,wBAAwB;AAAA,IACtD,wBAAwB,QAAQ,0BAA0B;AAAA,IAC1D,4BAA4B,QAAQ,8BAA8B;AAAA,IAClE,2BAA2B,QAAQ,6BAA6B;AAAA,EAClE,CAAC;AACD,SAAO;AACT;AAEO,SAAS,YAAY,OAA0B;AACpD,MAAI,CAAC,OAAQ;AACb,SAAO,OAAO,KAAK;AACrB;AAEA,eAAsB,aAA4B;AAChD,MAAI,CAAC,OAAQ;AACb,QAAM,OAAO,MAAM;AACrB;AAEA,eAAsB,aAA4B;AAChD,MAAI,CAAC,OAAQ;AACb,QAAM,OAAO,MAAM;AACnB,WAAS;AACX;AAEA,SAAS,UAAU,QAA0B;AAC3C,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,IAAI,SAAS,OAAO,WAAW,OAAO,OAAO;AAAA,IACtD,KAAK;AACH,aAAO,IAAI,gBAAgB,OAAO,IAAI;AAAA,IACxC,KAAK;AACH,aAAO,OAAO;AAAA,EAClB;AACF;AAEA,SAAS,iBAAyB;AAChC,QAAM,IAAI,QAAQ,SAAS;AAC3B,SAAO,QAAQ,CAAC;AAClB;","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/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 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: JSON.stringify(event),\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"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -81,6 +81,8 @@ interface InstallResult {
|
|
|
81
81
|
packageManager: PackageManager;
|
|
82
82
|
packageInstalled: boolean;
|
|
83
83
|
entryWiring: EntryWiringResult;
|
|
84
|
+
/** True when an existing project mapping was reused instead of minting a fresh one. */
|
|
85
|
+
reused: boolean;
|
|
84
86
|
}
|
|
85
87
|
type EntryWiringResult = {
|
|
86
88
|
kind: "injected";
|
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ interface InstallResult {
|
|
|
81
81
|
packageManager: PackageManager;
|
|
82
82
|
packageInstalled: boolean;
|
|
83
83
|
entryWiring: EntryWiringResult;
|
|
84
|
+
/** True when an existing project mapping was reused instead of minting a fresh one. */
|
|
85
|
+
reused: boolean;
|
|
84
86
|
}
|
|
85
87
|
type EntryWiringResult = {
|
|
86
88
|
kind: "injected";
|
package/dist/index.js
CHANGED
|
@@ -379,15 +379,24 @@ async function install(opts = {}) {
|
|
|
379
379
|
const pkgPath = join2(projectRoot, "package.json");
|
|
380
380
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
381
381
|
const projectName = opts.projectName ?? pkg.name ?? projectRoot.split("/").pop() ?? "unnamed";
|
|
382
|
-
const
|
|
382
|
+
const home = opts.homeDir ?? homedir2();
|
|
383
|
+
const projectsJsonPath = join2(home, ".gg", "projects.json");
|
|
384
|
+
const envFilePath = join2(projectRoot, ".env");
|
|
385
|
+
const existing = findMappingByPath(projectsJsonPath, projectRoot);
|
|
386
|
+
const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
|
|
387
|
+
let created;
|
|
388
|
+
let reused = false;
|
|
389
|
+
if (existing && existingKey) {
|
|
390
|
+
created = { id: existing.id, key: existingKey };
|
|
391
|
+
reused = true;
|
|
392
|
+
} else {
|
|
393
|
+
created = await createProject(fetchFn, ingestUrl, projectName);
|
|
394
|
+
}
|
|
383
395
|
const pm = detectPackageManager(projectRoot);
|
|
384
396
|
const packageInstalled = opts.skipPackageInstall ? false : runInstall(projectRoot, pm, "@kenkaiiii/gg-pixel");
|
|
385
397
|
const initFilePath = join2(projectRoot, "gg-pixel.init.mjs");
|
|
386
398
|
writeFileSync(initFilePath, renderInitFile(ingestUrl), "utf8");
|
|
387
|
-
const envFilePath = join2(projectRoot, ".env");
|
|
388
399
|
writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
|
|
389
|
-
const home = opts.homeDir ?? homedir2();
|
|
390
|
-
const projectsJsonPath = join2(home, ".gg", "projects.json");
|
|
391
400
|
writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
|
|
392
401
|
const entryWiring = wireEntryFile(projectRoot, initFilePath, pkg);
|
|
393
402
|
return {
|
|
@@ -399,9 +408,33 @@ async function install(opts = {}) {
|
|
|
399
408
|
projectsJsonPath,
|
|
400
409
|
packageManager: pm,
|
|
401
410
|
packageInstalled,
|
|
402
|
-
entryWiring
|
|
411
|
+
entryWiring,
|
|
412
|
+
reused
|
|
403
413
|
};
|
|
404
414
|
}
|
|
415
|
+
function findMappingByPath(projectsJsonPath, projectRoot) {
|
|
416
|
+
if (!existsSync2(projectsJsonPath)) return null;
|
|
417
|
+
let map;
|
|
418
|
+
try {
|
|
419
|
+
map = JSON.parse(readFileSync2(projectsJsonPath, "utf8"));
|
|
420
|
+
} catch {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
for (const [id, entry] of Object.entries(map)) {
|
|
424
|
+
if (entry.path === projectRoot) return { id, ...entry };
|
|
425
|
+
}
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
function readEnvKey(envPath, key) {
|
|
429
|
+
if (!existsSync2(envPath)) return null;
|
|
430
|
+
try {
|
|
431
|
+
const content = readFileSync2(envPath, "utf8");
|
|
432
|
+
const match = new RegExp(`^${key}=(.+)$`, "m").exec(content);
|
|
433
|
+
return match?.[1]?.trim() ?? null;
|
|
434
|
+
} catch {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
405
438
|
function findProjectRoot(start) {
|
|
406
439
|
let dir = start;
|
|
407
440
|
for (let i = 0; i < 20; i++) {
|
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 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: JSON.stringify(event),\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}\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 created = await createProject(fetchFn, ingestUrl, projectName);\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 const envFilePath = join(projectRoot, \".env\");\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n\n const home = opts.homeDir ?? homedir();\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\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 };\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/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 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: JSON.stringify(event),\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"]}
|