@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/cli.js CHANGED
@@ -50,8 +50,8 @@ async function install(opts = {}) {
50
50
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
51
51
  let created;
52
52
  let reused = false;
53
- if (existing && existingKey) {
54
- created = { id: existing.id, key: existingKey };
53
+ if (existing && existing.secret && existingKey) {
54
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
55
55
  reused = true;
56
56
  } else {
57
57
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -68,10 +68,11 @@ async function install(opts = {}) {
68
68
  if (kind !== "browser" && kind !== "tauri") {
69
69
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
70
70
  }
71
- writeProjectsMapping(projectsJsonPath, created.id, projectName, nodeRoot);
71
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, nodeRoot, created.secret);
72
72
  return {
73
73
  projectId: created.id,
74
74
  projectKey: created.key,
75
+ projectSecret: created.secret,
75
76
  projectName,
76
77
  projectKind: kind,
77
78
  initFilePath: wired.primaryInitPath,
@@ -128,8 +129,10 @@ async function createProject(fetchFn, ingestUrl, name) {
128
129
  throw new Error(`POST /api/projects failed: ${res.status} ${await safeText(res)}`);
129
130
  }
130
131
  const body = await res.json();
131
- if (!body.id || !body.key) throw new Error("response missing id/key");
132
- return { id: body.id, key: body.key };
132
+ if (!body.id || !body.key || !body.secret) {
133
+ throw new Error("response missing id/key/secret");
134
+ }
135
+ return { id: body.id, key: body.key, secret: body.secret };
133
136
  }
134
137
  async function safeText(r) {
135
138
  try {
@@ -377,11 +380,11 @@ function wireNextjs({ projectRoot, projectKey, ingestUrl }) {
377
380
  }
378
381
  function writeNextInstrumentation(path, ingestUrl, projectKey) {
379
382
  const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
380
- if (existing.includes("@kenkaiiii/gg-pixel")) return;
381
- const newContent = existing ? existing + "\n" + nextInstrumentationAppend(ingestUrl, projectKey) : nextInstrumentationStandalone(ingestUrl, projectKey);
382
- writeFileSync(path, newContent, "utf8");
383
+ const block = nextInstrumentationBlock(ingestUrl, projectKey);
384
+ const next = upsertPixelBlock(existing, block);
385
+ if (next !== existing) writeFileSync(path, next, "utf8");
383
386
  }
384
- function nextInstrumentationStandalone(ingestUrl, projectKey) {
387
+ function nextInstrumentationBlock(ingestUrl, projectKey) {
385
388
  const fallback = projectKey ? ` ?? ${JSON.stringify(projectKey)}` : "";
386
389
  return `// Next.js auto-loads this file on server start. Pixel hooks the
387
390
  // uncaughtExceptionMonitor + unhandledRejection events for API routes,
@@ -394,20 +397,7 @@ export async function register() {
394
397
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
395
398
  });
396
399
  }
397
- }
398
- `;
399
- }
400
- function nextInstrumentationAppend(ingestUrl, projectKey) {
401
- const fallback = projectKey ? ` ?? ${JSON.stringify(projectKey)}` : "";
402
- return `// gg-pixel: server-side error tracking
403
- import { initPixel } from "@kenkaiiii/gg-pixel";
404
- if (typeof process !== "undefined" && process.env.NEXT_RUNTIME === "nodejs") {
405
- initPixel({
406
- projectKey: process.env.GG_PIXEL_KEY${fallback},
407
- sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
408
- });
409
- }
410
- `;
400
+ }`;
411
401
  }
412
402
  function findNextLayout(projectRoot) {
413
403
  const candidates = [
@@ -540,25 +530,21 @@ function wireSveltekit({ projectRoot, projectKey, ingestUrl }) {
540
530
  const serverPath = join(projectRoot, "src/hooks.server.ts");
541
531
  const clientPath = join(projectRoot, "src/hooks.client.ts");
542
532
  if (!existsSync(dirname(serverPath))) mkdirSync(dirname(serverPath), { recursive: true });
543
- appendOrCreate(
533
+ upsertPixelBlockInFile(
544
534
  serverPath,
545
535
  `import { initPixel } from "@kenkaiiii/gg-pixel";
546
536
  initPixel({
547
537
  projectKey: process.env.GG_PIXEL_KEY ?? ${JSON.stringify(projectKey)},
548
538
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
549
- });
550
- `,
551
- "@kenkaiiii/gg-pixel"
539
+ });`
552
540
  );
553
- appendOrCreate(
541
+ upsertPixelBlockInFile(
554
542
  clientPath,
555
543
  `import { initPixel } from "@kenkaiiii/gg-pixel/browser";
556
544
  initPixel({
557
545
  projectKey: ${JSON.stringify(projectKey)},
558
546
  ingestUrl: ${JSON.stringify(ingestUrl)},
559
- });
560
- `,
561
- "@kenkaiiii/gg-pixel/browser"
547
+ });`
562
548
  );
563
549
  return {
564
550
  primaryInitPath: clientPath,
@@ -900,14 +886,33 @@ function pickPath(root, candidates) {
900
886
  }
901
887
  return null;
902
888
  }
903
- function appendOrCreate(filePath, snippet, marker) {
904
- if (existsSync(filePath)) {
905
- const existing = readFileSync(filePath, "utf8");
906
- if (existing.includes(marker)) return;
907
- writeFileSync(filePath, existing + "\n" + snippet, "utf8");
908
- return;
889
+ var PIXEL_MARK_BEGIN = "// >>> gg-pixel auto-generated \u2014 do not edit between these markers <<<";
890
+ var PIXEL_MARK_END = "// >>> /gg-pixel <<<";
891
+ function wrapPixelBlock(content) {
892
+ return `${PIXEL_MARK_BEGIN}
893
+ ${content.replace(/\s+$/, "")}
894
+ ${PIXEL_MARK_END}
895
+ `;
896
+ }
897
+ function upsertPixelBlock(existing, block) {
898
+ const wrapped = wrapPixelBlock(block);
899
+ const beginIdx = existing.indexOf(PIXEL_MARK_BEGIN);
900
+ if (beginIdx !== -1) {
901
+ const endIdx = existing.indexOf(PIXEL_MARK_END, beginIdx);
902
+ if (endIdx !== -1) {
903
+ const after = endIdx + PIXEL_MARK_END.length;
904
+ const trailNL = existing[after] === "\n" ? 1 : 0;
905
+ return existing.slice(0, beginIdx) + wrapped + existing.slice(after + trailNL);
906
+ }
909
907
  }
910
- writeFileSync(filePath, snippet, "utf8");
908
+ if (existing.length === 0) return wrapped;
909
+ const sep2 = existing.endsWith("\n") ? "" : "\n";
910
+ return existing + sep2 + "\n" + wrapped;
911
+ }
912
+ function upsertPixelBlockInFile(filePath, block) {
913
+ const existing = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
914
+ const next = upsertPixelBlock(existing, block);
915
+ if (next !== existing) writeFileSync(filePath, next, "utf8");
911
916
  }
912
917
  function injectImport(entryPath, initFilePath) {
913
918
  let content;
@@ -1035,8 +1040,8 @@ async function installGo(ctx) {
1035
1040
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
1036
1041
  let created;
1037
1042
  let reused = false;
1038
- if (existing && existingKey) {
1039
- created = { id: existing.id, key: existingKey };
1043
+ if (existing && existing.secret && existingKey) {
1044
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
1040
1045
  reused = true;
1041
1046
  } else {
1042
1047
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -1064,10 +1069,11 @@ func init() {
1064
1069
  "utf8"
1065
1070
  );
1066
1071
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
1067
- writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
1072
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot, created.secret);
1068
1073
  return {
1069
1074
  projectId: created.id,
1070
1075
  projectKey: created.key,
1076
+ projectSecret: created.secret,
1071
1077
  projectName,
1072
1078
  projectKind: "go",
1073
1079
  initFilePath,
@@ -1108,8 +1114,8 @@ async function installRuby(ctx) {
1108
1114
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
1109
1115
  let created;
1110
1116
  let reused = false;
1111
- if (existing && existingKey) {
1112
- created = { id: existing.id, key: existingKey };
1117
+ if (existing && existing.secret && existingKey) {
1118
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
1113
1119
  reused = true;
1114
1120
  } else {
1115
1121
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -1128,10 +1134,11 @@ GGPixel.init(
1128
1134
  "utf8"
1129
1135
  );
1130
1136
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
1131
- writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
1137
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot, created.secret);
1132
1138
  return {
1133
1139
  projectId: created.id,
1134
1140
  projectKey: created.key,
1141
+ projectSecret: created.secret,
1135
1142
  projectName,
1136
1143
  projectKind: "ruby",
1137
1144
  initFilePath,
@@ -1184,8 +1191,8 @@ async function installPython(ctx) {
1184
1191
  const existingKey = readEnvKey(envFilePath, "GG_PIXEL_KEY");
1185
1192
  let created;
1186
1193
  let reused = false;
1187
- if (existing && existingKey) {
1188
- created = { id: existing.id, key: existingKey };
1194
+ if (existing && existing.secret && existingKey) {
1195
+ created = { id: existing.id, key: existingKey, secret: existing.secret };
1189
1196
  reused = true;
1190
1197
  } else {
1191
1198
  created = await createProject(fetchFn, ingestUrl, projectName);
@@ -1195,11 +1202,12 @@ async function installPython(ctx) {
1195
1202
  const initFilePath = join(projectRoot, "gg_pixel_init.py");
1196
1203
  writeFileSync(initFilePath, renderPythonInitFile(ingestUrl, created.key), "utf8");
1197
1204
  writeEnvKey(envFilePath, "GG_PIXEL_KEY", created.key);
1198
- writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot);
1205
+ writeProjectsMapping(projectsJsonPath, created.id, projectName, projectRoot, created.secret);
1199
1206
  const entryWiring = wirePythonEntry(projectRoot, initFilePath);
1200
1207
  return {
1201
1208
  projectId: created.id,
1202
1209
  projectKey: created.key,
1210
+ projectSecret: created.secret,
1203
1211
  projectName,
1204
1212
  projectKind: "python",
1205
1213
  initFilePath,
@@ -1317,7 +1325,7 @@ function findPythonEntryFile(projectRoot) {
1317
1325
  }
1318
1326
  return null;
1319
1327
  }
1320
- function writeProjectsMapping(projectsJsonPath, projectId, name, path) {
1328
+ function writeProjectsMapping(projectsJsonPath, projectId, name, path, secret) {
1321
1329
  mkdirSync(dirname(projectsJsonPath), { recursive: true });
1322
1330
  let map = {};
1323
1331
  if (existsSync(projectsJsonPath)) {
@@ -1326,7 +1334,9 @@ function writeProjectsMapping(projectsJsonPath, projectId, name, path) {
1326
1334
  } catch {
1327
1335
  }
1328
1336
  }
1329
- map[projectId] = { name, path };
1337
+ const entry = { name, path };
1338
+ if (secret) entry.secret = secret;
1339
+ map[projectId] = entry;
1330
1340
  writeFileSync(projectsJsonPath, `${JSON.stringify(map, null, 2)}
1331
1341
  `, "utf8");
1332
1342
  }