@glasstrace/sdk 0.19.0 → 0.20.0
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/README.md +79 -0
- package/dist/{chunk-XNDHQN4S.js → chunk-6JRI4OGB.js} +286 -54
- package/dist/chunk-6JRI4OGB.js.map +1 -0
- package/dist/cli/init.cjs +481 -152
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +48 -2
- package/dist/cli/init.d.ts +48 -2
- package/dist/cli/init.js +104 -4
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.js +1 -1
- package/dist/cli/uninit.cjs +172 -54
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.d.cts +2 -0
- package/dist/cli/uninit.d.ts +2 -0
- package/dist/cli/uninit.js +2 -1
- package/dist/index.cjs +13 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-XNDHQN4S.js.map +0 -1
package/dist/cli/init.d.cts
CHANGED
|
@@ -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.d.ts
CHANGED
|
@@ -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
|
@@ -11,11 +11,15 @@ import {
|
|
|
11
11
|
} from "../chunk-VUZCLMIX.js";
|
|
12
12
|
import {
|
|
13
13
|
isInitCreatedInstrumentation,
|
|
14
|
+
relativeDiscoveryPath,
|
|
15
|
+
removeDiscoveryFile,
|
|
14
16
|
removeGlasstraceConfigImport,
|
|
15
17
|
removeRegisterGlasstrace,
|
|
18
|
+
resolveStaticRoot,
|
|
16
19
|
unwrapCJSExport,
|
|
17
|
-
unwrapExport
|
|
18
|
-
|
|
20
|
+
unwrapExport,
|
|
21
|
+
writeDiscoveryFile
|
|
22
|
+
} from "../chunk-6JRI4OGB.js";
|
|
19
23
|
import {
|
|
20
24
|
detectAgents,
|
|
21
25
|
generateInfoSection,
|
|
@@ -28,7 +32,6 @@ import {
|
|
|
28
32
|
getOrCreateAnonKey,
|
|
29
33
|
readAnonKey
|
|
30
34
|
} from "../chunk-YPXW2TN3.js";
|
|
31
|
-
import "../chunk-5N2IR4EO.js";
|
|
32
35
|
import {
|
|
33
36
|
addCoverageMapEnv,
|
|
34
37
|
isDevApiKey,
|
|
@@ -41,6 +44,7 @@ import {
|
|
|
41
44
|
scaffoldMcpMarker,
|
|
42
45
|
scaffoldNextConfig
|
|
43
46
|
} from "../chunk-O63DJKIJ.js";
|
|
47
|
+
import "../chunk-5N2IR4EO.js";
|
|
44
48
|
import {
|
|
45
49
|
MCP_ENDPOINT,
|
|
46
50
|
NEXT_CONFIG_NAMES,
|
|
@@ -105,6 +109,53 @@ async function promptYesNo(question, defaultValue) {
|
|
|
105
109
|
function cleanLeadingBlankLines(content) {
|
|
106
110
|
return content.replace(/^\n{2,}/, "\n");
|
|
107
111
|
}
|
|
112
|
+
function gitignoreExcludesDiscoveryFile(gitignoreContent, layout) {
|
|
113
|
+
const staticRoot = layout === "static" ? "static" : "public";
|
|
114
|
+
const rootTargets = [staticRoot, `${staticRoot}/`];
|
|
115
|
+
const wellKnownTargets = [
|
|
116
|
+
`${staticRoot}/.well-known`,
|
|
117
|
+
`${staticRoot}/.well-known/`,
|
|
118
|
+
".well-known",
|
|
119
|
+
".well-known/"
|
|
120
|
+
];
|
|
121
|
+
const fileTargets = [
|
|
122
|
+
`${staticRoot}/.well-known/glasstrace.json`,
|
|
123
|
+
".well-known/glasstrace.json"
|
|
124
|
+
];
|
|
125
|
+
let rootIgnored = false;
|
|
126
|
+
let wellKnownIgnored = false;
|
|
127
|
+
let fileIgnored = false;
|
|
128
|
+
for (const rawLine of gitignoreContent.split("\n")) {
|
|
129
|
+
const line = rawLine.trim();
|
|
130
|
+
if (line === "" || line.startsWith("#")) continue;
|
|
131
|
+
const negation = line.startsWith("!");
|
|
132
|
+
const pattern = negation ? line.slice(1).trim() : line;
|
|
133
|
+
if (pattern === "") continue;
|
|
134
|
+
const normalized = pattern.startsWith("/") ? pattern.slice(1) : pattern;
|
|
135
|
+
const matchesRoot = matchesDiscoveryPath(normalized, rootTargets);
|
|
136
|
+
const matchesWellKnown = matchesDiscoveryPath(normalized, wellKnownTargets);
|
|
137
|
+
const matchesFile = matchesDiscoveryPath(normalized, fileTargets);
|
|
138
|
+
if (!matchesRoot && !matchesWellKnown && !matchesFile) continue;
|
|
139
|
+
const newState = !negation;
|
|
140
|
+
if (matchesRoot) rootIgnored = newState;
|
|
141
|
+
if (matchesWellKnown) wellKnownIgnored = newState;
|
|
142
|
+
if (matchesFile) fileIgnored = newState;
|
|
143
|
+
}
|
|
144
|
+
return rootIgnored || wellKnownIgnored || fileIgnored;
|
|
145
|
+
}
|
|
146
|
+
function matchesDiscoveryPath(pattern, targets) {
|
|
147
|
+
const bare = pattern.endsWith("/") ? pattern.slice(0, -1) : pattern;
|
|
148
|
+
for (const target of targets) {
|
|
149
|
+
const tBare = target.endsWith("/") ? target.slice(0, -1) : target;
|
|
150
|
+
if (bare === tBare) return true;
|
|
151
|
+
if (pattern.startsWith("**/")) {
|
|
152
|
+
const suffix = pattern.slice(3);
|
|
153
|
+
const sBare = suffix.endsWith("/") ? suffix.slice(0, -1) : suffix;
|
|
154
|
+
if (tBare === sBare || tBare.endsWith(`/${sBare}`)) return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
108
159
|
async function rollbackSteps(steps, projectRoot, state) {
|
|
109
160
|
for (const step of [...steps].reverse()) {
|
|
110
161
|
try {
|
|
@@ -185,6 +236,10 @@ async function rollbackSteps(steps, projectRoot, state) {
|
|
|
185
236
|
}
|
|
186
237
|
break;
|
|
187
238
|
}
|
|
239
|
+
case "discovery-file": {
|
|
240
|
+
removeDiscoveryFile(projectRoot);
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
188
243
|
}
|
|
189
244
|
} catch {
|
|
190
245
|
}
|
|
@@ -348,6 +403,50 @@ Then add this as the first statement in your register() function:
|
|
|
348
403
|
if (preExistingAnonKey !== null) {
|
|
349
404
|
summary.push("Preserved existing .glasstrace/anon_key");
|
|
350
405
|
}
|
|
406
|
+
try {
|
|
407
|
+
const discoveryResult = writeDiscoveryFile(projectRoot, anonKey);
|
|
408
|
+
const relPath = relativeDiscoveryPath(discoveryResult.layout);
|
|
409
|
+
switch (discoveryResult.action) {
|
|
410
|
+
case "created":
|
|
411
|
+
summary.push(`Created ${relPath}`);
|
|
412
|
+
rollbackState.steps.push("discovery-file");
|
|
413
|
+
break;
|
|
414
|
+
case "updated-stale":
|
|
415
|
+
summary.push(`Updated ${relPath} (anon key had changed)`);
|
|
416
|
+
break;
|
|
417
|
+
case "skipped-matches":
|
|
418
|
+
summary.push(`Skipped ${relPath} (already matches anon key)`);
|
|
419
|
+
break;
|
|
420
|
+
case "skipped-foreign":
|
|
421
|
+
summary.push(
|
|
422
|
+
`Rewrote ${relPath} (existing file was malformed or not SDK-managed)`
|
|
423
|
+
);
|
|
424
|
+
break;
|
|
425
|
+
case "failed":
|
|
426
|
+
warnings.push(
|
|
427
|
+
`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.`
|
|
428
|
+
);
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
432
|
+
if (fs.existsSync(gitignorePath)) {
|
|
433
|
+
try {
|
|
434
|
+
const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
|
|
435
|
+
if (gitignoreExcludesDiscoveryFile(gitignoreContent, discoveryResult.layout)) {
|
|
436
|
+
warnings.push(
|
|
437
|
+
`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 + "`)."
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
} catch (err) {
|
|
444
|
+
warnings.push(
|
|
445
|
+
`Failed to write ${relativeDiscoveryPath(
|
|
446
|
+
resolveStaticRoot(projectRoot).layout
|
|
447
|
+
)}: ${err instanceof Error ? err.message : String(err)}`
|
|
448
|
+
);
|
|
449
|
+
}
|
|
351
450
|
let anyConfigWritten = false;
|
|
352
451
|
if (isCI) {
|
|
353
452
|
const genericAgent = {
|
|
@@ -509,7 +608,7 @@ async function verifyAnonKeyRegistration(projectRoot) {
|
|
|
509
608
|
}
|
|
510
609
|
const baseConfig = resolveConfig({ apiKey: devKey });
|
|
511
610
|
const config = { ...baseConfig, apiKey: devKey };
|
|
512
|
-
const sdkVersion = true ? "0.
|
|
611
|
+
const sdkVersion = true ? "0.20.0" : "0.0.0-dev";
|
|
513
612
|
const result = await verifyInitReachable(config, anonKey, sdkVersion);
|
|
514
613
|
if (result.ok) {
|
|
515
614
|
return { outcome: "verified" };
|
|
@@ -758,6 +857,7 @@ Usage:
|
|
|
758
857
|
}
|
|
759
858
|
export {
|
|
760
859
|
decideMcpConfigAction,
|
|
860
|
+
gitignoreExcludesDiscoveryFile,
|
|
761
861
|
meetsNodeVersion,
|
|
762
862
|
rollbackSteps,
|
|
763
863
|
runInit,
|