@glasstrace/sdk 0.19.0 → 0.20.1

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.
Files changed (63) hide show
  1. package/README.md +79 -0
  2. package/dist/chunk-BT2OCXCG.js +178 -0
  3. package/dist/chunk-BT2OCXCG.js.map +1 -0
  4. package/dist/{chunk-F2TZRBEH.js → chunk-DO2YPMQ5.js} +9 -181
  5. package/dist/chunk-DO2YPMQ5.js.map +1 -0
  6. package/dist/{chunk-YPXW2TN3.js → chunk-IP4NMDJK.js} +2 -2
  7. package/dist/{chunk-VN3GZDV6.js → chunk-IQN6TRMQ.js} +2 -2
  8. package/dist/{chunk-XNDHQN4S.js → chunk-LU3PPAOQ.js} +288 -54
  9. package/dist/chunk-LU3PPAOQ.js.map +1 -0
  10. package/dist/chunk-R4DAIPXD.js +4461 -0
  11. package/dist/chunk-R4DAIPXD.js.map +1 -0
  12. package/dist/{chunk-5N2IR4EO.js → chunk-TQ54WLCZ.js} +1 -1
  13. package/dist/{chunk-5N2IR4EO.js.map → chunk-TQ54WLCZ.js.map} +1 -1
  14. package/dist/chunk-Z2EGETTT.js +204 -0
  15. package/dist/chunk-Z2EGETTT.js.map +1 -0
  16. package/dist/cli/init.cjs +483 -152
  17. package/dist/cli/init.cjs.map +1 -1
  18. package/dist/cli/init.d.cts +48 -2
  19. package/dist/cli/init.d.ts +48 -2
  20. package/dist/cli/init.js +109 -7
  21. package/dist/cli/init.js.map +1 -1
  22. package/dist/cli/mcp-add.cjs.map +1 -1
  23. package/dist/cli/mcp-add.js +2 -2
  24. package/dist/cli/uninit.cjs +174 -54
  25. package/dist/cli/uninit.cjs.map +1 -1
  26. package/dist/cli/uninit.d.cts +2 -0
  27. package/dist/cli/uninit.d.ts +2 -0
  28. package/dist/cli/uninit.js +2 -1
  29. package/dist/edge-entry-Ds2fNOeh.d.ts +157 -0
  30. package/dist/edge-entry-FJFKkeFF.d.cts +157 -0
  31. package/dist/edge-entry.cjs +14939 -0
  32. package/dist/edge-entry.cjs.map +1 -0
  33. package/dist/edge-entry.d.cts +6 -0
  34. package/dist/edge-entry.d.ts +6 -0
  35. package/dist/edge-entry.js +16 -0
  36. package/dist/index.cjs +13 -4
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d-DgeH-pNJ.d.cts +191 -0
  39. package/dist/index.d-DgeH-pNJ.d.ts +191 -0
  40. package/dist/index.d.cts +9 -461
  41. package/dist/index.d.ts +9 -461
  42. package/dist/index.js +32 -4609
  43. package/dist/index.js.map +1 -1
  44. package/dist/node-entry.cjs +22492 -0
  45. package/dist/node-entry.cjs.map +1 -0
  46. package/dist/node-entry.d.cts +10 -0
  47. package/dist/node-entry.d.ts +10 -0
  48. package/dist/node-entry.js +101 -0
  49. package/dist/node-entry.js.map +1 -0
  50. package/dist/node-subpath.cjs +14506 -0
  51. package/dist/node-subpath.cjs.map +1 -0
  52. package/dist/node-subpath.d.cts +132 -0
  53. package/dist/node-subpath.d.ts +132 -0
  54. package/dist/node-subpath.js +30 -0
  55. package/dist/node-subpath.js.map +1 -0
  56. package/dist/{source-map-uploader-VPDZWWM2.js → source-map-uploader-YXWO6JLN.js} +3 -3
  57. package/dist/source-map-uploader-YXWO6JLN.js.map +1 -0
  58. package/package.json +4 -1
  59. package/dist/chunk-F2TZRBEH.js.map +0 -1
  60. package/dist/chunk-XNDHQN4S.js.map +0 -1
  61. /package/dist/{chunk-YPXW2TN3.js.map → chunk-IP4NMDJK.js.map} +0 -0
  62. /package/dist/{chunk-VN3GZDV6.js.map → chunk-IQN6TRMQ.js.map} +0 -0
  63. /package/dist/{source-map-uploader-VPDZWWM2.js.map → edge-entry.js.map} +0 -0
@@ -53,7 +53,7 @@ declare function decideMcpConfigAction(options: {
53
53
  * Identifies a scaffolding step that can be reversed during rollback.
54
54
  * Steps are tracked in execution order and rolled back in reverse.
55
55
  */
56
- type CompletedStep = "instrumentation" | "next-config" | "env-local" | "gitignore";
56
+ type CompletedStep = "instrumentation" | "next-config" | "env-local" | "gitignore" | "discovery-file";
57
57
  /**
58
58
  * Tracks state needed for accurate rollback of init steps.
59
59
  * Separating this from the step list allows rollback to restore
@@ -74,6 +74,52 @@ interface RollbackState {
74
74
  * When present, rollback restores this instead of using removeRegisterGlasstrace. */
75
75
  originalInstrumentationContent?: string;
76
76
  }
77
+ /**
78
+ * Returns true when the given `.gitignore` content would exclude the
79
+ * static discovery file at `<root>/public/.well-known/glasstrace.json`
80
+ * or `<root>/static/.well-known/glasstrace.json` (depending on `layout`)
81
+ * from being committed.
82
+ *
83
+ * Model: the file has three ancestors in its committed path — the
84
+ * static root directory (`public/` or `static/`), the `.well-known/`
85
+ * sub-directory, and the file itself. Each pattern in `.gitignore` is
86
+ * classified by which ancestor paths it matches, and each ancestor
87
+ * carries its own current ignore state that later patterns can flip.
88
+ * Patterns that don't match any of the three ancestors are ignored.
89
+ *
90
+ * Per `gitignore(5)`:
91
+ *
92
+ * > It is not possible to re-include a file if a parent directory of
93
+ * > that file is excluded.
94
+ *
95
+ * Consequently, the file is reported as ignored when the final state
96
+ * of ANY ancestor (static root, `.well-known/`, or the file itself)
97
+ * is ignored — a `!<file>` negation alone cannot "escape" an ignored
98
+ * ancestor.
99
+ *
100
+ * Per-ancestor tracking is what distinguishes overlapping patterns:
101
+ *
102
+ * - `public/` then `!public/` — root re-included, file OK.
103
+ * - `public/` then `!public/.well-known/` — root still ignored (scope-2
104
+ * negation doesn't match the scope-1 ancestor path), file ignored.
105
+ * - `.well-known/` then `!public/.well-known/` — `.well-known/` re-included
106
+ * (both patterns match the scope-2 ancestor), file OK.
107
+ * - `.well-known/` then `!public/` — `!public/` matches the
108
+ * scope-1 ancestor only; the scope-2 ancestor (`.well-known/`) is still
109
+ * ignored, so the file is ignored.
110
+ * - `<file>` then `!<file>` — file-level ignore flipped.
111
+ * - `<file>` then `!public/.well-known/` — directory negation does
112
+ * not match the file path; file still ignored.
113
+ *
114
+ * Not-modeled rules — glob wildcards (star, question mark, character
115
+ * classes), overlapping any-depth matches across multiple parents, and
116
+ * nested `.gitignore` files — skew the heuristic toward false positives
117
+ * (extra warning output) rather than false negatives. The warning is
118
+ * advisory.
119
+ *
120
+ * @internal Exported for unit testing only.
121
+ */
122
+ declare function gitignoreExcludesDiscoveryFile(gitignoreContent: string, layout: "public" | "static"): boolean;
77
123
  /**
78
124
  * Best-effort rollback of completed init steps in reverse order.
79
125
  * Each step is individually try/caught so that a failure in one
@@ -132,4 +178,4 @@ type VerifyAnonKeyOutcome = {
132
178
  */
133
179
  declare function verifyAnonKeyRegistration(projectRoot: string): Promise<VerifyAnonKeyOutcome>;
134
180
 
135
- export { type InitOptions, type InitResult, type VerifyAnonKeyOutcome, decideMcpConfigAction, meetsNodeVersion, rollbackSteps, runInit, verifyAnonKeyRegistration };
181
+ export { type InitOptions, type InitResult, type VerifyAnonKeyOutcome, decideMcpConfigAction, gitignoreExcludesDiscoveryFile, meetsNodeVersion, rollbackSteps, runInit, verifyAnonKeyRegistration };
@@ -53,7 +53,7 @@ declare function decideMcpConfigAction(options: {
53
53
  * Identifies a scaffolding step that can be reversed during rollback.
54
54
  * Steps are tracked in execution order and rolled back in reverse.
55
55
  */
56
- type CompletedStep = "instrumentation" | "next-config" | "env-local" | "gitignore";
56
+ type CompletedStep = "instrumentation" | "next-config" | "env-local" | "gitignore" | "discovery-file";
57
57
  /**
58
58
  * Tracks state needed for accurate rollback of init steps.
59
59
  * Separating this from the step list allows rollback to restore
@@ -74,6 +74,52 @@ interface RollbackState {
74
74
  * When present, rollback restores this instead of using removeRegisterGlasstrace. */
75
75
  originalInstrumentationContent?: string;
76
76
  }
77
+ /**
78
+ * Returns true when the given `.gitignore` content would exclude the
79
+ * static discovery file at `<root>/public/.well-known/glasstrace.json`
80
+ * or `<root>/static/.well-known/glasstrace.json` (depending on `layout`)
81
+ * from being committed.
82
+ *
83
+ * Model: the file has three ancestors in its committed path — the
84
+ * static root directory (`public/` or `static/`), the `.well-known/`
85
+ * sub-directory, and the file itself. Each pattern in `.gitignore` is
86
+ * classified by which ancestor paths it matches, and each ancestor
87
+ * carries its own current ignore state that later patterns can flip.
88
+ * Patterns that don't match any of the three ancestors are ignored.
89
+ *
90
+ * Per `gitignore(5)`:
91
+ *
92
+ * > It is not possible to re-include a file if a parent directory of
93
+ * > that file is excluded.
94
+ *
95
+ * Consequently, the file is reported as ignored when the final state
96
+ * of ANY ancestor (static root, `.well-known/`, or the file itself)
97
+ * is ignored — a `!<file>` negation alone cannot "escape" an ignored
98
+ * ancestor.
99
+ *
100
+ * Per-ancestor tracking is what distinguishes overlapping patterns:
101
+ *
102
+ * - `public/` then `!public/` — root re-included, file OK.
103
+ * - `public/` then `!public/.well-known/` — root still ignored (scope-2
104
+ * negation doesn't match the scope-1 ancestor path), file ignored.
105
+ * - `.well-known/` then `!public/.well-known/` — `.well-known/` re-included
106
+ * (both patterns match the scope-2 ancestor), file OK.
107
+ * - `.well-known/` then `!public/` — `!public/` matches the
108
+ * scope-1 ancestor only; the scope-2 ancestor (`.well-known/`) is still
109
+ * ignored, so the file is ignored.
110
+ * - `<file>` then `!<file>` — file-level ignore flipped.
111
+ * - `<file>` then `!public/.well-known/` — directory negation does
112
+ * not match the file path; file still ignored.
113
+ *
114
+ * Not-modeled rules — glob wildcards (star, question mark, character
115
+ * classes), overlapping any-depth matches across multiple parents, and
116
+ * nested `.gitignore` files — skew the heuristic toward false positives
117
+ * (extra warning output) rather than false negatives. The warning is
118
+ * advisory.
119
+ *
120
+ * @internal Exported for unit testing only.
121
+ */
122
+ declare function gitignoreExcludesDiscoveryFile(gitignoreContent: string, layout: "public" | "static"): boolean;
77
123
  /**
78
124
  * Best-effort rollback of completed init steps in reverse order.
79
125
  * Each step is individually try/caught so that a failure in one
@@ -132,4 +178,4 @@ type VerifyAnonKeyOutcome = {
132
178
  */
133
179
  declare function verifyAnonKeyRegistration(projectRoot: string): Promise<VerifyAnonKeyOutcome>;
134
180
 
135
- export { type InitOptions, type InitResult, type VerifyAnonKeyOutcome, decideMcpConfigAction, meetsNodeVersion, rollbackSteps, runInit, verifyAnonKeyRegistration };
181
+ export { type InitOptions, type InitResult, type VerifyAnonKeyOutcome, decideMcpConfigAction, gitignoreExcludesDiscoveryFile, meetsNodeVersion, rollbackSteps, runInit, verifyAnonKeyRegistration };
package/dist/cli/init.js CHANGED
@@ -3,19 +3,25 @@ import {
3
3
  resolveProjectRoot
4
4
  } from "../chunk-55FBXXER.js";
5
5
  import {
6
- buildImportGraph,
7
6
  verifyInitReachable
8
- } from "../chunk-F2TZRBEH.js";
7
+ } from "../chunk-DO2YPMQ5.js";
8
+ import {
9
+ buildImportGraph
10
+ } from "../chunk-BT2OCXCG.js";
9
11
  import {
10
12
  resolveConfig
11
13
  } from "../chunk-VUZCLMIX.js";
12
14
  import {
13
15
  isInitCreatedInstrumentation,
16
+ relativeDiscoveryPath,
17
+ removeDiscoveryFile,
14
18
  removeGlasstraceConfigImport,
15
19
  removeRegisterGlasstrace,
20
+ resolveStaticRoot,
16
21
  unwrapCJSExport,
17
- unwrapExport
18
- } from "../chunk-XNDHQN4S.js";
22
+ unwrapExport,
23
+ writeDiscoveryFile
24
+ } from "../chunk-LU3PPAOQ.js";
19
25
  import {
20
26
  detectAgents,
21
27
  generateInfoSection,
@@ -27,8 +33,7 @@ import {
27
33
  import {
28
34
  getOrCreateAnonKey,
29
35
  readAnonKey
30
- } from "../chunk-YPXW2TN3.js";
31
- import "../chunk-5N2IR4EO.js";
36
+ } from "../chunk-IP4NMDJK.js";
32
37
  import {
33
38
  addCoverageMapEnv,
34
39
  isDevApiKey,
@@ -41,6 +46,7 @@ import {
41
46
  scaffoldMcpMarker,
42
47
  scaffoldNextConfig
43
48
  } from "../chunk-O63DJKIJ.js";
49
+ import "../chunk-TQ54WLCZ.js";
44
50
  import {
45
51
  MCP_ENDPOINT,
46
52
  NEXT_CONFIG_NAMES,
@@ -105,6 +111,53 @@ async function promptYesNo(question, defaultValue) {
105
111
  function cleanLeadingBlankLines(content) {
106
112
  return content.replace(/^\n{2,}/, "\n");
107
113
  }
114
+ function gitignoreExcludesDiscoveryFile(gitignoreContent, layout) {
115
+ const staticRoot = layout === "static" ? "static" : "public";
116
+ const rootTargets = [staticRoot, `${staticRoot}/`];
117
+ const wellKnownTargets = [
118
+ `${staticRoot}/.well-known`,
119
+ `${staticRoot}/.well-known/`,
120
+ ".well-known",
121
+ ".well-known/"
122
+ ];
123
+ const fileTargets = [
124
+ `${staticRoot}/.well-known/glasstrace.json`,
125
+ ".well-known/glasstrace.json"
126
+ ];
127
+ let rootIgnored = false;
128
+ let wellKnownIgnored = false;
129
+ let fileIgnored = false;
130
+ for (const rawLine of gitignoreContent.split("\n")) {
131
+ const line = rawLine.trim();
132
+ if (line === "" || line.startsWith("#")) continue;
133
+ const negation = line.startsWith("!");
134
+ const pattern = negation ? line.slice(1).trim() : line;
135
+ if (pattern === "") continue;
136
+ const normalized = pattern.startsWith("/") ? pattern.slice(1) : pattern;
137
+ const matchesRoot = matchesDiscoveryPath(normalized, rootTargets);
138
+ const matchesWellKnown = matchesDiscoveryPath(normalized, wellKnownTargets);
139
+ const matchesFile = matchesDiscoveryPath(normalized, fileTargets);
140
+ if (!matchesRoot && !matchesWellKnown && !matchesFile) continue;
141
+ const newState = !negation;
142
+ if (matchesRoot) rootIgnored = newState;
143
+ if (matchesWellKnown) wellKnownIgnored = newState;
144
+ if (matchesFile) fileIgnored = newState;
145
+ }
146
+ return rootIgnored || wellKnownIgnored || fileIgnored;
147
+ }
148
+ function matchesDiscoveryPath(pattern, targets) {
149
+ const bare = pattern.endsWith("/") ? pattern.slice(0, -1) : pattern;
150
+ for (const target of targets) {
151
+ const tBare = target.endsWith("/") ? target.slice(0, -1) : target;
152
+ if (bare === tBare) return true;
153
+ if (pattern.startsWith("**/")) {
154
+ const suffix = pattern.slice(3);
155
+ const sBare = suffix.endsWith("/") ? suffix.slice(0, -1) : suffix;
156
+ if (tBare === sBare || tBare.endsWith(`/${sBare}`)) return true;
157
+ }
158
+ }
159
+ return false;
160
+ }
108
161
  async function rollbackSteps(steps, projectRoot, state) {
109
162
  for (const step of [...steps].reverse()) {
110
163
  try {
@@ -185,6 +238,10 @@ async function rollbackSteps(steps, projectRoot, state) {
185
238
  }
186
239
  break;
187
240
  }
241
+ case "discovery-file": {
242
+ removeDiscoveryFile(projectRoot);
243
+ break;
244
+ }
188
245
  }
189
246
  } catch {
190
247
  }
@@ -348,6 +405,50 @@ Then add this as the first statement in your register() function:
348
405
  if (preExistingAnonKey !== null) {
349
406
  summary.push("Preserved existing .glasstrace/anon_key");
350
407
  }
408
+ try {
409
+ const discoveryResult = writeDiscoveryFile(projectRoot, anonKey);
410
+ const relPath = relativeDiscoveryPath(discoveryResult.layout);
411
+ switch (discoveryResult.action) {
412
+ case "created":
413
+ summary.push(`Created ${relPath}`);
414
+ rollbackState.steps.push("discovery-file");
415
+ break;
416
+ case "updated-stale":
417
+ summary.push(`Updated ${relPath} (anon key had changed)`);
418
+ break;
419
+ case "skipped-matches":
420
+ summary.push(`Skipped ${relPath} (already matches anon key)`);
421
+ break;
422
+ case "skipped-foreign":
423
+ summary.push(
424
+ `Rewrote ${relPath} (existing file was malformed or not SDK-managed)`
425
+ );
426
+ break;
427
+ case "failed":
428
+ warnings.push(
429
+ `Failed to write ${relPath}${discoveryResult.error !== void 0 ? `: ${discoveryResult.error}` : ""}. The Glasstrace browser extension will fall back to the runtime handler until the file is written.`
430
+ );
431
+ break;
432
+ }
433
+ const gitignorePath = path.join(projectRoot, ".gitignore");
434
+ if (fs.existsSync(gitignorePath)) {
435
+ try {
436
+ const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
437
+ if (gitignoreExcludesDiscoveryFile(gitignoreContent, discoveryResult.layout)) {
438
+ warnings.push(
439
+ `Your .gitignore excludes ${relPath} (directly or via a parent rule). The discovery file must be committed for the Glasstrace browser extension to find it in deployed builds. Remove the matching line from .gitignore or add an explicit negation (e.g. \`!` + relPath + "`)."
440
+ );
441
+ }
442
+ } catch {
443
+ }
444
+ }
445
+ } catch (err) {
446
+ warnings.push(
447
+ `Failed to write ${relativeDiscoveryPath(
448
+ resolveStaticRoot(projectRoot).layout
449
+ )}: ${err instanceof Error ? err.message : String(err)}`
450
+ );
451
+ }
351
452
  let anyConfigWritten = false;
352
453
  if (isCI) {
353
454
  const genericAgent = {
@@ -509,7 +610,7 @@ async function verifyAnonKeyRegistration(projectRoot) {
509
610
  }
510
611
  const baseConfig = resolveConfig({ apiKey: devKey });
511
612
  const config = { ...baseConfig, apiKey: devKey };
512
- const sdkVersion = true ? "0.19.0" : "0.0.0-dev";
613
+ const sdkVersion = true ? "0.20.1" : "0.0.0-dev";
513
614
  const result = await verifyInitReachable(config, anonKey, sdkVersion);
514
615
  if (result.ok) {
515
616
  return { outcome: "verified" };
@@ -758,6 +859,7 @@ Usage:
758
859
  }
759
860
  export {
760
861
  decideMcpConfigAction,
862
+ gitignoreExcludesDiscoveryFile,
761
863
  meetsNodeVersion,
762
864
  rollbackSteps,
763
865
  runInit,