@glasstrace/sdk 0.9.1 → 0.10.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-Y6V7BTF3.js → chunk-5MAHIPFH.js} +2 -2
- package/dist/chunk-KOYJ2UQE.js +417 -0
- package/dist/chunk-KOYJ2UQE.js.map +1 -0
- package/dist/{chunk-PQWAKVQ5.js → chunk-O3Y45VGV.js} +33 -102
- package/dist/chunk-O3Y45VGV.js.map +1 -0
- package/dist/chunk-ZRNG36LU.js +77 -0
- package/dist/chunk-ZRNG36LU.js.map +1 -0
- package/dist/cli/init.cjs +55 -18
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +3 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.js +2 -1
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/uninit.cjs +57 -18
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.d.cts +34 -2
- package/dist/cli/uninit.d.ts +34 -2
- package/dist/cli/uninit.js +55 -18
- package/dist/cli/uninit.js.map +1 -1
- package/dist/index.cjs +15837 -15140
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +38 -404
- package/dist/index.js.map +1 -1
- package/dist/source-map-uploader-OA5NCDOK.js +25 -0
- package/dist/source-map-uploader-OA5NCDOK.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-PQWAKVQ5.js.map +0 -1
- /package/dist/{chunk-Y6V7BTF3.js.map → chunk-5MAHIPFH.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PRESIGNED_THRESHOLD_BYTES,
|
|
3
|
+
collectSourceMaps,
|
|
4
|
+
computeBuildHash,
|
|
5
|
+
installConsoleCapture,
|
|
6
|
+
isAnonymousMode,
|
|
7
|
+
isProductionDisabled,
|
|
8
|
+
maybeShowMcpNudge,
|
|
9
|
+
readEnvVars,
|
|
10
|
+
resolveConfig,
|
|
11
|
+
uploadSourceMaps,
|
|
12
|
+
uploadSourceMapsAuto,
|
|
13
|
+
uploadSourceMapsPresigned
|
|
14
|
+
} from "./chunk-KOYJ2UQE.js";
|
|
1
15
|
import {
|
|
2
16
|
buildImportGraph,
|
|
3
17
|
discoverTestFiles,
|
|
4
18
|
extractImports
|
|
5
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-5MAHIPFH.js";
|
|
20
|
+
import {
|
|
21
|
+
getOrCreateAnonKey,
|
|
22
|
+
readAnonKey
|
|
23
|
+
} from "./chunk-ZRNG36LU.js";
|
|
6
24
|
import {
|
|
7
25
|
DEFAULT_CAPTURE_CONFIG,
|
|
8
26
|
GLASSTRACE_ATTRIBUTE_NAMES,
|
|
9
|
-
PresignedUploadResponseSchema,
|
|
10
27
|
SdkCachedConfigSchema,
|
|
11
28
|
SdkInitResponseSchema,
|
|
12
|
-
SessionIdSchema
|
|
13
|
-
|
|
14
|
-
SourceMapUploadResponseSchema,
|
|
15
|
-
getOrCreateAnonKey,
|
|
16
|
-
readAnonKey
|
|
17
|
-
} from "./chunk-PQWAKVQ5.js";
|
|
29
|
+
SessionIdSchema
|
|
30
|
+
} from "./chunk-O3Y45VGV.js";
|
|
18
31
|
import {
|
|
19
32
|
INVALID_SPAN_CONTEXT,
|
|
20
33
|
SamplingDecision,
|
|
@@ -42,56 +55,6 @@ var SdkError = class extends Error {
|
|
|
42
55
|
}
|
|
43
56
|
};
|
|
44
57
|
|
|
45
|
-
// src/env-detection.ts
|
|
46
|
-
var DEFAULT_ENDPOINT = "https://api.glasstrace.dev";
|
|
47
|
-
function readEnvVars() {
|
|
48
|
-
return {
|
|
49
|
-
GLASSTRACE_API_KEY: process.env.GLASSTRACE_API_KEY?.trim() || void 0,
|
|
50
|
-
GLASSTRACE_FORCE_ENABLE: process.env.GLASSTRACE_FORCE_ENABLE,
|
|
51
|
-
GLASSTRACE_ENV: process.env.GLASSTRACE_ENV,
|
|
52
|
-
GLASSTRACE_COVERAGE_MAP: process.env.GLASSTRACE_COVERAGE_MAP,
|
|
53
|
-
NODE_ENV: process.env.NODE_ENV,
|
|
54
|
-
VERCEL_ENV: process.env.VERCEL_ENV
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function resolveConfig(options) {
|
|
58
|
-
const env = readEnvVars();
|
|
59
|
-
return {
|
|
60
|
-
apiKey: options?.apiKey ?? env.GLASSTRACE_API_KEY,
|
|
61
|
-
endpoint: options?.endpoint ?? DEFAULT_ENDPOINT,
|
|
62
|
-
forceEnable: options?.forceEnable ?? env.GLASSTRACE_FORCE_ENABLE === "true",
|
|
63
|
-
verbose: options?.verbose ?? false,
|
|
64
|
-
environment: env.GLASSTRACE_ENV,
|
|
65
|
-
coverageMapEnabled: env.GLASSTRACE_COVERAGE_MAP === "true",
|
|
66
|
-
nodeEnv: env.NODE_ENV,
|
|
67
|
-
vercelEnv: env.VERCEL_ENV
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function isProductionDisabled(config) {
|
|
71
|
-
if (config.forceEnable) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
if (config.nodeEnv === "production") {
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
if (config.vercelEnv === "production") {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
function isAnonymousMode(config) {
|
|
83
|
-
if (config.apiKey === void 0) {
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
if (config.apiKey.trim() === "") {
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
if (config.apiKey.startsWith("gt_anon_")) {
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
58
|
// src/session.ts
|
|
96
59
|
import { createHash } from "crypto";
|
|
97
60
|
var FOUR_HOURS_MS = 4 * 60 * 60 * 1e3;
|
|
@@ -2230,7 +2193,7 @@ function appendRootPathToUrlIfNeeded(url) {
|
|
|
2230
2193
|
return void 0;
|
|
2231
2194
|
}
|
|
2232
2195
|
}
|
|
2233
|
-
function appendResourcePathToUrl(url,
|
|
2196
|
+
function appendResourcePathToUrl(url, path2) {
|
|
2234
2197
|
try {
|
|
2235
2198
|
new URL(url);
|
|
2236
2199
|
} catch {
|
|
@@ -2240,11 +2203,11 @@ function appendResourcePathToUrl(url, path3) {
|
|
|
2240
2203
|
if (!url.endsWith("/")) {
|
|
2241
2204
|
url = url + "/";
|
|
2242
2205
|
}
|
|
2243
|
-
url +=
|
|
2206
|
+
url += path2;
|
|
2244
2207
|
try {
|
|
2245
2208
|
new URL(url);
|
|
2246
2209
|
} catch {
|
|
2247
|
-
diag.warn(`Configuration: Provided URL appended with '${
|
|
2210
|
+
diag.warn(`Configuration: Provided URL appended with '${path2}' is not a valid URL, using 'undefined' instead of '${url}'`);
|
|
2248
2211
|
return void 0;
|
|
2249
2212
|
}
|
|
2250
2213
|
return url;
|
|
@@ -3488,112 +3451,6 @@ async function configureOtel(config, sessionManager) {
|
|
|
3488
3451
|
registerShutdownHooks(provider);
|
|
3489
3452
|
}
|
|
3490
3453
|
|
|
3491
|
-
// src/nudge/error-nudge.ts
|
|
3492
|
-
import { existsSync } from "fs";
|
|
3493
|
-
import { join as join2 } from "path";
|
|
3494
|
-
var hasFired = false;
|
|
3495
|
-
function sanitize(input) {
|
|
3496
|
-
return input.replace(/[\x00-\x1f\x7f]/g, "");
|
|
3497
|
-
}
|
|
3498
|
-
function maybeShowMcpNudge(errorSummary) {
|
|
3499
|
-
if (hasFired) {
|
|
3500
|
-
return;
|
|
3501
|
-
}
|
|
3502
|
-
const config = resolveConfig();
|
|
3503
|
-
if (isProductionDisabled(config)) {
|
|
3504
|
-
hasFired = true;
|
|
3505
|
-
return;
|
|
3506
|
-
}
|
|
3507
|
-
let markerExists = false;
|
|
3508
|
-
try {
|
|
3509
|
-
const markerPath = join2(process.cwd(), ".glasstrace", "mcp-connected");
|
|
3510
|
-
markerExists = existsSync(markerPath);
|
|
3511
|
-
} catch {
|
|
3512
|
-
markerExists = false;
|
|
3513
|
-
}
|
|
3514
|
-
if (markerExists) {
|
|
3515
|
-
hasFired = true;
|
|
3516
|
-
return;
|
|
3517
|
-
}
|
|
3518
|
-
hasFired = true;
|
|
3519
|
-
const safe = sanitize(errorSummary);
|
|
3520
|
-
process.stderr.write(
|
|
3521
|
-
`[glasstrace] Error captured: ${safe}
|
|
3522
|
-
Debug with AI: ask your agent "What's the latest Glasstrace error?"
|
|
3523
|
-
Not connected? Run: npx glasstrace mcp add
|
|
3524
|
-
`
|
|
3525
|
-
);
|
|
3526
|
-
}
|
|
3527
|
-
|
|
3528
|
-
// src/console-capture.ts
|
|
3529
|
-
var isGlasstraceLog = false;
|
|
3530
|
-
var originalError = null;
|
|
3531
|
-
var originalWarn = null;
|
|
3532
|
-
var installed = false;
|
|
3533
|
-
var otelApi = null;
|
|
3534
|
-
function formatArgs(args) {
|
|
3535
|
-
return args.map((arg) => {
|
|
3536
|
-
if (typeof arg === "string") return arg;
|
|
3537
|
-
if (arg instanceof Error) return arg.stack ?? arg.message;
|
|
3538
|
-
try {
|
|
3539
|
-
return JSON.stringify(arg);
|
|
3540
|
-
} catch {
|
|
3541
|
-
return String(arg);
|
|
3542
|
-
}
|
|
3543
|
-
}).join(" ");
|
|
3544
|
-
}
|
|
3545
|
-
function isSdkMessage(args) {
|
|
3546
|
-
return typeof args[0] === "string" && args[0].startsWith("[glasstrace]");
|
|
3547
|
-
}
|
|
3548
|
-
async function installConsoleCapture() {
|
|
3549
|
-
if (installed) return;
|
|
3550
|
-
try {
|
|
3551
|
-
otelApi = await import("./esm-POMEQPKL.js");
|
|
3552
|
-
} catch {
|
|
3553
|
-
otelApi = null;
|
|
3554
|
-
}
|
|
3555
|
-
originalError = console.error;
|
|
3556
|
-
originalWarn = console.warn;
|
|
3557
|
-
installed = true;
|
|
3558
|
-
console.error = (...args) => {
|
|
3559
|
-
originalError.apply(console, args);
|
|
3560
|
-
if (isGlasstraceLog || isSdkMessage(args)) return;
|
|
3561
|
-
if (otelApi) {
|
|
3562
|
-
const span = otelApi.trace.getSpan(otelApi.context.active());
|
|
3563
|
-
if (span) {
|
|
3564
|
-
const formattedMessage = formatArgs(args);
|
|
3565
|
-
span.addEvent("console.error", {
|
|
3566
|
-
"console.message": formattedMessage
|
|
3567
|
-
});
|
|
3568
|
-
try {
|
|
3569
|
-
maybeShowMcpNudge(formattedMessage);
|
|
3570
|
-
} catch {
|
|
3571
|
-
}
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
};
|
|
3575
|
-
console.warn = (...args) => {
|
|
3576
|
-
originalWarn.apply(console, args);
|
|
3577
|
-
if (isGlasstraceLog || isSdkMessage(args)) return;
|
|
3578
|
-
if (otelApi) {
|
|
3579
|
-
const span = otelApi.trace.getSpan(otelApi.context.active());
|
|
3580
|
-
if (span) {
|
|
3581
|
-
span.addEvent("console.warn", {
|
|
3582
|
-
"console.message": formatArgs(args)
|
|
3583
|
-
});
|
|
3584
|
-
}
|
|
3585
|
-
}
|
|
3586
|
-
};
|
|
3587
|
-
}
|
|
3588
|
-
function sdkLog(level, message) {
|
|
3589
|
-
isGlasstraceLog = true;
|
|
3590
|
-
try {
|
|
3591
|
-
console[level](message);
|
|
3592
|
-
} finally {
|
|
3593
|
-
isGlasstraceLog = false;
|
|
3594
|
-
}
|
|
3595
|
-
}
|
|
3596
|
-
|
|
3597
3454
|
// src/register.ts
|
|
3598
3455
|
var consoleCaptureInstalled = false;
|
|
3599
3456
|
var discoveryHandler = null;
|
|
@@ -3604,6 +3461,12 @@ function registerGlasstrace(options) {
|
|
|
3604
3461
|
if (isRegistered) {
|
|
3605
3462
|
return;
|
|
3606
3463
|
}
|
|
3464
|
+
if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
|
|
3465
|
+
console.warn(
|
|
3466
|
+
"[glasstrace] SDK requires a Node.js runtime. Edge Runtime, browser, and Deno without Node compat are not supported. Glasstrace is disabled in this environment."
|
|
3467
|
+
);
|
|
3468
|
+
return;
|
|
3469
|
+
}
|
|
3607
3470
|
const config = resolveConfig(options);
|
|
3608
3471
|
if (config.verbose) {
|
|
3609
3472
|
console.info("[glasstrace] Config resolved.");
|
|
@@ -3734,7 +3597,7 @@ async function backgroundInit(config, anonKeyForInit, generation) {
|
|
|
3734
3597
|
if (config.verbose) {
|
|
3735
3598
|
console.info("[glasstrace] Background init firing.");
|
|
3736
3599
|
}
|
|
3737
|
-
const initResult = await performInit(config, anonKeyForInit, "0.
|
|
3600
|
+
const initResult = await performInit(config, anonKeyForInit, "0.10.0");
|
|
3738
3601
|
if (generation !== registrationGeneration) return;
|
|
3739
3602
|
if (initResult?.claimResult) {
|
|
3740
3603
|
setResolvedApiKey(initResult.claimResult.newApiKey);
|
|
@@ -3761,241 +3624,11 @@ function isDiscoveryEnabled(config) {
|
|
|
3761
3624
|
return false;
|
|
3762
3625
|
}
|
|
3763
3626
|
|
|
3764
|
-
// src/source-map-uploader.ts
|
|
3765
|
-
import * as fs2 from "fs/promises";
|
|
3766
|
-
import * as path2 from "path";
|
|
3767
|
-
import * as crypto from "crypto";
|
|
3768
|
-
import { execFileSync } from "child_process";
|
|
3769
|
-
async function collectSourceMaps(buildDir) {
|
|
3770
|
-
const results = [];
|
|
3771
|
-
try {
|
|
3772
|
-
await walkDir(buildDir, buildDir, results);
|
|
3773
|
-
} catch {
|
|
3774
|
-
return [];
|
|
3775
|
-
}
|
|
3776
|
-
return results;
|
|
3777
|
-
}
|
|
3778
|
-
async function walkDir(baseDir, currentDir, results) {
|
|
3779
|
-
let entries;
|
|
3780
|
-
try {
|
|
3781
|
-
entries = await fs2.readdir(currentDir, { withFileTypes: true });
|
|
3782
|
-
} catch {
|
|
3783
|
-
return;
|
|
3784
|
-
}
|
|
3785
|
-
for (const entry of entries) {
|
|
3786
|
-
const fullPath = path2.join(currentDir, entry.name);
|
|
3787
|
-
if (entry.isDirectory()) {
|
|
3788
|
-
await walkDir(baseDir, fullPath, results);
|
|
3789
|
-
} else if (entry.isFile() && entry.name.endsWith(".map")) {
|
|
3790
|
-
try {
|
|
3791
|
-
const content = await fs2.readFile(fullPath, "utf-8");
|
|
3792
|
-
const relativePath = path2.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
3793
|
-
const compiledPath = relativePath.replace(/\.map$/, "");
|
|
3794
|
-
results.push({ filePath: compiledPath, content });
|
|
3795
|
-
} catch {
|
|
3796
|
-
}
|
|
3797
|
-
}
|
|
3798
|
-
}
|
|
3799
|
-
}
|
|
3800
|
-
async function computeBuildHash(maps) {
|
|
3801
|
-
try {
|
|
3802
|
-
const sha = execFileSync("git", ["rev-parse", "HEAD"], { encoding: "utf-8" }).trim();
|
|
3803
|
-
if (sha) {
|
|
3804
|
-
return sha;
|
|
3805
|
-
}
|
|
3806
|
-
} catch {
|
|
3807
|
-
}
|
|
3808
|
-
const sortedMaps = [...maps ?? []].sort(
|
|
3809
|
-
(a, b) => a.filePath.localeCompare(b.filePath)
|
|
3810
|
-
);
|
|
3811
|
-
const hashInput = sortedMaps.map((m) => `${m.filePath}
|
|
3812
|
-
${m.content.length}
|
|
3813
|
-
${m.content}`).join("");
|
|
3814
|
-
const hash = crypto.createHash("sha256").update(hashInput).digest("hex");
|
|
3815
|
-
return hash;
|
|
3816
|
-
}
|
|
3817
|
-
async function uploadSourceMaps(apiKey, endpoint, buildHash, maps) {
|
|
3818
|
-
const body = {
|
|
3819
|
-
apiKey,
|
|
3820
|
-
buildHash,
|
|
3821
|
-
files: maps.map((m) => ({
|
|
3822
|
-
filePath: m.filePath,
|
|
3823
|
-
sourceMap: m.content
|
|
3824
|
-
}))
|
|
3825
|
-
};
|
|
3826
|
-
const baseUrl = stripTrailingSlashes(endpoint);
|
|
3827
|
-
const response = await fetch(`${baseUrl}/v1/source-maps`, {
|
|
3828
|
-
method: "POST",
|
|
3829
|
-
headers: {
|
|
3830
|
-
"Content-Type": "application/json",
|
|
3831
|
-
Authorization: `Bearer ${apiKey}`
|
|
3832
|
-
},
|
|
3833
|
-
body: JSON.stringify(body)
|
|
3834
|
-
});
|
|
3835
|
-
if (!response.ok) {
|
|
3836
|
-
try {
|
|
3837
|
-
await response.text();
|
|
3838
|
-
} catch {
|
|
3839
|
-
}
|
|
3840
|
-
throw new Error(
|
|
3841
|
-
`Source map upload failed: ${String(response.status)} ${response.statusText}`
|
|
3842
|
-
);
|
|
3843
|
-
}
|
|
3844
|
-
const json = await response.json();
|
|
3845
|
-
return SourceMapUploadResponseSchema.parse(json);
|
|
3846
|
-
}
|
|
3847
|
-
var PRESIGNED_THRESHOLD_BYTES = 45e5;
|
|
3848
|
-
function stripTrailingSlashes(url) {
|
|
3849
|
-
let result = url;
|
|
3850
|
-
while (result.endsWith("/")) {
|
|
3851
|
-
result = result.slice(0, -1);
|
|
3852
|
-
}
|
|
3853
|
-
return result;
|
|
3854
|
-
}
|
|
3855
|
-
async function requestPresignedTokens(apiKey, endpoint, buildHash, files) {
|
|
3856
|
-
const baseUrl = stripTrailingSlashes(endpoint);
|
|
3857
|
-
const response = await fetch(`${baseUrl}/v1/source-maps/presign`, {
|
|
3858
|
-
method: "POST",
|
|
3859
|
-
headers: {
|
|
3860
|
-
"Content-Type": "application/json",
|
|
3861
|
-
Authorization: `Bearer ${apiKey}`
|
|
3862
|
-
},
|
|
3863
|
-
body: JSON.stringify({ buildHash, files })
|
|
3864
|
-
});
|
|
3865
|
-
if (!response.ok) {
|
|
3866
|
-
try {
|
|
3867
|
-
await response.text();
|
|
3868
|
-
} catch {
|
|
3869
|
-
}
|
|
3870
|
-
throw new Error(
|
|
3871
|
-
`Presigned token request failed: ${String(response.status)} ${response.statusText}`
|
|
3872
|
-
);
|
|
3873
|
-
}
|
|
3874
|
-
const json = await response.json();
|
|
3875
|
-
return PresignedUploadResponseSchema.parse(json);
|
|
3876
|
-
}
|
|
3877
|
-
async function uploadToBlob(clientToken, pathname, content) {
|
|
3878
|
-
let mod;
|
|
3879
|
-
try {
|
|
3880
|
-
mod = await import("@vercel/blob/client");
|
|
3881
|
-
} catch (err) {
|
|
3882
|
-
const code = err.code;
|
|
3883
|
-
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
|
|
3884
|
-
throw new Error(
|
|
3885
|
-
"Presigned upload requires @vercel/blob. Install it: npm install @vercel/blob"
|
|
3886
|
-
);
|
|
3887
|
-
}
|
|
3888
|
-
throw err;
|
|
3889
|
-
}
|
|
3890
|
-
const result = await mod.put(pathname, new Blob([content]), {
|
|
3891
|
-
access: "public",
|
|
3892
|
-
token: clientToken
|
|
3893
|
-
});
|
|
3894
|
-
return { url: result.url, size: Buffer.byteLength(content, "utf-8") };
|
|
3895
|
-
}
|
|
3896
|
-
async function submitManifest(apiKey, endpoint, uploadId, buildHash, files) {
|
|
3897
|
-
const baseUrl = stripTrailingSlashes(endpoint);
|
|
3898
|
-
const response = await fetch(`${baseUrl}/v1/source-maps/manifest`, {
|
|
3899
|
-
method: "POST",
|
|
3900
|
-
headers: {
|
|
3901
|
-
"Content-Type": "application/json",
|
|
3902
|
-
Authorization: `Bearer ${apiKey}`
|
|
3903
|
-
},
|
|
3904
|
-
body: JSON.stringify({ uploadId, buildHash, files })
|
|
3905
|
-
});
|
|
3906
|
-
if (!response.ok) {
|
|
3907
|
-
try {
|
|
3908
|
-
await response.text();
|
|
3909
|
-
} catch {
|
|
3910
|
-
}
|
|
3911
|
-
throw new Error(
|
|
3912
|
-
`Source map manifest submission failed: ${String(response.status)} ${response.statusText}`
|
|
3913
|
-
);
|
|
3914
|
-
}
|
|
3915
|
-
const json = await response.json();
|
|
3916
|
-
return SourceMapManifestResponseSchema.parse(json);
|
|
3917
|
-
}
|
|
3918
|
-
async function uploadSourceMapsPresigned(apiKey, endpoint, buildHash, maps, blobUploader = uploadToBlob) {
|
|
3919
|
-
if (maps.length === 0) {
|
|
3920
|
-
throw new Error("No source maps to upload");
|
|
3921
|
-
}
|
|
3922
|
-
const presigned = await requestPresignedTokens(
|
|
3923
|
-
apiKey,
|
|
3924
|
-
endpoint,
|
|
3925
|
-
buildHash,
|
|
3926
|
-
maps.map((m) => ({
|
|
3927
|
-
filePath: m.filePath,
|
|
3928
|
-
sizeBytes: Buffer.byteLength(m.content, "utf-8")
|
|
3929
|
-
}))
|
|
3930
|
-
);
|
|
3931
|
-
const mapsByPath = new Map(maps.map((m) => [m.filePath, m]));
|
|
3932
|
-
if (mapsByPath.size !== maps.length) {
|
|
3933
|
-
throw new Error("Duplicate filePath entries in source maps");
|
|
3934
|
-
}
|
|
3935
|
-
for (const token of presigned.files) {
|
|
3936
|
-
if (!mapsByPath.has(token.filePath)) {
|
|
3937
|
-
throw new Error(
|
|
3938
|
-
`Presigned token for "${token.filePath}" has no matching source map entry`
|
|
3939
|
-
);
|
|
3940
|
-
}
|
|
3941
|
-
}
|
|
3942
|
-
const CONCURRENCY = 5;
|
|
3943
|
-
const uploadResults = [];
|
|
3944
|
-
for (let i = 0; i < presigned.files.length; i += CONCURRENCY) {
|
|
3945
|
-
const chunk = presigned.files.slice(i, i + CONCURRENCY);
|
|
3946
|
-
const chunkResults = await Promise.all(
|
|
3947
|
-
chunk.map(async (token) => {
|
|
3948
|
-
const entry = mapsByPath.get(token.filePath);
|
|
3949
|
-
const result = await blobUploader(token.clientToken, token.pathname, entry.content);
|
|
3950
|
-
return {
|
|
3951
|
-
filePath: token.filePath,
|
|
3952
|
-
sizeBytes: result.size,
|
|
3953
|
-
blobUrl: result.url
|
|
3954
|
-
};
|
|
3955
|
-
})
|
|
3956
|
-
);
|
|
3957
|
-
uploadResults.push(...chunkResults);
|
|
3958
|
-
}
|
|
3959
|
-
return submitManifest(apiKey, endpoint, presigned.uploadId, buildHash, uploadResults);
|
|
3960
|
-
}
|
|
3961
|
-
async function uploadSourceMapsAuto(apiKey, endpoint, buildHash, maps, options) {
|
|
3962
|
-
if (maps.length === 0) {
|
|
3963
|
-
throw new Error("No source maps to upload");
|
|
3964
|
-
}
|
|
3965
|
-
const totalBytes = maps.reduce(
|
|
3966
|
-
(sum, m) => sum + Buffer.byteLength(m.content, "utf-8"),
|
|
3967
|
-
0
|
|
3968
|
-
);
|
|
3969
|
-
if (totalBytes < PRESIGNED_THRESHOLD_BYTES) {
|
|
3970
|
-
return uploadSourceMaps(apiKey, endpoint, buildHash, maps);
|
|
3971
|
-
}
|
|
3972
|
-
const checkAvailable = options?.checkBlobAvailable ?? (async () => {
|
|
3973
|
-
try {
|
|
3974
|
-
await import("@vercel/blob/client");
|
|
3975
|
-
return true;
|
|
3976
|
-
} catch {
|
|
3977
|
-
return false;
|
|
3978
|
-
}
|
|
3979
|
-
});
|
|
3980
|
-
const blobAvailable = await checkAvailable();
|
|
3981
|
-
if (blobAvailable) {
|
|
3982
|
-
return uploadSourceMapsPresigned(
|
|
3983
|
-
apiKey,
|
|
3984
|
-
endpoint,
|
|
3985
|
-
buildHash,
|
|
3986
|
-
maps,
|
|
3987
|
-
options?.blobUploader
|
|
3988
|
-
);
|
|
3989
|
-
}
|
|
3990
|
-
sdkLog(
|
|
3991
|
-
"warn",
|
|
3992
|
-
`[glasstrace] Build exceeds 4.5MB (${totalBytes} bytes). Install @vercel/blob for presigned uploads to avoid serverless body size limits. Falling back to legacy upload.`
|
|
3993
|
-
);
|
|
3994
|
-
return uploadSourceMaps(apiKey, endpoint, buildHash, maps);
|
|
3995
|
-
}
|
|
3996
|
-
|
|
3997
3627
|
// src/config-wrapper.ts
|
|
3998
3628
|
function withGlasstraceConfig(nextConfig) {
|
|
3629
|
+
if (typeof process === "undefined" || typeof process.versions?.node !== "string") {
|
|
3630
|
+
return nextConfig != null ? { ...nextConfig } : {};
|
|
3631
|
+
}
|
|
3999
3632
|
const config = nextConfig != null ? { ...nextConfig } : {};
|
|
4000
3633
|
const existingExperimental = config.experimental ?? {};
|
|
4001
3634
|
config.experimental = { ...existingExperimental, serverSourceMaps: true };
|
|
@@ -4038,13 +3671,14 @@ async function handleSourceMapUpload(distDir) {
|
|
|
4038
3671
|
);
|
|
4039
3672
|
return;
|
|
4040
3673
|
}
|
|
4041
|
-
const
|
|
3674
|
+
const { collectSourceMaps: collectSourceMaps2, computeBuildHash: computeBuildHash2, uploadSourceMaps: uploadSourceMaps2 } = await import("./source-map-uploader-OA5NCDOK.js");
|
|
3675
|
+
const maps = await collectSourceMaps2(distDir);
|
|
4042
3676
|
if (maps.length === 0) {
|
|
4043
3677
|
console.info("[glasstrace] No source map files found. Skipping upload.");
|
|
4044
3678
|
return;
|
|
4045
3679
|
}
|
|
4046
|
-
const buildHash = await
|
|
4047
|
-
await
|
|
3680
|
+
const buildHash = await computeBuildHash2(maps);
|
|
3681
|
+
await uploadSourceMaps2(apiKey, endpoint, buildHash, maps);
|
|
4048
3682
|
console.info(
|
|
4049
3683
|
`[glasstrace] Uploaded ${String(maps.length)} source map(s) for build ${buildHash}.`
|
|
4050
3684
|
);
|