bulletin-deploy 0.7.0 → 0.7.2
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 +1 -0
- package/bin/bulletin-deploy +19 -2
- package/dist/bug-report.d.ts +14 -3
- package/dist/bug-report.js +17 -111
- package/dist/{chunk-Q42TQHNL.js → chunk-4FUUYJP2.js} +66 -34
- package/dist/{chunk-PA3AS7QR.js → chunk-4UNQGG3O.js} +1 -1
- package/dist/chunk-LMSMDKVU.js +223 -0
- package/dist/{chunk-OCOCVZQV.js → chunk-NEV6WTYM.js} +1 -1
- package/dist/{chunk-G3YCSH44.js → chunk-VJLTIZ6S.js} +10 -3
- package/dist/deploy.js +5 -3
- package/dist/dotns.js +2 -2
- package/dist/index.js +5 -3
- package/dist/memory-report.d.ts +6 -4
- package/dist/memory-report.js +5 -1
- package/dist/telemetry.d.ts +2 -1
- package/dist/telemetry.js +3 -1
- package/dist/version-check.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -259,6 +259,7 @@ Sentry telemetry is **off by default for external users**. It's automatically on
|
|
|
259
259
|
|
|
260
260
|
- `BULLETIN_DEPLOY_TELEMETRY=1` — explicit opt-in (useful if you want to help us debug an issue you're seeing).
|
|
261
261
|
- `BULLETIN_DEPLOY_TELEMETRY=0` — force off regardless of context.
|
|
262
|
+
- When running under **Bun**, the Parity-internal memory-report diagnostic bundle is skipped (basic deploy telemetry still works). The bundle relies on Node's `v8` module, which Bun implements only partially.
|
|
262
263
|
|
|
263
264
|
Detection signals (OR'd together):
|
|
264
265
|
1. `GITHUB_REPOSITORY` matches a known-internal org — Parity-owned CI workflow.
|
package/bin/bulletin-deploy
CHANGED
|
@@ -4,9 +4,13 @@ import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXI
|
|
|
4
4
|
import { bootstrapPool } from "../dist/pool.js";
|
|
5
5
|
import { VERSION } from "../dist/telemetry.js";
|
|
6
6
|
import { handleFailedDeploy, preReleaseWarning } from "../dist/version-check.js";
|
|
7
|
-
import { setDeployContext } from "../dist/bug-report.js";
|
|
7
|
+
import { setDeployContext, installLogCapture, buildCliFlagsSummary } from "../dist/bug-report.js";
|
|
8
8
|
import * as fs from "fs";
|
|
9
9
|
|
|
10
|
+
// Install early so anything printed during flag parsing / preflight is
|
|
11
|
+
// available to the bug-report log tail.
|
|
12
|
+
installLogCapture();
|
|
13
|
+
|
|
10
14
|
const args = process.argv.slice(2);
|
|
11
15
|
|
|
12
16
|
const flags = {};
|
|
@@ -67,12 +71,25 @@ try {
|
|
|
67
71
|
if (!domain) { console.error("Error: domain required (e.g. my-app.dot)"); process.exit(1); }
|
|
68
72
|
if (!fs.existsSync(buildDir)) { console.error(`Error: ${buildDir} does not exist`); process.exit(1); }
|
|
69
73
|
|
|
74
|
+
const effectiveRpc = flags.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC;
|
|
75
|
+
const deployTag = flags.tag ?? process.env.DEPLOY_TAG;
|
|
76
|
+
const ci = process.env.GITHUB_ACTIONS === "true" ? {
|
|
77
|
+
runUrl: process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY && process.env.GITHUB_RUN_ID
|
|
78
|
+
? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}${process.env.GITHUB_RUN_ATTEMPT ? `/attempts/${process.env.GITHUB_RUN_ATTEMPT}` : ""}`
|
|
79
|
+
: undefined,
|
|
80
|
+
workflow: process.env.GITHUB_WORKFLOW,
|
|
81
|
+
job: process.env.GITHUB_JOB,
|
|
82
|
+
sha: process.env.GITHUB_SHA,
|
|
83
|
+
} : undefined;
|
|
70
84
|
setDeployContext({
|
|
71
85
|
domain,
|
|
72
|
-
rpc:
|
|
86
|
+
rpc: effectiveRpc,
|
|
73
87
|
repo: process.env.GITHUB_REPOSITORY,
|
|
74
88
|
branch: process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME,
|
|
75
89
|
signerMode: flags.mnemonic ? "direct" : "pool",
|
|
90
|
+
deployTag,
|
|
91
|
+
cliFlags: buildCliFlagsSummary(flags),
|
|
92
|
+
ci,
|
|
76
93
|
});
|
|
77
94
|
|
|
78
95
|
const result = await deploy(buildDir, domain, {
|
package/dist/bug-report.d.ts
CHANGED
|
@@ -6,13 +6,24 @@ interface DeployContext {
|
|
|
6
6
|
chunkCount?: number;
|
|
7
7
|
totalSize?: string;
|
|
8
8
|
rpc?: string;
|
|
9
|
-
|
|
9
|
+
deployTag?: string;
|
|
10
|
+
cliFlags?: string;
|
|
11
|
+
ci?: {
|
|
12
|
+
runUrl?: string;
|
|
13
|
+
workflow?: string;
|
|
14
|
+
job?: string;
|
|
15
|
+
sha?: string;
|
|
16
|
+
};
|
|
10
17
|
}
|
|
11
18
|
declare function setDeployContext(ctx: Partial<DeployContext>): void;
|
|
19
|
+
declare function installLogCapture(): void;
|
|
20
|
+
declare function getCapturedTail(): string;
|
|
21
|
+
declare function scrubSecrets(text: string): string;
|
|
22
|
+
declare function buildCliFlagsSummary(flags: Record<string, unknown>): string;
|
|
12
23
|
declare function buildReportBody(error: Error): string;
|
|
13
24
|
declare function buildTitle(error: Error): string;
|
|
14
25
|
declare function buildLabels(error: Error): string[];
|
|
15
|
-
declare function createGhIssue(title: string, body: string, labels: string[]):
|
|
26
|
+
declare function createGhIssue(title: string, body: string, labels: string[]): string;
|
|
16
27
|
declare function offerBugReport(error: Error): Promise<void>;
|
|
17
28
|
|
|
18
|
-
export { buildLabels, buildReportBody, buildTitle, createGhIssue, offerBugReport, setDeployContext };
|
|
29
|
+
export { buildCliFlagsSummary, buildLabels, buildReportBody, buildTitle, createGhIssue, getCapturedTail, installLogCapture, offerBugReport, scrubSecrets, setDeployContext };
|
package/dist/bug-report.js
CHANGED
|
@@ -1,121 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
buildCliFlagsSummary,
|
|
3
|
+
buildLabels,
|
|
4
|
+
buildReportBody,
|
|
5
|
+
buildTitle,
|
|
6
|
+
createGhIssue,
|
|
7
|
+
getCapturedTail,
|
|
8
|
+
installLogCapture,
|
|
9
|
+
offerBugReport,
|
|
10
|
+
scrubSecrets,
|
|
11
|
+
setDeployContext
|
|
12
|
+
} from "./chunk-LMSMDKVU.js";
|
|
13
|
+
import "./chunk-4UNQGG3O.js";
|
|
14
|
+
import "./chunk-4FUUYJP2.js";
|
|
9
15
|
import "./chunk-QGM4M3NI.js";
|
|
10
|
-
|
|
11
|
-
// src/bug-report.ts
|
|
12
|
-
import { execSync, execFileSync } from "child_process";
|
|
13
|
-
import * as os from "os";
|
|
14
|
-
var _deployContext = {};
|
|
15
|
-
function setDeployContext(ctx) {
|
|
16
|
-
_deployContext = { ..._deployContext, ...ctx };
|
|
17
|
-
}
|
|
18
|
-
function hasGhCli() {
|
|
19
|
-
try {
|
|
20
|
-
execSync("gh --version", { stdio: "pipe" });
|
|
21
|
-
return true;
|
|
22
|
-
} catch {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function buildReportBody(error) {
|
|
27
|
-
const lines = [
|
|
28
|
-
"## Environment",
|
|
29
|
-
"",
|
|
30
|
-
`- **bulletin-deploy**: ${VERSION}`,
|
|
31
|
-
`- **Node.js**: ${process.version}`,
|
|
32
|
-
`- **OS**: ${os.platform()} ${os.arch()} ${os.release()}`,
|
|
33
|
-
"",
|
|
34
|
-
"## Error",
|
|
35
|
-
"",
|
|
36
|
-
"```",
|
|
37
|
-
error.stack || error.message,
|
|
38
|
-
"```",
|
|
39
|
-
""
|
|
40
|
-
];
|
|
41
|
-
const ctx = _deployContext;
|
|
42
|
-
if (ctx.domain || ctx.repo || ctx.rpc) {
|
|
43
|
-
lines.push("## Deploy Context", "");
|
|
44
|
-
if (ctx.domain) lines.push(`- **Domain**: ${ctx.domain}`);
|
|
45
|
-
if (ctx.repo) lines.push(`- **Repo**: ${ctx.repo}`);
|
|
46
|
-
if (ctx.branch) lines.push(`- **Branch**: ${ctx.branch}`);
|
|
47
|
-
if (ctx.signerMode) lines.push(`- **Signer mode**: ${ctx.signerMode}`);
|
|
48
|
-
if (ctx.chunkCount != null) lines.push(`- **Chunks**: ${ctx.chunkCount}`);
|
|
49
|
-
if (ctx.totalSize) lines.push(`- **Total size**: ${ctx.totalSize}`);
|
|
50
|
-
if (ctx.rpc) lines.push(`- **RPC**: ${ctx.rpc}`);
|
|
51
|
-
if (ctx.sentryTraceId) lines.push(`- **Sentry trace**: ${ctx.sentryTraceId}`);
|
|
52
|
-
lines.push("");
|
|
53
|
-
}
|
|
54
|
-
return lines.join("\n");
|
|
55
|
-
}
|
|
56
|
-
function buildTitle(error) {
|
|
57
|
-
const msg = error.message.slice(0, 60);
|
|
58
|
-
return `[deploy-bug] ${msg}`;
|
|
59
|
-
}
|
|
60
|
-
function buildLabels(error) {
|
|
61
|
-
const labels = ["bug", "auto-report"];
|
|
62
|
-
const area = classifyErrorArea(error.message);
|
|
63
|
-
if (area) labels.push(area);
|
|
64
|
-
return labels;
|
|
65
|
-
}
|
|
66
|
-
function createGhIssue(title, body, labels) {
|
|
67
|
-
const args = [
|
|
68
|
-
"issue",
|
|
69
|
-
"create",
|
|
70
|
-
"--repo",
|
|
71
|
-
"paritytech/bulletin-deploy",
|
|
72
|
-
"--title",
|
|
73
|
-
title,
|
|
74
|
-
...labels.flatMap((l) => ["--label", l]),
|
|
75
|
-
"--body-file",
|
|
76
|
-
"-"
|
|
77
|
-
];
|
|
78
|
-
execFileSync("gh", args, { input: body, stdio: ["pipe", "inherit", "inherit"] });
|
|
79
|
-
}
|
|
80
|
-
async function offerBugReport(error) {
|
|
81
|
-
if (!isInteractive()) return;
|
|
82
|
-
const yes = await promptYesNo("\n This looks like a bug. Open an issue with debug info? [Y/n] ");
|
|
83
|
-
if (!yes) return;
|
|
84
|
-
const title = buildTitle(error);
|
|
85
|
-
const body = buildReportBody(error);
|
|
86
|
-
const labels = buildLabels(error);
|
|
87
|
-
if (hasGhCli()) {
|
|
88
|
-
try {
|
|
89
|
-
createGhIssue(title, body, labels);
|
|
90
|
-
console.error(" Issue created.");
|
|
91
|
-
} catch {
|
|
92
|
-
try {
|
|
93
|
-
console.error(" Retrying without labels...");
|
|
94
|
-
createGhIssue(title, body, []);
|
|
95
|
-
console.error(" Issue created (without labels).");
|
|
96
|
-
} catch {
|
|
97
|
-
console.error(" Failed to create issue. Debug info below:\n");
|
|
98
|
-
printFallback(title, body, labels);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
console.error("\n gh CLI not found. Debug info below \u2014 paste into a new issue:\n");
|
|
103
|
-
console.error(` https://github.com/paritytech/bulletin-deploy/issues/new
|
|
104
|
-
`);
|
|
105
|
-
printFallback(title, body, labels);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function printFallback(title, body, labels) {
|
|
109
|
-
console.error(` Title: ${title}`);
|
|
110
|
-
console.error(` Labels: ${labels.join(", ")}
|
|
111
|
-
`);
|
|
112
|
-
console.error(body);
|
|
113
|
-
}
|
|
114
16
|
export {
|
|
17
|
+
buildCliFlagsSummary,
|
|
115
18
|
buildLabels,
|
|
116
19
|
buildReportBody,
|
|
117
20
|
buildTitle,
|
|
118
21
|
createGhIssue,
|
|
22
|
+
getCapturedTail,
|
|
23
|
+
installLogCapture,
|
|
119
24
|
offerBugReport,
|
|
25
|
+
scrubSecrets,
|
|
120
26
|
setDeployContext
|
|
121
27
|
};
|
|
@@ -13,7 +13,7 @@ import * as path from "path";
|
|
|
13
13
|
// package.json
|
|
14
14
|
var package_default = {
|
|
15
15
|
name: "bulletin-deploy",
|
|
16
|
-
version: "0.7.
|
|
16
|
+
version: "0.7.2",
|
|
17
17
|
private: false,
|
|
18
18
|
repository: {
|
|
19
19
|
type: "git",
|
|
@@ -316,35 +316,41 @@ async function withDeploySpan(domain, fn) {
|
|
|
316
316
|
} finally {
|
|
317
317
|
sampleMemory("end");
|
|
318
318
|
if (memoryPeak) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
319
|
+
try {
|
|
320
|
+
const report = maybeWriteMemoryReport({
|
|
321
|
+
peak: sampleFromBytes(memoryPeak),
|
|
322
|
+
stages: stageSamples,
|
|
323
|
+
deploy: {
|
|
324
|
+
domain,
|
|
325
|
+
repo: attrs["deploy.repo"],
|
|
326
|
+
deployTag: attrs["deploy.tag"],
|
|
327
|
+
durationMs: Date.now() - deployStartMs,
|
|
328
|
+
sentryTraceId: span.spanContext?.().traceId,
|
|
329
|
+
...reportContext
|
|
330
|
+
},
|
|
331
|
+
outputDir: reportContext.outputDir,
|
|
332
|
+
onSentryAttach: (r) => {
|
|
333
|
+
try {
|
|
334
|
+
Sentry.captureMessage(`deploy memory threshold crossed (${r.threshold.peakRssMb} MB)`, {
|
|
335
|
+
level: "warning",
|
|
336
|
+
tags: { "deploy.mem.report": "1" },
|
|
337
|
+
extra: { memoryReport: r }
|
|
338
|
+
});
|
|
339
|
+
} catch {
|
|
340
|
+
}
|
|
339
341
|
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
console.log(`
|
|
342
|
+
});
|
|
343
|
+
if (report.status === "written") {
|
|
344
|
+
span.setAttribute("deploy.mem.report_written", "true");
|
|
345
|
+
span.setAttribute("deploy.mem.report_path", report.path);
|
|
346
|
+
console.log(`
|
|
346
347
|
High memory usage detected (peak ${report.peakRssMb} MB, threshold ${report.thresholdMb} MB).`);
|
|
347
|
-
|
|
348
|
+
console.log(` Diagnostic report written to ${report.path}`);
|
|
349
|
+
}
|
|
350
|
+
} catch (e) {
|
|
351
|
+
captureWarning("maybeWriteMemoryReport threw", {
|
|
352
|
+
error: e?.message?.slice(0, 200)
|
|
353
|
+
});
|
|
348
354
|
}
|
|
349
355
|
}
|
|
350
356
|
}
|
|
@@ -365,6 +371,12 @@ function setDeployAttribute(key, value) {
|
|
|
365
371
|
const span = Sentry.getActiveSpan();
|
|
366
372
|
if (span) span.setAttribute(key, value);
|
|
367
373
|
}
|
|
374
|
+
function getCurrentSentryTraceId() {
|
|
375
|
+
if (!Sentry) return void 0;
|
|
376
|
+
const span = Sentry.getActiveSpan();
|
|
377
|
+
if (!span) return void 0;
|
|
378
|
+
return span.spanContext?.().traceId;
|
|
379
|
+
}
|
|
368
380
|
function setDeploySentryTag(key, value) {
|
|
369
381
|
if (!Sentry) return;
|
|
370
382
|
Sentry.setTag(key, value);
|
|
@@ -385,10 +397,20 @@ async function flush() {
|
|
|
385
397
|
}
|
|
386
398
|
|
|
387
399
|
// src/memory-report.ts
|
|
400
|
+
function isBunRuntime() {
|
|
401
|
+
return typeof globalThis.Bun !== "undefined" || typeof process.versions.bun === "string";
|
|
402
|
+
}
|
|
388
403
|
var DEFAULT_THRESHOLD_MB = 1500;
|
|
389
404
|
function toMb2(bytes) {
|
|
390
405
|
return Math.round(bytes / 1024 / 1024 * 100) / 100;
|
|
391
406
|
}
|
|
407
|
+
function safeHeap(f) {
|
|
408
|
+
try {
|
|
409
|
+
return f();
|
|
410
|
+
} catch {
|
|
411
|
+
return void 0;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
392
414
|
function countByType(items) {
|
|
393
415
|
const counts = {};
|
|
394
416
|
for (const item of items) {
|
|
@@ -399,13 +421,17 @@ function countByType(items) {
|
|
|
399
421
|
}
|
|
400
422
|
function readActiveHandles() {
|
|
401
423
|
const proc = process;
|
|
402
|
-
|
|
403
|
-
|
|
424
|
+
return safeHeap(() => {
|
|
425
|
+
const handles = typeof proc._getActiveHandles === "function" ? proc._getActiveHandles() : [];
|
|
426
|
+
return countByType(handles);
|
|
427
|
+
}) ?? {};
|
|
404
428
|
}
|
|
405
429
|
function readActiveRequests() {
|
|
406
430
|
const proc = process;
|
|
407
|
-
|
|
408
|
-
|
|
431
|
+
return safeHeap(() => {
|
|
432
|
+
const reqs = typeof proc._getActiveRequests === "function" ? proc._getActiveRequests() : [];
|
|
433
|
+
return countByType(reqs);
|
|
434
|
+
}) ?? {};
|
|
409
435
|
}
|
|
410
436
|
function readPolkadotApiVersion() {
|
|
411
437
|
try {
|
|
@@ -432,8 +458,8 @@ function buildMemoryReport(input) {
|
|
|
432
458
|
deploy: input.deploy,
|
|
433
459
|
memory: { peak: input.peak, stages: input.stages },
|
|
434
460
|
v8: {
|
|
435
|
-
heapStatistics: v8.getHeapStatistics(),
|
|
436
|
-
heapSpaceStatistics: v8.getHeapSpaceStatistics()
|
|
461
|
+
heapStatistics: safeHeap(() => v8.getHeapStatistics()),
|
|
462
|
+
heapSpaceStatistics: safeHeap(() => v8.getHeapSpaceStatistics())
|
|
437
463
|
},
|
|
438
464
|
runtime: {
|
|
439
465
|
nodeVersion: process.version,
|
|
@@ -454,6 +480,9 @@ function maybeWriteMemoryReport(input) {
|
|
|
454
480
|
if (process.env.BULLETIN_DEPLOY_MEM_REPORT === "0") {
|
|
455
481
|
return { status: "disabled", thresholdMb, peakRssMb };
|
|
456
482
|
}
|
|
483
|
+
if (isBunRuntime()) {
|
|
484
|
+
return { status: "unsupported-runtime", thresholdMb, peakRssMb };
|
|
485
|
+
}
|
|
457
486
|
if (!Number.isFinite(thresholdMb) || peakRssMb < thresholdMb) {
|
|
458
487
|
return { status: "below-threshold", thresholdMb, peakRssMb };
|
|
459
488
|
}
|
|
@@ -482,7 +511,9 @@ function sampleFromBytes(m) {
|
|
|
482
511
|
}
|
|
483
512
|
|
|
484
513
|
export {
|
|
514
|
+
isBunRuntime,
|
|
485
515
|
DEFAULT_THRESHOLD_MB,
|
|
516
|
+
safeHeap,
|
|
486
517
|
buildMemoryReport,
|
|
487
518
|
maybeWriteMemoryReport,
|
|
488
519
|
sampleFromBytes,
|
|
@@ -504,6 +535,7 @@ export {
|
|
|
504
535
|
withDeploySpan,
|
|
505
536
|
setDeployReportContext,
|
|
506
537
|
setDeployAttribute,
|
|
538
|
+
getCurrentSentryTraceId,
|
|
507
539
|
setDeploySentryTag,
|
|
508
540
|
captureWarning,
|
|
509
541
|
flush
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import {
|
|
2
|
+
classifyErrorArea,
|
|
3
|
+
isInteractive,
|
|
4
|
+
promptYesNo
|
|
5
|
+
} from "./chunk-4UNQGG3O.js";
|
|
6
|
+
import {
|
|
7
|
+
VERSION,
|
|
8
|
+
getCurrentSentryTraceId
|
|
9
|
+
} from "./chunk-4FUUYJP2.js";
|
|
10
|
+
|
|
11
|
+
// src/bug-report.ts
|
|
12
|
+
import { execSync, execFileSync } from "child_process";
|
|
13
|
+
import * as os from "os";
|
|
14
|
+
var _deployContext = {};
|
|
15
|
+
function setDeployContext(ctx) {
|
|
16
|
+
_deployContext = { ..._deployContext, ...ctx };
|
|
17
|
+
}
|
|
18
|
+
function hasGhCli() {
|
|
19
|
+
try {
|
|
20
|
+
execSync("gh --version", { stdio: "pipe" });
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var LOG_TAIL_BYTES = 32 * 1024;
|
|
27
|
+
var _logBuffer = "";
|
|
28
|
+
var _logCaptureInstalled = false;
|
|
29
|
+
function installLogCapture() {
|
|
30
|
+
if (_logCaptureInstalled) return;
|
|
31
|
+
_logCaptureInstalled = true;
|
|
32
|
+
const append = (args) => {
|
|
33
|
+
const line = args.map((a) => typeof a === "string" ? a : safeStringify(a)).join(" ") + "\n";
|
|
34
|
+
_logBuffer += line;
|
|
35
|
+
if (_logBuffer.length > LOG_TAIL_BYTES * 2) {
|
|
36
|
+
_logBuffer = _logBuffer.slice(_logBuffer.length - LOG_TAIL_BYTES);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const wrap = (key) => {
|
|
40
|
+
const orig = console[key].bind(console);
|
|
41
|
+
console[key] = (...a) => {
|
|
42
|
+
append(a);
|
|
43
|
+
orig(...a);
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
wrap("log");
|
|
47
|
+
wrap("error");
|
|
48
|
+
wrap("warn");
|
|
49
|
+
}
|
|
50
|
+
function safeStringify(v) {
|
|
51
|
+
try {
|
|
52
|
+
if (v instanceof Error) return v.stack || v.message;
|
|
53
|
+
return JSON.stringify(v);
|
|
54
|
+
} catch {
|
|
55
|
+
return String(v);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function getCapturedTail() {
|
|
59
|
+
if (!_logBuffer) return "";
|
|
60
|
+
const tail = _logBuffer.length > LOG_TAIL_BYTES ? "\u2026 [truncated]\n" + _logBuffer.slice(_logBuffer.length - LOG_TAIL_BYTES) : _logBuffer;
|
|
61
|
+
return scrubSecrets(tail);
|
|
62
|
+
}
|
|
63
|
+
function scrubSecrets(text) {
|
|
64
|
+
if (!text) return text;
|
|
65
|
+
let out = text;
|
|
66
|
+
out = out.replace(/(--mnemonic(?:=|\s+))("[^"]*"|'[^']*'|\S+)/gi, "$1<REDACTED>");
|
|
67
|
+
out = out.replace(/(--password(?:=|\s+))("[^"]*"|'[^']*'|\S+)/gi, "$1<REDACTED>");
|
|
68
|
+
out = out.replace(/\b(MNEMONIC|PASSWORD|BULLETIN_MNEMONIC|GITHUB_TOKEN|GH_TOKEN|NPM_TOKEN|SENTRY_AUTH_TOKEN)=([^\s]+)/gi, "$1=<REDACTED>");
|
|
69
|
+
out = out.replace(/\b(ghp|ghs|gho|ghu|ghr)_[A-Za-z0-9]{20,}\b/g, "<REDACTED_TOKEN>");
|
|
70
|
+
out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "<REDACTED_TOKEN>");
|
|
71
|
+
out = out.replace(/\b(?:[a-z]{3,10}\s+){11}[a-z]{3,10}\b/g, "<REDACTED_MNEMONIC>");
|
|
72
|
+
out = out.replace(/([a-z][a-z0-9+.-]*:\/\/)[^:@\s]+:[^@\s]+@/gi, "$1<REDACTED>@");
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
function buildCliFlagsSummary(flags) {
|
|
76
|
+
const parts = [];
|
|
77
|
+
if (flags.bootstrap) parts.push("--bootstrap");
|
|
78
|
+
if (flags.jsMerkle) parts.push("--js-merkle");
|
|
79
|
+
if (flags.ghPagesMirror) parts.push("--gh-pages-mirror");
|
|
80
|
+
if (flags.poolSize != null) parts.push(`--pool-size ${String(flags.poolSize)}`);
|
|
81
|
+
if (typeof flags.tag === "string" && flags.tag) parts.push(`--tag ${flags.tag}`);
|
|
82
|
+
if (flags.mnemonic) parts.push("--mnemonic <set>");
|
|
83
|
+
if (flags.password) parts.push("--password <set>");
|
|
84
|
+
if (flags.derivationPath) parts.push("--derivation-path <set>");
|
|
85
|
+
if (typeof flags.rpc === "string" && flags.rpc) parts.push("--rpc <set>");
|
|
86
|
+
return parts.join(" ");
|
|
87
|
+
}
|
|
88
|
+
function buildReportBody(error) {
|
|
89
|
+
const lines = [
|
|
90
|
+
"## Environment",
|
|
91
|
+
"",
|
|
92
|
+
`- **bulletin-deploy**: ${VERSION}`,
|
|
93
|
+
`- **Node.js**: ${process.version}`,
|
|
94
|
+
`- **OS**: ${os.platform()} ${os.arch()} ${os.release()}`,
|
|
95
|
+
"",
|
|
96
|
+
"## Error",
|
|
97
|
+
"",
|
|
98
|
+
"```",
|
|
99
|
+
scrubSecrets(error.stack || error.message),
|
|
100
|
+
"```",
|
|
101
|
+
""
|
|
102
|
+
];
|
|
103
|
+
const ctx = _deployContext;
|
|
104
|
+
const traceId = getCurrentSentryTraceId();
|
|
105
|
+
const hasCtx = ctx.domain || ctx.repo || ctx.rpc || ctx.cliFlags || ctx.ci?.runUrl || traceId;
|
|
106
|
+
if (hasCtx) {
|
|
107
|
+
lines.push("## Deploy Context", "");
|
|
108
|
+
if (ctx.domain) lines.push(`- **Domain**: ${ctx.domain}`);
|
|
109
|
+
if (ctx.repo) lines.push(`- **Repo**: ${ctx.repo}`);
|
|
110
|
+
if (ctx.branch) lines.push(`- **Branch**: ${ctx.branch}`);
|
|
111
|
+
if (ctx.signerMode) lines.push(`- **Signer mode**: ${ctx.signerMode}`);
|
|
112
|
+
if (ctx.chunkCount != null) lines.push(`- **Chunks**: ${ctx.chunkCount}`);
|
|
113
|
+
if (ctx.totalSize) lines.push(`- **Total size**: ${ctx.totalSize}`);
|
|
114
|
+
if (ctx.rpc) lines.push(`- **RPC**: ${ctx.rpc}`);
|
|
115
|
+
if (ctx.deployTag) lines.push(`- **Deploy tag**: ${ctx.deployTag}`);
|
|
116
|
+
if (ctx.cliFlags) lines.push(`- **CLI flags**: \`${ctx.cliFlags}\``);
|
|
117
|
+
if (traceId) lines.push(`- **Sentry trace**: ${traceId}`);
|
|
118
|
+
lines.push("");
|
|
119
|
+
}
|
|
120
|
+
if (ctx.ci?.runUrl) {
|
|
121
|
+
lines.push("## CI", "");
|
|
122
|
+
lines.push(`- **Run**: ${ctx.ci.runUrl}`);
|
|
123
|
+
if (ctx.ci.workflow) lines.push(`- **Workflow**: ${ctx.ci.workflow}`);
|
|
124
|
+
if (ctx.ci.job) lines.push(`- **Job**: ${ctx.ci.job}`);
|
|
125
|
+
if (ctx.ci.sha) lines.push(`- **SHA**: ${ctx.ci.sha}`);
|
|
126
|
+
lines.push("");
|
|
127
|
+
}
|
|
128
|
+
const tail = getCapturedTail();
|
|
129
|
+
if (tail) {
|
|
130
|
+
lines.push("## Log tail", "", "<details><summary>Last ~32 KB of stdout/stderr (secrets scrubbed)</summary>", "", "```", tail.trimEnd(), "```", "", "</details>", "");
|
|
131
|
+
}
|
|
132
|
+
return lines.join("\n");
|
|
133
|
+
}
|
|
134
|
+
function buildTitle(error) {
|
|
135
|
+
const msg = error.message.slice(0, 60);
|
|
136
|
+
return `[deploy-bug] ${msg}`;
|
|
137
|
+
}
|
|
138
|
+
function buildLabels(error) {
|
|
139
|
+
const labels = ["bug", "auto-report"];
|
|
140
|
+
const area = classifyErrorArea(error.message);
|
|
141
|
+
if (area) labels.push(area);
|
|
142
|
+
return labels;
|
|
143
|
+
}
|
|
144
|
+
function createGhIssue(title, body, labels) {
|
|
145
|
+
const args = [
|
|
146
|
+
"issue",
|
|
147
|
+
"create",
|
|
148
|
+
"--repo",
|
|
149
|
+
"paritytech/bulletin-deploy",
|
|
150
|
+
"--title",
|
|
151
|
+
title,
|
|
152
|
+
...labels.flatMap((l) => ["--label", l]),
|
|
153
|
+
"--body-file",
|
|
154
|
+
"-"
|
|
155
|
+
];
|
|
156
|
+
const out = execFileSync("gh", args, { input: body, stdio: ["pipe", "pipe", "inherit"] });
|
|
157
|
+
return out.toString("utf8").trim();
|
|
158
|
+
}
|
|
159
|
+
function applyCoreLabels(issueUrl) {
|
|
160
|
+
try {
|
|
161
|
+
execFileSync(
|
|
162
|
+
"gh",
|
|
163
|
+
["issue", "edit", issueUrl, "--add-label", "bug", "--add-label", "auto-report"],
|
|
164
|
+
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
165
|
+
);
|
|
166
|
+
return true;
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function offerBugReport(error) {
|
|
172
|
+
if (!isInteractive()) return;
|
|
173
|
+
const yes = await promptYesNo("\n This looks like a bug. Open an issue with debug info? [Y/n] ");
|
|
174
|
+
if (!yes) return;
|
|
175
|
+
const title = buildTitle(error);
|
|
176
|
+
const body = buildReportBody(error);
|
|
177
|
+
const labels = buildLabels(error);
|
|
178
|
+
if (!hasGhCli()) {
|
|
179
|
+
console.error("\n gh CLI not found. Debug info below \u2014 paste into a new issue:\n");
|
|
180
|
+
console.error(` https://github.com/paritytech/bulletin-deploy/issues/new
|
|
181
|
+
`);
|
|
182
|
+
printFallback(title, body, labels);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
const url = createGhIssue(title, body, labels);
|
|
187
|
+
console.error(` Issue created: ${url}`);
|
|
188
|
+
return;
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
console.error(" Retrying without labels...");
|
|
193
|
+
const url = createGhIssue(title, body, []);
|
|
194
|
+
const applied = applyCoreLabels(url);
|
|
195
|
+
if (applied) {
|
|
196
|
+
console.error(` Issue created: ${url} (labels applied after retry)`);
|
|
197
|
+
} else {
|
|
198
|
+
console.error(` Issue created: ${url} (labels could not be applied; please add 'bug' and 'auto-report' manually)`);
|
|
199
|
+
}
|
|
200
|
+
} catch {
|
|
201
|
+
console.error(" Failed to create issue. Debug info below:\n");
|
|
202
|
+
printFallback(title, body, labels);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function printFallback(title, body, labels) {
|
|
206
|
+
console.error(` Title: ${title}`);
|
|
207
|
+
console.error(` Labels: ${labels.join(", ")}
|
|
208
|
+
`);
|
|
209
|
+
console.error(body);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export {
|
|
213
|
+
setDeployContext,
|
|
214
|
+
installLogCapture,
|
|
215
|
+
getCapturedTail,
|
|
216
|
+
scrubSecrets,
|
|
217
|
+
buildCliFlagsSummary,
|
|
218
|
+
buildReportBody,
|
|
219
|
+
buildTitle,
|
|
220
|
+
buildLabels,
|
|
221
|
+
createGhIssue,
|
|
222
|
+
offerBugReport
|
|
223
|
+
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setDeployContext
|
|
3
|
+
} from "./chunk-LMSMDKVU.js";
|
|
1
4
|
import {
|
|
2
5
|
DotNS,
|
|
3
6
|
TX_TIMEOUT_MS,
|
|
4
7
|
fetchNonce,
|
|
5
8
|
popStatusName,
|
|
6
9
|
validateDomainLabel
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-NEV6WTYM.js";
|
|
8
11
|
import {
|
|
9
12
|
MirrorSkipped,
|
|
10
13
|
mirrorToGitHubPages,
|
|
@@ -23,7 +26,7 @@ import {
|
|
|
23
26
|
truncateAddress,
|
|
24
27
|
withDeploySpan,
|
|
25
28
|
withSpan
|
|
26
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-4FUUYJP2.js";
|
|
27
30
|
import {
|
|
28
31
|
merkleizeJS
|
|
29
32
|
} from "./chunk-B7GUYYAN.js";
|
|
@@ -77,7 +80,7 @@ var POOL_SIZE = DEFAULT_POOL_SIZE;
|
|
|
77
80
|
var CHUNK_SIZE = 2 * 1024 * 1024;
|
|
78
81
|
var MAX_FILE_SIZE = 8 * 1024 * 1024;
|
|
79
82
|
var MAX_RECONNECTIONS = parseInt(process.env.BULLETIN_MAX_RECONNECTIONS ?? "3", 10);
|
|
80
|
-
var CHUNK_TIMEOUT_MS = parseInt(process.env.BULLETIN_CHUNK_TIMEOUT_MS ?? "
|
|
83
|
+
var CHUNK_TIMEOUT_MS = parseInt(process.env.BULLETIN_CHUNK_TIMEOUT_MS ?? "180000", 10);
|
|
81
84
|
var RETRY_BASE_DELAY_MS = 2e3;
|
|
82
85
|
var RETRY_MAX_DELAY_MS = 15e3;
|
|
83
86
|
var WS_HEARTBEAT_TIMEOUT_MS = 3e5;
|
|
@@ -616,6 +619,10 @@ async function storeDirectory(directoryPath, providerOrOptions = {}, password, j
|
|
|
616
619
|
carBytes: carContent.length,
|
|
617
620
|
outputDir: path.dirname(directoryPath)
|
|
618
621
|
});
|
|
622
|
+
setDeployContext({
|
|
623
|
+
chunkCount: carChunks.length,
|
|
624
|
+
totalSize: `${(carContent.length / 1024 / 1024).toFixed(2)} MB`
|
|
625
|
+
});
|
|
619
626
|
const carMb = String(Math.round(carContent.length / 1024 / 1024 * 100) / 100);
|
|
620
627
|
const storageCid = await withSpan("deploy.chunk-upload", "1b. chunk-upload", { "deploy.chunks.total": String(carChunks.length), "deploy.car.bytes": String(carContent.length), "deploy.car.mb": carMb }, async () => {
|
|
621
628
|
sampleMemory("chunk_upload_start");
|
package/dist/deploy.js
CHANGED
|
@@ -24,10 +24,12 @@ import {
|
|
|
24
24
|
storeChunkedContent,
|
|
25
25
|
storeDirectory,
|
|
26
26
|
storeFile
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import "./chunk-
|
|
27
|
+
} from "./chunk-VJLTIZ6S.js";
|
|
28
|
+
import "./chunk-LMSMDKVU.js";
|
|
29
|
+
import "./chunk-4UNQGG3O.js";
|
|
30
|
+
import "./chunk-NEV6WTYM.js";
|
|
29
31
|
import "./chunk-2Q2WSKFD.js";
|
|
30
|
-
import "./chunk-
|
|
32
|
+
import "./chunk-4FUUYJP2.js";
|
|
31
33
|
import "./chunk-B7GUYYAN.js";
|
|
32
34
|
import "./chunk-JHNW2EKY.js";
|
|
33
35
|
import "./chunk-QGM4M3NI.js";
|
package/dist/dotns.js
CHANGED
|
@@ -29,8 +29,8 @@ import {
|
|
|
29
29
|
simulateUserStatus,
|
|
30
30
|
stripTrailingDigits,
|
|
31
31
|
validateDomainLabel
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-NEV6WTYM.js";
|
|
33
|
+
import "./chunk-4FUUYJP2.js";
|
|
34
34
|
import "./chunk-JHNW2EKY.js";
|
|
35
35
|
import "./chunk-QGM4M3NI.js";
|
|
36
36
|
export {
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deploy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VJLTIZ6S.js";
|
|
4
|
+
import "./chunk-LMSMDKVU.js";
|
|
5
|
+
import "./chunk-4UNQGG3O.js";
|
|
4
6
|
import {
|
|
5
7
|
DotNS
|
|
6
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NEV6WTYM.js";
|
|
7
9
|
import "./chunk-2Q2WSKFD.js";
|
|
8
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-4FUUYJP2.js";
|
|
9
11
|
import {
|
|
10
12
|
merkleizeJS
|
|
11
13
|
} from "./chunk-B7GUYYAN.js";
|
package/dist/memory-report.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as v8 from 'node:v8';
|
|
2
2
|
|
|
3
|
+
declare function isBunRuntime(): boolean;
|
|
3
4
|
declare const DEFAULT_THRESHOLD_MB = 1500;
|
|
4
5
|
interface MemorySampleMb {
|
|
5
6
|
rssMb: number;
|
|
@@ -35,8 +36,8 @@ interface MemoryReport {
|
|
|
35
36
|
stages: Record<string, MemorySampleMb>;
|
|
36
37
|
};
|
|
37
38
|
v8: {
|
|
38
|
-
heapStatistics: ReturnType<typeof v8.getHeapStatistics
|
|
39
|
-
heapSpaceStatistics: ReturnType<typeof v8.getHeapSpaceStatistics
|
|
39
|
+
heapStatistics: ReturnType<typeof v8.getHeapStatistics> | undefined;
|
|
40
|
+
heapSpaceStatistics: ReturnType<typeof v8.getHeapSpaceStatistics> | undefined;
|
|
40
41
|
};
|
|
41
42
|
runtime: {
|
|
42
43
|
nodeVersion: string;
|
|
@@ -53,6 +54,7 @@ interface MemoryReport {
|
|
|
53
54
|
clientsCreated?: number;
|
|
54
55
|
};
|
|
55
56
|
}
|
|
57
|
+
declare function safeHeap<T>(f: () => T): T | undefined;
|
|
56
58
|
declare function buildMemoryReport(input: {
|
|
57
59
|
thresholdMb: number;
|
|
58
60
|
peak: MemorySampleMb;
|
|
@@ -76,7 +78,7 @@ interface MaybeWriteMemoryReportInput {
|
|
|
76
78
|
}
|
|
77
79
|
interface MemoryReportResult {
|
|
78
80
|
/** Why the report did/didn't fire. Useful for tests and CLI logging. */
|
|
79
|
-
status: "disabled" | "below-threshold" | "not-internal" | "written";
|
|
81
|
+
status: "disabled" | "below-threshold" | "not-internal" | "written" | "unsupported-runtime";
|
|
80
82
|
thresholdMb: number;
|
|
81
83
|
peakRssMb: number;
|
|
82
84
|
path?: string;
|
|
@@ -90,4 +92,4 @@ declare function sampleFromBytes(m: {
|
|
|
90
92
|
arrayBuffers: number;
|
|
91
93
|
}): MemorySampleMb;
|
|
92
94
|
|
|
93
|
-
export { DEFAULT_THRESHOLD_MB, type DeployContextForReport, type MaybeWriteMemoryReportInput, type MemoryReport, type MemoryReportResult, type MemorySampleMb, buildMemoryReport, maybeWriteMemoryReport, sampleFromBytes };
|
|
95
|
+
export { DEFAULT_THRESHOLD_MB, type DeployContextForReport, type MaybeWriteMemoryReportInput, type MemoryReport, type MemoryReportResult, type MemorySampleMb, buildMemoryReport, isBunRuntime, maybeWriteMemoryReport, safeHeap, sampleFromBytes };
|
package/dist/memory-report.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_THRESHOLD_MB,
|
|
3
3
|
buildMemoryReport,
|
|
4
|
+
isBunRuntime,
|
|
4
5
|
maybeWriteMemoryReport,
|
|
6
|
+
safeHeap,
|
|
5
7
|
sampleFromBytes
|
|
6
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-4FUUYJP2.js";
|
|
7
9
|
import "./chunk-QGM4M3NI.js";
|
|
8
10
|
export {
|
|
9
11
|
DEFAULT_THRESHOLD_MB,
|
|
10
12
|
buildMemoryReport,
|
|
13
|
+
isBunRuntime,
|
|
11
14
|
maybeWriteMemoryReport,
|
|
15
|
+
safeHeap,
|
|
12
16
|
sampleFromBytes
|
|
13
17
|
};
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -26,8 +26,9 @@ declare function setDeployReportContext(patch: Partial<DeployContextForReport> &
|
|
|
26
26
|
outputDir?: string;
|
|
27
27
|
}): void;
|
|
28
28
|
declare function setDeployAttribute(key: string, value: string | number | boolean): void;
|
|
29
|
+
declare function getCurrentSentryTraceId(): string | undefined;
|
|
29
30
|
declare function setDeploySentryTag(key: string, value: string): void;
|
|
30
31
|
declare function captureWarning(message: string, context?: Record<string, unknown>): void;
|
|
31
32
|
declare function flush(): Promise<void>;
|
|
32
33
|
|
|
33
|
-
export { type InternalContextSignals, VERSION, captureWarning, flush, getDeployAttributes, initTelemetry, isExpectedError, isInternalContext, isInternalContextFromSignals, resolveRepo, resolveRunner, resolveRunnerType, sampleMemory, sanitizeBranch, sanitizeRepo, scrubPaths, setDeployAttribute, setDeployReportContext, setDeploySentryTag, truncateAddress, withDeploySpan, withSpan };
|
|
34
|
+
export { type InternalContextSignals, VERSION, captureWarning, flush, getCurrentSentryTraceId, getDeployAttributes, initTelemetry, isExpectedError, isInternalContext, isInternalContextFromSignals, resolveRepo, resolveRunner, resolveRunnerType, sampleMemory, sanitizeBranch, sanitizeRepo, scrubPaths, setDeployAttribute, setDeployReportContext, setDeploySentryTag, truncateAddress, withDeploySpan, withSpan };
|
package/dist/telemetry.js
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
VERSION,
|
|
3
3
|
captureWarning,
|
|
4
4
|
flush,
|
|
5
|
+
getCurrentSentryTraceId,
|
|
5
6
|
getDeployAttributes,
|
|
6
7
|
initTelemetry,
|
|
7
8
|
isExpectedError,
|
|
@@ -20,12 +21,13 @@ import {
|
|
|
20
21
|
truncateAddress,
|
|
21
22
|
withDeploySpan,
|
|
22
23
|
withSpan
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-4FUUYJP2.js";
|
|
24
25
|
import "./chunk-QGM4M3NI.js";
|
|
25
26
|
export {
|
|
26
27
|
VERSION,
|
|
27
28
|
captureWarning,
|
|
28
29
|
flush,
|
|
30
|
+
getCurrentSentryTraceId,
|
|
29
31
|
getDeployAttributes,
|
|
30
32
|
initTelemetry,
|
|
31
33
|
isExpectedError,
|
package/dist/version-check.js
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
isPreReleaseVersion,
|
|
9
9
|
preReleaseWarning,
|
|
10
10
|
promptYesNo
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-4UNQGG3O.js";
|
|
12
|
+
import "./chunk-4FUUYJP2.js";
|
|
13
13
|
import "./chunk-QGM4M3NI.js";
|
|
14
14
|
export {
|
|
15
15
|
assessVersion,
|