bulletin-deploy 0.6.16 → 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/README.md +5 -20
- package/bin/bulletin-deploy +0 -3
- package/dist/bug-report.js +2 -2
- package/dist/{chunk-UZVOH3HB.js → chunk-2Q2WSKFD.js} +33 -3
- package/dist/{chunk-QILGABSF.js → chunk-B7GUYYAN.js} +22 -14
- package/dist/{chunk-K7TA53E2.js → chunk-G3YCSH44.js} +123 -365
- package/dist/{chunk-3C7PWPPG.js → chunk-OCOCVZQV.js} +4 -4
- package/dist/{chunk-BGLOVKHX.js → chunk-PA3AS7QR.js} +1 -1
- package/dist/{chunk-LF3XAUCI.js → chunk-Q42TQHNL.js} +193 -5
- package/dist/deploy.d.ts +17 -3
- package/dist/deploy.js +7 -5
- package/dist/dotns.js +2 -2
- package/dist/gh-pages-mirror.d.ts +25 -1
- package/dist/gh-pages-mirror.js +3 -1
- package/dist/index.js +5 -5
- package/dist/memory-report.d.ts +93 -0
- package/dist/memory-report.js +13 -0
- package/dist/merkle.js +1 -1
- package/dist/telemetry.d.ts +8 -1
- package/dist/telemetry.js +5 -1
- package/dist/version-check.js +2 -2
- package/package.json +3 -5
- package/cdm.json +0 -248
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// src/memory-report.ts
|
|
2
|
+
import * as fs2 from "fs";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import * as path2 from "path";
|
|
5
|
+
import * as v8 from "v8";
|
|
6
|
+
|
|
1
7
|
// src/telemetry.ts
|
|
2
8
|
import { execSync } from "child_process";
|
|
3
9
|
import { createHash } from "crypto";
|
|
@@ -7,7 +13,7 @@ import * as path from "path";
|
|
|
7
13
|
// package.json
|
|
8
14
|
var package_default = {
|
|
9
15
|
name: "bulletin-deploy",
|
|
10
|
-
version: "0.
|
|
16
|
+
version: "0.7.0",
|
|
11
17
|
private: false,
|
|
12
18
|
repository: {
|
|
13
19
|
type: "git",
|
|
@@ -31,11 +37,10 @@ var package_default = {
|
|
|
31
37
|
},
|
|
32
38
|
files: [
|
|
33
39
|
"dist",
|
|
34
|
-
"bin"
|
|
35
|
-
"cdm.json"
|
|
40
|
+
"bin"
|
|
36
41
|
],
|
|
37
42
|
scripts: {
|
|
38
|
-
build: "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts --format esm --dts --clean --target node22",
|
|
43
|
+
build: "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/memory-report.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts --format esm --dts --clean --target node22",
|
|
39
44
|
prepare: "npm run build",
|
|
40
45
|
test: "npm run build && node --test test/test.js test/pool.test.js test/helpers/e2e-helpers.test.js",
|
|
41
46
|
"test:e2e": "npm run build && node --test test/e2e.test.js",
|
|
@@ -45,7 +50,6 @@ var package_default = {
|
|
|
45
50
|
benchmark: "npm run build && node benchmark.js"
|
|
46
51
|
},
|
|
47
52
|
dependencies: {
|
|
48
|
-
"@dotdm/cdm": "^0.5.1",
|
|
49
53
|
"@ipld/car": "^5.4.3",
|
|
50
54
|
"@ipld/dag-pb": "^4.1.3",
|
|
51
55
|
"@noble/hashes": "^1.7.2",
|
|
@@ -244,11 +248,51 @@ async function withSpan(op, description, attributes, fn) {
|
|
|
244
248
|
}
|
|
245
249
|
});
|
|
246
250
|
}
|
|
251
|
+
var memoryPeak = null;
|
|
252
|
+
var deployRootSpan = null;
|
|
253
|
+
var stageSamples = {};
|
|
254
|
+
var reportContext = {};
|
|
255
|
+
function toMb(bytes) {
|
|
256
|
+
return Math.round(bytes / 1024 / 1024 * 100) / 100;
|
|
257
|
+
}
|
|
258
|
+
function sampleMemory(stage) {
|
|
259
|
+
if (!Sentry) return;
|
|
260
|
+
const m = process.memoryUsage();
|
|
261
|
+
const active = Sentry.getActiveSpan();
|
|
262
|
+
if (process.env.BULLETIN_DEPLOY_MEM_DEBUG) {
|
|
263
|
+
console.error(`[sampleMemory] stage=${stage} active=${active ? active.description ?? active.name ?? "?" : "null"} rss=${toMb(m.rss)}MB`);
|
|
264
|
+
}
|
|
265
|
+
if (active) {
|
|
266
|
+
active.setAttribute(`mem.${stage}.rss_mb`, String(toMb(m.rss)));
|
|
267
|
+
active.setAttribute(`mem.${stage}.heap_used_mb`, String(toMb(m.heapUsed)));
|
|
268
|
+
active.setAttribute(`mem.${stage}.external_mb`, String(toMb(m.external)));
|
|
269
|
+
active.setAttribute(`mem.${stage}.array_buffers_mb`, String(toMb(m.arrayBuffers)));
|
|
270
|
+
}
|
|
271
|
+
stageSamples[stage] = sampleFromBytes(m);
|
|
272
|
+
if (memoryPeak) {
|
|
273
|
+
if (m.rss > memoryPeak.rss) memoryPeak.rss = m.rss;
|
|
274
|
+
if (m.heapUsed > memoryPeak.heapUsed) memoryPeak.heapUsed = m.heapUsed;
|
|
275
|
+
if (m.external > memoryPeak.external) memoryPeak.external = m.external;
|
|
276
|
+
if (m.arrayBuffers > memoryPeak.arrayBuffers) memoryPeak.arrayBuffers = m.arrayBuffers;
|
|
277
|
+
if (deployRootSpan) {
|
|
278
|
+
deployRootSpan.setAttribute("deploy.mem.peak_rss_mb", String(toMb(memoryPeak.rss)));
|
|
279
|
+
deployRootSpan.setAttribute("deploy.mem.peak_heap_used_mb", String(toMb(memoryPeak.heapUsed)));
|
|
280
|
+
deployRootSpan.setAttribute("deploy.mem.peak_external_mb", String(toMb(memoryPeak.external)));
|
|
281
|
+
deployRootSpan.setAttribute("deploy.mem.peak_array_buffers_mb", String(toMb(memoryPeak.arrayBuffers)));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
247
285
|
async function withDeploySpan(domain, fn) {
|
|
248
286
|
if (!Sentry) return fn();
|
|
249
287
|
const attrs = { ...getDeployAttributes(domain), "deploy.domain": domain };
|
|
288
|
+
const m0 = process.memoryUsage();
|
|
289
|
+
memoryPeak = { rss: m0.rss, heapUsed: m0.heapUsed, external: m0.external, arrayBuffers: m0.arrayBuffers };
|
|
290
|
+
stageSamples = {};
|
|
291
|
+
reportContext = {};
|
|
292
|
+
const deployStartMs = Date.now();
|
|
250
293
|
try {
|
|
251
294
|
return await Sentry.startSpan({ op: "deploy", name: `deploy ${domain}`, attributes: attrs }, async (span) => {
|
|
295
|
+
deployRootSpan = span;
|
|
252
296
|
Sentry.setTags({
|
|
253
297
|
"deploy.repo": attrs["deploy.repo"],
|
|
254
298
|
"deploy.branch": attrs["deploy.branch"],
|
|
@@ -269,12 +313,53 @@ async function withDeploySpan(domain, fn) {
|
|
|
269
313
|
span.setStatus({ code: 2, message: "internal_error" });
|
|
270
314
|
}
|
|
271
315
|
throw error;
|
|
316
|
+
} finally {
|
|
317
|
+
sampleMemory("end");
|
|
318
|
+
if (memoryPeak) {
|
|
319
|
+
const report = maybeWriteMemoryReport({
|
|
320
|
+
peak: sampleFromBytes(memoryPeak),
|
|
321
|
+
stages: stageSamples,
|
|
322
|
+
deploy: {
|
|
323
|
+
domain,
|
|
324
|
+
repo: attrs["deploy.repo"],
|
|
325
|
+
deployTag: attrs["deploy.tag"],
|
|
326
|
+
durationMs: Date.now() - deployStartMs,
|
|
327
|
+
sentryTraceId: span.spanContext?.().traceId,
|
|
328
|
+
...reportContext
|
|
329
|
+
},
|
|
330
|
+
outputDir: reportContext.outputDir,
|
|
331
|
+
onSentryAttach: (r) => {
|
|
332
|
+
try {
|
|
333
|
+
Sentry.captureMessage(`deploy memory threshold crossed (${r.threshold.peakRssMb} MB)`, {
|
|
334
|
+
level: "warning",
|
|
335
|
+
tags: { "deploy.mem.report": "1" },
|
|
336
|
+
extra: { memoryReport: r }
|
|
337
|
+
});
|
|
338
|
+
} catch {
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
if (report.status === "written") {
|
|
343
|
+
span.setAttribute("deploy.mem.report_written", "true");
|
|
344
|
+
span.setAttribute("deploy.mem.report_path", report.path);
|
|
345
|
+
console.log(`
|
|
346
|
+
High memory usage detected (peak ${report.peakRssMb} MB, threshold ${report.thresholdMb} MB).`);
|
|
347
|
+
console.log(` Diagnostic report written to ${report.path}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
272
350
|
}
|
|
273
351
|
});
|
|
274
352
|
} finally {
|
|
353
|
+
memoryPeak = null;
|
|
354
|
+
deployRootSpan = null;
|
|
355
|
+
stageSamples = {};
|
|
356
|
+
reportContext = {};
|
|
275
357
|
await Sentry.flush(5e3);
|
|
276
358
|
}
|
|
277
359
|
}
|
|
360
|
+
function setDeployReportContext(patch) {
|
|
361
|
+
reportContext = { ...reportContext, ...patch };
|
|
362
|
+
}
|
|
278
363
|
function setDeployAttribute(key, value) {
|
|
279
364
|
if (!Sentry) return;
|
|
280
365
|
const span = Sentry.getActiveSpan();
|
|
@@ -299,7 +384,108 @@ async function flush() {
|
|
|
299
384
|
await Sentry.flush(5e3);
|
|
300
385
|
}
|
|
301
386
|
|
|
387
|
+
// src/memory-report.ts
|
|
388
|
+
var DEFAULT_THRESHOLD_MB = 1500;
|
|
389
|
+
function toMb2(bytes) {
|
|
390
|
+
return Math.round(bytes / 1024 / 1024 * 100) / 100;
|
|
391
|
+
}
|
|
392
|
+
function countByType(items) {
|
|
393
|
+
const counts = {};
|
|
394
|
+
for (const item of items) {
|
|
395
|
+
const name = item?.constructor?.name ?? "Unknown";
|
|
396
|
+
counts[name] = (counts[name] ?? 0) + 1;
|
|
397
|
+
}
|
|
398
|
+
return counts;
|
|
399
|
+
}
|
|
400
|
+
function readActiveHandles() {
|
|
401
|
+
const proc = process;
|
|
402
|
+
const handles = typeof proc._getActiveHandles === "function" ? proc._getActiveHandles() : [];
|
|
403
|
+
return countByType(handles);
|
|
404
|
+
}
|
|
405
|
+
function readActiveRequests() {
|
|
406
|
+
const proc = process;
|
|
407
|
+
const reqs = typeof proc._getActiveRequests === "function" ? proc._getActiveRequests() : [];
|
|
408
|
+
return countByType(reqs);
|
|
409
|
+
}
|
|
410
|
+
function readPolkadotApiVersion() {
|
|
411
|
+
try {
|
|
412
|
+
const candidates = [
|
|
413
|
+
path2.join(process.cwd(), "node_modules/polkadot-api/package.json"),
|
|
414
|
+
path2.join(process.cwd(), "../node_modules/polkadot-api/package.json")
|
|
415
|
+
];
|
|
416
|
+
for (const p of candidates) {
|
|
417
|
+
if (fs2.existsSync(p)) {
|
|
418
|
+
const pkg = JSON.parse(fs2.readFileSync(p, "utf-8"));
|
|
419
|
+
return typeof pkg.version === "string" ? pkg.version : void 0;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
} catch {
|
|
423
|
+
}
|
|
424
|
+
return void 0;
|
|
425
|
+
}
|
|
426
|
+
function buildMemoryReport(input) {
|
|
427
|
+
return {
|
|
428
|
+
schemaVersion: 1,
|
|
429
|
+
toolVersion: VERSION,
|
|
430
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
431
|
+
threshold: { thresholdMb: input.thresholdMb, peakRssMb: input.peak.rssMb },
|
|
432
|
+
deploy: input.deploy,
|
|
433
|
+
memory: { peak: input.peak, stages: input.stages },
|
|
434
|
+
v8: {
|
|
435
|
+
heapStatistics: v8.getHeapStatistics(),
|
|
436
|
+
heapSpaceStatistics: v8.getHeapSpaceStatistics()
|
|
437
|
+
},
|
|
438
|
+
runtime: {
|
|
439
|
+
nodeVersion: process.version,
|
|
440
|
+
platform: process.platform,
|
|
441
|
+
arch: process.arch,
|
|
442
|
+
totalMemMb: Math.round(os.totalmem() / 1024 / 1024),
|
|
443
|
+
freeMemMb: Math.round(os.freemem() / 1024 / 1024),
|
|
444
|
+
cpuCount: os.cpus().length,
|
|
445
|
+
activeHandlesByType: readActiveHandles(),
|
|
446
|
+
activeRequestsByType: readActiveRequests()
|
|
447
|
+
},
|
|
448
|
+
polkadotApi: { version: readPolkadotApiVersion() }
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
function maybeWriteMemoryReport(input) {
|
|
452
|
+
const thresholdMb = input.thresholdMbOverride ?? (process.env.BULLETIN_DEPLOY_MEM_REPORT_THRESHOLD_MB ? Number(process.env.BULLETIN_DEPLOY_MEM_REPORT_THRESHOLD_MB) : DEFAULT_THRESHOLD_MB);
|
|
453
|
+
const peakRssMb = input.peak.rssMb;
|
|
454
|
+
if (process.env.BULLETIN_DEPLOY_MEM_REPORT === "0") {
|
|
455
|
+
return { status: "disabled", thresholdMb, peakRssMb };
|
|
456
|
+
}
|
|
457
|
+
if (!Number.isFinite(thresholdMb) || peakRssMb < thresholdMb) {
|
|
458
|
+
return { status: "below-threshold", thresholdMb, peakRssMb };
|
|
459
|
+
}
|
|
460
|
+
const isInternal = input.isInternal ?? isInternalContext;
|
|
461
|
+
if (!isInternal()) {
|
|
462
|
+
return { status: "not-internal", thresholdMb, peakRssMb };
|
|
463
|
+
}
|
|
464
|
+
const report = buildMemoryReport({
|
|
465
|
+
thresholdMb,
|
|
466
|
+
peak: input.peak,
|
|
467
|
+
stages: input.stages,
|
|
468
|
+
deploy: input.deploy
|
|
469
|
+
});
|
|
470
|
+
const outDir = input.outputDir ?? process.cwd();
|
|
471
|
+
const filePath = path2.join(outDir, ".bulletin-memory-report.json");
|
|
472
|
+
const write = input.writeFile ?? ((p, c) => fs2.writeFileSync(p, c));
|
|
473
|
+
try {
|
|
474
|
+
write(filePath, JSON.stringify(report, null, 2));
|
|
475
|
+
} catch {
|
|
476
|
+
}
|
|
477
|
+
if (input.onSentryAttach) input.onSentryAttach(report);
|
|
478
|
+
return { status: "written", thresholdMb, peakRssMb, path: filePath };
|
|
479
|
+
}
|
|
480
|
+
function sampleFromBytes(m) {
|
|
481
|
+
return { rssMb: toMb2(m.rss), heapUsedMb: toMb2(m.heapUsed), externalMb: toMb2(m.external), arrayBuffersMb: toMb2(m.arrayBuffers) };
|
|
482
|
+
}
|
|
483
|
+
|
|
302
484
|
export {
|
|
485
|
+
DEFAULT_THRESHOLD_MB,
|
|
486
|
+
buildMemoryReport,
|
|
487
|
+
maybeWriteMemoryReport,
|
|
488
|
+
sampleFromBytes,
|
|
303
489
|
VERSION,
|
|
304
490
|
isInternalContextFromSignals,
|
|
305
491
|
isInternalContext,
|
|
@@ -314,7 +500,9 @@ export {
|
|
|
314
500
|
getDeployAttributes,
|
|
315
501
|
isExpectedError,
|
|
316
502
|
withSpan,
|
|
503
|
+
sampleMemory,
|
|
317
504
|
withDeploySpan,
|
|
505
|
+
setDeployReportContext,
|
|
318
506
|
setDeployAttribute,
|
|
319
507
|
setDeploySentryTag,
|
|
320
508
|
captureWarning,
|
package/dist/deploy.d.ts
CHANGED
|
@@ -50,13 +50,27 @@ declare function merkleize(directoryPath: string, outputCarPath: string): Promis
|
|
|
50
50
|
carPath: string;
|
|
51
51
|
cid: string;
|
|
52
52
|
}>;
|
|
53
|
-
declare function
|
|
53
|
+
declare function computeStorageCid(chunks: Uint8Array[]): string;
|
|
54
|
+
interface StoreDirectoryOptions {
|
|
55
|
+
provider?: ExistingProvider;
|
|
56
|
+
password?: string;
|
|
57
|
+
jsMerkle?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Fires exactly once, right after the CAR has been merkleized + encrypted
|
|
60
|
+
* and the final storage CID is known, but BEFORE the chunk upload to
|
|
61
|
+
* Bulletin starts. Use to kick off parallel side-effects (e.g. the
|
|
62
|
+
* gh-pages mirror) that can run concurrently with the slow upload. The
|
|
63
|
+
* returned promise is awaited at the end of the deploy; errors are passed
|
|
64
|
+
* through to the caller so they can decide fatal / non-fatal policy.
|
|
65
|
+
*/
|
|
66
|
+
onCarReady?: (carBytes: Uint8Array, storageCid: string) => Promise<void> | void;
|
|
67
|
+
}
|
|
68
|
+
declare function storeDirectory(directoryPath: string, providerOrOptions?: ExistingProvider | StoreDirectoryOptions, password?: string, jsMerkle?: boolean): Promise<{
|
|
54
69
|
storageCid: string;
|
|
55
70
|
ipfsCid: string;
|
|
56
71
|
carBytes: Uint8Array;
|
|
57
72
|
}>;
|
|
58
73
|
interface DeployOptions {
|
|
59
|
-
playground?: boolean;
|
|
60
74
|
mnemonic?: string;
|
|
61
75
|
/** Optional derivation path applied to the mnemonic (e.g. "//deploy/3"). Defaults to "" (root key). */
|
|
62
76
|
derivationPath?: string;
|
|
@@ -89,4 +103,4 @@ interface DeployOptions {
|
|
|
89
103
|
declare function estimateUploadBytes(content: DeployContent): Promise<number | null>;
|
|
90
104
|
declare function deploy(content: DeployContent, domainName?: string | null, options?: DeployOptions): Promise<DeployResult>;
|
|
91
105
|
|
|
92
|
-
export { DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, type DeployContent, type DeployOptions, type DeployResult, ENCRYPT_KEY_LEN, ENCRYPT_MAGIC, ENCRYPT_NONCE_LEN, ENCRYPT_PBKDF2_ITERATIONS, ENCRYPT_SALT_LEN, ENCRYPT_TAG_LEN, EXIT_CODE_NO_RETRY, NonRetryableError, chunk, createCID, deploy, deriveRootSigner, encodeContenthash, encryptContent, estimateUploadBytes, friendlyChainError, hasIPFS, isConnectionError, merkleize, storeChunkedContent, storeDirectory, storeFile };
|
|
106
|
+
export { DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, type DeployContent, type DeployOptions, type DeployResult, ENCRYPT_KEY_LEN, ENCRYPT_MAGIC, ENCRYPT_NONCE_LEN, ENCRYPT_PBKDF2_ITERATIONS, ENCRYPT_SALT_LEN, ENCRYPT_TAG_LEN, EXIT_CODE_NO_RETRY, NonRetryableError, type StoreDirectoryOptions, chunk, computeStorageCid, createCID, deploy, deriveRootSigner, encodeContenthash, encryptContent, estimateUploadBytes, friendlyChainError, hasIPFS, isConnectionError, merkleize, storeChunkedContent, storeDirectory, storeFile };
|
package/dist/deploy.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
EXIT_CODE_NO_RETRY,
|
|
11
11
|
NonRetryableError,
|
|
12
12
|
chunk,
|
|
13
|
+
computeStorageCid,
|
|
13
14
|
createCID,
|
|
14
15
|
deploy,
|
|
15
16
|
deriveRootSigner,
|
|
@@ -23,12 +24,12 @@ import {
|
|
|
23
24
|
storeChunkedContent,
|
|
24
25
|
storeDirectory,
|
|
25
26
|
storeFile
|
|
26
|
-
} from "./chunk-
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
27
|
+
} from "./chunk-G3YCSH44.js";
|
|
28
|
+
import "./chunk-OCOCVZQV.js";
|
|
29
|
+
import "./chunk-2Q2WSKFD.js";
|
|
30
|
+
import "./chunk-Q42TQHNL.js";
|
|
31
|
+
import "./chunk-B7GUYYAN.js";
|
|
30
32
|
import "./chunk-JHNW2EKY.js";
|
|
31
|
-
import "./chunk-LF3XAUCI.js";
|
|
32
33
|
import "./chunk-QGM4M3NI.js";
|
|
33
34
|
export {
|
|
34
35
|
DEFAULT_BULLETIN_RPC,
|
|
@@ -42,6 +43,7 @@ export {
|
|
|
42
43
|
EXIT_CODE_NO_RETRY,
|
|
43
44
|
NonRetryableError,
|
|
44
45
|
chunk,
|
|
46
|
+
computeStorageCid,
|
|
45
47
|
createCID,
|
|
46
48
|
deploy,
|
|
47
49
|
deriveRootSigner,
|
package/dist/dotns.js
CHANGED
|
@@ -29,9 +29,9 @@ import {
|
|
|
29
29
|
simulateUserStatus,
|
|
30
30
|
stripTrailingDigits,
|
|
31
31
|
validateDomainLabel
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-OCOCVZQV.js";
|
|
33
|
+
import "./chunk-Q42TQHNL.js";
|
|
33
34
|
import "./chunk-JHNW2EKY.js";
|
|
34
|
-
import "./chunk-LF3XAUCI.js";
|
|
35
35
|
import "./chunk-QGM4M3NI.js";
|
|
36
36
|
export {
|
|
37
37
|
CONNECTION_TIMEOUT_MS,
|
|
@@ -34,6 +34,30 @@ interface MirrorManifest {
|
|
|
34
34
|
declare class MirrorSkipped extends Error {
|
|
35
35
|
constructor(reason: string);
|
|
36
36
|
}
|
|
37
|
+
interface FreshnessPollResult {
|
|
38
|
+
verified: boolean;
|
|
39
|
+
attempts: number;
|
|
40
|
+
durationMs: number;
|
|
41
|
+
lastCid: string | null;
|
|
42
|
+
lastStatus: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Poll the mirror's manifest URL until its `cid` field equals the expected
|
|
46
|
+
* value. Pages is CDN-backed — a fresh commit may return HTTP 200 for
|
|
47
|
+
* several seconds to a few minutes while Fastly still serves stale bytes,
|
|
48
|
+
* so we can't just 200-check. Matching the manifest CID proves the edge
|
|
49
|
+
* has picked up the current deploy; the sibling .car URL is then guaranteed
|
|
50
|
+
* fresh for the same commit.
|
|
51
|
+
*
|
|
52
|
+
* Non-fatal to the deploy — returns `{ verified: false }` if the poll times
|
|
53
|
+
* out so the caller can log a warning without aborting a deploy whose
|
|
54
|
+
* on-chain state is already good.
|
|
55
|
+
*/
|
|
56
|
+
declare function pollMirrorFreshness(mirrorUrl: string, expectedCid: string, opts?: {
|
|
57
|
+
timeoutMs?: number;
|
|
58
|
+
intervalMs?: number;
|
|
59
|
+
fetchFn?: typeof fetch;
|
|
60
|
+
}): Promise<FreshnessPollResult>;
|
|
37
61
|
declare function parseGitRemoteUrl(url: string): {
|
|
38
62
|
owner: string;
|
|
39
63
|
repo: string;
|
|
@@ -48,4 +72,4 @@ declare function mirrorUrl(owner: string, repo: string, domainFilename: string):
|
|
|
48
72
|
declare function buildManifest(input: Omit<MirrorInput, "carBytes" | "repoPath" | "githubToken">): MirrorManifest;
|
|
49
73
|
declare function mirrorToGitHubPages(input: MirrorInput): Promise<MirrorResult>;
|
|
50
74
|
|
|
51
|
-
export { GH_PAGES_MIRROR_BRANCH, GH_PAGES_MIRROR_DIR, GH_PAGES_MIRROR_MAX_BYTES, type MirrorInput, type MirrorManifest, type MirrorResult, MirrorSkipped, buildManifest, mirrorToGitHubPages, mirrorUrl, normalizeDomainFilename, parseGitRemoteUrl, resolveOwnerRepo, resolveSourceCommit };
|
|
75
|
+
export { type FreshnessPollResult, GH_PAGES_MIRROR_BRANCH, GH_PAGES_MIRROR_DIR, GH_PAGES_MIRROR_MAX_BYTES, type MirrorInput, type MirrorManifest, type MirrorResult, MirrorSkipped, buildManifest, mirrorToGitHubPages, mirrorUrl, normalizeDomainFilename, parseGitRemoteUrl, pollMirrorFreshness, resolveOwnerRepo, resolveSourceCommit };
|
package/dist/gh-pages-mirror.js
CHANGED
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
mirrorUrl,
|
|
9
9
|
normalizeDomainFilename,
|
|
10
10
|
parseGitRemoteUrl,
|
|
11
|
+
pollMirrorFreshness,
|
|
11
12
|
resolveOwnerRepo,
|
|
12
13
|
resolveSourceCommit
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-2Q2WSKFD.js";
|
|
14
15
|
import "./chunk-QGM4M3NI.js";
|
|
15
16
|
export {
|
|
16
17
|
GH_PAGES_MIRROR_BRANCH,
|
|
@@ -22,6 +23,7 @@ export {
|
|
|
22
23
|
mirrorUrl,
|
|
23
24
|
normalizeDomainFilename,
|
|
24
25
|
parseGitRemoteUrl,
|
|
26
|
+
pollMirrorFreshness,
|
|
25
27
|
resolveOwnerRepo,
|
|
26
28
|
resolveSourceCommit
|
|
27
29
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deploy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-G3YCSH44.js";
|
|
4
4
|
import {
|
|
5
5
|
DotNS
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-OCOCVZQV.js";
|
|
7
|
+
import "./chunk-2Q2WSKFD.js";
|
|
8
|
+
import "./chunk-Q42TQHNL.js";
|
|
8
9
|
import {
|
|
9
10
|
merkleizeJS
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-B7GUYYAN.js";
|
|
11
12
|
import {
|
|
12
13
|
bootstrapPool,
|
|
13
14
|
derivePoolAccounts,
|
|
@@ -15,7 +16,6 @@ import {
|
|
|
15
16
|
fetchPoolAuthorizations,
|
|
16
17
|
selectAccount
|
|
17
18
|
} from "./chunk-JHNW2EKY.js";
|
|
18
|
-
import "./chunk-LF3XAUCI.js";
|
|
19
19
|
import "./chunk-QGM4M3NI.js";
|
|
20
20
|
export {
|
|
21
21
|
DotNS,
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as v8 from 'node:v8';
|
|
2
|
+
|
|
3
|
+
declare const DEFAULT_THRESHOLD_MB = 1500;
|
|
4
|
+
interface MemorySampleMb {
|
|
5
|
+
rssMb: number;
|
|
6
|
+
heapUsedMb: number;
|
|
7
|
+
externalMb: number;
|
|
8
|
+
arrayBuffersMb: number;
|
|
9
|
+
}
|
|
10
|
+
interface DeployContextForReport {
|
|
11
|
+
/** Sanitized domain label (sanitizeBranch equivalent). No dots. */
|
|
12
|
+
domain?: string;
|
|
13
|
+
/** Sanitized repo slug. Matches what the deploy span already carries. */
|
|
14
|
+
repo?: string;
|
|
15
|
+
deployTag?: string;
|
|
16
|
+
deployMode?: "pool" | "direct" | "external";
|
|
17
|
+
jsMerkle?: boolean;
|
|
18
|
+
chunkCount?: number;
|
|
19
|
+
carBytes?: number;
|
|
20
|
+
reconnects?: number;
|
|
21
|
+
durationMs?: number;
|
|
22
|
+
sentryTraceId?: string;
|
|
23
|
+
}
|
|
24
|
+
interface MemoryReport {
|
|
25
|
+
schemaVersion: 1;
|
|
26
|
+
toolVersion: string;
|
|
27
|
+
generatedAt: string;
|
|
28
|
+
threshold: {
|
|
29
|
+
thresholdMb: number;
|
|
30
|
+
peakRssMb: number;
|
|
31
|
+
};
|
|
32
|
+
deploy: DeployContextForReport;
|
|
33
|
+
memory: {
|
|
34
|
+
peak: MemorySampleMb;
|
|
35
|
+
stages: Record<string, MemorySampleMb>;
|
|
36
|
+
};
|
|
37
|
+
v8: {
|
|
38
|
+
heapStatistics: ReturnType<typeof v8.getHeapStatistics>;
|
|
39
|
+
heapSpaceStatistics: ReturnType<typeof v8.getHeapSpaceStatistics>;
|
|
40
|
+
};
|
|
41
|
+
runtime: {
|
|
42
|
+
nodeVersion: string;
|
|
43
|
+
platform: string;
|
|
44
|
+
arch: string;
|
|
45
|
+
totalMemMb: number;
|
|
46
|
+
freeMemMb: number;
|
|
47
|
+
cpuCount: number;
|
|
48
|
+
activeHandlesByType: Record<string, number>;
|
|
49
|
+
activeRequestsByType: Record<string, number>;
|
|
50
|
+
};
|
|
51
|
+
polkadotApi?: {
|
|
52
|
+
version?: string;
|
|
53
|
+
clientsCreated?: number;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
declare function buildMemoryReport(input: {
|
|
57
|
+
thresholdMb: number;
|
|
58
|
+
peak: MemorySampleMb;
|
|
59
|
+
stages: Record<string, MemorySampleMb>;
|
|
60
|
+
deploy: DeployContextForReport;
|
|
61
|
+
}): MemoryReport;
|
|
62
|
+
interface MaybeWriteMemoryReportInput {
|
|
63
|
+
peak: MemorySampleMb;
|
|
64
|
+
stages: Record<string, MemorySampleMb>;
|
|
65
|
+
deploy: DeployContextForReport;
|
|
66
|
+
/** Where to write the report file. Usually the build directory. */
|
|
67
|
+
outputDir?: string;
|
|
68
|
+
/** Override the default 1500 MB threshold (BULLETIN_DEPLOY_MEM_REPORT_THRESHOLD_MB). */
|
|
69
|
+
thresholdMbOverride?: number;
|
|
70
|
+
/** Hook for tests — defaults to isInternalContext(). */
|
|
71
|
+
isInternal?: () => boolean;
|
|
72
|
+
/** Hook for tests — defaults to real fs writes. */
|
|
73
|
+
writeFile?: (path: string, content: string) => void;
|
|
74
|
+
/** Hook for tests — receives the report when it would be attached to Sentry. */
|
|
75
|
+
onSentryAttach?: (report: MemoryReport) => void;
|
|
76
|
+
}
|
|
77
|
+
interface MemoryReportResult {
|
|
78
|
+
/** Why the report did/didn't fire. Useful for tests and CLI logging. */
|
|
79
|
+
status: "disabled" | "below-threshold" | "not-internal" | "written";
|
|
80
|
+
thresholdMb: number;
|
|
81
|
+
peakRssMb: number;
|
|
82
|
+
path?: string;
|
|
83
|
+
}
|
|
84
|
+
declare function maybeWriteMemoryReport(input: MaybeWriteMemoryReportInput): MemoryReportResult;
|
|
85
|
+
/** Convert a MemorySample with raw byte fields into the MB-shaped sample. */
|
|
86
|
+
declare function sampleFromBytes(m: {
|
|
87
|
+
rss: number;
|
|
88
|
+
heapUsed: number;
|
|
89
|
+
external: number;
|
|
90
|
+
arrayBuffers: number;
|
|
91
|
+
}): MemorySampleMb;
|
|
92
|
+
|
|
93
|
+
export { DEFAULT_THRESHOLD_MB, type DeployContextForReport, type MaybeWriteMemoryReportInput, type MemoryReport, type MemoryReportResult, type MemorySampleMb, buildMemoryReport, maybeWriteMemoryReport, sampleFromBytes };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_THRESHOLD_MB,
|
|
3
|
+
buildMemoryReport,
|
|
4
|
+
maybeWriteMemoryReport,
|
|
5
|
+
sampleFromBytes
|
|
6
|
+
} from "./chunk-Q42TQHNL.js";
|
|
7
|
+
import "./chunk-QGM4M3NI.js";
|
|
8
|
+
export {
|
|
9
|
+
DEFAULT_THRESHOLD_MB,
|
|
10
|
+
buildMemoryReport,
|
|
11
|
+
maybeWriteMemoryReport,
|
|
12
|
+
sampleFromBytes
|
|
13
|
+
};
|
package/dist/merkle.js
CHANGED
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { DeployContextForReport } from './memory-report.js';
|
|
2
|
+
import 'node:v8';
|
|
3
|
+
|
|
1
4
|
declare const VERSION: string;
|
|
2
5
|
interface InternalContextSignals {
|
|
3
6
|
githubRepository?: string;
|
|
@@ -17,10 +20,14 @@ declare function resolveRunnerType(): string;
|
|
|
17
20
|
declare function getDeployAttributes(domain: string): Record<string, string | number | boolean | undefined>;
|
|
18
21
|
declare function isExpectedError(msg: string): boolean;
|
|
19
22
|
declare function withSpan<T>(op: string, description: string, attributes: Record<string, string | number | boolean | undefined>, fn: () => T | Promise<T>): Promise<T>;
|
|
23
|
+
declare function sampleMemory(stage: string): void;
|
|
20
24
|
declare function withDeploySpan<T>(domain: string, fn: () => T | Promise<T>): Promise<T>;
|
|
25
|
+
declare function setDeployReportContext(patch: Partial<DeployContextForReport> & {
|
|
26
|
+
outputDir?: string;
|
|
27
|
+
}): void;
|
|
21
28
|
declare function setDeployAttribute(key: string, value: string | number | boolean): void;
|
|
22
29
|
declare function setDeploySentryTag(key: string, value: string): void;
|
|
23
30
|
declare function captureWarning(message: string, context?: Record<string, unknown>): void;
|
|
24
31
|
declare function flush(): Promise<void>;
|
|
25
32
|
|
|
26
|
-
export { type InternalContextSignals, VERSION, captureWarning, flush, getDeployAttributes, initTelemetry, isExpectedError, isInternalContext, isInternalContextFromSignals, resolveRepo, resolveRunner, resolveRunnerType, sanitizeBranch, sanitizeRepo, scrubPaths, setDeployAttribute, setDeploySentryTag, truncateAddress, withDeploySpan, withSpan };
|
|
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 };
|
package/dist/telemetry.js
CHANGED
|
@@ -10,15 +10,17 @@ import {
|
|
|
10
10
|
resolveRepo,
|
|
11
11
|
resolveRunner,
|
|
12
12
|
resolveRunnerType,
|
|
13
|
+
sampleMemory,
|
|
13
14
|
sanitizeBranch,
|
|
14
15
|
sanitizeRepo,
|
|
15
16
|
scrubPaths,
|
|
16
17
|
setDeployAttribute,
|
|
18
|
+
setDeployReportContext,
|
|
17
19
|
setDeploySentryTag,
|
|
18
20
|
truncateAddress,
|
|
19
21
|
withDeploySpan,
|
|
20
22
|
withSpan
|
|
21
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-Q42TQHNL.js";
|
|
22
24
|
import "./chunk-QGM4M3NI.js";
|
|
23
25
|
export {
|
|
24
26
|
VERSION,
|
|
@@ -32,10 +34,12 @@ export {
|
|
|
32
34
|
resolveRepo,
|
|
33
35
|
resolveRunner,
|
|
34
36
|
resolveRunnerType,
|
|
37
|
+
sampleMemory,
|
|
35
38
|
sanitizeBranch,
|
|
36
39
|
sanitizeRepo,
|
|
37
40
|
scrubPaths,
|
|
38
41
|
setDeployAttribute,
|
|
42
|
+
setDeployReportContext,
|
|
39
43
|
setDeploySentryTag,
|
|
40
44
|
truncateAddress,
|
|
41
45
|
withDeploySpan,
|
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-PA3AS7QR.js";
|
|
12
|
+
import "./chunk-Q42TQHNL.js";
|
|
13
13
|
import "./chunk-QGM4M3NI.js";
|
|
14
14
|
export {
|
|
15
15
|
assessVersion,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bulletin-deploy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,11 +24,10 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
|
-
"bin"
|
|
28
|
-
"cdm.json"
|
|
27
|
+
"bin"
|
|
29
28
|
],
|
|
30
29
|
"scripts": {
|
|
31
|
-
"build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts --format esm --dts --clean --target node22",
|
|
30
|
+
"build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/memory-report.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts --format esm --dts --clean --target node22",
|
|
32
31
|
"prepare": "npm run build",
|
|
33
32
|
"test": "npm run build && node --test test/test.js test/pool.test.js test/helpers/e2e-helpers.test.js",
|
|
34
33
|
"test:e2e": "npm run build && node --test test/e2e.test.js",
|
|
@@ -38,7 +37,6 @@
|
|
|
38
37
|
"benchmark": "npm run build && node benchmark.js"
|
|
39
38
|
},
|
|
40
39
|
"dependencies": {
|
|
41
|
-
"@dotdm/cdm": "^0.5.1",
|
|
42
40
|
"@ipld/car": "^5.4.3",
|
|
43
41
|
"@ipld/dag-pb": "^4.1.3",
|
|
44
42
|
"@noble/hashes": "^1.7.2",
|