@kenkaiiii/gg-pixel 4.3.84 → 4.3.86

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/index.d.ts CHANGED
@@ -74,6 +74,12 @@ interface InstallOptions {
74
74
  interface InstallResult {
75
75
  projectId: string;
76
76
  projectKey: string;
77
+ /**
78
+ * Per-project bearer secret returned by the server on creation. Stored in
79
+ * ~/.gg/projects.json and required for every /api/* call (read/list/patch/
80
+ * delete). Never leaves the user's machine — never inlined into source.
81
+ */
82
+ projectSecret: string;
77
83
  projectName: string;
78
84
  projectKind: ProjectKind;
79
85
  initFilePath: string;
package/dist/index.js CHANGED
@@ -457,8 +457,8 @@ async function install(opts = {}) {
457
457
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
458
458
  let created;
459
459
  let reused = false;
460
- if (existing && existingKey) {
461
- created = { id: existing.id, key: existingKey };
460
+ if (existing && existing.secret && existingKey) {
461
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
462
462
  reused = true;
463
463
  } else {
464
464
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -475,10 +475,11 @@ async function install(opts = {}) {
475
475
  if (kind !== "browser" && kind !== "tauri") {
476
476
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
477
477
  }
478
- writeProjectsMapping(projectsJsonPath, created.id, projectName, nodeRoot);
478
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, nodeRoot, created.secret);
479
479
  return {
480
480
  projectId: created.id,
481
481
  projectKey: created.key,
482
+ projectSecret: created.secret,
482
483
  projectName,
483
484
  projectKind: kind,
484
485
  initFilePath: wired.primaryInitPath,
@@ -535,8 +536,10 @@ async function createProject(fetchFn, ingestUrl, name) {
535
536
  throw new Error(`POST /api/projects failed: ${res.status} ${await safeText(res)}`);
536
537
  }
537
538
  const body = await res.json();
538
- if (!body.id || !body.key) throw new Error("response missing id/key");
539
- return { id: body.id, key: body.key };
539
+ if (!body.id || !body.key || !body.secret) {
540
+ throw new Error("response missing id/key/secret");
541
+ }
542
+ return { id: body.id, key: body.key, secret: body.secret };
540
543
  }
541
544
  async function safeText(r) {
542
545
  try {
@@ -784,11 +787,11 @@ function wireNextjs({ projectRoot, projectKey, ingestUrl }) {
784
787
  }
785
788
  function writeNextInstrumentation(path, ingestUrl, projectKey) {
786
789
  const existing = existsSync2(path) ? readFileSync2(path, "utf8") : "";
787
- if (existing.includes("@kenkaiiii/gg-pixel")) return;
788
- const newContent = existing ? existing + "\n" + nextInstrumentationAppend(ingestUrl, projectKey) : nextInstrumentationStandalone(ingestUrl, projectKey);
789
- writeFileSync(path, newContent, "utf8");
790
+ const block = nextInstrumentationBlock(ingestUrl, projectKey);
791
+ const next = upsertPixelBlock(existing, block);
792
+ if (next !== existing) writeFileSync(path, next, "utf8");
790
793
  }
791
- function nextInstrumentationStandalone(ingestUrl, projectKey) {
794
+ function nextInstrumentationBlock(ingestUrl, projectKey) {
792
795
  const fallback = projectKey ? ` ?? ${JSON.stringify(projectKey)}` : "";
793
796
  return `// Next.js auto-loads this file on server start. Pixel hooks the
794
797
  // uncaughtExceptionMonitor + unhandledRejection events for API routes,
@@ -801,20 +804,7 @@ export async function register() {
801
804
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
802
805
  });
803
806
  }
804
- }
805
- `;
806
- }
807
- function nextInstrumentationAppend(ingestUrl, projectKey) {
808
- const fallback = projectKey ? ` ?? ${JSON.stringify(projectKey)}` : "";
809
- return `// gg-pixel: server-side error tracking
810
- import { initPixel } from "@kenkaiiii/gg-pixel";
811
- if (typeof process !== "undefined" && process.env.NEXT_RUNTIME === "nodejs") {
812
- initPixel({
813
- projectKey: process.env.GG_PIXEL_KEY${fallback},
814
- sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
815
- });
816
- }
817
- `;
807
+ }`;
818
808
  }
819
809
  function findNextLayout(projectRoot) {
820
810
  const candidates = [
@@ -947,25 +937,21 @@ function wireSveltekit({ projectRoot, projectKey, ingestUrl }) {
947
937
  const serverPath = join2(projectRoot, "src/hooks.server.ts");
948
938
  const clientPath = join2(projectRoot, "src/hooks.client.ts");
949
939
  if (!existsSync2(dirname2(serverPath))) mkdirSync2(dirname2(serverPath), { recursive: true });
950
- appendOrCreate(
940
+ upsertPixelBlockInFile(
951
941
  serverPath,
952
942
  `import { initPixel } from "@kenkaiiii/gg-pixel";
953
943
  initPixel({
954
944
  projectKey: process.env.GG_PIXEL_KEY ?? ${JSON.stringify(projectKey)},
955
945
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
956
- });
957
- `,
958
- "@kenkaiiii/gg-pixel"
946
+ });`
959
947
  );
960
- appendOrCreate(
948
+ upsertPixelBlockInFile(
961
949
  clientPath,
962
950
  `import { initPixel } from "@kenkaiiii/gg-pixel/browser";
963
951
  initPixel({
964
952
  projectKey: ${JSON.stringify(projectKey)},
965
953
  ingestUrl: ${JSON.stringify(ingestUrl)},
966
- });
967
- `,
968
- "@kenkaiiii/gg-pixel/browser"
954
+ });`
969
955
  );
970
956
  return {
971
957
  primaryInitPath: clientPath,
@@ -1307,14 +1293,33 @@ function pickPath(root, candidates) {
1307
1293
  }
1308
1294
  return null;
1309
1295
  }
1310
- function appendOrCreate(filePath, snippet, marker) {
1311
- if (existsSync2(filePath)) {
1312
- const existing = readFileSync2(filePath, "utf8");
1313
- if (existing.includes(marker)) return;
1314
- writeFileSync(filePath, existing + "\n" + snippet, "utf8");
1315
- return;
1296
+ var PIXEL_MARK_BEGIN = "// >>> gg-pixel auto-generated \u2014 do not edit between these markers <<<";
1297
+ var PIXEL_MARK_END = "// >>> /gg-pixel <<<";
1298
+ function wrapPixelBlock(content) {
1299
+ return `${PIXEL_MARK_BEGIN}
1300
+ ${content.replace(/\s+$/, "")}
1301
+ ${PIXEL_MARK_END}
1302
+ `;
1303
+ }
1304
+ function upsertPixelBlock(existing, block) {
1305
+ const wrapped = wrapPixelBlock(block);
1306
+ const beginIdx = existing.indexOf(PIXEL_MARK_BEGIN);
1307
+ if (beginIdx !== -1) {
1308
+ const endIdx = existing.indexOf(PIXEL_MARK_END, beginIdx);
1309
+ if (endIdx !== -1) {
1310
+ const after = endIdx + PIXEL_MARK_END.length;
1311
+ const trailNL = existing[after] === "\n" ? 1 : 0;
1312
+ return existing.slice(0, beginIdx) + wrapped + existing.slice(after + trailNL);
1313
+ }
1316
1314
  }
1317
- writeFileSync(filePath, snippet, "utf8");
1315
+ if (existing.length === 0) return wrapped;
1316
+ const sep2 = existing.endsWith("\n") ? "" : "\n";
1317
+ return existing + sep2 + "\n" + wrapped;
1318
+ }
1319
+ function upsertPixelBlockInFile(filePath, block) {
1320
+ const existing = existsSync2(filePath) ? readFileSync2(filePath, "utf8") : "";
1321
+ const next = upsertPixelBlock(existing, block);
1322
+ if (next !== existing) writeFileSync(filePath, next, "utf8");
1318
1323
  }
1319
1324
  function injectImport(entryPath, initFilePath) {
1320
1325
  let content;
@@ -1442,8 +1447,8 @@ async function installGo(ctx) {
1442
1447
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
1443
1448
  let created;
1444
1449
  let reused = false;
1445
- if (existing && existingKey) {
1446
- created = { id: existing.id, key: existingKey };
1450
+ if (existing && existing.secret && existingKey) {
1451
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
1447
1452
  reused = true;
1448
1453
  } else {
1449
1454
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -1471,10 +1476,11 @@ func init() {
1471
1476
  "utf8"
1472
1477
  );
1473
1478
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
1474
- writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
1479
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot, created.secret);
1475
1480
  return {
1476
1481
  projectId: created.id,
1477
1482
  projectKey: created.key,
1483
+ projectSecret: created.secret,
1478
1484
  projectName,
1479
1485
  projectKind: "go",
1480
1486
  initFilePath,
@@ -1515,8 +1521,8 @@ async function installRuby(ctx) {
1515
1521
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
1516
1522
  let created;
1517
1523
  let reused = false;
1518
- if (existing && existingKey) {
1519
- created = { id: existing.id, key: existingKey };
1524
+ if (existing && existing.secret && existingKey) {
1525
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
1520
1526
  reused = true;
1521
1527
  } else {
1522
1528
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -1535,10 +1541,11 @@ GGPixel.init(
1535
1541
  "utf8"
1536
1542
  );
1537
1543
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
1538
- writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
1544
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot, created.secret);
1539
1545
  return {
1540
1546
  projectId: created.id,
1541
1547
  projectKey: created.key,
1548
+ projectSecret: created.secret,
1542
1549
  projectName,
1543
1550
  projectKind: "ruby",
1544
1551
  initFilePath,
@@ -1591,8 +1598,8 @@ async function installPython(ctx) {
1591
1598
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
1592
1599
  let created;
1593
1600
  let reused = false;
1594
- if (existing && existingKey) {
1595
- created = { id: existing.id, key: existingKey };
1601
+ if (existing && existing.secret && existingKey) {
1602
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
1596
1603
  reused = true;
1597
1604
  } else {
1598
1605
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -1602,11 +1609,12 @@ async function installPython(ctx) {
1602
1609
  const initFilePath = join2(projectRoot, "gg_pixel_init.py");
1603
1610
  writeFileSync(initFilePath, renderPythonInitFile(ingestUrl, created.key), "utf8");
1604
1611
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
1605
- writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
1612
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot, created.secret);
1606
1613
  const entryWiring = wirePythonEntry(projectRoot, initFilePath);
1607
1614
  return {
1608
1615
  projectId: created.id,
1609
1616
  projectKey: created.key,
1617
+ projectSecret: created.secret,
1610
1618
  projectName,
1611
1619
  projectKind: "python",
1612
1620
  initFilePath,
@@ -1724,7 +1732,7 @@ function findPythonEntryFile(projectRoot) {
1724
1732
  }
1725
1733
  return null;
1726
1734
  }
1727
- function writeProjectsMapping(projectsJsonPath, projectId, name, path) {
1735
+ function writeProjectsMapping(projectsJsonPath, projectId, name, path, secret) {
1728
1736
  mkdirSync2(dirname2(projectsJsonPath), { recursive: true });
1729
1737
  let map = {};
1730
1738
  if (existsSync2(projectsJsonPath)) {
@@ -1733,7 +1741,9 @@ function writeProjectsMapping(projectsJsonPath, projectId, name, path) {
1733
1741
  } catch {
1734
1742
  }
1735
1743
  }
1736
- map[projectId] = { name, path };
1744
+ const entry = { name, path };
1745
+ if (secret) entry.secret = secret;
1746
+ map[projectId] = entry;
1737
1747
  writeFileSync(projectsJsonPath, `${JSON.stringify(map, null, 2)}
1738
1748
  `, "utf8");
1739
1749
  }