@kenkaiiii/gg-pixel 4.3.69 → 4.3.70
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 +367 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +360 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +360 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 projectKind: ProjectKind;\n initFilePath: string;\n envFilePath: string;\n projectsJsonPath: string;\n packageManager: PackageManager | PythonPackageManager;\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 browser?: unknown;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport type ProjectKind = \"node\" | \"browser\" | \"python\";\n\nexport type PythonPackageManager = \"uv\" | \"poetry\" | \"pipenv\" | \"pip\";\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 const home = opts.homeDir ?? homedir();\n\n // Detect project kind. We pick the closer root if both Node and Python\n // markers exist (e.g. polyglot monorepos).\n const nodeRoot = findProjectRoot(cwd);\n const pythonRoot = findPythonProjectRoot(cwd);\n if (!nodeRoot && !pythonRoot) {\n throw new Error(\n `No project found at ${cwd}: looked for package.json (Node/JS), pyproject.toml, setup.py, requirements.txt, Pipfile (Python).`,\n );\n }\n\n const useNode = pickCloserRoot(nodeRoot, pythonRoot) === nodeRoot;\n if (!useNode && pythonRoot) {\n return installPython({ projectRoot: pythonRoot, opts, ingestUrl, fetchFn, home });\n }\n\n // Node or browser path.\n if (!nodeRoot) {\n throw new Error(\"Internal: no nodeRoot but useNode==true\");\n }\n const pkgPath = join(nodeRoot, \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as PackageJson;\n const projectName = opts.projectName ?? pkg.name ?? nodeRoot.split(\"/\").pop() ?? \"unnamed\";\n const isBrowser = isBrowserProject(pkg, nodeRoot);\n\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(nodeRoot, \".env\");\n\n const existing = findMappingByPath(projectsJsonPath, nodeRoot);\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(nodeRoot);\n const packageInstalled = opts.skipPackageInstall\n ? false\n : runInstall(nodeRoot, pm, \"@kenkaiiii/gg-pixel\");\n\n const initFilePath = join(nodeRoot, \"gg-pixel.init.mjs\");\n const initContent = isBrowser\n ? renderBrowserInitFile(ingestUrl, created.key)\n : renderInitFile(ingestUrl);\n writeFileSync(initFilePath, initContent, \"utf8\");\n\n if (!isBrowser) {\n // Browser bundlers usually inject env at build time via VITE_*, NEXT_PUBLIC_*\n // etc; the project_key is publishable so we bake it directly into the init file.\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n }\n\n writeProjectsMapping(projectsJsonPath, created.id, projectName, nodeRoot);\n\n const entryWiring = wireEntryFile(nodeRoot, initFilePath, pkg);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n projectKind: isBrowser ? \"browser\" : \"node\",\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 isBrowserProject(pkg: PackageJson, projectRoot: string): boolean {\n const all = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n const browserishDeps = [\n \"react\",\n \"react-dom\",\n \"vue\",\n \"@vue/runtime-core\",\n \"svelte\",\n \"next\",\n \"vite\",\n \"@vitejs/plugin-react\",\n \"@angular/core\",\n \"solid-js\",\n \"preact\",\n \"@remix-run/react\",\n \"astro\",\n \"qwik\",\n \"@sveltejs/kit\",\n \"expo\",\n ];\n if (browserishDeps.some((d) => d in all)) return true;\n if (pkg.browser !== undefined) return true;\n if (existsSync(join(projectRoot, \"index.html\"))) return true;\n if (existsSync(join(projectRoot, \"public\", \"index.html\"))) return true;\n return false;\n}\n\nexport function renderBrowserInitFile(ingestUrl: string, projectKey: string): string {\n return `// gg-pixel init — auto-generated by ggcoder pixel install.\n// The project_key is publishable (designed to live in browser bundles).\nimport { initPixel } from \"@kenkaiiii/gg-pixel/browser\";\n\ninitPixel({\n projectKey: ${JSON.stringify(projectKey)},\n ingestUrl: ${JSON.stringify(ingestUrl)},\n});\n`;\n}\n\n// ── Python ──────────────────────────────────────────────────────────\n\nconst PYTHON_MARKERS = [\"pyproject.toml\", \"setup.py\", \"requirements.txt\", \"Pipfile\"];\n\nexport function findPythonProjectRoot(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 20; i++) {\n if (PYTHON_MARKERS.some((m) => existsSync(join(dir, m)))) return dir;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n return null;\n}\n\nexport function detectPythonPackageManager(projectRoot: string): PythonPackageManager {\n if (existsSync(join(projectRoot, \"uv.lock\"))) return \"uv\";\n if (existsSync(join(projectRoot, \"poetry.lock\"))) return \"poetry\";\n if (existsSync(join(projectRoot, \"Pipfile.lock\"))) return \"pipenv\";\n return \"pip\";\n}\n\nfunction pickCloserRoot(a: string | null, b: string | null): string | null {\n if (!a) return b;\n if (!b) return a;\n // The deeper (more nested) path is the more specific project root.\n return a.length >= b.length ? a : b;\n}\n\ninterface PythonInstallContext {\n projectRoot: string;\n opts: InstallOptions;\n ingestUrl: string;\n fetchFn: typeof fetch;\n home: string;\n}\n\nasync function installPython(ctx: PythonInstallContext): Promise<InstallResult> {\n const { projectRoot, opts, ingestUrl, fetchFn, home } = ctx;\n const projectName =\n opts.projectName ?? readPyprojectName(projectRoot) ?? projectRoot.split(\"/\").pop() ?? \"unnamed\";\n\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(projectRoot, \".env\");\n\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 = detectPythonPackageManager(projectRoot);\n const packageInstalled = opts.skipPackageInstall ? false : runPythonInstall(projectRoot, pm);\n\n const initFilePath = join(projectRoot, \"gg_pixel_init.py\");\n writeFileSync(initFilePath, renderPythonInitFile(ingestUrl, created.key), \"utf8\");\n\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);\n\n const entryWiring = wirePythonEntry(projectRoot, initFilePath);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n projectKind: \"python\",\n initFilePath,\n envFilePath,\n projectsJsonPath,\n packageManager: pm,\n packageInstalled,\n entryWiring,\n reused,\n };\n}\n\nfunction readPyprojectName(projectRoot: string): string | null {\n const path = join(projectRoot, \"pyproject.toml\");\n if (!existsSync(path)) return null;\n try {\n const content = readFileSync(path, \"utf8\");\n const match = /^\\s*name\\s*=\\s*[\"']([^\"']+)[\"']/m.exec(content);\n return match?.[1] ?? null;\n } catch {\n return null;\n }\n}\n\nfunction runPythonInstall(projectRoot: string, pm: PythonPackageManager): boolean {\n const cmd =\n pm === \"uv\"\n ? [\"uv\", [\"add\", \"gg-pixel\"]]\n : pm === \"poetry\"\n ? [\"poetry\", [\"add\", \"gg-pixel\"]]\n : pm === \"pipenv\"\n ? [\"pipenv\", [\"install\", \"gg-pixel\"]]\n : [\"pip\", [\"install\", \"gg-pixel\"]];\n const result = spawnSync(cmd[0] as string, cmd[1] as string[], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n if (result.status === 0) return true;\n // Fallback: many systems only have `pip3` on PATH.\n if (pm === \"pip\") {\n const r2 = spawnSync(\"pip3\", [\"install\", \"gg-pixel\"], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n if (r2.status === 0) return true;\n const r3 = spawnSync(\"python3\", [\"-m\", \"pip\", \"install\", \"gg-pixel\"], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n return r3.status === 0;\n }\n return false;\n}\n\nexport function renderPythonInitFile(ingestUrl: string, projectKey: string): string {\n return `\"\"\"gg-pixel init — auto-generated by ggcoder pixel install.\n\nThis file initializes error tracking. Importing it (which the install step\nwires into your entry file) registers the global Python error handlers.\n\"\"\"\nimport os\n\nimport gg_pixel\n\ngg_pixel.init_pixel(\n project_key=os.environ.get(\"GG_PIXEL_KEY\") or ${JSON.stringify(projectKey)},\n ingest_url=${JSON.stringify(`${ingestUrl}/ingest`)},\n)\n`;\n}\n\nfunction wirePythonEntry(projectRoot: string, initFilePath: string): EntryWiringResult {\n const entryPath = findPythonEntryFile(projectRoot);\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 name from the relative path. gg_pixel_init.py at root →\n // `gg_pixel_init`. For nested, the user can adjust manually.\n const fromDir = dirname(entryPath);\n const rel = relative(fromDir, initFilePath).split(sep).join(\"/\");\n let moduleSpec: string;\n if (rel === \"gg_pixel_init.py\") {\n moduleSpec = \"gg_pixel_init\";\n } else if (rel.startsWith(\"../\")) {\n // Init is above the entry — Python imports don't traverse via path,\n // so insert via sys.path manipulation as a fallback.\n moduleSpec = \"gg_pixel_init\";\n } else {\n // Same-or-deeper directory: use module path.\n moduleSpec = rel.replace(/\\.py$/, \"\").replace(/\\//g, \".\");\n }\n\n const importLine = `import ${moduleSpec} # noqa: F401, E402 -- gg-pixel`;\n\n const lines = content.split(\"\\n\");\n let insertAt = 0;\n if (lines[0]?.startsWith(\"#!\")) insertAt = 1;\n // Skip encoding declarations and module docstrings.\n while (insertAt < lines.length && /^\\s*(?:#.*coding[:=]|[\"']{3}|#)/.test(lines[insertAt] ?? \"\")) {\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 findPythonEntryFile(projectRoot: string): string | null {\n const tryPath = (rel: string): string | null => {\n const p = join(projectRoot, rel);\n return existsSync(p) ? p : null;\n };\n const candidates = [\n \"main.py\",\n \"app.py\",\n \"server.py\",\n \"manage.py\",\n \"wsgi.py\",\n \"asgi.py\",\n \"__main__.py\",\n \"src/main.py\",\n \"src/app.py\",\n \"src/server.py\",\n \"src/__main__.py\",\n ];\n for (const c of candidates) {\n const found = tryPath(c);\n if (found) return found;\n }\n return null;\n}\n\n// ── /Python ─────────────────────────────────────────────────────────\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(` Kind: ${result.projectKind}`);\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 projectKind: ProjectKind;\n initFilePath: string;\n envFilePath: string;\n projectsJsonPath: string;\n packageManager: PackageManager | PythonPackageManager;\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 /** Hybrid frameworks: a second init file (e.g. server-side for Next.js). */\n secondaryInit?: { path: string; description: string };\n /** Honest disclaimers — surfaced in the CLI summary. */\n warnings: string[];\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 browser?: unknown;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport type ProjectKind =\n | \"node\"\n | \"browser\"\n | \"python\"\n | \"nextjs\"\n | \"sveltekit\"\n | \"nuxt\"\n | \"remix\"\n | \"electron\"\n | \"tauri\"\n | \"react-native\";\n\nexport type PythonPackageManager = \"uv\" | \"poetry\" | \"pipenv\" | \"pip\";\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 const home = opts.homeDir ?? homedir();\n\n // Detect project kind. We pick the closer root if both Node and Python\n // markers exist (e.g. polyglot monorepos).\n const nodeRoot = findProjectRoot(cwd);\n const pythonRoot = findPythonProjectRoot(cwd);\n if (!nodeRoot && !pythonRoot) {\n throw new Error(\n `No project found at ${cwd}: looked for package.json (Node/JS), pyproject.toml, setup.py, requirements.txt, Pipfile (Python).`,\n );\n }\n\n const useNode = pickCloserRoot(nodeRoot, pythonRoot) === nodeRoot;\n if (!useNode && pythonRoot) {\n return installPython({ projectRoot: pythonRoot, opts, ingestUrl, fetchFn, home });\n }\n\n // Node / browser / hybrid framework path.\n if (!nodeRoot) {\n throw new Error(\"Internal: no nodeRoot but useNode==true\");\n }\n const pkgPath = join(nodeRoot, \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as PackageJson;\n const projectName = opts.projectName ?? pkg.name ?? nodeRoot.split(\"/\").pop() ?? \"unnamed\";\n const kind = detectJsProjectKind(pkg, nodeRoot);\n\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(nodeRoot, \".env\");\n\n const existing = findMappingByPath(projectsJsonPath, nodeRoot);\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(nodeRoot);\n const packageInstalled = opts.skipPackageInstall\n ? false\n : runInstall(nodeRoot, pm, \"@kenkaiiii/gg-pixel\");\n\n // Dispatch to per-framework wiring.\n const wired = wireFramework({\n kind,\n projectRoot: nodeRoot,\n pkg,\n projectKey: created.key,\n ingestUrl,\n });\n\n // .env: write the key for runtimes that read it from process.env (Node servers,\n // Electron main, Next.js server, etc). Pure browser apps don't need it (key\n // is inlined into the init file).\n if (kind !== \"browser\" && kind !== \"tauri\") {\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n }\n\n writeProjectsMapping(projectsJsonPath, created.id, projectName, nodeRoot);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n projectKind: kind,\n initFilePath: wired.primaryInitPath,\n envFilePath,\n projectsJsonPath,\n packageManager: pm,\n packageInstalled,\n entryWiring: wired.entryWiring,\n reused,\n secondaryInit: wired.secondaryInit,\n warnings: wired.warnings,\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\n// ── Framework detection + wiring ────────────────────────────────────\n\nexport function detectJsProjectKind(pkg: PackageJson, projectRoot: string): ProjectKind {\n const all = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n // Order matters: more specific first (Electron + React = electron, not browser).\n if (\"electron\" in all) return \"electron\";\n if (existsSync(join(projectRoot, \"src-tauri\")) || \"@tauri-apps/api\" in all) return \"tauri\";\n if (\"react-native\" in all) return \"react-native\";\n if (\"next\" in all) return \"nextjs\";\n if (\"@sveltejs/kit\" in all) return \"sveltekit\";\n if (\"nuxt\" in all || \"nuxt3\" in all) return \"nuxt\";\n if (\"@remix-run/react\" in all || \"@remix-run/node\" in all) return \"remix\";\n if (isBrowserProject(pkg, projectRoot)) return \"browser\";\n return \"node\";\n}\n\ninterface WiringInput {\n kind: ProjectKind;\n projectRoot: string;\n pkg: PackageJson;\n projectKey: string;\n ingestUrl: string;\n}\n\ninterface WiringResult {\n primaryInitPath: string;\n entryWiring: EntryWiringResult;\n secondaryInit?: { path: string; description: string };\n warnings: string[];\n}\n\nfunction wireFramework(w: WiringInput): WiringResult {\n switch (w.kind) {\n case \"node\":\n return wireNode(w);\n case \"browser\":\n return wireBrowser(w);\n case \"nextjs\":\n return wireNextjs(w);\n case \"sveltekit\":\n return wireSveltekit(w);\n case \"nuxt\":\n return wireNuxt(w);\n case \"remix\":\n return wireRemix(w);\n case \"electron\":\n return wireElectron(w);\n case \"tauri\":\n return wireTauri(w);\n case \"react-native\":\n return wireReactNative(w);\n case \"python\":\n throw new Error(\"Internal: python should have been handled earlier\");\n }\n}\n\nfunction wireNode({ projectRoot, pkg, ingestUrl }: WiringInput): WiringResult {\n const initPath = join(projectRoot, \"gg-pixel.init.mjs\");\n writeFileSync(initPath, renderInitFile(ingestUrl), \"utf8\");\n return {\n primaryInitPath: initPath,\n entryWiring: wireEntryFile(projectRoot, initPath, pkg),\n warnings: [],\n };\n}\n\nfunction wireBrowser({ projectRoot, pkg, projectKey, ingestUrl }: WiringInput): WiringResult {\n const initPath = join(projectRoot, \"gg-pixel.init.mjs\");\n writeFileSync(initPath, renderBrowserInitFile(ingestUrl, projectKey), \"utf8\");\n return {\n primaryInitPath: initPath,\n entryWiring: wireEntryFile(projectRoot, initPath, pkg),\n warnings: [],\n };\n}\n\nfunction wireNextjs({ projectRoot, projectKey, ingestUrl }: WiringInput): WiringResult {\n // Next.js auto-loads `instrumentation.ts` for the server. No entry wiring needed.\n // For the client, we drop a registration script and import it from the root layout.\n const warnings: string[] = [];\n\n // ── Server: instrumentation.ts ─────────────\n const serverInitPath = pickPath(projectRoot, [\"instrumentation.ts\", \"instrumentation.js\"]);\n const finalServerPath = serverInitPath ?? join(projectRoot, \"instrumentation.ts\");\n writeNextInstrumentation(finalServerPath, ingestUrl);\n\n // ── Client: drop a small init module + wire into the root layout ────\n const clientInitPath = join(projectRoot, \"gg-pixel.client.mjs\");\n writeFileSync(clientInitPath, renderBrowserInitFile(ingestUrl, projectKey), \"utf8\");\n\n const layoutPath = findNextLayout(projectRoot);\n let entryWiring: EntryWiringResult;\n if (!layoutPath) {\n warnings.push(\n 'Could not auto-wire the Next.js client init — no app/layout.{tsx,jsx} or pages/_app.{tsx,jsx} found. Add `import \"./gg-pixel.client.mjs\";` to your root layout/_app.',\n );\n entryWiring = { kind: \"no_entry_found\" };\n } else {\n entryWiring = injectImport(layoutPath, clientInitPath);\n }\n\n return {\n primaryInitPath: clientInitPath,\n entryWiring,\n secondaryInit: {\n path: finalServerPath,\n description: \"Next.js server instrumentation (auto-loaded by Next runtime)\",\n },\n warnings,\n };\n}\n\nfunction writeNextInstrumentation(path: string, ingestUrl: string): void {\n const existing = existsSync(path) ? readFileSync(path, \"utf8\") : \"\";\n if (existing.includes(\"@kenkaiiii/gg-pixel\")) return; // idempotent\n\n const newContent = existing\n ? existing + \"\\n\" + nextInstrumentationAppend(ingestUrl)\n : nextInstrumentationStandalone(ingestUrl);\n writeFileSync(path, newContent, \"utf8\");\n}\n\nfunction nextInstrumentationStandalone(ingestUrl: string): string {\n return `// Next.js auto-loads this file on server start. Pixel hooks the\n// uncaughtExceptionMonitor + unhandledRejection events for API routes,\n// Server Components, and route handlers.\nexport async function register() {\n if (process.env.NEXT_RUNTIME === \"nodejs\") {\n const { initPixel } = await import(\"@kenkaiiii/gg-pixel\");\n initPixel({\n projectKey: process.env.GG_PIXEL_KEY ?? \"\",\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\n });\n }\n}\n`;\n}\n\nfunction nextInstrumentationAppend(ingestUrl: string): string {\n return `// gg-pixel: server-side error tracking\nimport { initPixel } from \"@kenkaiiii/gg-pixel\";\nif (typeof process !== \"undefined\" && process.env.NEXT_RUNTIME === \"nodejs\") {\n initPixel({\n projectKey: process.env.GG_PIXEL_KEY ?? \"\",\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\n });\n}\n`;\n}\n\nfunction findNextLayout(projectRoot: string): string | null {\n const candidates = [\n \"app/layout.tsx\",\n \"app/layout.jsx\",\n \"app/layout.ts\",\n \"src/app/layout.tsx\",\n \"src/app/layout.jsx\",\n \"pages/_app.tsx\",\n \"pages/_app.jsx\",\n \"src/pages/_app.tsx\",\n \"src/pages/_app.jsx\",\n ];\n for (const c of candidates) {\n const p = join(projectRoot, c);\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nfunction wireSveltekit({ projectRoot, projectKey, ingestUrl }: WiringInput): WiringResult {\n // SvelteKit auto-loads src/hooks.server.ts and src/hooks.client.ts.\n const serverPath = join(projectRoot, \"src/hooks.server.ts\");\n const clientPath = join(projectRoot, \"src/hooks.client.ts\");\n if (!existsSync(dirname(serverPath))) mkdirSync(dirname(serverPath), { recursive: true });\n appendOrCreate(\n serverPath,\n `import { initPixel } from \"@kenkaiiii/gg-pixel\";\\ninitPixel({\\n projectKey: process.env.GG_PIXEL_KEY ?? \"\",\\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\\n});\\n`,\n \"@kenkaiiii/gg-pixel\",\n );\n appendOrCreate(\n clientPath,\n `import { initPixel } from \"@kenkaiiii/gg-pixel/browser\";\\ninitPixel({\\n projectKey: ${JSON.stringify(projectKey)},\\n ingestUrl: ${JSON.stringify(ingestUrl)},\\n});\\n`,\n \"@kenkaiiii/gg-pixel/browser\",\n );\n return {\n primaryInitPath: clientPath,\n entryWiring: { kind: \"injected\", entryPath: clientPath },\n secondaryInit: {\n path: serverPath,\n description: \"SvelteKit server hooks (auto-loaded)\",\n },\n warnings: [],\n };\n}\n\nfunction wireNuxt({ projectRoot, projectKey, ingestUrl }: WiringInput): WiringResult {\n // Nuxt auto-loads plugins/*.client.ts and plugins/*.server.ts.\n const pluginsDir = join(projectRoot, \"plugins\");\n mkdirSync(pluginsDir, { recursive: true });\n const serverPath = join(pluginsDir, \"gg-pixel.server.ts\");\n const clientPath = join(pluginsDir, \"gg-pixel.client.ts\");\n writeFileSync(\n serverPath,\n `import { initPixel } from \"@kenkaiiii/gg-pixel\";\\nexport default defineNuxtPlugin(() => {\\n initPixel({\\n projectKey: process.env.GG_PIXEL_KEY ?? \"\",\\n sink: { kind: \"http\", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },\\n });\\n});\\n`,\n \"utf8\",\n );\n writeFileSync(\n clientPath,\n `import { initPixel } from \"@kenkaiiii/gg-pixel/browser\";\\nexport default defineNuxtPlugin(() => {\\n initPixel({\\n projectKey: ${JSON.stringify(projectKey)},\\n ingestUrl: ${JSON.stringify(ingestUrl)},\\n });\\n});\\n`,\n \"utf8\",\n );\n return {\n primaryInitPath: clientPath,\n entryWiring: { kind: \"injected\", entryPath: clientPath },\n secondaryInit: { path: serverPath, description: \"Nuxt server plugin (auto-loaded)\" },\n warnings: [],\n };\n}\n\nfunction wireRemix({ projectRoot, projectKey, ingestUrl }: WiringInput): WiringResult {\n // Remix uses app/entry.server.tsx and app/entry.client.tsx.\n const serverPath = pickPath(projectRoot, [\"app/entry.server.tsx\", \"app/entry.server.jsx\"]);\n const clientPath = pickPath(projectRoot, [\"app/entry.client.tsx\", \"app/entry.client.jsx\"]);\n const warnings: string[] = [];\n\n // Drop a small init module to import.\n const clientInitPath = join(projectRoot, \"gg-pixel.client.mjs\");\n writeFileSync(clientInitPath, renderBrowserInitFile(ingestUrl, projectKey), \"utf8\");\n\n if (clientPath) {\n injectImport(clientPath, clientInitPath);\n } else {\n warnings.push(\n \"No app/entry.client.tsx found. Run `npx remix reveal` then re-run pixel install.\",\n );\n }\n\n // Server-side: write a small init we import from entry.server.\n const serverInitPath = join(projectRoot, \"gg-pixel.server.mjs\");\n writeFileSync(serverInitPath, renderInitFile(ingestUrl), \"utf8\");\n let serverEntry: EntryWiringResult = { kind: \"no_entry_found\" };\n if (serverPath) {\n serverEntry = injectImport(serverPath, serverInitPath);\n } else {\n warnings.push(\n \"No app/entry.server.tsx found. Run `npx remix reveal` then re-run pixel install.\",\n );\n }\n void serverEntry;\n\n return {\n primaryInitPath: clientInitPath,\n entryWiring: clientPath\n ? { kind: \"injected\", entryPath: clientPath }\n : { kind: \"no_entry_found\" },\n secondaryInit: { path: serverInitPath, description: \"Remix server init\" },\n warnings,\n };\n}\n\nfunction wireElectron({ projectRoot, pkg, projectKey, ingestUrl }: WiringInput): WiringResult {\n // Two surfaces:\n // - Main process: Node SDK. Wired into pkg.main.\n // - Renderer: Browser SDK. Wired into the renderer entry (auto-detected).\n const mainInitPath = join(projectRoot, \"gg-pixel.main.mjs\");\n writeFileSync(mainInitPath, renderInitFile(ingestUrl), \"utf8\");\n\n const rendererInitPath = join(projectRoot, \"gg-pixel.renderer.mjs\");\n writeFileSync(rendererInitPath, renderBrowserInitFile(ingestUrl, projectKey), \"utf8\");\n\n // Main entry: pkg.main, fallback to common Electron entry names.\n const mainEntry = pkg.main\n ? join(projectRoot, pkg.main)\n : pickPath(projectRoot, [\n \"main.js\",\n \"main.ts\",\n \"src/main.js\",\n \"src/main.ts\",\n \"electron/main.js\",\n \"electron/main.ts\",\n ]);\n let mainWiring: EntryWiringResult = { kind: \"no_entry_found\" };\n if (mainEntry && existsSync(mainEntry)) {\n mainWiring = injectImport(mainEntry, mainInitPath);\n }\n\n // Renderer entry: tries common conventions used by Electron starters.\n const rendererEntry = pickPath(projectRoot, [\n \"src/renderer/index.ts\",\n \"src/renderer/index.tsx\",\n \"src/renderer/main.ts\",\n \"src/renderer/main.tsx\",\n \"renderer/index.ts\",\n \"renderer/index.tsx\",\n \"renderer.ts\",\n \"renderer.tsx\",\n \"src/index.tsx\",\n \"src/main.tsx\",\n ]);\n if (rendererEntry) {\n injectImport(rendererEntry, rendererInitPath);\n }\n\n const warnings: string[] = [];\n if (!rendererEntry) {\n warnings.push(\n 'Could not auto-detect the Electron renderer entry. Add `import \"./gg-pixel.renderer.mjs\";` to the top of your renderer entry file.',\n );\n }\n\n return {\n primaryInitPath: rendererInitPath,\n entryWiring: rendererEntry\n ? { kind: \"injected\", entryPath: rendererEntry }\n : { kind: \"no_entry_found\" },\n secondaryInit: {\n path: mainInitPath,\n description:\n \"Electron main-process init\" +\n (mainWiring.kind === \"injected\" ? ` (wired into ${mainEntry})` : \"\"),\n },\n warnings,\n };\n}\n\nfunction wireTauri({ projectRoot, pkg, projectKey, ingestUrl }: WiringInput): WiringResult {\n // Tauri frontend = web. Use Browser SDK on the JS side.\n // The Rust backend has no SDK yet — we say so honestly.\n const initPath = join(projectRoot, \"gg-pixel.init.mjs\");\n writeFileSync(initPath, renderBrowserInitFile(ingestUrl, projectKey), \"utf8\");\n const entryWiring = wireEntryFile(projectRoot, initPath, pkg);\n return {\n primaryInitPath: initPath,\n entryWiring,\n warnings: [\n \"Tauri Rust backend is not instrumented — no Rust SDK exists yet. Frontend errors are captured.\",\n ],\n };\n}\n\nfunction wireReactNative({ projectRoot }: WiringInput): WiringResult {\n // RN's JS engine is neither a real browser nor Node. Our current SDKs\n // don't reliably hook it. Be honest rather than ship something broken.\n return {\n primaryInitPath: join(projectRoot, \"(not-installed)\"),\n entryWiring: { kind: \"skipped\", reason: \"react-native SDK not built yet\" },\n warnings: [\n \"React Native is not yet supported — its JS runtime is neither browser nor Node.\",\n \"A dedicated React Native SDK will be a future slice.\",\n ],\n };\n}\n\n// ── small helpers used by the per-framework writers ────────────────\n\nfunction pickPath(root: string, candidates: string[]): string | null {\n for (const c of candidates) {\n const p = join(root, c);\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nfunction appendOrCreate(filePath: string, snippet: string, marker: string): void {\n if (existsSync(filePath)) {\n const existing = readFileSync(filePath, \"utf8\");\n if (existing.includes(marker)) return;\n writeFileSync(filePath, existing + \"\\n\" + snippet, \"utf8\");\n return;\n }\n writeFileSync(filePath, snippet, \"utf8\");\n}\n\nfunction injectImport(entryPath: string, initFilePath: string): EntryWiringResult {\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 const initBasename = initFilePath.split(sep).pop() ?? \"gg-pixel.init.mjs\";\n if (content.includes(initBasename) || content.includes(\"@kenkaiiii/gg-pixel\")) {\n return { kind: \"already_present\", entryPath };\n }\n const fromDir = dirname(entryPath);\n let spec = relative(fromDir, initFilePath).split(sep).join(\"/\");\n if (!spec.startsWith(\".\")) spec = \"./\" + spec;\n const importLine = `import ${JSON.stringify(spec)};`;\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 const updated = [...lines.slice(0, insertAt), importLine, ...lines.slice(insertAt)].join(\"\\n\");\n writeFileSync(entryPath, updated, \"utf8\");\n return { kind: \"injected\", entryPath };\n}\n\n// ── /Framework wiring ───────────────────────────────────────────────\n\nexport function isBrowserProject(pkg: PackageJson, projectRoot: string): boolean {\n const all = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n const browserishDeps = [\n \"react\",\n \"react-dom\",\n \"vue\",\n \"@vue/runtime-core\",\n \"svelte\",\n \"next\",\n \"vite\",\n \"@vitejs/plugin-react\",\n \"@angular/core\",\n \"solid-js\",\n \"preact\",\n \"@remix-run/react\",\n \"astro\",\n \"qwik\",\n \"@sveltejs/kit\",\n \"expo\",\n ];\n if (browserishDeps.some((d) => d in all)) return true;\n if (pkg.browser !== undefined) return true;\n if (existsSync(join(projectRoot, \"index.html\"))) return true;\n if (existsSync(join(projectRoot, \"public\", \"index.html\"))) return true;\n return false;\n}\n\nexport function renderBrowserInitFile(ingestUrl: string, projectKey: string): string {\n return `// gg-pixel init — auto-generated by ggcoder pixel install.\n// The project_key is publishable (designed to live in browser bundles).\nimport { initPixel } from \"@kenkaiiii/gg-pixel/browser\";\n\ninitPixel({\n projectKey: ${JSON.stringify(projectKey)},\n ingestUrl: ${JSON.stringify(ingestUrl)},\n});\n`;\n}\n\n// ── Python ──────────────────────────────────────────────────────────\n\nconst PYTHON_MARKERS = [\"pyproject.toml\", \"setup.py\", \"requirements.txt\", \"Pipfile\"];\n\nexport function findPythonProjectRoot(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 20; i++) {\n if (PYTHON_MARKERS.some((m) => existsSync(join(dir, m)))) return dir;\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n return null;\n}\n\nexport function detectPythonPackageManager(projectRoot: string): PythonPackageManager {\n if (existsSync(join(projectRoot, \"uv.lock\"))) return \"uv\";\n if (existsSync(join(projectRoot, \"poetry.lock\"))) return \"poetry\";\n if (existsSync(join(projectRoot, \"Pipfile.lock\"))) return \"pipenv\";\n return \"pip\";\n}\n\nfunction pickCloserRoot(a: string | null, b: string | null): string | null {\n if (!a) return b;\n if (!b) return a;\n // The deeper (more nested) path is the more specific project root.\n return a.length >= b.length ? a : b;\n}\n\ninterface PythonInstallContext {\n projectRoot: string;\n opts: InstallOptions;\n ingestUrl: string;\n fetchFn: typeof fetch;\n home: string;\n}\n\nasync function installPython(ctx: PythonInstallContext): Promise<InstallResult> {\n const { projectRoot, opts, ingestUrl, fetchFn, home } = ctx;\n const projectName =\n opts.projectName ?? readPyprojectName(projectRoot) ?? projectRoot.split(\"/\").pop() ?? \"unnamed\";\n\n const projectsJsonPath = join(home, \".gg\", \"projects.json\");\n const envFilePath = join(projectRoot, \".env\");\n\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 = detectPythonPackageManager(projectRoot);\n const packageInstalled = opts.skipPackageInstall ? false : runPythonInstall(projectRoot, pm);\n\n const initFilePath = join(projectRoot, \"gg_pixel_init.py\");\n writeFileSync(initFilePath, renderPythonInitFile(ingestUrl, created.key), \"utf8\");\n\n writeEnvKey(envFilePath, \"GG_PIXEL_KEY\", created.key);\n writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);\n\n const entryWiring = wirePythonEntry(projectRoot, initFilePath);\n\n return {\n projectId: created.id,\n projectKey: created.key,\n projectName,\n projectKind: \"python\",\n initFilePath,\n envFilePath,\n projectsJsonPath,\n packageManager: pm,\n packageInstalled,\n entryWiring,\n reused,\n warnings: [],\n };\n}\n\nfunction readPyprojectName(projectRoot: string): string | null {\n const path = join(projectRoot, \"pyproject.toml\");\n if (!existsSync(path)) return null;\n try {\n const content = readFileSync(path, \"utf8\");\n const match = /^\\s*name\\s*=\\s*[\"']([^\"']+)[\"']/m.exec(content);\n return match?.[1] ?? null;\n } catch {\n return null;\n }\n}\n\nfunction runPythonInstall(projectRoot: string, pm: PythonPackageManager): boolean {\n const cmd =\n pm === \"uv\"\n ? [\"uv\", [\"add\", \"gg-pixel\"]]\n : pm === \"poetry\"\n ? [\"poetry\", [\"add\", \"gg-pixel\"]]\n : pm === \"pipenv\"\n ? [\"pipenv\", [\"install\", \"gg-pixel\"]]\n : [\"pip\", [\"install\", \"gg-pixel\"]];\n const result = spawnSync(cmd[0] as string, cmd[1] as string[], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n if (result.status === 0) return true;\n // Fallback: many systems only have `pip3` on PATH.\n if (pm === \"pip\") {\n const r2 = spawnSync(\"pip3\", [\"install\", \"gg-pixel\"], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n if (r2.status === 0) return true;\n const r3 = spawnSync(\"python3\", [\"-m\", \"pip\", \"install\", \"gg-pixel\"], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n return r3.status === 0;\n }\n return false;\n}\n\nexport function renderPythonInitFile(ingestUrl: string, projectKey: string): string {\n return `\"\"\"gg-pixel init — auto-generated by ggcoder pixel install.\n\nThis file initializes error tracking. Importing it (which the install step\nwires into your entry file) registers the global Python error handlers.\n\"\"\"\nimport os\n\nimport gg_pixel\n\ngg_pixel.init_pixel(\n project_key=os.environ.get(\"GG_PIXEL_KEY\") or ${JSON.stringify(projectKey)},\n ingest_url=${JSON.stringify(`${ingestUrl}/ingest`)},\n)\n`;\n}\n\nfunction wirePythonEntry(projectRoot: string, initFilePath: string): EntryWiringResult {\n const entryPath = findPythonEntryFile(projectRoot);\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 name from the relative path. gg_pixel_init.py at root →\n // `gg_pixel_init`. For nested, the user can adjust manually.\n const fromDir = dirname(entryPath);\n const rel = relative(fromDir, initFilePath).split(sep).join(\"/\");\n let moduleSpec: string;\n if (rel === \"gg_pixel_init.py\") {\n moduleSpec = \"gg_pixel_init\";\n } else if (rel.startsWith(\"../\")) {\n // Init is above the entry — Python imports don't traverse via path,\n // so insert via sys.path manipulation as a fallback.\n moduleSpec = \"gg_pixel_init\";\n } else {\n // Same-or-deeper directory: use module path.\n moduleSpec = rel.replace(/\\.py$/, \"\").replace(/\\//g, \".\");\n }\n\n const importLine = `import ${moduleSpec} # noqa: F401, E402 -- gg-pixel`;\n\n const lines = content.split(\"\\n\");\n let insertAt = 0;\n if (lines[0]?.startsWith(\"#!\")) insertAt = 1;\n // Skip encoding declarations and module docstrings.\n while (insertAt < lines.length && /^\\s*(?:#.*coding[:=]|[\"']{3}|#)/.test(lines[insertAt] ?? \"\")) {\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 findPythonEntryFile(projectRoot: string): string | null {\n const tryPath = (rel: string): string | null => {\n const p = join(projectRoot, rel);\n return existsSync(p) ? p : null;\n };\n const candidates = [\n \"main.py\",\n \"app.py\",\n \"server.py\",\n \"manage.py\",\n \"wsgi.py\",\n \"asgi.py\",\n \"__main__.py\",\n \"src/main.py\",\n \"src/app.py\",\n \"src/server.py\",\n \"src/__main__.py\",\n ];\n for (const c of candidates) {\n const found = tryPath(c);\n if (found) return found;\n }\n return null;\n}\n\n// ── /Python ─────────────────────────────────────────────────────────\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(` Kind: ${result.projectKind}`);\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 if (result.secondaryInit) {\n console.log(` Also wrote: ${result.secondaryInit.path}`);\n console.log(` ${result.secondaryInit.description}`);\n }\n for (const w of result.warnings) {\n console.log(` ⚠ ${w}`);\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":";;;AAAA,SAAS,YAAY,cAAc,eAAe,gBAAgB,iBAAiB;AACnF,SAAS,eAAe;AACxB,SAAS,SAAS,MAAM,UAAU,SAAS,WAAW;AACtD,SAAS,iBAAiB;AAEnB,IAAM,qBAAqB;AA+DlC,eAAsB,QAAQ,OAAuB,CAAC,GAA2B;AAC/E,QAAM,MAAM,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC;AAC7C,QAAM,aAAa,KAAK,aAAa,oBAAoB,QAAQ,QAAQ,EAAE;AAC3E,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,OAAO,KAAK,WAAW,QAAQ;AAIrC,QAAM,WAAW,gBAAgB,GAAG;AACpC,QAAM,aAAa,sBAAsB,GAAG;AAC5C,MAAI,CAAC,YAAY,CAAC,YAAY;AAC5B,UAAM,IAAI;AAAA,MACR,uBAAuB,GAAG;AAAA,IAC5B;AAAA,EACF;AAEA,QAAM,UAAU,eAAe,UAAU,UAAU,MAAM;AACzD,MAAI,CAAC,WAAW,YAAY;AAC1B,WAAO,cAAc,EAAE,aAAa,YAAY,MAAM,WAAW,SAAS,KAAK,CAAC;AAAA,EAClF;AAGA,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AACA,QAAM,UAAU,KAAK,UAAU,cAAc;AAC7C,QAAM,MAAM,KAAK,MAAM,aAAa,SAAS,MAAM,CAAC;AACpD,QAAM,cAAc,KAAK,eAAe,IAAI,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AACjF,QAAM,OAAO,oBAAoB,KAAK,QAAQ;AAE9C,QAAM,mBAAmB,KAAK,MAAM,OAAO,eAAe;AAC1D,QAAM,cAAc,KAAK,UAAU,MAAM;AAEzC,QAAM,WAAW,kBAAkB,kBAAkB,QAAQ;AAC7D,QAAM,cAAc,WAAW,aAAa,cAAc;AAC1D,MAAI;AACJ,MAAI,SAAS;AACb,MAAI,YAAY,aAAa;AAC3B,cAAU,EAAE,IAAI,SAAS,IAAI,KAAK,YAAY;AAC9C,aAAS;AAAA,EACX,OAAO;AACL,cAAU,MAAM,cAAc,SAAS,WAAW,WAAW;AAAA,EAC/D;AAEA,QAAM,KAAK,qBAAqB,QAAQ;AACxC,QAAM,mBAAmB,KAAK,qBAC1B,QACA,WAAW,UAAU,IAAI,qBAAqB;AAGlD,QAAM,QAAQ,cAAc;AAAA,IAC1B;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA,YAAY,QAAQ;AAAA,IACpB;AAAA,EACF,CAAC;AAKD,MAAI,SAAS,aAAa,SAAS,SAAS;AAC1C,gBAAY,aAAa,gBAAgB,QAAQ,GAAG;AAAA,EACtD;AAEA,uBAAqB,kBAAkB,QAAQ,IAAI,aAAa,QAAQ;AAExE,SAAO;AAAA,IACL,WAAW,QAAQ;AAAA,IACnB,YAAY,QAAQ;AAAA,IACpB;AAAA,IACA,aAAa;AAAA,IACb,cAAc,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA,aAAa,MAAM;AAAA,IACnB;AAAA,IACA,eAAe,MAAM;AAAA,IACrB,UAAU,MAAM;AAAA,EAClB;AACF;AAEA,SAAS,kBACP,kBACA,aACmD;AACnD,MAAI,CAAC,WAAW,gBAAgB,EAAG,QAAO;AAC1C,MAAI;AACJ,MAAI;AACF,UAAM,KAAK,MAAM,aAAa,kBAAkB,MAAM,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,aAAW,CAAC,IAAI,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC7C,QAAI,MAAM,SAAS,YAAa,QAAO,EAAE,IAAI,GAAG,MAAM;AAAA,EACxD;AACA,SAAO;AACT;AAEA,SAAS,WAAW,SAAiB,KAA4B;AAC/D,MAAI,CAAC,WAAW,OAAO,EAAG,QAAO;AACjC,MAAI;AACF,UAAM,UAAU,aAAa,SAAS,MAAM;AAC5C,UAAM,QAAQ,IAAI,OAAO,IAAI,GAAG,UAAU,GAAG,EAAE,KAAK,OAAO;AAC3D,WAAO,QAAQ,CAAC,GAAG,KAAK,KAAK;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAgB,OAA8B;AACrD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,QAAI,WAAW,KAAK,KAAK,cAAc,CAAC,EAAG,QAAO;AAClD,UAAM,SAAS,QAAQ,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,MAAI,WAAW,KAAK,aAAa,gBAAgB,CAAC,EAAG,QAAO;AAC5D,MAAI,WAAW,KAAK,aAAa,WAAW,CAAC,EAAG,QAAO;AACvD,MAAI,WAAW,KAAK,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,SAAS,UAAU,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,MAAI,WAAW,OAAO,GAAG;AACvB,UAAM,UAAU,aAAa,SAAS,MAAM;AAC5C,UAAM,YAAY,IAAI,OAAO,IAAI,GAAG,QAAQ,GAAG;AAC/C,QAAI,UAAU,KAAK,OAAO,GAAG;AAC3B,oBAAc,SAAS,QAAQ,QAAQ,WAAW,GAAG,GAAG,IAAI,KAAK,EAAE,GAAG,MAAM;AAC5E;AAAA,IACF;AACA,UAAMA,OAAM,QAAQ,SAAS,IAAI,KAAK,QAAQ,WAAW,IAAI,KAAK;AAClE,mBAAe,SAAS,GAAGA,IAAG,GAAG,GAAG,IAAI,KAAK;AAAA,GAAM,MAAM;AACzD;AAAA,EACF;AACA,gBAAc,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,cAAU,aAAa,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,UAAU,QAAQ,SAAS;AACjC,MAAI,OAAO,SAAS,SAAS,YAAY,EAAE,MAAM,GAAG,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,gBAAc,WAAW,SAAS,MAAM;AACxC,SAAO,EAAE,MAAM,YAAY,UAAU;AACvC;AAEA,SAAS,cAAc,aAAqB,KAAiC;AAC3E,QAAM,UAAU,CAAC,QAA+B;AAC9C,UAAM,IAAI,KAAK,aAAa,GAAG;AAC/B,QAAI,WAAW,CAAC,EAAG,QAAO;AAE1B,QAAI,IAAI,SAAS,KAAK,GAAG;AACvB,YAAM,KAAK,KAAK,aAAa,IAAI,QAAQ,SAAS,KAAK,CAAC;AACxD,UAAI,WAAW,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;AAIO,SAAS,oBAAoB,KAAkB,aAAkC;AACtF,QAAM,MAAM,EAAE,GAAI,IAAI,gBAAgB,CAAC,GAAI,GAAI,IAAI,mBAAmB,CAAC,EAAG;AAE1E,MAAI,cAAc,IAAK,QAAO;AAC9B,MAAI,WAAW,KAAK,aAAa,WAAW,CAAC,KAAK,qBAAqB,IAAK,QAAO;AACnF,MAAI,kBAAkB,IAAK,QAAO;AAClC,MAAI,UAAU,IAAK,QAAO;AAC1B,MAAI,mBAAmB,IAAK,QAAO;AACnC,MAAI,UAAU,OAAO,WAAW,IAAK,QAAO;AAC5C,MAAI,sBAAsB,OAAO,qBAAqB,IAAK,QAAO;AAClE,MAAI,iBAAiB,KAAK,WAAW,EAAG,QAAO;AAC/C,SAAO;AACT;AAiBA,SAAS,cAAc,GAA8B;AACnD,UAAQ,EAAE,MAAM;AAAA,IACd,KAAK;AACH,aAAO,SAAS,CAAC;AAAA,IACnB,KAAK;AACH,aAAO,YAAY,CAAC;AAAA,IACtB,KAAK;AACH,aAAO,WAAW,CAAC;AAAA,IACrB,KAAK;AACH,aAAO,cAAc,CAAC;AAAA,IACxB,KAAK;AACH,aAAO,SAAS,CAAC;AAAA,IACnB,KAAK;AACH,aAAO,UAAU,CAAC;AAAA,IACpB,KAAK;AACH,aAAO,aAAa,CAAC;AAAA,IACvB,KAAK;AACH,aAAO,UAAU,CAAC;AAAA,IACpB,KAAK;AACH,aAAO,gBAAgB,CAAC;AAAA,IAC1B,KAAK;AACH,YAAM,IAAI,MAAM,mDAAmD;AAAA,EACvE;AACF;AAEA,SAAS,SAAS,EAAE,aAAa,KAAK,UAAU,GAA8B;AAC5E,QAAM,WAAW,KAAK,aAAa,mBAAmB;AACtD,gBAAc,UAAU,eAAe,SAAS,GAAG,MAAM;AACzD,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,aAAa,cAAc,aAAa,UAAU,GAAG;AAAA,IACrD,UAAU,CAAC;AAAA,EACb;AACF;AAEA,SAAS,YAAY,EAAE,aAAa,KAAK,YAAY,UAAU,GAA8B;AAC3F,QAAM,WAAW,KAAK,aAAa,mBAAmB;AACtD,gBAAc,UAAU,sBAAsB,WAAW,UAAU,GAAG,MAAM;AAC5E,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,aAAa,cAAc,aAAa,UAAU,GAAG;AAAA,IACrD,UAAU,CAAC;AAAA,EACb;AACF;AAEA,SAAS,WAAW,EAAE,aAAa,YAAY,UAAU,GAA8B;AAGrF,QAAM,WAAqB,CAAC;AAG5B,QAAM,iBAAiB,SAAS,aAAa,CAAC,sBAAsB,oBAAoB,CAAC;AACzF,QAAM,kBAAkB,kBAAkB,KAAK,aAAa,oBAAoB;AAChF,2BAAyB,iBAAiB,SAAS;AAGnD,QAAM,iBAAiB,KAAK,aAAa,qBAAqB;AAC9D,gBAAc,gBAAgB,sBAAsB,WAAW,UAAU,GAAG,MAAM;AAElF,QAAM,aAAa,eAAe,WAAW;AAC7C,MAAI;AACJ,MAAI,CAAC,YAAY;AACf,aAAS;AAAA,MACP;AAAA,IACF;AACA,kBAAc,EAAE,MAAM,iBAAiB;AAAA,EACzC,OAAO;AACL,kBAAc,aAAa,YAAY,cAAc;AAAA,EACvD;AAEA,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB;AAAA,IACA,eAAe;AAAA,MACb,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,MAAc,WAAyB;AACvE,QAAM,WAAW,WAAW,IAAI,IAAI,aAAa,MAAM,MAAM,IAAI;AACjE,MAAI,SAAS,SAAS,qBAAqB,EAAG;AAE9C,QAAM,aAAa,WACf,WAAW,OAAO,0BAA0B,SAAS,IACrD,8BAA8B,SAAS;AAC3C,gBAAc,MAAM,YAAY,MAAM;AACxC;AAEA,SAAS,8BAA8B,WAA2B;AAChE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAQgC,KAAK,UAAU,GAAG,SAAS,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA;AAK9E;AAEA,SAAS,0BAA0B,WAA2B;AAC5D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,uCAK8B,KAAK,UAAU,GAAG,SAAS,SAAS,CAAC;AAAA;AAAA;AAAA;AAI5E;AAEA,SAAS,eAAe,aAAoC;AAC1D,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,aAAW,KAAK,YAAY;AAC1B,UAAM,IAAI,KAAK,aAAa,CAAC;AAC7B,QAAI,WAAW,CAAC,EAAG,QAAO;AAAA,EAC5B;AACA,SAAO;AACT;AAEA,SAAS,cAAc,EAAE,aAAa,YAAY,UAAU,GAA8B;AAExF,QAAM,aAAa,KAAK,aAAa,qBAAqB;AAC1D,QAAM,aAAa,KAAK,aAAa,qBAAqB;AAC1D,MAAI,CAAC,WAAW,QAAQ,UAAU,CAAC,EAAG,WAAU,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AACxF;AAAA,IACE;AAAA,IACA;AAAA;AAAA;AAAA,qCAAoJ,KAAK,UAAU,GAAG,SAAS,SAAS,CAAC;AAAA;AAAA;AAAA,IACzL;AAAA,EACF;AACA;AAAA,IACE;AAAA,IACA;AAAA;AAAA,gBAAwF,KAAK,UAAU,UAAU,CAAC;AAAA,eAAmB,KAAK,UAAU,SAAS,CAAC;AAAA;AAAA;AAAA,IAC9J;AAAA,EACF;AACA,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,aAAa,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACvD,eAAe;AAAA,MACb,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,UAAU,CAAC;AAAA,EACb;AACF;AAEA,SAAS,SAAS,EAAE,aAAa,YAAY,UAAU,GAA8B;AAEnF,QAAM,aAAa,KAAK,aAAa,SAAS;AAC9C,YAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,QAAM,aAAa,KAAK,YAAY,oBAAoB;AACxD,QAAM,aAAa,KAAK,YAAY,oBAAoB;AACxD;AAAA,IACE;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,uCAAmM,KAAK,UAAU,GAAG,SAAS,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA,IACxO;AAAA,EACF;AACA;AAAA,IACE;AAAA,IACA;AAAA;AAAA;AAAA,kBAAqI,KAAK,UAAU,UAAU,CAAC;AAAA,iBAAqB,KAAK,UAAU,SAAS,CAAC;AAAA;AAAA;AAAA;AAAA,IAC7M;AAAA,EACF;AACA,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,aAAa,EAAE,MAAM,YAAY,WAAW,WAAW;AAAA,IACvD,eAAe,EAAE,MAAM,YAAY,aAAa,mCAAmC;AAAA,IACnF,UAAU,CAAC;AAAA,EACb;AACF;AAEA,SAAS,UAAU,EAAE,aAAa,YAAY,UAAU,GAA8B;AAEpF,QAAM,aAAa,SAAS,aAAa,CAAC,wBAAwB,sBAAsB,CAAC;AACzF,QAAM,aAAa,SAAS,aAAa,CAAC,wBAAwB,sBAAsB,CAAC;AACzF,QAAM,WAAqB,CAAC;AAG5B,QAAM,iBAAiB,KAAK,aAAa,qBAAqB;AAC9D,gBAAc,gBAAgB,sBAAsB,WAAW,UAAU,GAAG,MAAM;AAElF,MAAI,YAAY;AACd,iBAAa,YAAY,cAAc;AAAA,EACzC,OAAO;AACL,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAiB,KAAK,aAAa,qBAAqB;AAC9D,gBAAc,gBAAgB,eAAe,SAAS,GAAG,MAAM;AAC/D,MAAI,cAAiC,EAAE,MAAM,iBAAiB;AAC9D,MAAI,YAAY;AACd,kBAAc,aAAa,YAAY,cAAc;AAAA,EACvD,OAAO;AACL,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACA,OAAK;AAEL,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,aAAa,aACT,EAAE,MAAM,YAAY,WAAW,WAAW,IAC1C,EAAE,MAAM,iBAAiB;AAAA,IAC7B,eAAe,EAAE,MAAM,gBAAgB,aAAa,oBAAoB;AAAA,IACxE;AAAA,EACF;AACF;AAEA,SAAS,aAAa,EAAE,aAAa,KAAK,YAAY,UAAU,GAA8B;AAI5F,QAAM,eAAe,KAAK,aAAa,mBAAmB;AAC1D,gBAAc,cAAc,eAAe,SAAS,GAAG,MAAM;AAE7D,QAAM,mBAAmB,KAAK,aAAa,uBAAuB;AAClE,gBAAc,kBAAkB,sBAAsB,WAAW,UAAU,GAAG,MAAM;AAGpF,QAAM,YAAY,IAAI,OAClB,KAAK,aAAa,IAAI,IAAI,IAC1B,SAAS,aAAa;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACL,MAAI,aAAgC,EAAE,MAAM,iBAAiB;AAC7D,MAAI,aAAa,WAAW,SAAS,GAAG;AACtC,iBAAa,aAAa,WAAW,YAAY;AAAA,EACnD;AAGA,QAAM,gBAAgB,SAAS,aAAa;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,eAAe;AACjB,iBAAa,eAAe,gBAAgB;AAAA,EAC9C;AAEA,QAAM,WAAqB,CAAC;AAC5B,MAAI,CAAC,eAAe;AAClB,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,aAAa,gBACT,EAAE,MAAM,YAAY,WAAW,cAAc,IAC7C,EAAE,MAAM,iBAAiB;AAAA,IAC7B,eAAe;AAAA,MACb,MAAM;AAAA,MACN,aACE,gCACC,WAAW,SAAS,aAAa,gBAAgB,SAAS,MAAM;AAAA,IACrE;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,UAAU,EAAE,aAAa,KAAK,YAAY,UAAU,GAA8B;AAGzF,QAAM,WAAW,KAAK,aAAa,mBAAmB;AACtD,gBAAc,UAAU,sBAAsB,WAAW,UAAU,GAAG,MAAM;AAC5E,QAAM,cAAc,cAAc,aAAa,UAAU,GAAG;AAC5D,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB;AAAA,IACA,UAAU;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,EAAE,YAAY,GAA8B;AAGnE,SAAO;AAAA,IACL,iBAAiB,KAAK,aAAa,iBAAiB;AAAA,IACpD,aAAa,EAAE,MAAM,WAAW,QAAQ,iCAAiC;AAAA,IACzE,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAIA,SAAS,SAAS,MAAc,YAAqC;AACnE,aAAW,KAAK,YAAY;AAC1B,UAAM,IAAI,KAAK,MAAM,CAAC;AACtB,QAAI,WAAW,CAAC,EAAG,QAAO;AAAA,EAC5B;AACA,SAAO;AACT;AAEA,SAAS,eAAe,UAAkB,SAAiB,QAAsB;AAC/E,MAAI,WAAW,QAAQ,GAAG;AACxB,UAAM,WAAW,aAAa,UAAU,MAAM;AAC9C,QAAI,SAAS,SAAS,MAAM,EAAG;AAC/B,kBAAc,UAAU,WAAW,OAAO,SAAS,MAAM;AACzD;AAAA,EACF;AACA,gBAAc,UAAU,SAAS,MAAM;AACzC;AAEA,SAAS,aAAa,WAAmB,cAAyC;AAChF,MAAI;AACJ,MAAI;AACF,cAAU,aAAa,WAAW,MAAM;AAAA,EAC1C,SAAS,KAAK;AACZ,WAAO,EAAE,MAAM,WAAW,QAAQ,eAAgB,IAAc,OAAO,GAAG;AAAA,EAC5E;AACA,QAAM,eAAe,aAAa,MAAM,GAAG,EAAE,IAAI,KAAK;AACtD,MAAI,QAAQ,SAAS,YAAY,KAAK,QAAQ,SAAS,qBAAqB,GAAG;AAC7E,WAAO,EAAE,MAAM,mBAAmB,UAAU;AAAA,EAC9C;AACA,QAAM,UAAU,QAAQ,SAAS;AACjC,MAAI,OAAO,SAAS,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AAC9D,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO,OAAO;AACzC,QAAM,aAAa,UAAU,KAAK,UAAU,IAAI,CAAC;AACjD,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;AACA,QAAM,UAAU,CAAC,GAAG,MAAM,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,MAAM,QAAQ,CAAC,EAAE,KAAK,IAAI;AAC7F,gBAAc,WAAW,SAAS,MAAM;AACxC,SAAO,EAAE,MAAM,YAAY,UAAU;AACvC;AAIO,SAAS,iBAAiB,KAAkB,aAA8B;AAC/E,QAAM,MAAM,EAAE,GAAI,IAAI,gBAAgB,CAAC,GAAI,GAAI,IAAI,mBAAmB,CAAC,EAAG;AAC1E,QAAM,iBAAiB;AAAA,IACrB;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,MAAI,eAAe,KAAK,CAAC,MAAM,KAAK,GAAG,EAAG,QAAO;AACjD,MAAI,IAAI,YAAY,OAAW,QAAO;AACtC,MAAI,WAAW,KAAK,aAAa,YAAY,CAAC,EAAG,QAAO;AACxD,MAAI,WAAW,KAAK,aAAa,UAAU,YAAY,CAAC,EAAG,QAAO;AAClE,SAAO;AACT;AAEO,SAAS,sBAAsB,WAAmB,YAA4B;AACnF,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKO,KAAK,UAAU,UAAU,CAAC;AAAA,eAC3B,KAAK,UAAU,SAAS,CAAC;AAAA;AAAA;AAGxC;AAIA,IAAM,iBAAiB,CAAC,kBAAkB,YAAY,oBAAoB,SAAS;AAE5E,SAAS,sBAAsB,OAA8B;AAClE,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,QAAI,eAAe,KAAK,CAAC,MAAM,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,EAAG,QAAO;AACjE,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEO,SAAS,2BAA2B,aAA2C;AACpF,MAAI,WAAW,KAAK,aAAa,SAAS,CAAC,EAAG,QAAO;AACrD,MAAI,WAAW,KAAK,aAAa,aAAa,CAAC,EAAG,QAAO;AACzD,MAAI,WAAW,KAAK,aAAa,cAAc,CAAC,EAAG,QAAO;AAC1D,SAAO;AACT;AAEA,SAAS,eAAe,GAAkB,GAAiC;AACzE,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,CAAC,EAAG,QAAO;AAEf,SAAO,EAAE,UAAU,EAAE,SAAS,IAAI;AACpC;AAUA,eAAe,cAAc,KAAmD;AAC9E,QAAM,EAAE,aAAa,MAAM,WAAW,SAAS,KAAK,IAAI;AACxD,QAAM,cACJ,KAAK,eAAe,kBAAkB,WAAW,KAAK,YAAY,MAAM,GAAG,EAAE,IAAI,KAAK;AAExF,QAAM,mBAAmB,KAAK,MAAM,OAAO,eAAe;AAC1D,QAAM,cAAc,KAAK,aAAa,MAAM;AAE5C,QAAM,WAAW,kBAAkB,kBAAkB,WAAW;AAChE,QAAM,cAAc,WAAW,aAAa,cAAc;AAC1D,MAAI;AACJ,MAAI,SAAS;AACb,MAAI,YAAY,aAAa;AAC3B,cAAU,EAAE,IAAI,SAAS,IAAI,KAAK,YAAY;AAC9C,aAAS;AAAA,EACX,OAAO;AACL,cAAU,MAAM,cAAc,SAAS,WAAW,WAAW;AAAA,EAC/D;AAEA,QAAM,KAAK,2BAA2B,WAAW;AACjD,QAAM,mBAAmB,KAAK,qBAAqB,QAAQ,iBAAiB,aAAa,EAAE;AAE3F,QAAM,eAAe,KAAK,aAAa,kBAAkB;AACzD,gBAAc,cAAc,qBAAqB,WAAW,QAAQ,GAAG,GAAG,MAAM;AAEhF,cAAY,aAAa,gBAAgB,QAAQ,GAAG;AACpD,uBAAqB,kBAAkB,QAAQ,IAAI,aAAa,WAAW;AAE3E,QAAM,cAAc,gBAAgB,aAAa,YAAY;AAE7D,SAAO;AAAA,IACL,WAAW,QAAQ;AAAA,IACnB,YAAY,QAAQ;AAAA,IACpB;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,CAAC;AAAA,EACb;AACF;AAEA,SAAS,kBAAkB,aAAoC;AAC7D,QAAM,OAAO,KAAK,aAAa,gBAAgB;AAC/C,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,UAAU,aAAa,MAAM,MAAM;AACzC,UAAM,QAAQ,mCAAmC,KAAK,OAAO;AAC7D,WAAO,QAAQ,CAAC,KAAK;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,aAAqB,IAAmC;AAChF,QAAM,MACJ,OAAO,OACH,CAAC,MAAM,CAAC,OAAO,UAAU,CAAC,IAC1B,OAAO,WACL,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,IAC9B,OAAO,WACL,CAAC,UAAU,CAAC,WAAW,UAAU,CAAC,IAClC,CAAC,OAAO,CAAC,WAAW,UAAU,CAAC;AACzC,QAAM,SAAS,UAAU,IAAI,CAAC,GAAa,IAAI,CAAC,GAAe;AAAA,IAC7D,KAAK;AAAA,IACL,OAAO;AAAA,EACT,CAAC;AACD,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,MAAI,OAAO,OAAO;AAChB,UAAM,KAAK,UAAU,QAAQ,CAAC,WAAW,UAAU,GAAG;AAAA,MACpD,KAAK;AAAA,MACL,OAAO;AAAA,IACT,CAAC;AACD,QAAI,GAAG,WAAW,EAAG,QAAO;AAC5B,UAAM,KAAK,UAAU,WAAW,CAAC,MAAM,OAAO,WAAW,UAAU,GAAG;AAAA,MACpE,KAAK;AAAA,MACL,OAAO;AAAA,IACT,CAAC;AACD,WAAO,GAAG,WAAW;AAAA,EACvB;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,WAAmB,YAA4B;AAClF,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oDAU2C,KAAK,UAAU,UAAU,CAAC;AAAA,iBAC7D,KAAK,UAAU,GAAG,SAAS,SAAS,CAAC;AAAA;AAAA;AAGtD;AAEA,SAAS,gBAAgB,aAAqB,cAAyC;AACrF,QAAM,YAAY,oBAAoB,WAAW;AACjD,MAAI,CAAC,UAAW,QAAO,EAAE,MAAM,iBAAiB;AAEhD,MAAI;AACJ,MAAI;AACF,cAAU,aAAa,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;AAIA,QAAM,UAAU,QAAQ,SAAS;AACjC,QAAM,MAAM,SAAS,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AAC/D,MAAI;AACJ,MAAI,QAAQ,oBAAoB;AAC9B,iBAAa;AAAA,EACf,WAAW,IAAI,WAAW,KAAK,GAAG;AAGhC,iBAAa;AAAA,EACf,OAAO;AAEL,iBAAa,IAAI,QAAQ,SAAS,EAAE,EAAE,QAAQ,OAAO,GAAG;AAAA,EAC1D;AAEA,QAAM,aAAa,UAAU,UAAU;AAEvC,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,MAAI,WAAW;AACf,MAAI,MAAM,CAAC,GAAG,WAAW,IAAI,EAAG,YAAW;AAE3C,SAAO,WAAW,MAAM,UAAU,kCAAkC,KAAK,MAAM,QAAQ,KAAK,EAAE,GAAG;AAC/F;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,GAAG,MAAM,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,MAAM,QAAQ,CAAC,EAAE,KAAK,IAAI;AAC7F,gBAAc,WAAW,SAAS,MAAM;AACxC,SAAO,EAAE,MAAM,YAAY,UAAU;AACvC;AAEA,SAAS,oBAAoB,aAAoC;AAC/D,QAAM,UAAU,CAAC,QAA+B;AAC9C,UAAM,IAAI,KAAK,aAAa,GAAG;AAC/B,WAAO,WAAW,CAAC,IAAI,IAAI;AAAA,EAC7B;AACA,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,EACF;AACA,aAAW,KAAK,YAAY;AAC1B,UAAM,QAAQ,QAAQ,CAAC;AACvB,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,SAAO;AACT;AAIO,SAAS,qBACd,kBACA,WACA,MACA,MACM;AACN,YAAU,QAAQ,gBAAgB,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,MAAI,MAAsD,CAAC;AAC3D,MAAI,WAAW,gBAAgB,GAAG;AAChC,QAAI;AACF,YAAM,KAAK,MAAM,aAAa,kBAAkB,MAAM,CAAC;AAAA,IACzD,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI,SAAS,IAAI,EAAE,MAAM,KAAK;AAC9B,gBAAc,kBAAkB,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AAC7E;;;ACvhCA,SAAS,MAAM,MAA4B;AACzC,QAAM,MAAkB,EAAE,SAAS,KAAK,CAAC,KAAK,IAAI,oBAAoB,OAAO,MAAM,MAAM;AACzF,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,MAAM,eAAgB,KAAI,YAAY,KAAK,EAAE,CAAC;AAAA,aACzC,MAAM,SAAU,KAAI,OAAO,KAAK,EAAE,CAAC;AAAA,aACnC,MAAM,iBAAkB,KAAI,qBAAqB;AAAA,aACjD,MAAM,YAAY,MAAM,KAAM,KAAI,OAAO;AAAA,EACpD;AACA,SAAO;AACT;AAEA,SAAS,aAAmB;AAC1B,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8CAOgC,kBAAkB;AAAA;AAAA,CAE/D;AACD;AAEA,eAAe,KAAK,MAA+B;AACjD,QAAM,OAAO,MAAM,IAAI;AACvB,MAAI,KAAK,QAAQ,CAAC,KAAK,SAAS;AAC9B,eAAW;AACX;AAAA,EACF;AACA,MAAI,KAAK,YAAY,WAAW;AAC9B,YAAQ,MAAM,oBAAoB,KAAK,OAAO,EAAE;AAChD,eAAW;AACX,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,WAAW,KAAK;AAAA,IAChB,aAAa,KAAK;AAAA,IAClB,oBAAoB,KAAK;AAAA,EAC3B,CAAC;AAED,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,OAAO,SAAS,uCAAuC,kBAAkB;AACrF,UAAQ,IAAI,oBAAoB,OAAO,WAAW,KAAK,OAAO,SAAS,GAAG;AAC1E,UAAQ,IAAI,oBAAoB,OAAO,WAAW,EAAE;AACpD,UAAQ,IAAI,oBAAoB,OAAO,YAAY,EAAE;AACrD,UAAQ,IAAI,oBAAoB,OAAO,WAAW,EAAE;AACpD,UAAQ,IAAI,oBAAoB,OAAO,gBAAgB,EAAE;AACzD,UAAQ,OAAO,YAAY,MAAM;AAAA,IAC/B,KAAK;AACH,cAAQ,IAAI,oBAAoB,OAAO,YAAY,SAAS,EAAE;AAC9D;AAAA,IACF,KAAK;AACH,cAAQ,IAAI,oBAAoB,OAAO,YAAY,SAAS,kBAAkB;AAC9E;AAAA,IACF,KAAK;AACH,cAAQ,IAAI,kDAA6C;AACzD,cAAQ,IAAI,4DAA4D;AACxE,cAAQ,IAAI,sCAAsC;AAClD;AAAA,IACF,KAAK;AACH,cAAQ,IAAI,mCAA8B,OAAO,YAAY,MAAM,EAAE;AACrE;AAAA,EACJ;AACA,MAAI,CAAC,OAAO,oBAAoB,CAAC,KAAK,oBAAoB;AACxD,YAAQ,IAAI,wCAAmC,OAAO,cAAc,oBAAoB;AAAA,EAC1F;AACA,MAAI,OAAO,eAAe;AACxB,YAAQ,IAAI,oBAAoB,OAAO,cAAc,IAAI,EAAE;AAC3D,YAAQ,IAAI,oBAAoB,OAAO,cAAc,WAAW,EAAE;AAAA,EACpE;AACA,aAAW,KAAK,OAAO,UAAU;AAC/B,YAAQ,IAAI,aAAQ,CAAC,EAAE;AAAA,EACzB;AACA,UAAQ,IAAI,EAAE;AAChB;AAEA,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,QAAiB;AAClD,UAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC9D,UAAQ,WAAW;AACrB,CAAC;","names":["sep"]}
|
package/dist/index.cjs
CHANGED
|
@@ -476,7 +476,7 @@ async function install(opts = {}) {
|
|
|
476
476
|
const pkgPath = (0, import_node_path2.join)(nodeRoot, "package.json");
|
|
477
477
|
const pkg = JSON.parse((0, import_node_fs3.readFileSync)(pkgPath, "utf8"));
|
|
478
478
|
const projectName = opts.projectName ?? pkg.name ?? nodeRoot.split("/").pop() ?? "unnamed";
|
|
479
|
-
const
|
|
479
|
+
const kind = detectJsProjectKind(pkg, nodeRoot);
|
|
480
480
|
const projectsJsonPath = (0, import_node_path2.join)(home, ".gg", "projects.json");
|
|
481
481
|
const envFilePath = (0, import_node_path2.join)(nodeRoot, ".env");
|
|
482
482
|
const existing = findMappingByPath(projectsJsonPath, nodeRoot);
|
|
@@ -491,26 +491,31 @@ async function install(opts = {}) {
|
|
|
491
491
|
}
|
|
492
492
|
const pm = detectPackageManager(nodeRoot);
|
|
493
493
|
const packageInstalled = opts.skipPackageInstall ? false : runInstall(nodeRoot, pm, "@kenkaiiii/gg-pixel");
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
494
|
+
const wired = wireFramework({
|
|
495
|
+
kind,
|
|
496
|
+
projectRoot: nodeRoot,
|
|
497
|
+
pkg,
|
|
498
|
+
projectKey: created.key,
|
|
499
|
+
ingestUrl
|
|
500
|
+
});
|
|
501
|
+
if (kind !== "browser" && kind !== "tauri") {
|
|
498
502
|
writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
|
|
499
503
|
}
|
|
500
504
|
writeProjectsMapping(projectsJsonPath, created.id, projectName, nodeRoot);
|
|
501
|
-
const entryWiring = wireEntryFile(nodeRoot, initFilePath, pkg);
|
|
502
505
|
return {
|
|
503
506
|
projectId: created.id,
|
|
504
507
|
projectKey: created.key,
|
|
505
508
|
projectName,
|
|
506
|
-
projectKind:
|
|
507
|
-
initFilePath,
|
|
509
|
+
projectKind: kind,
|
|
510
|
+
initFilePath: wired.primaryInitPath,
|
|
508
511
|
envFilePath,
|
|
509
512
|
projectsJsonPath,
|
|
510
513
|
packageManager: pm,
|
|
511
514
|
packageInstalled,
|
|
512
|
-
entryWiring,
|
|
513
|
-
reused
|
|
515
|
+
entryWiring: wired.entryWiring,
|
|
516
|
+
reused,
|
|
517
|
+
secondaryInit: wired.secondaryInit,
|
|
518
|
+
warnings: wired.warnings
|
|
514
519
|
};
|
|
515
520
|
}
|
|
516
521
|
function findMappingByPath(projectsJsonPath, projectRoot) {
|
|
@@ -700,6 +705,349 @@ function isCommonJsEntry(entryPath, pkg) {
|
|
|
700
705
|
if (entryPath.endsWith(".ts") || entryPath.endsWith(".tsx")) return false;
|
|
701
706
|
return pkg.type !== "module";
|
|
702
707
|
}
|
|
708
|
+
function detectJsProjectKind(pkg, projectRoot) {
|
|
709
|
+
const all = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
710
|
+
if ("electron" in all) return "electron";
|
|
711
|
+
if ((0, import_node_fs3.existsSync)((0, import_node_path2.join)(projectRoot, "src-tauri")) || "@tauri-apps/api" in all) return "tauri";
|
|
712
|
+
if ("react-native" in all) return "react-native";
|
|
713
|
+
if ("next" in all) return "nextjs";
|
|
714
|
+
if ("@sveltejs/kit" in all) return "sveltekit";
|
|
715
|
+
if ("nuxt" in all || "nuxt3" in all) return "nuxt";
|
|
716
|
+
if ("@remix-run/react" in all || "@remix-run/node" in all) return "remix";
|
|
717
|
+
if (isBrowserProject(pkg, projectRoot)) return "browser";
|
|
718
|
+
return "node";
|
|
719
|
+
}
|
|
720
|
+
function wireFramework(w) {
|
|
721
|
+
switch (w.kind) {
|
|
722
|
+
case "node":
|
|
723
|
+
return wireNode(w);
|
|
724
|
+
case "browser":
|
|
725
|
+
return wireBrowser(w);
|
|
726
|
+
case "nextjs":
|
|
727
|
+
return wireNextjs(w);
|
|
728
|
+
case "sveltekit":
|
|
729
|
+
return wireSveltekit(w);
|
|
730
|
+
case "nuxt":
|
|
731
|
+
return wireNuxt(w);
|
|
732
|
+
case "remix":
|
|
733
|
+
return wireRemix(w);
|
|
734
|
+
case "electron":
|
|
735
|
+
return wireElectron(w);
|
|
736
|
+
case "tauri":
|
|
737
|
+
return wireTauri(w);
|
|
738
|
+
case "react-native":
|
|
739
|
+
return wireReactNative(w);
|
|
740
|
+
case "python":
|
|
741
|
+
throw new Error("Internal: python should have been handled earlier");
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
function wireNode({ projectRoot, pkg, ingestUrl }) {
|
|
745
|
+
const initPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.init.mjs");
|
|
746
|
+
(0, import_node_fs3.writeFileSync)(initPath, renderInitFile(ingestUrl), "utf8");
|
|
747
|
+
return {
|
|
748
|
+
primaryInitPath: initPath,
|
|
749
|
+
entryWiring: wireEntryFile(projectRoot, initPath, pkg),
|
|
750
|
+
warnings: []
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
function wireBrowser({ projectRoot, pkg, projectKey, ingestUrl }) {
|
|
754
|
+
const initPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.init.mjs");
|
|
755
|
+
(0, import_node_fs3.writeFileSync)(initPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|
|
756
|
+
return {
|
|
757
|
+
primaryInitPath: initPath,
|
|
758
|
+
entryWiring: wireEntryFile(projectRoot, initPath, pkg),
|
|
759
|
+
warnings: []
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
function wireNextjs({ projectRoot, projectKey, ingestUrl }) {
|
|
763
|
+
const warnings = [];
|
|
764
|
+
const serverInitPath = pickPath(projectRoot, ["instrumentation.ts", "instrumentation.js"]);
|
|
765
|
+
const finalServerPath = serverInitPath ?? (0, import_node_path2.join)(projectRoot, "instrumentation.ts");
|
|
766
|
+
writeNextInstrumentation(finalServerPath, ingestUrl);
|
|
767
|
+
const clientInitPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.client.mjs");
|
|
768
|
+
(0, import_node_fs3.writeFileSync)(clientInitPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|
|
769
|
+
const layoutPath = findNextLayout(projectRoot);
|
|
770
|
+
let entryWiring;
|
|
771
|
+
if (!layoutPath) {
|
|
772
|
+
warnings.push(
|
|
773
|
+
'Could not auto-wire the Next.js client init \u2014 no app/layout.{tsx,jsx} or pages/_app.{tsx,jsx} found. Add `import "./gg-pixel.client.mjs";` to your root layout/_app.'
|
|
774
|
+
);
|
|
775
|
+
entryWiring = { kind: "no_entry_found" };
|
|
776
|
+
} else {
|
|
777
|
+
entryWiring = injectImport(layoutPath, clientInitPath);
|
|
778
|
+
}
|
|
779
|
+
return {
|
|
780
|
+
primaryInitPath: clientInitPath,
|
|
781
|
+
entryWiring,
|
|
782
|
+
secondaryInit: {
|
|
783
|
+
path: finalServerPath,
|
|
784
|
+
description: "Next.js server instrumentation (auto-loaded by Next runtime)"
|
|
785
|
+
},
|
|
786
|
+
warnings
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
function writeNextInstrumentation(path, ingestUrl) {
|
|
790
|
+
const existing = (0, import_node_fs3.existsSync)(path) ? (0, import_node_fs3.readFileSync)(path, "utf8") : "";
|
|
791
|
+
if (existing.includes("@kenkaiiii/gg-pixel")) return;
|
|
792
|
+
const newContent = existing ? existing + "\n" + nextInstrumentationAppend(ingestUrl) : nextInstrumentationStandalone(ingestUrl);
|
|
793
|
+
(0, import_node_fs3.writeFileSync)(path, newContent, "utf8");
|
|
794
|
+
}
|
|
795
|
+
function nextInstrumentationStandalone(ingestUrl) {
|
|
796
|
+
return `// Next.js auto-loads this file on server start. Pixel hooks the
|
|
797
|
+
// uncaughtExceptionMonitor + unhandledRejection events for API routes,
|
|
798
|
+
// Server Components, and route handlers.
|
|
799
|
+
export async function register() {
|
|
800
|
+
if (process.env.NEXT_RUNTIME === "nodejs") {
|
|
801
|
+
const { initPixel } = await import("@kenkaiiii/gg-pixel");
|
|
802
|
+
initPixel({
|
|
803
|
+
projectKey: process.env.GG_PIXEL_KEY ?? "",
|
|
804
|
+
sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
`;
|
|
809
|
+
}
|
|
810
|
+
function nextInstrumentationAppend(ingestUrl) {
|
|
811
|
+
return `// gg-pixel: server-side error tracking
|
|
812
|
+
import { initPixel } from "@kenkaiiii/gg-pixel";
|
|
813
|
+
if (typeof process !== "undefined" && process.env.NEXT_RUNTIME === "nodejs") {
|
|
814
|
+
initPixel({
|
|
815
|
+
projectKey: process.env.GG_PIXEL_KEY ?? "",
|
|
816
|
+
sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
`;
|
|
820
|
+
}
|
|
821
|
+
function findNextLayout(projectRoot) {
|
|
822
|
+
const candidates = [
|
|
823
|
+
"app/layout.tsx",
|
|
824
|
+
"app/layout.jsx",
|
|
825
|
+
"app/layout.ts",
|
|
826
|
+
"src/app/layout.tsx",
|
|
827
|
+
"src/app/layout.jsx",
|
|
828
|
+
"pages/_app.tsx",
|
|
829
|
+
"pages/_app.jsx",
|
|
830
|
+
"src/pages/_app.tsx",
|
|
831
|
+
"src/pages/_app.jsx"
|
|
832
|
+
];
|
|
833
|
+
for (const c of candidates) {
|
|
834
|
+
const p = (0, import_node_path2.join)(projectRoot, c);
|
|
835
|
+
if ((0, import_node_fs3.existsSync)(p)) return p;
|
|
836
|
+
}
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
function wireSveltekit({ projectRoot, projectKey, ingestUrl }) {
|
|
840
|
+
const serverPath = (0, import_node_path2.join)(projectRoot, "src/hooks.server.ts");
|
|
841
|
+
const clientPath = (0, import_node_path2.join)(projectRoot, "src/hooks.client.ts");
|
|
842
|
+
if (!(0, import_node_fs3.existsSync)((0, import_node_path2.dirname)(serverPath))) (0, import_node_fs3.mkdirSync)((0, import_node_path2.dirname)(serverPath), { recursive: true });
|
|
843
|
+
appendOrCreate(
|
|
844
|
+
serverPath,
|
|
845
|
+
`import { initPixel } from "@kenkaiiii/gg-pixel";
|
|
846
|
+
initPixel({
|
|
847
|
+
projectKey: process.env.GG_PIXEL_KEY ?? "",
|
|
848
|
+
sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
|
|
849
|
+
});
|
|
850
|
+
`,
|
|
851
|
+
"@kenkaiiii/gg-pixel"
|
|
852
|
+
);
|
|
853
|
+
appendOrCreate(
|
|
854
|
+
clientPath,
|
|
855
|
+
`import { initPixel } from "@kenkaiiii/gg-pixel/browser";
|
|
856
|
+
initPixel({
|
|
857
|
+
projectKey: ${JSON.stringify(projectKey)},
|
|
858
|
+
ingestUrl: ${JSON.stringify(ingestUrl)},
|
|
859
|
+
});
|
|
860
|
+
`,
|
|
861
|
+
"@kenkaiiii/gg-pixel/browser"
|
|
862
|
+
);
|
|
863
|
+
return {
|
|
864
|
+
primaryInitPath: clientPath,
|
|
865
|
+
entryWiring: { kind: "injected", entryPath: clientPath },
|
|
866
|
+
secondaryInit: {
|
|
867
|
+
path: serverPath,
|
|
868
|
+
description: "SvelteKit server hooks (auto-loaded)"
|
|
869
|
+
},
|
|
870
|
+
warnings: []
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
function wireNuxt({ projectRoot, projectKey, ingestUrl }) {
|
|
874
|
+
const pluginsDir = (0, import_node_path2.join)(projectRoot, "plugins");
|
|
875
|
+
(0, import_node_fs3.mkdirSync)(pluginsDir, { recursive: true });
|
|
876
|
+
const serverPath = (0, import_node_path2.join)(pluginsDir, "gg-pixel.server.ts");
|
|
877
|
+
const clientPath = (0, import_node_path2.join)(pluginsDir, "gg-pixel.client.ts");
|
|
878
|
+
(0, import_node_fs3.writeFileSync)(
|
|
879
|
+
serverPath,
|
|
880
|
+
`import { initPixel } from "@kenkaiiii/gg-pixel";
|
|
881
|
+
export default defineNuxtPlugin(() => {
|
|
882
|
+
initPixel({
|
|
883
|
+
projectKey: process.env.GG_PIXEL_KEY ?? "",
|
|
884
|
+
sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
|
|
885
|
+
});
|
|
886
|
+
});
|
|
887
|
+
`,
|
|
888
|
+
"utf8"
|
|
889
|
+
);
|
|
890
|
+
(0, import_node_fs3.writeFileSync)(
|
|
891
|
+
clientPath,
|
|
892
|
+
`import { initPixel } from "@kenkaiiii/gg-pixel/browser";
|
|
893
|
+
export default defineNuxtPlugin(() => {
|
|
894
|
+
initPixel({
|
|
895
|
+
projectKey: ${JSON.stringify(projectKey)},
|
|
896
|
+
ingestUrl: ${JSON.stringify(ingestUrl)},
|
|
897
|
+
});
|
|
898
|
+
});
|
|
899
|
+
`,
|
|
900
|
+
"utf8"
|
|
901
|
+
);
|
|
902
|
+
return {
|
|
903
|
+
primaryInitPath: clientPath,
|
|
904
|
+
entryWiring: { kind: "injected", entryPath: clientPath },
|
|
905
|
+
secondaryInit: { path: serverPath, description: "Nuxt server plugin (auto-loaded)" },
|
|
906
|
+
warnings: []
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
function wireRemix({ projectRoot, projectKey, ingestUrl }) {
|
|
910
|
+
const serverPath = pickPath(projectRoot, ["app/entry.server.tsx", "app/entry.server.jsx"]);
|
|
911
|
+
const clientPath = pickPath(projectRoot, ["app/entry.client.tsx", "app/entry.client.jsx"]);
|
|
912
|
+
const warnings = [];
|
|
913
|
+
const clientInitPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.client.mjs");
|
|
914
|
+
(0, import_node_fs3.writeFileSync)(clientInitPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|
|
915
|
+
if (clientPath) {
|
|
916
|
+
injectImport(clientPath, clientInitPath);
|
|
917
|
+
} else {
|
|
918
|
+
warnings.push(
|
|
919
|
+
"No app/entry.client.tsx found. Run `npx remix reveal` then re-run pixel install."
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
const serverInitPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.server.mjs");
|
|
923
|
+
(0, import_node_fs3.writeFileSync)(serverInitPath, renderInitFile(ingestUrl), "utf8");
|
|
924
|
+
let serverEntry = { kind: "no_entry_found" };
|
|
925
|
+
if (serverPath) {
|
|
926
|
+
serverEntry = injectImport(serverPath, serverInitPath);
|
|
927
|
+
} else {
|
|
928
|
+
warnings.push(
|
|
929
|
+
"No app/entry.server.tsx found. Run `npx remix reveal` then re-run pixel install."
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
void serverEntry;
|
|
933
|
+
return {
|
|
934
|
+
primaryInitPath: clientInitPath,
|
|
935
|
+
entryWiring: clientPath ? { kind: "injected", entryPath: clientPath } : { kind: "no_entry_found" },
|
|
936
|
+
secondaryInit: { path: serverInitPath, description: "Remix server init" },
|
|
937
|
+
warnings
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
|
|
941
|
+
const mainInitPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.main.mjs");
|
|
942
|
+
(0, import_node_fs3.writeFileSync)(mainInitPath, renderInitFile(ingestUrl), "utf8");
|
|
943
|
+
const rendererInitPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.renderer.mjs");
|
|
944
|
+
(0, import_node_fs3.writeFileSync)(rendererInitPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|
|
945
|
+
const mainEntry = pkg.main ? (0, import_node_path2.join)(projectRoot, pkg.main) : pickPath(projectRoot, [
|
|
946
|
+
"main.js",
|
|
947
|
+
"main.ts",
|
|
948
|
+
"src/main.js",
|
|
949
|
+
"src/main.ts",
|
|
950
|
+
"electron/main.js",
|
|
951
|
+
"electron/main.ts"
|
|
952
|
+
]);
|
|
953
|
+
let mainWiring = { kind: "no_entry_found" };
|
|
954
|
+
if (mainEntry && (0, import_node_fs3.existsSync)(mainEntry)) {
|
|
955
|
+
mainWiring = injectImport(mainEntry, mainInitPath);
|
|
956
|
+
}
|
|
957
|
+
const rendererEntry = pickPath(projectRoot, [
|
|
958
|
+
"src/renderer/index.ts",
|
|
959
|
+
"src/renderer/index.tsx",
|
|
960
|
+
"src/renderer/main.ts",
|
|
961
|
+
"src/renderer/main.tsx",
|
|
962
|
+
"renderer/index.ts",
|
|
963
|
+
"renderer/index.tsx",
|
|
964
|
+
"renderer.ts",
|
|
965
|
+
"renderer.tsx",
|
|
966
|
+
"src/index.tsx",
|
|
967
|
+
"src/main.tsx"
|
|
968
|
+
]);
|
|
969
|
+
if (rendererEntry) {
|
|
970
|
+
injectImport(rendererEntry, rendererInitPath);
|
|
971
|
+
}
|
|
972
|
+
const warnings = [];
|
|
973
|
+
if (!rendererEntry) {
|
|
974
|
+
warnings.push(
|
|
975
|
+
'Could not auto-detect the Electron renderer entry. Add `import "./gg-pixel.renderer.mjs";` to the top of your renderer entry file.'
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
return {
|
|
979
|
+
primaryInitPath: rendererInitPath,
|
|
980
|
+
entryWiring: rendererEntry ? { kind: "injected", entryPath: rendererEntry } : { kind: "no_entry_found" },
|
|
981
|
+
secondaryInit: {
|
|
982
|
+
path: mainInitPath,
|
|
983
|
+
description: "Electron main-process init" + (mainWiring.kind === "injected" ? ` (wired into ${mainEntry})` : "")
|
|
984
|
+
},
|
|
985
|
+
warnings
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
function wireTauri({ projectRoot, pkg, projectKey, ingestUrl }) {
|
|
989
|
+
const initPath = (0, import_node_path2.join)(projectRoot, "gg-pixel.init.mjs");
|
|
990
|
+
(0, import_node_fs3.writeFileSync)(initPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
|
|
991
|
+
const entryWiring = wireEntryFile(projectRoot, initPath, pkg);
|
|
992
|
+
return {
|
|
993
|
+
primaryInitPath: initPath,
|
|
994
|
+
entryWiring,
|
|
995
|
+
warnings: [
|
|
996
|
+
"Tauri Rust backend is not instrumented \u2014 no Rust SDK exists yet. Frontend errors are captured."
|
|
997
|
+
]
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
function wireReactNative({ projectRoot }) {
|
|
1001
|
+
return {
|
|
1002
|
+
primaryInitPath: (0, import_node_path2.join)(projectRoot, "(not-installed)"),
|
|
1003
|
+
entryWiring: { kind: "skipped", reason: "react-native SDK not built yet" },
|
|
1004
|
+
warnings: [
|
|
1005
|
+
"React Native is not yet supported \u2014 its JS runtime is neither browser nor Node.",
|
|
1006
|
+
"A dedicated React Native SDK will be a future slice."
|
|
1007
|
+
]
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function pickPath(root, candidates) {
|
|
1011
|
+
for (const c of candidates) {
|
|
1012
|
+
const p = (0, import_node_path2.join)(root, c);
|
|
1013
|
+
if ((0, import_node_fs3.existsSync)(p)) return p;
|
|
1014
|
+
}
|
|
1015
|
+
return null;
|
|
1016
|
+
}
|
|
1017
|
+
function appendOrCreate(filePath, snippet, marker) {
|
|
1018
|
+
if ((0, import_node_fs3.existsSync)(filePath)) {
|
|
1019
|
+
const existing = (0, import_node_fs3.readFileSync)(filePath, "utf8");
|
|
1020
|
+
if (existing.includes(marker)) return;
|
|
1021
|
+
(0, import_node_fs3.writeFileSync)(filePath, existing + "\n" + snippet, "utf8");
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
(0, import_node_fs3.writeFileSync)(filePath, snippet, "utf8");
|
|
1025
|
+
}
|
|
1026
|
+
function injectImport(entryPath, initFilePath) {
|
|
1027
|
+
let content;
|
|
1028
|
+
try {
|
|
1029
|
+
content = (0, import_node_fs3.readFileSync)(entryPath, "utf8");
|
|
1030
|
+
} catch (err) {
|
|
1031
|
+
return { kind: "skipped", reason: `unreadable: ${err.message}` };
|
|
1032
|
+
}
|
|
1033
|
+
const initBasename = initFilePath.split(import_node_path2.sep).pop() ?? "gg-pixel.init.mjs";
|
|
1034
|
+
if (content.includes(initBasename) || content.includes("@kenkaiiii/gg-pixel")) {
|
|
1035
|
+
return { kind: "already_present", entryPath };
|
|
1036
|
+
}
|
|
1037
|
+
const fromDir = (0, import_node_path2.dirname)(entryPath);
|
|
1038
|
+
let spec = (0, import_node_path2.relative)(fromDir, initFilePath).split(import_node_path2.sep).join("/");
|
|
1039
|
+
if (!spec.startsWith(".")) spec = "./" + spec;
|
|
1040
|
+
const importLine = `import ${JSON.stringify(spec)};`;
|
|
1041
|
+
const lines = content.split("\n");
|
|
1042
|
+
let insertAt = 0;
|
|
1043
|
+
if (lines[0]?.startsWith("#!")) insertAt = 1;
|
|
1044
|
+
while (insertAt < lines.length && /^\s*(?:["']use strict["']|\/\/|\/\*)/.test(lines[insertAt] ?? "")) {
|
|
1045
|
+
insertAt++;
|
|
1046
|
+
}
|
|
1047
|
+
const updated = [...lines.slice(0, insertAt), importLine, ...lines.slice(insertAt)].join("\n");
|
|
1048
|
+
(0, import_node_fs3.writeFileSync)(entryPath, updated, "utf8");
|
|
1049
|
+
return { kind: "injected", entryPath };
|
|
1050
|
+
}
|
|
703
1051
|
function isBrowserProject(pkg, projectRoot) {
|
|
704
1052
|
const all = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
705
1053
|
const browserishDeps = [
|
|
@@ -792,7 +1140,8 @@ async function installPython(ctx) {
|
|
|
792
1140
|
packageManager: pm,
|
|
793
1141
|
packageInstalled,
|
|
794
1142
|
entryWiring,
|
|
795
|
-
reused
|
|
1143
|
+
reused,
|
|
1144
|
+
warnings: []
|
|
796
1145
|
};
|
|
797
1146
|
}
|
|
798
1147
|
function readPyprojectName(projectRoot) {
|