-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathstorage.ts
More file actions
144 lines (136 loc) · 6.07 KB
/
Copy pathstorage.ts
File metadata and controls
144 lines (136 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/**
* Wrapper around `bulletin-deploy`'s `deploy()` that:
* - intercepts bulletin-deploy's `console.log` stream and turns it into
* typed progress events for the TUI,
* - surfaces bulletin-deploy's returned artifact IDs unchanged.
*
* Note: we deliberately do NOT pass `jsMerkle: true` — bulletin-deploy's
* pure-JS merkleizer drops DAG-PB structural blocks under the `rawLeaves`
* + `wrapWithDirectory` path we use, leaving deployed sites unparseable.
* We rely on the Kubo binary path (installed by `dot init`) until upstream
* fixes `merkleizeJS`. See the call site below and CLAUDE.md for context.
*
* All retry, nonce recovery, pool authorization, and DAG-PB verification
* stays inside bulletin-deploy — we do not reimplement any of it here.
*/
import {
deploy as bulletinDeploy,
type DeployContent,
type DeployOptions,
type DeployResult,
} from "bulletin-deploy";
import { DeployLogParser, type DeployLogEvent } from "./progress.js";
import { getChainConfig, type Env } from "../../config.js";
export interface StorageDeployOptions {
/**
* What to upload — a filesystem path (file or directory) or raw bytes.
* Matches bulletin-deploy's `DeployContent` type.
*/
content: DeployContent;
/**
* DotNS domain name (without `.dot`) or `null` to skip DotNS registration
* (used for the metadata JSON upload in the playground flow).
*/
domainName: string | null;
/**
* Auth options forwarded to bulletin-deploy. Usually produced by
* `resolveSignerSetup()`. May be `{}` for the dev path.
*/
auth: Pick<DeployOptions, "signer" | "signerAddress" | "mnemonic">;
/** Emits progress events derived from bulletin-deploy's log output. */
onLogEvent?: (event: DeployLogEvent) => void;
/** Target environment — currently only `testnet` is supported. */
env?: Env;
/**
* Extra telemetry attributes merged into bulletin-deploy's deploy span.
* Defaults to `{ "deploy.source": "playground-cli" }`.
*/
attributes?: Record<string, string>;
}
export async function runStorageDeploy(options: StorageDeployOptions): Promise<DeployResult> {
const cfg = getChainConfig(options.env);
const parser = new DeployLogParser();
const restore = interceptConsoleLog(options.onLogEvent, parser);
try {
return await bulletinDeploy(options.content, options.domainName, {
// Intentionally NOT setting `jsMerkle: true` — bulletin-deploy's
// pure-JS merkleizer (`merkleizeJS`) produces CARs that are
// missing their DAG-PB structural blocks (directory + file nodes)
// because `blockstore-core/memory`'s `getAll()` iterator drops
// them in the `rawLeaves: true` + `wrapWithDirectory: true` code
// path. We verified this against a real deployed CAR: 157 blocks,
// zero DAG-PB, declared root not in the blocks — polkadot-desktop
// parses zero files.
//
// Falling back to the Kubo binary path (default) produces a
// complete, parseable CAR. `dot init` installs `ipfs` so the
// binary is present on any machine that finished setup.
//
// Revisit when bulletin-deploy's `merkleizeJS` is fixed upstream
// — then flip `jsMerkle: true` back on for the WebContainer (RevX)
// story. See `src/utils/deploy/playground.ts` for an ongoing
// WebContainer-safe path for metadata upload.
rpc: cfg.bulletinRpc,
...options.auth,
attributes: {
"deploy.source": "playground-cli",
...options.attributes,
},
});
} finally {
restore();
}
}
/**
* Replace `console.log` / `console.error` / `console.warn` with a shim that
* feeds each line into the progress parser. Returns a `restore()` that puts
* the originals back — always call it from a `finally` block.
*
* We silence the direct prints because the TUI renders its own view derived
* from the parsed events. If there is no `onLogEvent` sink we still parse
* but emit nothing, so pool/DotNS log noise doesn't leak into the Ink render.
*
* `DOT_DEPLOY_VERBOSE=1`: in addition to parsing, write every bulletin-deploy
* log line to stderr prefixed with a `[+<seconds>s]` timestamp. This is the
* diagnostic path for OOM / freeze reports — you get the exact last line
* bulletin-deploy managed to print before the process froze, plus timing for
* every chunk state transition (`broadcasting` → `included` → `finalized`).
* Combine with `DOT_MEMORY_TRACE=1` to correlate log events with RSS growth.
*/
function interceptConsoleLog(
onEvent: ((event: DeployLogEvent) => void) | undefined,
parser: DeployLogParser,
): () => void {
const originalLog = console.log;
const originalWarn = console.warn;
const originalError = console.error;
const verbose = process.env.DOT_DEPLOY_VERBOSE === "1";
const started = Date.now();
const feed = (parts: unknown[]) => {
const combined = parts.map((p) => (typeof p === "string" ? p : String(p))).join(" ");
if (verbose) {
const elapsed = ((Date.now() - started) / 1000).toFixed(1);
process.stderr.write(`[+${elapsed}s] ${combined}\n`);
}
for (const line of combined.split("\n")) {
const event = parser.feed(line);
if (event && onEvent) onEvent(event);
}
};
console.log = (...args: unknown[]) => feed(args);
console.warn = (...args: unknown[]) => feed(args);
// bulletin-deploy only prints errors on the sad path; keep them visible on
// stderr so diagnostics don't disappear if something unexpected happens.
// In verbose mode `feed()` already wrote to stderr — skip the double-print.
console.error = (...args: unknown[]) => {
feed(args);
if (!verbose) {
originalError.apply(console, args as Parameters<typeof console.error>);
}
};
return () => {
console.log = originalLog;
console.warn = originalWarn;
console.error = originalError;
};
}