bulletin-deploy 0.7.27 → 0.7.28-rc.1

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.
Files changed (52) hide show
  1. package/README.md +10 -0
  2. package/assets/environments.json +2 -1
  3. package/bin/bulletin-deploy +136 -7
  4. package/dist/bug-report.js +4 -4
  5. package/dist/{chunk-I7YT2IAO.js → chunk-5DKLSM7C.js} +5 -2
  6. package/dist/{chunk-AXIJLJZK.js → chunk-FOPTSHK2.js} +1 -1
  7. package/dist/chunk-GQAKFSMZ.js +164 -0
  8. package/dist/chunk-GZD2UFLR.js +8 -0
  9. package/dist/{chunk-TILLNN33.js → chunk-KP64NWAS.js} +372 -30
  10. package/dist/chunk-LZJMVPYW.js +156 -0
  11. package/dist/{chunk-W4R7HNRX.js → chunk-MEC7GWLJ.js} +1 -1
  12. package/dist/chunk-MMAZFJDG.js +91 -0
  13. package/dist/{chunk-MGU5I7H5.js → chunk-OITUIM2E.js} +2 -1
  14. package/dist/{chunk-6TIWKKDS.js → chunk-PJCHSHMU.js} +4 -3
  15. package/dist/chunk-RI3ZLNPN.js +71 -0
  16. package/dist/{chunk-FW4HEUMH.js → chunk-SJKPP7KA.js} +2 -2
  17. package/dist/{chunk-JIKWTM5P.js → chunk-VUHKPUWQ.js} +66 -8
  18. package/dist/chunk-probe.js +3 -3
  19. package/dist/deploy.d.ts +23 -5
  20. package/dist/deploy.js +12 -10
  21. package/dist/dotns.d.ts +130 -1
  22. package/dist/dotns.js +14 -4
  23. package/dist/environments.js +1 -1
  24. package/dist/index.d.ts +5 -0
  25. package/dist/index.js +42 -8
  26. package/dist/manifest/byte-budget.d.ts +46 -0
  27. package/dist/manifest/byte-budget.js +14 -0
  28. package/dist/manifest/config-load.d.ts +36 -0
  29. package/dist/manifest/config-load.js +10 -0
  30. package/dist/manifest/publish.d.ts +54 -0
  31. package/dist/manifest/publish.js +23 -0
  32. package/dist/manifest/schema.d.ts +29 -0
  33. package/dist/manifest/schema.js +10 -0
  34. package/dist/manifest/types.d.ts +90 -0
  35. package/dist/manifest/types.js +6 -0
  36. package/dist/memory-report.js +2 -2
  37. package/dist/merkle.js +8 -8
  38. package/dist/personhood/bind-paid-alias.js +2 -2
  39. package/dist/personhood/bind-personal-id.js +2 -2
  40. package/dist/personhood/bootstrap.js +12 -12
  41. package/dist/personhood/claim-pgas.js +2 -2
  42. package/dist/personhood/member-key.js +2 -2
  43. package/dist/personhood/people-client.js +4 -4
  44. package/dist/personhood/reprove.js +5 -5
  45. package/dist/run-state.js +1 -1
  46. package/dist/telemetry.js +2 -2
  47. package/dist/version-check.js +3 -3
  48. package/package.json +4 -3
  49. package/dist/{chunk-74ETPOKH.js → chunk-2VAUMZB2.js} +5 -5
  50. package/dist/{chunk-QHOZEY5X.js → chunk-5VZQ2KSU.js} +7 -7
  51. package/dist/{chunk-EJ5TNGAY.js → chunk-BMAEWZYV.js} +3 -3
  52. package/dist/{chunk-A5IQ5MKO.js → chunk-IDYGYIMH.js} +3 -3
package/README.md CHANGED
@@ -215,6 +215,16 @@ await deploy("./dist", "my-app00.dot", { jsMerkle: true });
215
215
  | `IPFS CLI not installed` | Install Kubo or switch to `--js-merkle`. |
216
216
  | Previous deploy did not exit cleanly / OOM hint | Retry with a larger Node heap, for example `NODE_OPTIONS='--max-old-space-size=8192'`. |
217
217
 
218
+ ## Contributing
219
+
220
+ New to the codebase? Start with **[ONBOARDING.md](ONBOARDING.md)** — it covers install, the mental model, the first task, and the working conventions for this repo (worktree-per-branch, squash-merge policy, never-delete-tests, where the per-directory rules live).
221
+
222
+ The team uses Claude Code as a primary tool. The repo ships team-shared Claude configuration: `.claude/skills/` (project-specific commands like `/e2e-local`, `/dotns-diagnose`, `/sentry-query`), `.claude/settings.json` (Bash allowlist), and per-directory `CLAUDE.md` files in `src/`, `sentry/`, `test/`, `tools/` that load on demand. Running `claude` inside this repo picks all of that up automatically.
223
+
224
+ Already have Claude Code installed? Clone, `npm install`, open `ONBOARDING.md`. New to Claude Code itself? The same doc covers install.
225
+
226
+ For maintainers and engineers familiar with the release flow, the canonical procedures live in the root [`CLAUDE.md`](CLAUDE.md): change workflow, dual-stage RC → stable release, post-release Sentry monitoring, and the squash-merge convention that satisfies branch protection without per-commit GPG signing.
227
+
218
228
  ## More Docs
219
229
 
220
230
  - [Bootstrap and operator setup](docs/bootstrap.md)
@@ -80,7 +80,8 @@
80
80
  "POP_RULES": "0x2002C1c15b88632Ad01c7770f6EbE1Ca05c8472E",
81
81
  "STORE_FACTORY": "0x0DE5De70d61cc6b44B45d6595afDe8dB9b55bc31",
82
82
  "LABEL_STORE_BEACON": "0xD033F7Ada687E8BC776928AB239505F9f0479Ce7",
83
- "USER_STORE_BEACON": "0x7eD9b7D137Fa535965048F93b3B0248fEd2fcd32"
83
+ "USER_STORE_BEACON": "0x7eD9b7D137Fa535965048F93b3B0248fEd2fcd32",
84
+ "PUBLISHER": "0x1307fc02d308f879a16b1ae3a49b4927aed53649"
84
85
  }
85
86
  },
86
87
  {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXIT_CODE_NO_RETRY, isConnectionError } from "../dist/deploy.js";
3
+ import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE, NonRetryableError, EXIT_CODE_NO_RETRY, isConnectionError, unpublish } from "../dist/deploy.js";
4
4
  import { VERSION, setDeployAttribute, captureWarning, closeTelemetry, setRunStateActive, markRelaunchOomHintShown } from "../dist/telemetry.js";
5
5
  import { handleFailedDeploy, handlePreflightVersionCheck, fetchVersionInfo, preReleaseWarning, checkNodeVersion } from "../dist/version-check.js";
6
6
  import { setDeployContext, installLogCapture, buildCliFlagsSummary } from "../dist/bug-report.js";
@@ -36,19 +36,26 @@ for (let i = 0; i < args.length; i++) {
36
36
  else if (args[i] === "--js-merkle") { flags.jsMerkle = true; }
37
37
  else if (args[i] === "--input-car") { flags.inputCar = args[++i]; }
38
38
  else if (args[i] === "--tag") { flags.tag = args[++i]; }
39
- else if (args[i] === "--name") { flags.name = args[++i]; }
40
- else if (args[i] === "--description") { flags.description = args[++i]; }
39
+ else if (args[i] === "--config") { flags.config = args[++i]; }
41
40
  else if (args[i] === "--gh-pages-mirror") { flags.ghPagesMirror = true; }
42
41
  else if (args[i] === "--allow-large-deploy") { flags.allowLargeDeploy = true; }
43
42
  else if (args[i] === "--reproducible") { flags.reproducibleSource = "commit"; }
44
43
  else if (args[i].startsWith("--reproducible=")) { flags.reproducibleSource = args[i].slice("--reproducible=".length); }
45
44
  else if (args[i] === "--dump-car") { flags.dumpCar = true; }
46
45
  else if (args[i].startsWith("--dump-car=")) { flags.dumpCar = args[i].slice("--dump-car=".length); }
46
+ else if (args[i] === "--publish") { flags.publish = true; }
47
+ else if (args[i] === "--unpublish") { flags.unpublish = true; }
48
+ else if (args[i] === "--fail-on-publish-error") { flags.failOnPublishError = true; }
47
49
  else if (args[i] === "--version" || args[i] === "-V") { flags.version = true; }
48
50
  else if (args[i] === "--help" || args[i] === "-h") { flags.help = true; }
49
51
  else { positional.push(args[i]); }
50
52
  }
51
53
 
54
+ if (flags.publish && flags.unpublish) {
55
+ console.error("Error: --publish and --unpublish are mutually exclusive.");
56
+ process.exit(1);
57
+ }
58
+
52
59
  if (flags.version) {
53
60
  console.log(`bulletin-deploy v${VERSION}`);
54
61
  process.exit(0);
@@ -72,7 +79,74 @@ if (flags.listEnvironments) {
72
79
  }
73
80
  }
74
81
 
82
+ if (flags.unpublish) {
83
+ if (!flags.mnemonic && !process.env.MNEMONIC) {
84
+ console.error("Error: --unpublish requires --mnemonic (or MNEMONIC env var).");
85
+ process.exit(1);
86
+ }
87
+ const [domain] = positional;
88
+ if (!domain) {
89
+ console.error("Error: --unpublish requires a domain (e.g. my-app.dot)");
90
+ process.exit(1);
91
+ }
92
+ try {
93
+ const result = await unpublish(domain, {
94
+ mnemonic: flags.mnemonic,
95
+ derivationPath: flags.derivationPath,
96
+ rpc: flags.rpc,
97
+ env: flags.env,
98
+ });
99
+ console.log(`Domain: ${result.domainName}`);
100
+ console.log(`Status: ${result.status}`);
101
+ process.exit(0);
102
+ } catch (e) {
103
+ console.error(`Unpublish failed:`, e?.message ?? e);
104
+ process.exit(1);
105
+ }
106
+ }
75
107
 
108
+ // `product` subcommand. Only `validate` is wired today. `publish` and `resolve` arrive in later phases.
109
+ if (positional[0] === "product") {
110
+ const verb = positional[1];
111
+ if (verb === "validate") {
112
+ try {
113
+ const { loadProductConfig, pessimisticSizePreflight, getTextRecordBudgetBytes } =
114
+ await import("../dist/index.js");
115
+ const explicitPath = positional[2];
116
+ const { config, sourcePath } = explicitPath
117
+ ? await loadProductConfig({ path: explicitPath })
118
+ : await loadProductConfig();
119
+ console.log(`✓ Loaded ${sourcePath}`);
120
+ console.log(`✓ Schema ${config.domain} (${config.executables.length} executable${config.executables.length === 1 ? "" : "s"})`);
121
+ const budget = getTextRecordBudgetBytes();
122
+ const report = pessimisticSizePreflight(config, budget);
123
+ for (const check of report.checks) {
124
+ const tag = check.ok ? "✓" : "✗";
125
+ console.log(`${tag} ${check.key.padEnd(40)} ${check.bytes} B / ${check.budget} B`);
126
+ }
127
+ if (!report.ok) {
128
+ console.error("Pessimistic size preflight failed — at least one manifest exceeds the dotNS text-record budget.");
129
+ process.exit(EXIT_CODE_NO_RETRY);
130
+ }
131
+ console.log("Validate complete.");
132
+ process.exit(0);
133
+ } catch (err) {
134
+ console.error(`Error: ${err?.message ?? err}`);
135
+ process.exit(err instanceof NonRetryableError ? EXIT_CODE_NO_RETRY : 1);
136
+ }
137
+ }
138
+ if (verb === "publish" || verb === "resolve") {
139
+ console.error(`'product ${verb}' is not implemented yet (planned for a later phase).`);
140
+ process.exit(2);
141
+ }
142
+ console.error(`Unknown product subcommand: ${verb ?? "(none)"}. Try: bulletin-deploy product validate [<config-path>]`);
143
+ process.exit(2);
144
+ }
145
+
146
+ if (flags.publish && !flags.mnemonic && !process.env.MNEMONIC) {
147
+ console.error("Error: --publish requires --mnemonic (or MNEMONIC env var).");
148
+ process.exit(1);
149
+ }
76
150
 
77
151
  if (flags.help || positional.length === 0) {
78
152
  console.log(`bulletin-deploy v${VERSION}
@@ -97,10 +171,23 @@ Options:
97
171
  --dump-car[=<path>] Save the pre-upload CAR file to disk. Default path: <buildDir>.bulletin.car.
98
172
  Override path with =<path>. Also settable via BULLETIN_DEPLOY_DUMP_CAR env var.
99
173
  --tag "..." Label deploy in telemetry (or set DEPLOY_TAG env var); see Telemetry in README
100
- --name "..." Optional. Sets the "name" text record on the domain.
101
- --description "..." Optional. Sets the "description" text record (≤100 chars recommended).
174
+ --config <path> Explicit path to a bulletin-deploy.config.ts (default: walk up from
175
+ <build-dir> looking for bulletin-deploy.config.{ts,js,mjs}). When a
176
+ config is found, deploy ALSO writes the manifest + executable text
177
+ records on <domain> and its app/widget/worker subnames.
102
178
  --gh-pages-mirror After deploy, push the CAR to the current repo's gh-pages branch
103
179
  at bulletin/<domain>.dot.car (opt-in; also set GH_PAGES_MIRROR=1)
180
+ --publish After deploy, list <domain> in the on-chain Publisher
181
+ registry (Publisher.publish). Only takes effect on envs
182
+ with a deployed Publisher (currently: paseo-next-v2).
183
+ Requires --mnemonic (the signer must own the label).
184
+ --unpublish Standalone mode: removes <domain> from the Publisher
185
+ registry (Publisher.unpublish). Skips the deploy.
186
+ Usage: bulletin-deploy --unpublish <domain.dot>
187
+ Requires --mnemonic. Mutually exclusive with --publish.
188
+ --fail-on-publish-error
189
+ Exit non-zero if --publish fails after a successful deploy.
190
+ Default: non-fatal (warning logged, exit 0).
104
191
  --version Show version
105
192
  --help Show this help`);
106
193
  process.exit(0);
@@ -269,11 +356,11 @@ try {
269
356
  inputCar: flags.inputCar,
270
357
  tag: flags.tag,
271
358
  ghPagesMirror: flags.ghPagesMirror,
272
- name: flags.name,
273
- description: flags.description,
274
359
  allowLargeDeploy: flags.allowLargeDeploy,
275
360
  reproducibleSource: flags.reproducibleSource,
276
361
  dumpCar: flags.dumpCar,
362
+ publish: flags.publish,
363
+ failOnPublishError: flags.failOnPublishError,
277
364
  });
278
365
 
279
366
  const output = process.env.GITHUB_OUTPUT;
@@ -285,6 +372,48 @@ try {
285
372
  console.log(`CID: ${result.cid}`);
286
373
  console.log(`Domain: ${result.domainName}`);
287
374
 
375
+ // Opt-in manifest publish on top of the legacy contenthash deploy.
376
+ //
377
+ // Walks up from <build-dir> (or honours --config) looking for
378
+ // bulletin-deploy.config.{ts,js,mjs}. When found, writes the root + per-
379
+ // executable text records, otherwise the legacy flow returns unchanged.
380
+ {
381
+ const { tryLoadProductConfig, publishManifest } = await import("../dist/index.js");
382
+ const path = await import("node:path");
383
+ const buildDirAbs = path.resolve(buildDir);
384
+ const loaded = await tryLoadProductConfig(
385
+ flags.config ? { path: flags.config } : { cwd: buildDirAbs, walkUp: true },
386
+ );
387
+ if (loaded) {
388
+ try {
389
+ await publishManifest({
390
+ loaded,
391
+ domain,
392
+ buildDirCid: { absPath: buildDirAbs, cid: result.cid },
393
+ env: flags.env,
394
+ rpc: flags.rpc,
395
+ mnemonic: flags.mnemonic,
396
+ derivationPath: flags.derivationPath,
397
+ });
398
+ } catch (err) {
399
+ console.error(`Manifest publish failed: ${err?.message ?? err}`);
400
+ process.exit(err instanceof NonRetryableError ? EXIT_CODE_NO_RETRY : 1);
401
+ }
402
+ } else {
403
+ const where = flags.config
404
+ ? `--config ${flags.config}`
405
+ : `bulletin-deploy.config.{ts,js,mjs} via walking up from ${buildDirAbs}`;
406
+ console.log("");
407
+ console.log(`⚠ No bulletin-deploy.config.ts found (${where}).`);
408
+ console.log(` ${domain} was published as legacy contenthash only.`);
409
+ console.log(" Add a bulletin-deploy.config.ts to enable the product manifest:");
410
+ console.log(" • product icon, displayName, description on the base name");
411
+ console.log(" • per-modality subnames (app.<id>.dot, widget.<id>.dot, worker.<id>.dot)");
412
+ console.log(" • each modality’s archive CID on its subname contenthash");
413
+ console.log(" See: https://github.com/paritytech/triangle-js-sdks (Product Manifest RFC)");
414
+ }
415
+ }
416
+
288
417
  if (!flags.help && !flags.version) {
289
418
  try { writeRunState({ status: "succeeded", endedAt: Date.now() }); } catch {}
290
419
  }
@@ -9,10 +9,10 @@ import {
9
9
  offerBugReport,
10
10
  scrubSecrets,
11
11
  setDeployContext
12
- } from "./chunk-I7YT2IAO.js";
13
- import "./chunk-AXIJLJZK.js";
14
- import "./chunk-FW4HEUMH.js";
15
- import "./chunk-6TIWKKDS.js";
12
+ } from "./chunk-5DKLSM7C.js";
13
+ import "./chunk-FOPTSHK2.js";
14
+ import "./chunk-SJKPP7KA.js";
15
+ import "./chunk-PJCHSHMU.js";
16
16
  export {
17
17
  buildCliFlagsSummary,
18
18
  buildLabels,
@@ -2,11 +2,11 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-AXIJLJZK.js";
5
+ } from "./chunk-FOPTSHK2.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId
9
- } from "./chunk-FW4HEUMH.js";
9
+ } from "./chunk-SJKPP7KA.js";
10
10
 
11
11
  // src/bug-report.ts
12
12
  import { execSync, execFileSync } from "child_process";
@@ -76,6 +76,9 @@ function buildCliFlagsSummary(flags) {
76
76
  const parts = [];
77
77
  if (flags.jsMerkle) parts.push("--js-merkle");
78
78
  if (flags.ghPagesMirror) parts.push("--gh-pages-mirror");
79
+ if (flags.publish) parts.push("--publish");
80
+ if (flags.unpublish) parts.push("--unpublish");
81
+ if (flags.failOnPublishError) parts.push("--fail-on-publish-error");
79
82
  if (flags.poolSize != null) parts.push(`--pool-size ${String(flags.poolSize)}`);
80
83
  if (typeof flags.tag === "string" && flags.tag) parts.push(`--tag ${flags.tag}`);
81
84
  if (flags.mnemonic) parts.push("--mnemonic <set>");
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-FW4HEUMH.js";
3
+ } from "./chunk-SJKPP7KA.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
@@ -0,0 +1,164 @@
1
+ import {
2
+ pessimisticSizePreflight
3
+ } from "./chunk-RI3ZLNPN.js";
4
+ import {
5
+ encodeContenthash,
6
+ resolveDotnsConnectOptions,
7
+ storeDirectory,
8
+ storeFile
9
+ } from "./chunk-VUHKPUWQ.js";
10
+ import {
11
+ DotNS
12
+ } from "./chunk-KP64NWAS.js";
13
+ import {
14
+ getPopSelfServeConfig,
15
+ loadEnvironments,
16
+ resolveEndpoints
17
+ } from "./chunk-OITUIM2E.js";
18
+ import {
19
+ NonRetryableError
20
+ } from "./chunk-ZOC4GITL.js";
21
+
22
+ // src/manifest/publish.ts
23
+ import * as fs from "fs/promises";
24
+ import * as path from "path";
25
+ async function publishManifest(opts) {
26
+ const { config, sourcePath } = opts.loaded;
27
+ if (config.domain !== opts.domain) {
28
+ throw new NonRetryableError(
29
+ `Config domain '${config.domain}' (in ${sourcePath}) does not match deploy domain '${opts.domain}'. Either update the config or pass the matching <domain> argument.`
30
+ );
31
+ }
32
+ const sizeReport = pessimisticSizePreflight(config);
33
+ if (!sizeReport.ok) {
34
+ const failing = sizeReport.checks.filter((c) => !c.ok).map((c) => `${c.key}: ${c.bytes}/${c.budget} B`).join(", ");
35
+ throw new NonRetryableError(
36
+ `Manifest size preflight failed: ${failing}. Shrink displayName / description / paths or override BULLETIN_TEXT_BUDGET.`
37
+ );
38
+ }
39
+ const configDir = path.dirname(sourcePath);
40
+ const iconAbs = path.resolve(configDir, config.icon.path);
41
+ const iconBytes = await readFileOrThrow(iconAbs, "icon");
42
+ console.log(`
43
+ Manifest publish \u2014 ${config.domain}`);
44
+ console.log(` Loaded config: ${sourcePath}`);
45
+ console.log(` Uploading icon (${iconBytes.length} B)\u2026`);
46
+ const iconCid = await storeFile(iconBytes);
47
+ console.log(` Icon CID: ${iconCid}`);
48
+ const executableCids = {};
49
+ for (const exec of config.executables) {
50
+ const execAbs = path.resolve(configDir, exec.path);
51
+ if (opts.buildDirCid && path.resolve(opts.buildDirCid.absPath) === execAbs) {
52
+ console.log(` Executable [${exec.kind}] reused build-dir CID: ${opts.buildDirCid.cid}`);
53
+ executableCids[exec.kind] = opts.buildDirCid.cid;
54
+ continue;
55
+ }
56
+ console.log(` Uploading executable [${exec.kind}] from ${execAbs}\u2026`);
57
+ const { storageCid } = await storeDirectory(execAbs, {}, void 0, true);
58
+ console.log(` Executable [${exec.kind}] CID: ${storageCid}`);
59
+ executableCids[exec.kind] = storageCid;
60
+ }
61
+ const dotns = await connectDotNS(opts);
62
+ try {
63
+ const baseLabel = stripDotSuffix(config.domain);
64
+ await dotns.ensureContentResolver(baseLabel);
65
+ const rootManifest = composeRoot(config, iconCid);
66
+ const rootJson = JSON.stringify(rootManifest);
67
+ console.log(` Writing root manifest text record on ${config.domain} (${Buffer.byteLength(rootJson, "utf8")} B)\u2026`);
68
+ await dotns.setTextRecord(baseLabel, "manifest", rootJson);
69
+ let textRecordsWritten = 1;
70
+ for (const exec of config.executables) {
71
+ const cid = executableCids[exec.kind];
72
+ if (!cid) throw new NonRetryableError(`Internal: missing CID for executable kind '${exec.kind}'`);
73
+ const ownership = await dotns.checkSubdomainOwnership(exec.kind, baseLabel);
74
+ if (!ownership.owned) {
75
+ if (ownership.owner) {
76
+ throw new NonRetryableError(
77
+ `Subname ${exec.kind}.${config.domain} is owned by ${ownership.owner}, not the publisher. Aborting.`
78
+ );
79
+ }
80
+ console.log(` Registering subname ${exec.kind}.${config.domain}\u2026`);
81
+ await dotns.registerSubdomain(exec.kind, baseLabel);
82
+ }
83
+ await dotns.ensureContentResolver(`${exec.kind}.${baseLabel}`);
84
+ const subContenthash = `0x${encodeContenthash(cid)}`;
85
+ console.log(` Setting contenthash on ${exec.kind}.${config.domain} \u2192 ${cid}\u2026`);
86
+ await dotns.setContenthash(`${exec.kind}.${baseLabel}`, subContenthash);
87
+ const execManifest = composeExecutable(exec);
88
+ const execJson = JSON.stringify(execManifest);
89
+ console.log(` Writing executable manifest on ${exec.kind}.${config.domain} (${Buffer.byteLength(execJson, "utf8")} B)\u2026`);
90
+ await dotns.setTextRecord(`${exec.kind}.${baseLabel}`, "executable", execJson);
91
+ textRecordsWritten++;
92
+ }
93
+ console.log(` \u2713 ${textRecordsWritten} text record${textRecordsWritten === 1 ? "" : "s"} written.`);
94
+ return { iconCid, executableCids, textRecordsWritten };
95
+ } finally {
96
+ dotns.disconnect();
97
+ }
98
+ }
99
+ async function readFileOrThrow(p, label) {
100
+ try {
101
+ return await fs.readFile(p);
102
+ } catch (err) {
103
+ throw new NonRetryableError(`Cannot read ${label} at ${p}: ${err.message}`);
104
+ }
105
+ }
106
+ async function connectDotNS(opts) {
107
+ const envId = opts.env ?? "paseo-next-v2";
108
+ const { doc } = await loadEnvironments();
109
+ const resolved = resolveEndpoints(doc, envId);
110
+ const popSelfServe = getPopSelfServeConfig(doc, envId);
111
+ const deployOptsShim = {
112
+ mnemonic: opts.mnemonic,
113
+ derivationPath: opts.derivationPath
114
+ };
115
+ const connectOpts = resolveDotnsConnectOptions(
116
+ deployOptsShim,
117
+ resolved.assetHub,
118
+ resolved.autoAccountMapping,
119
+ resolved.contracts,
120
+ resolved.nativeToEthRatio,
121
+ envId,
122
+ popSelfServe,
123
+ resolved.registerStorageDeposit
124
+ );
125
+ const dotns = new DotNS();
126
+ await dotns.connect(connectOpts);
127
+ return dotns;
128
+ }
129
+ function composeRoot(config, iconCid) {
130
+ return {
131
+ $v: 1,
132
+ displayName: config.displayName,
133
+ description: config.description,
134
+ icon: { cid: iconCid, format: config.icon.format }
135
+ };
136
+ }
137
+ function composeExecutable(exec) {
138
+ if (exec.kind === "app") {
139
+ return { $v: 1, kind: "app", appVersion: exec.appVersion };
140
+ }
141
+ if (exec.kind === "widget") {
142
+ return {
143
+ $v: 1,
144
+ kind: "widget",
145
+ appVersion: exec.appVersion,
146
+ dimensions: exec.dimensions,
147
+ ...exec.description !== void 0 ? { description: exec.description } : {}
148
+ };
149
+ }
150
+ return {
151
+ $v: 1,
152
+ kind: "worker",
153
+ appVersion: exec.appVersion,
154
+ entrypoint: exec.entrypoint,
155
+ includes: exec.includes
156
+ };
157
+ }
158
+ function stripDotSuffix(domain) {
159
+ return domain.replace(/\.dot$/i, "");
160
+ }
161
+
162
+ export {
163
+ publishManifest
164
+ };
@@ -0,0 +1,8 @@
1
+ // src/manifest/types.ts
2
+ function defineConfig(config) {
3
+ return config;
4
+ }
5
+
6
+ export {
7
+ defineConfig
8
+ };