@kenkaiiii/gg-pixel 4.3.79 → 4.3.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -758,7 +758,7 @@ function wireNextjs({ projectRoot, projectKey, ingestUrl }) {
758
758
  const warnings = [];
759
759
  const serverInitPath = pickPath(projectRoot, ["instrumentation.ts", "instrumentation.js"]);
760
760
  const finalServerPath = serverInitPath ?? join2(projectRoot, "instrumentation.ts");
761
- writeNextInstrumentation(finalServerPath, ingestUrl);
761
+ writeNextInstrumentation(finalServerPath, ingestUrl, projectKey);
762
762
  patchNextConfig(projectRoot);
763
763
  const clientInitPath = join2(projectRoot, "gg-pixel.client.tsx");
764
764
  writeFileSync(clientInitPath, renderNextClientComponent(ingestUrl, projectKey), "utf8");
@@ -782,13 +782,14 @@ function wireNextjs({ projectRoot, projectKey, ingestUrl }) {
782
782
  warnings
783
783
  };
784
784
  }
785
- function writeNextInstrumentation(path, ingestUrl) {
785
+ function writeNextInstrumentation(path, ingestUrl, projectKey) {
786
786
  const existing = existsSync2(path) ? readFileSync2(path, "utf8") : "";
787
787
  if (existing.includes("@kenkaiiii/gg-pixel")) return;
788
- const newContent = existing ? existing + "\n" + nextInstrumentationAppend(ingestUrl) : nextInstrumentationStandalone(ingestUrl);
788
+ const newContent = existing ? existing + "\n" + nextInstrumentationAppend(ingestUrl, projectKey) : nextInstrumentationStandalone(ingestUrl, projectKey);
789
789
  writeFileSync(path, newContent, "utf8");
790
790
  }
791
- function nextInstrumentationStandalone(ingestUrl) {
791
+ function nextInstrumentationStandalone(ingestUrl, projectKey) {
792
+ const fallback = projectKey ? ` ?? ${JSON.stringify(projectKey)}` : "";
792
793
  return `// Next.js auto-loads this file on server start. Pixel hooks the
793
794
  // uncaughtExceptionMonitor + unhandledRejection events for API routes,
794
795
  // Server Components, and route handlers.
@@ -796,19 +797,20 @@ export async function register() {
796
797
  if (process.env.NEXT_RUNTIME === "nodejs") {
797
798
  const { initPixel } = await import("@kenkaiiii/gg-pixel");
798
799
  initPixel({
799
- projectKey: process.env.GG_PIXEL_KEY ?? "",
800
+ projectKey: process.env.GG_PIXEL_KEY${fallback},
800
801
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
801
802
  });
802
803
  }
803
804
  }
804
805
  `;
805
806
  }
806
- function nextInstrumentationAppend(ingestUrl) {
807
+ function nextInstrumentationAppend(ingestUrl, projectKey) {
808
+ const fallback = projectKey ? ` ?? ${JSON.stringify(projectKey)}` : "";
807
809
  return `// gg-pixel: server-side error tracking
808
810
  import { initPixel } from "@kenkaiiii/gg-pixel";
809
811
  if (typeof process !== "undefined" && process.env.NEXT_RUNTIME === "nodejs") {
810
812
  initPixel({
811
- projectKey: process.env.GG_PIXEL_KEY ?? "",
813
+ projectKey: process.env.GG_PIXEL_KEY${fallback},
812
814
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
813
815
  });
814
816
  }
@@ -946,7 +948,7 @@ function wireSveltekit({ projectRoot, projectKey, ingestUrl }) {
946
948
  serverPath,
947
949
  `import { initPixel } from "@kenkaiiii/gg-pixel";
948
950
  initPixel({
949
- projectKey: process.env.GG_PIXEL_KEY ?? "",
951
+ projectKey: process.env.GG_PIXEL_KEY ?? ${JSON.stringify(projectKey)},
950
952
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
951
953
  });
952
954
  `,
@@ -982,7 +984,7 @@ function wireNuxt({ projectRoot, projectKey, ingestUrl }) {
982
984
  `import { initPixel } from "@kenkaiiii/gg-pixel";
983
985
  export default defineNuxtPlugin(() => {
984
986
  initPixel({
985
- projectKey: process.env.GG_PIXEL_KEY ?? "",
987
+ projectKey: process.env.GG_PIXEL_KEY ?? ${JSON.stringify(projectKey)},
986
988
  sink: { kind: "http", ingestUrl: ${JSON.stringify(`${ingestUrl}/ingest`)} },
987
989
  });
988
990
  });
@@ -1040,6 +1042,7 @@ function wireRemix({ projectRoot, projectKey, ingestUrl }) {
1040
1042
  };
1041
1043
  }
1042
1044
  function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
1045
+ const warnings = [];
1043
1046
  const isMainEsm = pkg.type === "module";
1044
1047
  const mainInitPath = isMainEsm ? join2(projectRoot, "gg-pixel.main.mjs") : join2(projectRoot, "gg-pixel.main.cjs");
1045
1048
  writeFileSync(
@@ -1047,50 +1050,62 @@ function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
1047
1050
  isMainEsm ? renderInitFile(ingestUrl, projectKey) : renderInitFileCjs(ingestUrl, projectKey),
1048
1051
  "utf8"
1049
1052
  );
1050
- const rendererInitPath = join2(projectRoot, "gg-pixel.renderer.mjs");
1051
- writeFileSync(rendererInitPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
1052
- const mainEntry = pkg.main ? join2(projectRoot, pkg.main) : pickPath(projectRoot, [
1053
- "main.js",
1054
- "main.ts",
1055
- "src/main.js",
1056
- "src/main.ts",
1057
- "electron/main.js",
1058
- "electron/main.ts"
1059
- ]);
1053
+ const mainEntry = resolveMainEntryFromPkg(projectRoot, pkg);
1060
1054
  let mainWiring = { kind: "no_entry_found" };
1061
1055
  if (mainEntry && existsSync2(mainEntry)) {
1062
1056
  mainWiring = injectImport(mainEntry, mainInitPath);
1063
1057
  }
1064
- const rendererEntry = pickPath(projectRoot, [
1065
- "src/renderer/index.ts",
1066
- "src/renderer/index.tsx",
1067
- "src/renderer/index.js",
1068
- "src/renderer/main.ts",
1069
- "src/renderer/main.tsx",
1070
- "src/renderer/main.js",
1071
- "renderer/index.ts",
1072
- "renderer/index.tsx",
1073
- "renderer/index.js",
1074
- "renderer.ts",
1075
- "renderer.tsx",
1076
- "renderer.js",
1077
- "src/index.tsx",
1078
- "src/index.jsx",
1079
- "src/main.tsx",
1080
- "src/main.jsx"
1081
- ]);
1082
- if (rendererEntry) {
1083
- injectImport(rendererEntry, rendererInitPath);
1084
- }
1085
- const warnings = [];
1086
- if (!rendererEntry) {
1087
- warnings.push(
1088
- 'Could not auto-detect the Electron renderer entry. Add `import "./gg-pixel.renderer.mjs";` to the top of your renderer entry file.'
1089
- );
1058
+ const htmlFiles = findRendererHtmlFiles(projectRoot);
1059
+ let rendererInitPath;
1060
+ if (htmlFiles.length > 0) {
1061
+ const rendererDir = dirname2(htmlFiles[0]);
1062
+ rendererInitPath = join2(rendererDir, "gg-pixel.browser.iife.js");
1063
+ if (!copyIifeBundle(projectRoot, rendererInitPath)) {
1064
+ warnings.push(
1065
+ "Could not copy gg-pixel browser IIFE bundle \u2014 install @kenkaiiii/gg-pixel and re-run."
1066
+ );
1067
+ }
1068
+ let patchedAny = false;
1069
+ for (const html of htmlFiles) {
1070
+ if (patchRendererHtml(html, rendererInitPath, projectKey, ingestUrl) === "patched") {
1071
+ patchedAny = true;
1072
+ }
1073
+ }
1074
+ if (!patchedAny) {
1075
+ warnings.push(
1076
+ `Found HTML files in ${rendererDir} but couldn't patch any \u2014 they may have unusual CSP or no <head>.`
1077
+ );
1078
+ }
1079
+ } else {
1080
+ rendererInitPath = join2(projectRoot, "gg-pixel.renderer.mjs");
1081
+ writeFileSync(rendererInitPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");
1082
+ const rendererEntry = pickPath(projectRoot, [
1083
+ "src/renderer/index.ts",
1084
+ "src/renderer/index.tsx",
1085
+ "src/renderer/index.js",
1086
+ "src/renderer/main.ts",
1087
+ "src/renderer/main.tsx",
1088
+ "src/renderer/main.js",
1089
+ "renderer/index.ts",
1090
+ "renderer/index.tsx",
1091
+ "renderer/index.js",
1092
+ "renderer.ts",
1093
+ "renderer.tsx",
1094
+ "renderer.js",
1095
+ "src/index.tsx",
1096
+ "src/index.jsx",
1097
+ "src/main.tsx",
1098
+ "src/main.jsx"
1099
+ ]);
1100
+ if (rendererEntry) injectImport(rendererEntry, rendererInitPath);
1101
+ else
1102
+ warnings.push(
1103
+ 'Could not auto-detect the Electron renderer entry. Add `import "./gg-pixel.renderer.mjs";` to the top of your renderer entry file.'
1104
+ );
1090
1105
  }
1091
1106
  return {
1092
1107
  primaryInitPath: rendererInitPath,
1093
- entryWiring: rendererEntry ? { kind: "injected", entryPath: rendererEntry } : { kind: "no_entry_found" },
1108
+ entryWiring: { kind: "injected", entryPath: rendererInitPath },
1094
1109
  secondaryInit: {
1095
1110
  path: mainInitPath,
1096
1111
  description: "Electron main-process init" + (mainWiring.kind === "injected" ? ` (wired into ${mainEntry})` : "")
@@ -1098,6 +1113,124 @@ function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
1098
1113
  warnings
1099
1114
  };
1100
1115
  }
1116
+ function resolveMainEntryFromPkg(projectRoot, pkg) {
1117
+ if (pkg.main) {
1118
+ const sourceCandidates = [];
1119
+ const main = pkg.main;
1120
+ if (/^(dist|build|\.next|out)\//.test(main)) {
1121
+ const swap = main.replace(/^(dist|build|\.next|out)\//, "src/");
1122
+ if (swap.endsWith(".js")) {
1123
+ sourceCandidates.push(swap.replace(/\.js$/, ".ts"));
1124
+ sourceCandidates.push(swap.replace(/\.js$/, ".tsx"));
1125
+ }
1126
+ sourceCandidates.push(swap);
1127
+ }
1128
+ if (main.endsWith(".js")) {
1129
+ sourceCandidates.push(main.replace(/\.js$/, ".ts"));
1130
+ sourceCandidates.push(main.replace(/\.js$/, ".tsx"));
1131
+ }
1132
+ for (const c of sourceCandidates) {
1133
+ const p = join2(projectRoot, c);
1134
+ if (existsSync2(p)) return p;
1135
+ }
1136
+ const literal = join2(projectRoot, main);
1137
+ if (existsSync2(literal)) return literal;
1138
+ }
1139
+ return pickPath(projectRoot, [
1140
+ "main.js",
1141
+ "main.ts",
1142
+ "src/main.js",
1143
+ "src/main.ts",
1144
+ "src/main/index.ts",
1145
+ "src/main/index.js",
1146
+ "electron/main.js",
1147
+ "electron/main.ts"
1148
+ ]);
1149
+ }
1150
+ var RENDERER_HTML_DIRS = ["ui", "renderer", "src/renderer", "public", "static"];
1151
+ function findRendererHtmlFiles(projectRoot) {
1152
+ for (const dir of RENDERER_HTML_DIRS) {
1153
+ const root = join2(projectRoot, dir);
1154
+ if (!existsSync2(root)) continue;
1155
+ const html = [];
1156
+ let entries;
1157
+ try {
1158
+ entries = readdirSync(root);
1159
+ } catch {
1160
+ continue;
1161
+ }
1162
+ for (const e of entries) {
1163
+ if (!e.endsWith(".html")) continue;
1164
+ const p = join2(root, e);
1165
+ try {
1166
+ const c = readFileSync2(p, "utf8");
1167
+ if (/<meta[^>]+content-security-policy/i.test(c) || /<script[\s>]/i.test(c)) {
1168
+ html.push(p);
1169
+ }
1170
+ } catch {
1171
+ }
1172
+ }
1173
+ if (html.length > 0) return html;
1174
+ }
1175
+ return [];
1176
+ }
1177
+ function copyIifeBundle(projectRoot, dest) {
1178
+ const candidates = [
1179
+ join2(projectRoot, "node_modules/@kenkaiiii/gg-pixel/dist/browser.iife.global.js"),
1180
+ join2(projectRoot, "node_modules/@kenkaiiii/gg-pixel/dist/browser.iife.js")
1181
+ ];
1182
+ for (const c of candidates) {
1183
+ if (existsSync2(c)) {
1184
+ try {
1185
+ writeFileSync(dest, readFileSync2(c, "utf8"), "utf8");
1186
+ return true;
1187
+ } catch {
1188
+ }
1189
+ }
1190
+ }
1191
+ return false;
1192
+ }
1193
+ function patchRendererHtml(htmlPath, iifePath, projectKey, ingestUrl) {
1194
+ let content;
1195
+ try {
1196
+ content = readFileSync2(htmlPath, "utf8");
1197
+ } catch {
1198
+ return "not-applicable";
1199
+ }
1200
+ if (content.includes("gg-pixel.browser.iife")) return "already";
1201
+ const ingestOrigin = new URL(ingestUrl).origin;
1202
+ content = content.replace(
1203
+ /(<meta[^>]+http-equiv=["']?content-security-policy["']?[^>]+content=["'])([^"']+)(["'])/i,
1204
+ (_match, before, csp, after) => {
1205
+ let updated = csp;
1206
+ if (/connect-src\s/i.test(csp)) {
1207
+ if (!csp.includes(ingestOrigin)) {
1208
+ updated = csp.replace(/(connect-src[^;]*)/i, `$1 ${ingestOrigin}`);
1209
+ }
1210
+ } else {
1211
+ updated = csp.trim().replace(/;?$/, `; connect-src 'self' ${ingestOrigin};`);
1212
+ }
1213
+ return before + updated + after;
1214
+ }
1215
+ );
1216
+ const relScript = relative(dirname2(htmlPath), iifePath).split(sep).join("/");
1217
+ const inject = `
1218
+ <!-- gg-pixel: auto-wired by ggcoder pixel install -->
1219
+ <script src="${relScript}"></script>
1220
+ <script>
1221
+ if (window.GGPixel) GGPixel.initPixel({ projectKey: ${JSON.stringify(projectKey)}, ingestUrl: ${JSON.stringify(ingestUrl)} });
1222
+ </script>
1223
+ `;
1224
+ if (/<head[^>]*>/i.test(content)) {
1225
+ content = content.replace(/(<head[^>]*>)/i, `$1${inject}`);
1226
+ } else if (/<html[^>]*>/i.test(content)) {
1227
+ content = content.replace(/(<html[^>]*>)/i, `$1<head>${inject}</head>`);
1228
+ } else {
1229
+ return "not-applicable";
1230
+ }
1231
+ writeFileSync(htmlPath, content, "utf8");
1232
+ return "patched";
1233
+ }
1101
1234
  function wireTauri({ projectRoot, pkg, projectKey, ingestUrl }) {
1102
1235
  const initPath = join2(projectRoot, "gg-pixel.init.mjs");
1103
1236
  writeFileSync(initPath, renderBrowserInitFile(ingestUrl, projectKey), "utf8");