@kenkaiiii/gg-pixel 4.3.90 → 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,
@@ -1599,6 +1602,7 @@ func init() {
1599
1602
  projectSecret: created.secret,
1600
1603
  projectName,
1601
1604
  projectKind: "go",
1605
+ projectRoot,
1602
1606
  initFilePath,
1603
1607
  envFilePath,
1604
1608
  projectsJsonPath,
@@ -1664,6 +1668,7 @@ GGPixel.init(
1664
1668
  projectSecret: created.secret,
1665
1669
  projectName,
1666
1670
  projectKind: "ruby",
1671
+ projectRoot,
1667
1672
  initFilePath,
1668
1673
  envFilePath,
1669
1674
  projectsJsonPath,
@@ -1733,6 +1738,7 @@ async function installPython(ctx) {
1733
1738
  projectSecret: created.secret,
1734
1739
  projectName,
1735
1740
  projectKind: "python",
1741
+ projectRoot,
1736
1742
  initFilePath,
1737
1743
  envFilePath,
1738
1744
  projectsJsonPath,
@@ -1864,6 +1870,203 @@ function writeProjectsMapping(projectsJsonPath, projectId, name, path, secret) {
1864
1870
  `, "utf8");
1865
1871
  }
1866
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
+
1867
2070
  // src/index.ts
1868
2071
  var active = null;
1869
2072
  function initPixel(options) {
@@ -1916,6 +2119,8 @@ function defaultRuntime() {
1916
2119
  flushPixel,
1917
2120
  initPixel,
1918
2121
  install,
1919
- reportPixel
2122
+ isInstallProbeFingerprint,
2123
+ reportPixel,
2124
+ verifyInstall
1920
2125
  });
1921
2126
  //# sourceMappingURL=index.cjs.map