@kenkaiiii/gg-pixel 4.3.89 → 4.3.91

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.cjs CHANGED
@@ -25,7 +25,9 @@ __export(index_exports, {
25
25
  flushPixel: () => flushPixel,
26
26
  initPixel: () => initPixel,
27
27
  install: () => install,
28
- reportPixel: () => reportPixel
28
+ isInstallProbeFingerprint: () => isInstallProbeFingerprint,
29
+ reportPixel: () => reportPixel,
30
+ verifyInstall: () => verifyInstall
29
31
  });
30
32
  module.exports = __toCommonJS(index_exports);
31
33
 
@@ -520,6 +522,7 @@ async function install(opts = {}) {
520
522
  projectSecret: created.secret,
521
523
  projectName,
522
524
  projectKind: kind,
525
+ projectRoot: nodeRoot,
523
526
  initFilePath: wired.primaryInitPath,
524
527
  envFilePath,
525
528
  projectsJsonPath,
@@ -1122,6 +1125,11 @@ function wireElectron({ projectRoot, pkg, projectKey, ingestUrl }) {
1122
1125
  "renderer.ts",
1123
1126
  "renderer.tsx",
1124
1127
  "renderer.js",
1128
+ // `src/renderer.{ts,tsx,js}` is the convention used by multi-window
1129
+ // Electron apps that keep all renderer entries in src/.
1130
+ "src/renderer.ts",
1131
+ "src/renderer.tsx",
1132
+ "src/renderer.js",
1125
1133
  "src/index.tsx",
1126
1134
  "src/index.jsx",
1127
1135
  "src/main.tsx",
@@ -1177,7 +1185,7 @@ function resolveMainEntryFromPkg(projectRoot, pkg) {
1177
1185
  "electron/main.ts"
1178
1186
  ]);
1179
1187
  }
1180
- var RENDERER_HTML_DIRS = ["ui", "renderer", "src/renderer", "public", "static"];
1188
+ var RENDERER_HTML_DIRS = ["ui", "renderer", "src/renderer", "src", "public", "static"];
1181
1189
  function findRendererHtmlFiles(projectRoot) {
1182
1190
  for (const dir of RENDERER_HTML_DIRS) {
1183
1191
  const root = (0, import_node_path2.join)(projectRoot, dir);
@@ -1594,6 +1602,7 @@ func init() {
1594
1602
  projectSecret: created.secret,
1595
1603
  projectName,
1596
1604
  projectKind: "go",
1605
+ projectRoot,
1597
1606
  initFilePath,
1598
1607
  envFilePath,
1599
1608
  projectsJsonPath,
@@ -1659,6 +1668,7 @@ GGPixel.init(
1659
1668
  projectSecret: created.secret,
1660
1669
  projectName,
1661
1670
  projectKind: "ruby",
1671
+ projectRoot,
1662
1672
  initFilePath,
1663
1673
  envFilePath,
1664
1674
  projectsJsonPath,
@@ -1728,6 +1738,7 @@ async function installPython(ctx) {
1728
1738
  projectSecret: created.secret,
1729
1739
  projectName,
1730
1740
  projectKind: "python",
1741
+ projectRoot,
1731
1742
  initFilePath,
1732
1743
  envFilePath,
1733
1744
  projectsJsonPath,
@@ -1859,6 +1870,203 @@ function writeProjectsMapping(projectsJsonPath, projectId, name, path, secret) {
1859
1870
  `, "utf8");
1860
1871
  }
1861
1872
 
1873
+ // src/verify.ts
1874
+ var import_node_child_process3 = require("child_process");
1875
+ var import_node_fs4 = require("fs");
1876
+ var import_node_path3 = require("path");
1877
+ var import_node_crypto3 = require("crypto");
1878
+ var PROBE_FINGERPRINT_PREFIX = "__pixel_install_probe__";
1879
+ function isInstallProbeFingerprint(fingerprint2) {
1880
+ return typeof fingerprint2 === "string" && fingerprint2.startsWith(PROBE_FINGERPRINT_PREFIX);
1881
+ }
1882
+ async function verifyInstall(opts) {
1883
+ const fetchFn = opts.fetchFn ?? fetch;
1884
+ const spawnFn = opts.spawnFn ?? import_node_child_process3.spawn;
1885
+ const timeoutMs = opts.timeoutMs ?? 5e3;
1886
+ const ingest = opts.ingestUrl.replace(/\/+$/, "");
1887
+ const fingerprint2 = `${PROBE_FINGERPRINT_PREFIX}${(0, import_node_crypto3.randomBytes)(6).toString("hex")}`;
1888
+ const start = Date.now();
1889
+ let method;
1890
+ let probeError = null;
1891
+ if (opts.skipChildProbe) {
1892
+ try {
1893
+ await postDirectIngest({
1894
+ ingestUrl: ingest,
1895
+ projectKey: opts.projectKey,
1896
+ fingerprint: fingerprint2,
1897
+ fetchFn
1898
+ });
1899
+ method = "direct_ingest";
1900
+ } catch (err) {
1901
+ return {
1902
+ kind: "failed",
1903
+ reason: "Direct ingest failed",
1904
+ hint: err.message
1905
+ };
1906
+ }
1907
+ } else {
1908
+ try {
1909
+ await runChildProbe({
1910
+ projectRoot: opts.projectRoot,
1911
+ ingestUrl: ingest,
1912
+ projectKey: opts.projectKey,
1913
+ fingerprint: fingerprint2,
1914
+ spawnFn
1915
+ });
1916
+ method = "child_process";
1917
+ } catch (err) {
1918
+ probeError = err.message;
1919
+ try {
1920
+ await postDirectIngest({
1921
+ ingestUrl: ingest,
1922
+ projectKey: opts.projectKey,
1923
+ fingerprint: fingerprint2,
1924
+ fetchFn
1925
+ });
1926
+ method = "direct_ingest";
1927
+ } catch (err2) {
1928
+ return {
1929
+ kind: "failed",
1930
+ reason: "Could not deliver probe event",
1931
+ hint: `child-process: ${probeError}; direct ingest: ${err2.message}`
1932
+ };
1933
+ }
1934
+ }
1935
+ }
1936
+ const probeRow = await pollForFingerprint({
1937
+ ingestUrl: ingest,
1938
+ projectId: opts.projectId,
1939
+ projectSecret: opts.projectSecret,
1940
+ fingerprint: fingerprint2,
1941
+ timeoutMs,
1942
+ fetchFn
1943
+ });
1944
+ if (!probeRow) {
1945
+ return {
1946
+ kind: "failed",
1947
+ reason: `Probe sent (${method}) but didn't appear in /api/projects/${opts.projectId}/errors within ${timeoutMs}ms`,
1948
+ hint: probeError ?? void 0
1949
+ };
1950
+ }
1951
+ try {
1952
+ await fetchFn(`${ingest}/api/errors/${probeRow.id}`, {
1953
+ method: "DELETE",
1954
+ headers: { authorization: `Bearer ${opts.projectSecret}` }
1955
+ });
1956
+ } catch {
1957
+ }
1958
+ return {
1959
+ kind: "ok",
1960
+ method,
1961
+ latencyMs: Date.now() - start
1962
+ };
1963
+ }
1964
+ async function runChildProbe(args) {
1965
+ const ggDir = (0, import_node_path3.join)(args.projectRoot, ".gg");
1966
+ if (!(0, import_node_fs4.existsSync)(ggDir)) (0, import_node_fs4.mkdirSync)(ggDir, { recursive: true });
1967
+ const probePath = (0, import_node_path3.join)(ggDir, `pixel-probe-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.mjs`);
1968
+ const script = `import "@kenkaiiii/gg-pixel";
1969
+ const body = ${JSON.stringify({
1970
+ project_key: args.projectKey,
1971
+ fingerprint: args.fingerprint,
1972
+ type: "InstallProbe",
1973
+ message: "Install verification probe \u2014 auto-generated, safe to delete",
1974
+ stack: [],
1975
+ code_context: null,
1976
+ runtime: "",
1977
+ manual_report: true,
1978
+ level: "error"
1979
+ })};
1980
+ body.event_id = "evt_probe_" + crypto.randomUUID();
1981
+ body.runtime = "installer-node-" + process.versions.node;
1982
+ body.occurred_at = new Date().toISOString();
1983
+ const res = await fetch(${JSON.stringify(args.ingestUrl + "/ingest")}, {
1984
+ method: "POST",
1985
+ headers: { "content-type": "application/json" },
1986
+ body: JSON.stringify(body),
1987
+ });
1988
+ if (!res.ok) {
1989
+ const txt = await res.text().catch(() => "");
1990
+ console.error("probe ingest failed: status=" + res.status + " body=" + txt.slice(0, 200));
1991
+ process.exit(1);
1992
+ }
1993
+ `;
1994
+ (0, import_node_fs4.writeFileSync)(probePath, script, "utf8");
1995
+ try {
1996
+ await new Promise((resolve2, reject) => {
1997
+ const opts = { cwd: args.projectRoot, stdio: "pipe" };
1998
+ const child = args.spawnFn("node", [probePath], opts);
1999
+ let stderr = "";
2000
+ child.stderr?.on("data", (b) => {
2001
+ stderr += b.toString();
2002
+ });
2003
+ const timer = setTimeout(() => {
2004
+ child.kill("SIGKILL");
2005
+ reject(new Error("Probe child timed out after 10s"));
2006
+ }, 1e4);
2007
+ child.on("error", (err) => {
2008
+ clearTimeout(timer);
2009
+ reject(err);
2010
+ });
2011
+ child.on("exit", (code) => {
2012
+ clearTimeout(timer);
2013
+ if (code === 0) resolve2();
2014
+ else reject(new Error(`Probe exited code=${code}; stderr: ${stderr.trim().slice(0, 400)}`));
2015
+ });
2016
+ });
2017
+ } finally {
2018
+ try {
2019
+ (0, import_node_fs4.unlinkSync)(probePath);
2020
+ } catch {
2021
+ }
2022
+ }
2023
+ }
2024
+ async function postDirectIngest(args) {
2025
+ const res = await args.fetchFn(`${args.ingestUrl}/ingest`, {
2026
+ method: "POST",
2027
+ headers: { "content-type": "application/json" },
2028
+ body: JSON.stringify({
2029
+ event_id: `evt_probe_${(0, import_node_crypto3.randomBytes)(8).toString("hex")}`,
2030
+ project_key: args.projectKey,
2031
+ fingerprint: args.fingerprint,
2032
+ type: "InstallProbe",
2033
+ message: "Install verification probe",
2034
+ stack: [],
2035
+ code_context: null,
2036
+ runtime: `installer-node-${process.versions.node}`,
2037
+ manual_report: true,
2038
+ level: "error",
2039
+ occurred_at: (/* @__PURE__ */ new Date()).toISOString()
2040
+ })
2041
+ });
2042
+ if (!res.ok) {
2043
+ let body = "";
2044
+ try {
2045
+ body = await res.text();
2046
+ } catch {
2047
+ }
2048
+ throw new Error(`POST /ingest \u2192 ${res.status} ${body.slice(0, 200)}`);
2049
+ }
2050
+ }
2051
+ async function pollForFingerprint(args) {
2052
+ const deadline = Date.now() + args.timeoutMs;
2053
+ while (Date.now() < deadline) {
2054
+ try {
2055
+ const res = await args.fetchFn(`${args.ingestUrl}/api/projects/${args.projectId}/errors`, {
2056
+ headers: { authorization: `Bearer ${args.projectSecret}` }
2057
+ });
2058
+ if (res.ok) {
2059
+ const body = await res.json();
2060
+ const match = body.errors.find((e) => e.fingerprint === args.fingerprint);
2061
+ if (match) return { id: match.id };
2062
+ }
2063
+ } catch {
2064
+ }
2065
+ await new Promise((r) => setTimeout(r, 250));
2066
+ }
2067
+ return null;
2068
+ }
2069
+
1862
2070
  // src/index.ts
1863
2071
  var active = null;
1864
2072
  function initPixel(options) {
@@ -1911,6 +2119,8 @@ function defaultRuntime() {
1911
2119
  flushPixel,
1912
2120
  initPixel,
1913
2121
  install,
1914
- reportPixel
2122
+ isInstallProbeFingerprint,
2123
+ reportPixel,
2124
+ verifyInstall
1915
2125
  });
1916
2126
  //# sourceMappingURL=index.cjs.map