@glasstrace/sdk 0.4.2 → 0.7.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/dist/{chunk-TVOYTJ7I.js → chunk-QW6W4CSA.js} +48 -2
- package/dist/{chunk-TVOYTJ7I.js.map → chunk-QW6W4CSA.js.map} +1 -1
- package/dist/{chunk-67H2JEI4.js → chunk-SALPGSWK.js} +2 -2
- package/dist/cli/init.cjs +46 -2
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +2 -2
- package/dist/cli/mcp-add.cjs +45 -1
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +1 -1
- package/dist/index.cjs +243 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -2
- package/dist/index.d.ts +67 -2
- package/dist/index.js +199 -16
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
- /package/dist/{chunk-67H2JEI4.js.map → chunk-SALPGSWK.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -67,6 +67,7 @@ type GlasstraceEnvVars = z.infer<typeof GlasstraceEnvVarsSchema>;
|
|
|
67
67
|
* - SDK health diagnostics (embedded in init requests)
|
|
68
68
|
* - Discovery endpoint (GET /__glasstrace/config)
|
|
69
69
|
* - Source map upload (POST /v1/source-maps)
|
|
70
|
+
* - Presigned source map upload (POST /v1/source-maps/presign, POST /v1/source-maps/manifest)
|
|
70
71
|
*/
|
|
71
72
|
|
|
72
73
|
/** Test file import relationships, embedded in SDK init request. */
|
|
@@ -112,6 +113,11 @@ declare const SdkInitResponseSchema: z.ZodObject<{
|
|
|
112
113
|
maxTraceSizeBytes: z.ZodNumber;
|
|
113
114
|
maxConcurrentSessions: z.ZodNumber;
|
|
114
115
|
}, z.core.$strip>;
|
|
116
|
+
claimResult: z.ZodOptional<z.ZodObject<{
|
|
117
|
+
newApiKey: z.core.$ZodBranded<z.ZodString, "DevApiKey", "out">;
|
|
118
|
+
accountId: z.ZodString;
|
|
119
|
+
graceExpiresAt: z.ZodNumber;
|
|
120
|
+
}, z.core.$strip>>;
|
|
115
121
|
}, z.core.$strip>;
|
|
116
122
|
type SdkInitResponse = z.infer<typeof SdkInitResponseSchema>;
|
|
117
123
|
/** Response from POST /v1/source-maps. */
|
|
@@ -122,6 +128,15 @@ declare const SourceMapUploadResponseSchema: z.ZodObject<{
|
|
|
122
128
|
totalSizeBytes: z.ZodNumber;
|
|
123
129
|
}, z.core.$strip>;
|
|
124
130
|
type SourceMapUploadResponse = z.infer<typeof SourceMapUploadResponseSchema>;
|
|
131
|
+
/** Response confirming source map manifest activation. */
|
|
132
|
+
declare const SourceMapManifestResponseSchema: z.ZodObject<{
|
|
133
|
+
success: z.ZodLiteral<true>;
|
|
134
|
+
buildHash: z.core.$ZodBranded<z.ZodString, "BuildHash", "out">;
|
|
135
|
+
fileCount: z.ZodNumber;
|
|
136
|
+
totalSizeBytes: z.ZodNumber;
|
|
137
|
+
activatedAt: z.ZodNumber;
|
|
138
|
+
}, z.core.$strip>;
|
|
139
|
+
type SourceMapManifestResponse = z.infer<typeof SourceMapManifestResponseSchema>;
|
|
125
140
|
|
|
126
141
|
/**
|
|
127
142
|
* Internal SDK error class with a typed diagnostic code.
|
|
@@ -270,11 +285,24 @@ declare function sendInitRequest(config: ResolvedConfig, anonKey: AnonApiKey | n
|
|
|
270
285
|
message: string;
|
|
271
286
|
timestamp: number;
|
|
272
287
|
}>, signal?: AbortSignal): Promise<SdkInitResponse>;
|
|
288
|
+
/**
|
|
289
|
+
* Result returned by {@link performInit} when the backend reports an
|
|
290
|
+
* account claim transition. `null` means no claim was present.
|
|
291
|
+
*/
|
|
292
|
+
interface InitClaimResult {
|
|
293
|
+
claimResult: NonNullable<SdkInitResponse["claimResult"]>;
|
|
294
|
+
}
|
|
273
295
|
/**
|
|
274
296
|
* Orchestrates the full init flow: send request, update config, cache result.
|
|
275
297
|
* This function MUST NOT throw.
|
|
298
|
+
*
|
|
299
|
+
* Returns the claim result when the backend reports an account claim
|
|
300
|
+
* transition, or `null` when no claim result is available (including
|
|
301
|
+
* when init is skipped due to rate-limit backoff, missing API key,
|
|
302
|
+
* or request failure). Callers that do not need claim information
|
|
303
|
+
* can safely ignore the return value.
|
|
276
304
|
*/
|
|
277
|
-
declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string): Promise<
|
|
305
|
+
declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string): Promise<InitClaimResult | null>;
|
|
278
306
|
/**
|
|
279
307
|
* Returns the current capture config from the three-tier fallback chain:
|
|
280
308
|
* 1. In-memory config from latest init response
|
|
@@ -457,6 +485,43 @@ declare function computeBuildHash(maps?: SourceMapEntry[]): Promise<string>;
|
|
|
457
485
|
* and file entries. Validates the response against SourceMapUploadResponseSchema.
|
|
458
486
|
*/
|
|
459
487
|
declare function uploadSourceMaps(apiKey: string, endpoint: string, buildHash: string, maps: SourceMapEntry[]): Promise<SourceMapUploadResponse>;
|
|
488
|
+
/** Builds at or above this byte size route to the presigned upload flow. */
|
|
489
|
+
declare const PRESIGNED_THRESHOLD_BYTES = 4500000;
|
|
490
|
+
/** Signature for the blob upload function, injectable for testing. */
|
|
491
|
+
type BlobUploader = (clientToken: string, pathname: string, content: string) => Promise<{
|
|
492
|
+
url: string;
|
|
493
|
+
size: number;
|
|
494
|
+
}>;
|
|
495
|
+
/**
|
|
496
|
+
* Orchestrates the 3-phase presigned upload flow.
|
|
497
|
+
*
|
|
498
|
+
* 1. Requests presigned tokens for all source map files
|
|
499
|
+
* 2. Uploads each file to blob storage with a concurrency limit of 5
|
|
500
|
+
* 3. Submits the manifest to finalize the upload
|
|
501
|
+
*
|
|
502
|
+
* Accepts an optional `blobUploader` for test injection; defaults to
|
|
503
|
+
* {@link uploadToBlob}.
|
|
504
|
+
*/
|
|
505
|
+
declare function uploadSourceMapsPresigned(apiKey: string, endpoint: string, buildHash: string, maps: SourceMapEntry[], blobUploader?: BlobUploader): Promise<SourceMapManifestResponse>;
|
|
506
|
+
/**
|
|
507
|
+
* Options for {@link uploadSourceMapsAuto}, primarily used for test injection.
|
|
508
|
+
*/
|
|
509
|
+
interface AutoUploadOptions {
|
|
510
|
+
/** Override blob availability check (for testing). */
|
|
511
|
+
checkBlobAvailable?: () => Promise<boolean>;
|
|
512
|
+
/** Override blob uploader (for testing). */
|
|
513
|
+
blobUploader?: BlobUploader;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Automatically routes source map uploads based on total build size.
|
|
517
|
+
*
|
|
518
|
+
* - Below {@link PRESIGNED_THRESHOLD_BYTES}: uses the legacy single-request
|
|
519
|
+
* {@link uploadSourceMaps} endpoint.
|
|
520
|
+
* - At or above the threshold: checks if `@vercel/blob` is available and
|
|
521
|
+
* uses the presigned 3-phase flow. Falls back to legacy with a warning
|
|
522
|
+
* if the package is not installed.
|
|
523
|
+
*/
|
|
524
|
+
declare function uploadSourceMapsAuto(apiKey: string, endpoint: string, buildHash: string, maps: SourceMapEntry[], options?: AutoUploadOptions): Promise<SourceMapUploadResponse | SourceMapManifestResponse>;
|
|
460
525
|
|
|
461
526
|
/**
|
|
462
527
|
* Manual error capture API.
|
|
@@ -519,4 +584,4 @@ declare function extractImports(fileContent: string): string[];
|
|
|
519
584
|
*/
|
|
520
585
|
declare function buildImportGraph(projectRoot: string): Promise<ImportGraphPayload>;
|
|
521
586
|
|
|
522
|
-
export { type FetchTarget, GlasstraceExporter, type GlasstraceExporterOptions, GlasstraceSpanProcessor, type ResolvedConfig, SdkError, SessionManager, type SourceMapEntry, buildImportGraph, captureError, classifyFetchTarget, collectSourceMaps, computeBuildHash, createDiscoveryHandler, deriveSessionId, discoverTestFiles, extractImports, getActiveConfig, getDateString, getDiscoveryHandler, getOrCreateAnonKey, getOrigin, isAnonymousMode, isProductionDisabled, loadCachedConfig, performInit, readAnonKey, readEnvVars, registerGlasstrace, resolveConfig, saveCachedConfig, sendInitRequest, uploadSourceMaps, withGlasstraceConfig };
|
|
587
|
+
export { type AutoUploadOptions, type BlobUploader, type FetchTarget, GlasstraceExporter, type GlasstraceExporterOptions, GlasstraceSpanProcessor, type InitClaimResult, PRESIGNED_THRESHOLD_BYTES, type ResolvedConfig, SdkError, SessionManager, type SourceMapEntry, buildImportGraph, captureError, classifyFetchTarget, collectSourceMaps, computeBuildHash, createDiscoveryHandler, deriveSessionId, discoverTestFiles, extractImports, getActiveConfig, getDateString, getDiscoveryHandler, getOrCreateAnonKey, getOrigin, isAnonymousMode, isProductionDisabled, loadCachedConfig, performInit, readAnonKey, readEnvVars, registerGlasstrace, resolveConfig, saveCachedConfig, sendInitRequest, uploadSourceMaps, uploadSourceMapsAuto, uploadSourceMapsPresigned, withGlasstraceConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -67,6 +67,7 @@ type GlasstraceEnvVars = z.infer<typeof GlasstraceEnvVarsSchema>;
|
|
|
67
67
|
* - SDK health diagnostics (embedded in init requests)
|
|
68
68
|
* - Discovery endpoint (GET /__glasstrace/config)
|
|
69
69
|
* - Source map upload (POST /v1/source-maps)
|
|
70
|
+
* - Presigned source map upload (POST /v1/source-maps/presign, POST /v1/source-maps/manifest)
|
|
70
71
|
*/
|
|
71
72
|
|
|
72
73
|
/** Test file import relationships, embedded in SDK init request. */
|
|
@@ -112,6 +113,11 @@ declare const SdkInitResponseSchema: z.ZodObject<{
|
|
|
112
113
|
maxTraceSizeBytes: z.ZodNumber;
|
|
113
114
|
maxConcurrentSessions: z.ZodNumber;
|
|
114
115
|
}, z.core.$strip>;
|
|
116
|
+
claimResult: z.ZodOptional<z.ZodObject<{
|
|
117
|
+
newApiKey: z.core.$ZodBranded<z.ZodString, "DevApiKey", "out">;
|
|
118
|
+
accountId: z.ZodString;
|
|
119
|
+
graceExpiresAt: z.ZodNumber;
|
|
120
|
+
}, z.core.$strip>>;
|
|
115
121
|
}, z.core.$strip>;
|
|
116
122
|
type SdkInitResponse = z.infer<typeof SdkInitResponseSchema>;
|
|
117
123
|
/** Response from POST /v1/source-maps. */
|
|
@@ -122,6 +128,15 @@ declare const SourceMapUploadResponseSchema: z.ZodObject<{
|
|
|
122
128
|
totalSizeBytes: z.ZodNumber;
|
|
123
129
|
}, z.core.$strip>;
|
|
124
130
|
type SourceMapUploadResponse = z.infer<typeof SourceMapUploadResponseSchema>;
|
|
131
|
+
/** Response confirming source map manifest activation. */
|
|
132
|
+
declare const SourceMapManifestResponseSchema: z.ZodObject<{
|
|
133
|
+
success: z.ZodLiteral<true>;
|
|
134
|
+
buildHash: z.core.$ZodBranded<z.ZodString, "BuildHash", "out">;
|
|
135
|
+
fileCount: z.ZodNumber;
|
|
136
|
+
totalSizeBytes: z.ZodNumber;
|
|
137
|
+
activatedAt: z.ZodNumber;
|
|
138
|
+
}, z.core.$strip>;
|
|
139
|
+
type SourceMapManifestResponse = z.infer<typeof SourceMapManifestResponseSchema>;
|
|
125
140
|
|
|
126
141
|
/**
|
|
127
142
|
* Internal SDK error class with a typed diagnostic code.
|
|
@@ -270,11 +285,24 @@ declare function sendInitRequest(config: ResolvedConfig, anonKey: AnonApiKey | n
|
|
|
270
285
|
message: string;
|
|
271
286
|
timestamp: number;
|
|
272
287
|
}>, signal?: AbortSignal): Promise<SdkInitResponse>;
|
|
288
|
+
/**
|
|
289
|
+
* Result returned by {@link performInit} when the backend reports an
|
|
290
|
+
* account claim transition. `null` means no claim was present.
|
|
291
|
+
*/
|
|
292
|
+
interface InitClaimResult {
|
|
293
|
+
claimResult: NonNullable<SdkInitResponse["claimResult"]>;
|
|
294
|
+
}
|
|
273
295
|
/**
|
|
274
296
|
* Orchestrates the full init flow: send request, update config, cache result.
|
|
275
297
|
* This function MUST NOT throw.
|
|
298
|
+
*
|
|
299
|
+
* Returns the claim result when the backend reports an account claim
|
|
300
|
+
* transition, or `null` when no claim result is available (including
|
|
301
|
+
* when init is skipped due to rate-limit backoff, missing API key,
|
|
302
|
+
* or request failure). Callers that do not need claim information
|
|
303
|
+
* can safely ignore the return value.
|
|
276
304
|
*/
|
|
277
|
-
declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string): Promise<
|
|
305
|
+
declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string): Promise<InitClaimResult | null>;
|
|
278
306
|
/**
|
|
279
307
|
* Returns the current capture config from the three-tier fallback chain:
|
|
280
308
|
* 1. In-memory config from latest init response
|
|
@@ -457,6 +485,43 @@ declare function computeBuildHash(maps?: SourceMapEntry[]): Promise<string>;
|
|
|
457
485
|
* and file entries. Validates the response against SourceMapUploadResponseSchema.
|
|
458
486
|
*/
|
|
459
487
|
declare function uploadSourceMaps(apiKey: string, endpoint: string, buildHash: string, maps: SourceMapEntry[]): Promise<SourceMapUploadResponse>;
|
|
488
|
+
/** Builds at or above this byte size route to the presigned upload flow. */
|
|
489
|
+
declare const PRESIGNED_THRESHOLD_BYTES = 4500000;
|
|
490
|
+
/** Signature for the blob upload function, injectable for testing. */
|
|
491
|
+
type BlobUploader = (clientToken: string, pathname: string, content: string) => Promise<{
|
|
492
|
+
url: string;
|
|
493
|
+
size: number;
|
|
494
|
+
}>;
|
|
495
|
+
/**
|
|
496
|
+
* Orchestrates the 3-phase presigned upload flow.
|
|
497
|
+
*
|
|
498
|
+
* 1. Requests presigned tokens for all source map files
|
|
499
|
+
* 2. Uploads each file to blob storage with a concurrency limit of 5
|
|
500
|
+
* 3. Submits the manifest to finalize the upload
|
|
501
|
+
*
|
|
502
|
+
* Accepts an optional `blobUploader` for test injection; defaults to
|
|
503
|
+
* {@link uploadToBlob}.
|
|
504
|
+
*/
|
|
505
|
+
declare function uploadSourceMapsPresigned(apiKey: string, endpoint: string, buildHash: string, maps: SourceMapEntry[], blobUploader?: BlobUploader): Promise<SourceMapManifestResponse>;
|
|
506
|
+
/**
|
|
507
|
+
* Options for {@link uploadSourceMapsAuto}, primarily used for test injection.
|
|
508
|
+
*/
|
|
509
|
+
interface AutoUploadOptions {
|
|
510
|
+
/** Override blob availability check (for testing). */
|
|
511
|
+
checkBlobAvailable?: () => Promise<boolean>;
|
|
512
|
+
/** Override blob uploader (for testing). */
|
|
513
|
+
blobUploader?: BlobUploader;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Automatically routes source map uploads based on total build size.
|
|
517
|
+
*
|
|
518
|
+
* - Below {@link PRESIGNED_THRESHOLD_BYTES}: uses the legacy single-request
|
|
519
|
+
* {@link uploadSourceMaps} endpoint.
|
|
520
|
+
* - At or above the threshold: checks if `@vercel/blob` is available and
|
|
521
|
+
* uses the presigned 3-phase flow. Falls back to legacy with a warning
|
|
522
|
+
* if the package is not installed.
|
|
523
|
+
*/
|
|
524
|
+
declare function uploadSourceMapsAuto(apiKey: string, endpoint: string, buildHash: string, maps: SourceMapEntry[], options?: AutoUploadOptions): Promise<SourceMapUploadResponse | SourceMapManifestResponse>;
|
|
460
525
|
|
|
461
526
|
/**
|
|
462
527
|
* Manual error capture API.
|
|
@@ -519,4 +584,4 @@ declare function extractImports(fileContent: string): string[];
|
|
|
519
584
|
*/
|
|
520
585
|
declare function buildImportGraph(projectRoot: string): Promise<ImportGraphPayload>;
|
|
521
586
|
|
|
522
|
-
export { type FetchTarget, GlasstraceExporter, type GlasstraceExporterOptions, GlasstraceSpanProcessor, type ResolvedConfig, SdkError, SessionManager, type SourceMapEntry, buildImportGraph, captureError, classifyFetchTarget, collectSourceMaps, computeBuildHash, createDiscoveryHandler, deriveSessionId, discoverTestFiles, extractImports, getActiveConfig, getDateString, getDiscoveryHandler, getOrCreateAnonKey, getOrigin, isAnonymousMode, isProductionDisabled, loadCachedConfig, performInit, readAnonKey, readEnvVars, registerGlasstrace, resolveConfig, saveCachedConfig, sendInitRequest, uploadSourceMaps, withGlasstraceConfig };
|
|
587
|
+
export { type AutoUploadOptions, type BlobUploader, type FetchTarget, GlasstraceExporter, type GlasstraceExporterOptions, GlasstraceSpanProcessor, type InitClaimResult, PRESIGNED_THRESHOLD_BYTES, type ResolvedConfig, SdkError, SessionManager, type SourceMapEntry, buildImportGraph, captureError, classifyFetchTarget, collectSourceMaps, computeBuildHash, createDiscoveryHandler, deriveSessionId, discoverTestFiles, extractImports, getActiveConfig, getDateString, getDiscoveryHandler, getOrCreateAnonKey, getOrigin, isAnonymousMode, isProductionDisabled, loadCachedConfig, performInit, readAnonKey, readEnvVars, registerGlasstrace, resolveConfig, saveCachedConfig, sendInitRequest, uploadSourceMaps, uploadSourceMapsAuto, uploadSourceMapsPresigned, withGlasstraceConfig };
|
package/dist/index.js
CHANGED
|
@@ -2,17 +2,19 @@ import {
|
|
|
2
2
|
buildImportGraph,
|
|
3
3
|
discoverTestFiles,
|
|
4
4
|
extractImports
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SALPGSWK.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_CAPTURE_CONFIG,
|
|
8
8
|
GLASSTRACE_ATTRIBUTE_NAMES,
|
|
9
|
+
PresignedUploadResponseSchema,
|
|
9
10
|
SdkCachedConfigSchema,
|
|
10
11
|
SdkInitResponseSchema,
|
|
11
12
|
SessionIdSchema,
|
|
13
|
+
SourceMapManifestResponseSchema,
|
|
12
14
|
SourceMapUploadResponseSchema,
|
|
13
15
|
getOrCreateAnonKey,
|
|
14
16
|
readAnonKey
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-QW6W4CSA.js";
|
|
16
18
|
import {
|
|
17
19
|
INVALID_SPAN_CONTEXT,
|
|
18
20
|
SamplingDecision,
|
|
@@ -281,13 +283,13 @@ async function sendInitRequest(config, anonKey, sdkVersion, importGraph, healthR
|
|
|
281
283
|
async function performInit(config, anonKey, sdkVersion) {
|
|
282
284
|
if (rateLimitBackoff) {
|
|
283
285
|
rateLimitBackoff = false;
|
|
284
|
-
return;
|
|
286
|
+
return null;
|
|
285
287
|
}
|
|
286
288
|
try {
|
|
287
289
|
const effectiveKey = config.apiKey || anonKey;
|
|
288
290
|
if (!effectiveKey) {
|
|
289
291
|
console.warn("[glasstrace] No API key available for init request.");
|
|
290
|
-
return;
|
|
292
|
+
return null;
|
|
291
293
|
}
|
|
292
294
|
const controller = new AbortController();
|
|
293
295
|
const timeoutId = setTimeout(() => controller.abort(), INIT_TIMEOUT_MS);
|
|
@@ -304,45 +306,61 @@ async function performInit(config, anonKey, sdkVersion) {
|
|
|
304
306
|
clearTimeout(timeoutId);
|
|
305
307
|
currentConfig = result;
|
|
306
308
|
await saveCachedConfig(result);
|
|
309
|
+
if (result.claimResult) {
|
|
310
|
+
try {
|
|
311
|
+
process.stderr.write(
|
|
312
|
+
`[glasstrace] Account claimed! Update GLASSTRACE_API_KEY=${result.claimResult.newApiKey} in your .env file.
|
|
313
|
+
`
|
|
314
|
+
);
|
|
315
|
+
} catch (logErr) {
|
|
316
|
+
console.warn(
|
|
317
|
+
`[glasstrace] Failed to write claim migration message: ${logErr instanceof Error ? logErr.message : String(logErr)}`
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
return { claimResult: result.claimResult };
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
307
323
|
} catch (err) {
|
|
308
324
|
clearTimeout(timeoutId);
|
|
309
325
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
310
326
|
console.warn("[glasstrace] ingestion_unreachable: Init request timed out.");
|
|
311
|
-
return;
|
|
327
|
+
return null;
|
|
312
328
|
}
|
|
313
329
|
const status = err.status;
|
|
314
330
|
if (status === 401) {
|
|
315
331
|
console.warn(
|
|
316
332
|
"[glasstrace] ingestion_auth_failed: Check your GLASSTRACE_API_KEY."
|
|
317
333
|
);
|
|
318
|
-
return;
|
|
334
|
+
return null;
|
|
319
335
|
}
|
|
320
336
|
if (status === 429) {
|
|
321
337
|
console.warn("[glasstrace] ingestion_rate_limited: Backing off.");
|
|
322
338
|
rateLimitBackoff = true;
|
|
323
|
-
return;
|
|
339
|
+
return null;
|
|
324
340
|
}
|
|
325
341
|
if (typeof status === "number" && status >= 400) {
|
|
326
342
|
console.warn(
|
|
327
343
|
`[glasstrace] Init request failed with status ${status}. Using cached config.`
|
|
328
344
|
);
|
|
329
|
-
return;
|
|
345
|
+
return null;
|
|
330
346
|
}
|
|
331
347
|
if (err instanceof Error && err.name === "ZodError") {
|
|
332
348
|
console.warn(
|
|
333
349
|
"[glasstrace] Init response failed validation (schema version mismatch?). Using cached config."
|
|
334
350
|
);
|
|
335
|
-
return;
|
|
351
|
+
return null;
|
|
336
352
|
}
|
|
337
353
|
console.warn(
|
|
338
354
|
`[glasstrace] ingestion_unreachable: ${err instanceof Error ? err.message : String(err)}`
|
|
339
355
|
);
|
|
356
|
+
return null;
|
|
340
357
|
}
|
|
341
358
|
} catch (err) {
|
|
342
359
|
console.warn(
|
|
343
360
|
`[glasstrace] Unexpected init error: ${err instanceof Error ? err.message : String(err)}`
|
|
344
361
|
);
|
|
345
362
|
}
|
|
363
|
+
return null;
|
|
346
364
|
}
|
|
347
365
|
function getActiveConfig() {
|
|
348
366
|
if (currentConfig) {
|
|
@@ -3452,6 +3470,14 @@ async function installConsoleCapture() {
|
|
|
3452
3470
|
}
|
|
3453
3471
|
};
|
|
3454
3472
|
}
|
|
3473
|
+
function sdkLog(level, message) {
|
|
3474
|
+
isGlasstraceLog = true;
|
|
3475
|
+
try {
|
|
3476
|
+
console[level](message);
|
|
3477
|
+
} finally {
|
|
3478
|
+
isGlasstraceLog = false;
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3455
3481
|
|
|
3456
3482
|
// src/register.ts
|
|
3457
3483
|
var consoleCaptureInstalled = false;
|
|
@@ -3541,7 +3567,11 @@ function registerGlasstrace(options) {
|
|
|
3541
3567
|
if (config.verbose) {
|
|
3542
3568
|
console.info("[glasstrace] Background init firing.");
|
|
3543
3569
|
}
|
|
3544
|
-
await performInit(config, anonKey, "0.
|
|
3570
|
+
const initResult = await performInit(config, anonKey, "0.7.0");
|
|
3571
|
+
if (initResult?.claimResult) {
|
|
3572
|
+
setResolvedApiKey(initResult.claimResult.newApiKey);
|
|
3573
|
+
notifyApiKeyResolved();
|
|
3574
|
+
}
|
|
3545
3575
|
maybeInstallConsoleCapture();
|
|
3546
3576
|
} catch (err) {
|
|
3547
3577
|
console.warn(
|
|
@@ -3561,7 +3591,11 @@ function registerGlasstrace(options) {
|
|
|
3561
3591
|
if (config.verbose) {
|
|
3562
3592
|
console.info("[glasstrace] Background init firing.");
|
|
3563
3593
|
}
|
|
3564
|
-
await performInit(config, anonKey, "0.
|
|
3594
|
+
const initResult = await performInit(config, anonKey, "0.7.0");
|
|
3595
|
+
if (initResult?.claimResult) {
|
|
3596
|
+
setResolvedApiKey(initResult.claimResult.newApiKey);
|
|
3597
|
+
notifyApiKeyResolved();
|
|
3598
|
+
}
|
|
3565
3599
|
maybeInstallConsoleCapture();
|
|
3566
3600
|
} catch (err) {
|
|
3567
3601
|
console.warn(
|
|
@@ -3583,7 +3617,7 @@ function registerGlasstrace(options) {
|
|
|
3583
3617
|
if (config.verbose) {
|
|
3584
3618
|
console.info("[glasstrace] Background init firing.");
|
|
3585
3619
|
}
|
|
3586
|
-
await performInit(config, anonKeyForInit, "0.
|
|
3620
|
+
await performInit(config, anonKeyForInit, "0.7.0");
|
|
3587
3621
|
maybeInstallConsoleCapture();
|
|
3588
3622
|
} catch (err) {
|
|
3589
3623
|
console.warn(
|
|
@@ -3682,10 +3716,7 @@ async function uploadSourceMaps(apiKey, endpoint, buildHash, maps) {
|
|
|
3682
3716
|
sourceMap: m.content
|
|
3683
3717
|
}))
|
|
3684
3718
|
};
|
|
3685
|
-
|
|
3686
|
-
while (baseUrl.endsWith("/")) {
|
|
3687
|
-
baseUrl = baseUrl.slice(0, -1);
|
|
3688
|
-
}
|
|
3719
|
+
const baseUrl = stripTrailingSlashes(endpoint);
|
|
3689
3720
|
const response = await fetch(`${baseUrl}/v1/source-maps`, {
|
|
3690
3721
|
method: "POST",
|
|
3691
3722
|
headers: {
|
|
@@ -3706,6 +3737,155 @@ async function uploadSourceMaps(apiKey, endpoint, buildHash, maps) {
|
|
|
3706
3737
|
const json = await response.json();
|
|
3707
3738
|
return SourceMapUploadResponseSchema.parse(json);
|
|
3708
3739
|
}
|
|
3740
|
+
var PRESIGNED_THRESHOLD_BYTES = 45e5;
|
|
3741
|
+
function stripTrailingSlashes(url) {
|
|
3742
|
+
let result = url;
|
|
3743
|
+
while (result.endsWith("/")) {
|
|
3744
|
+
result = result.slice(0, -1);
|
|
3745
|
+
}
|
|
3746
|
+
return result;
|
|
3747
|
+
}
|
|
3748
|
+
async function requestPresignedTokens(apiKey, endpoint, buildHash, files) {
|
|
3749
|
+
const baseUrl = stripTrailingSlashes(endpoint);
|
|
3750
|
+
const response = await fetch(`${baseUrl}/v1/source-maps/presign`, {
|
|
3751
|
+
method: "POST",
|
|
3752
|
+
headers: {
|
|
3753
|
+
"Content-Type": "application/json",
|
|
3754
|
+
Authorization: `Bearer ${apiKey}`
|
|
3755
|
+
},
|
|
3756
|
+
body: JSON.stringify({ buildHash, files })
|
|
3757
|
+
});
|
|
3758
|
+
if (!response.ok) {
|
|
3759
|
+
try {
|
|
3760
|
+
await response.text();
|
|
3761
|
+
} catch {
|
|
3762
|
+
}
|
|
3763
|
+
throw new Error(
|
|
3764
|
+
`Presigned token request failed: ${String(response.status)} ${response.statusText}`
|
|
3765
|
+
);
|
|
3766
|
+
}
|
|
3767
|
+
const json = await response.json();
|
|
3768
|
+
return PresignedUploadResponseSchema.parse(json);
|
|
3769
|
+
}
|
|
3770
|
+
async function uploadToBlob(clientToken, pathname, content) {
|
|
3771
|
+
let mod;
|
|
3772
|
+
try {
|
|
3773
|
+
mod = await import("@vercel/blob/client");
|
|
3774
|
+
} catch (err) {
|
|
3775
|
+
const code = err.code;
|
|
3776
|
+
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
|
|
3777
|
+
throw new Error(
|
|
3778
|
+
"Presigned upload requires @vercel/blob. Install it: npm install @vercel/blob"
|
|
3779
|
+
);
|
|
3780
|
+
}
|
|
3781
|
+
throw err;
|
|
3782
|
+
}
|
|
3783
|
+
const result = await mod.put(pathname, new Blob([content]), {
|
|
3784
|
+
access: "public",
|
|
3785
|
+
token: clientToken
|
|
3786
|
+
});
|
|
3787
|
+
return { url: result.url, size: Buffer.byteLength(content, "utf-8") };
|
|
3788
|
+
}
|
|
3789
|
+
async function submitManifest(apiKey, endpoint, uploadId, buildHash, files) {
|
|
3790
|
+
const baseUrl = stripTrailingSlashes(endpoint);
|
|
3791
|
+
const response = await fetch(`${baseUrl}/v1/source-maps/manifest`, {
|
|
3792
|
+
method: "POST",
|
|
3793
|
+
headers: {
|
|
3794
|
+
"Content-Type": "application/json",
|
|
3795
|
+
Authorization: `Bearer ${apiKey}`
|
|
3796
|
+
},
|
|
3797
|
+
body: JSON.stringify({ uploadId, buildHash, files })
|
|
3798
|
+
});
|
|
3799
|
+
if (!response.ok) {
|
|
3800
|
+
try {
|
|
3801
|
+
await response.text();
|
|
3802
|
+
} catch {
|
|
3803
|
+
}
|
|
3804
|
+
throw new Error(
|
|
3805
|
+
`Source map manifest submission failed: ${String(response.status)} ${response.statusText}`
|
|
3806
|
+
);
|
|
3807
|
+
}
|
|
3808
|
+
const json = await response.json();
|
|
3809
|
+
return SourceMapManifestResponseSchema.parse(json);
|
|
3810
|
+
}
|
|
3811
|
+
async function uploadSourceMapsPresigned(apiKey, endpoint, buildHash, maps, blobUploader = uploadToBlob) {
|
|
3812
|
+
if (maps.length === 0) {
|
|
3813
|
+
throw new Error("No source maps to upload");
|
|
3814
|
+
}
|
|
3815
|
+
const presigned = await requestPresignedTokens(
|
|
3816
|
+
apiKey,
|
|
3817
|
+
endpoint,
|
|
3818
|
+
buildHash,
|
|
3819
|
+
maps.map((m) => ({
|
|
3820
|
+
filePath: m.filePath,
|
|
3821
|
+
sizeBytes: Buffer.byteLength(m.content, "utf-8")
|
|
3822
|
+
}))
|
|
3823
|
+
);
|
|
3824
|
+
const mapsByPath = new Map(maps.map((m) => [m.filePath, m]));
|
|
3825
|
+
if (mapsByPath.size !== maps.length) {
|
|
3826
|
+
throw new Error("Duplicate filePath entries in source maps");
|
|
3827
|
+
}
|
|
3828
|
+
for (const token of presigned.files) {
|
|
3829
|
+
if (!mapsByPath.has(token.filePath)) {
|
|
3830
|
+
throw new Error(
|
|
3831
|
+
`Presigned token for "${token.filePath}" has no matching source map entry`
|
|
3832
|
+
);
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
const CONCURRENCY = 5;
|
|
3836
|
+
const uploadResults = [];
|
|
3837
|
+
for (let i = 0; i < presigned.files.length; i += CONCURRENCY) {
|
|
3838
|
+
const chunk = presigned.files.slice(i, i + CONCURRENCY);
|
|
3839
|
+
const chunkResults = await Promise.all(
|
|
3840
|
+
chunk.map(async (token) => {
|
|
3841
|
+
const entry = mapsByPath.get(token.filePath);
|
|
3842
|
+
const result = await blobUploader(token.clientToken, token.pathname, entry.content);
|
|
3843
|
+
return {
|
|
3844
|
+
filePath: token.filePath,
|
|
3845
|
+
sizeBytes: result.size,
|
|
3846
|
+
blobUrl: result.url
|
|
3847
|
+
};
|
|
3848
|
+
})
|
|
3849
|
+
);
|
|
3850
|
+
uploadResults.push(...chunkResults);
|
|
3851
|
+
}
|
|
3852
|
+
return submitManifest(apiKey, endpoint, presigned.uploadId, buildHash, uploadResults);
|
|
3853
|
+
}
|
|
3854
|
+
async function uploadSourceMapsAuto(apiKey, endpoint, buildHash, maps, options) {
|
|
3855
|
+
if (maps.length === 0) {
|
|
3856
|
+
throw new Error("No source maps to upload");
|
|
3857
|
+
}
|
|
3858
|
+
const totalBytes = maps.reduce(
|
|
3859
|
+
(sum, m) => sum + Buffer.byteLength(m.content, "utf-8"),
|
|
3860
|
+
0
|
|
3861
|
+
);
|
|
3862
|
+
if (totalBytes < PRESIGNED_THRESHOLD_BYTES) {
|
|
3863
|
+
return uploadSourceMaps(apiKey, endpoint, buildHash, maps);
|
|
3864
|
+
}
|
|
3865
|
+
const checkAvailable = options?.checkBlobAvailable ?? (async () => {
|
|
3866
|
+
try {
|
|
3867
|
+
await import("@vercel/blob/client");
|
|
3868
|
+
return true;
|
|
3869
|
+
} catch {
|
|
3870
|
+
return false;
|
|
3871
|
+
}
|
|
3872
|
+
});
|
|
3873
|
+
const blobAvailable = await checkAvailable();
|
|
3874
|
+
if (blobAvailable) {
|
|
3875
|
+
return uploadSourceMapsPresigned(
|
|
3876
|
+
apiKey,
|
|
3877
|
+
endpoint,
|
|
3878
|
+
buildHash,
|
|
3879
|
+
maps,
|
|
3880
|
+
options?.blobUploader
|
|
3881
|
+
);
|
|
3882
|
+
}
|
|
3883
|
+
sdkLog(
|
|
3884
|
+
"warn",
|
|
3885
|
+
`[glasstrace] Build exceeds 4.5MB (${totalBytes} bytes). Install @vercel/blob for presigned uploads to avoid serverless body size limits. Falling back to legacy upload.`
|
|
3886
|
+
);
|
|
3887
|
+
return uploadSourceMaps(apiKey, endpoint, buildHash, maps);
|
|
3888
|
+
}
|
|
3709
3889
|
|
|
3710
3890
|
// src/config-wrapper.ts
|
|
3711
3891
|
function withGlasstraceConfig(nextConfig) {
|
|
@@ -3823,6 +4003,7 @@ function captureError(error) {
|
|
|
3823
4003
|
export {
|
|
3824
4004
|
GlasstraceExporter,
|
|
3825
4005
|
GlasstraceSpanProcessor,
|
|
4006
|
+
PRESIGNED_THRESHOLD_BYTES,
|
|
3826
4007
|
SdkError,
|
|
3827
4008
|
SessionManager,
|
|
3828
4009
|
buildImportGraph,
|
|
@@ -3850,6 +4031,8 @@ export {
|
|
|
3850
4031
|
saveCachedConfig,
|
|
3851
4032
|
sendInitRequest,
|
|
3852
4033
|
uploadSourceMaps,
|
|
4034
|
+
uploadSourceMapsAuto,
|
|
4035
|
+
uploadSourceMapsPresigned,
|
|
3853
4036
|
withGlasstraceConfig
|
|
3854
4037
|
};
|
|
3855
4038
|
//# sourceMappingURL=index.js.map
|