@artblocks/abx-cli 0.1.0-alpha.25 → 0.1.0-alpha.26

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 (46) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/dist/commands/deploy.d.ts +12 -4
  3. package/dist/commands/deploy.d.ts.map +1 -1
  4. package/dist/commands/deploy.js +67 -13
  5. package/dist/commands/deploy.js.map +1 -1
  6. package/dist/commands/project.d.ts.map +1 -1
  7. package/dist/commands/project.js +15 -0
  8. package/dist/commands/project.js.map +1 -1
  9. package/dist/commands/scaffold.d.ts.map +1 -1
  10. package/dist/commands/scaffold.js +19 -3
  11. package/dist/commands/scaffold.js.map +1 -1
  12. package/dist/commands/storage.d.ts +14 -0
  13. package/dist/commands/storage.d.ts.map +1 -1
  14. package/dist/commands/storage.js +31 -4
  15. package/dist/commands/storage.js.map +1 -1
  16. package/dist/config.d.ts +13 -0
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +25 -1
  19. package/dist/config.js.map +1 -1
  20. package/dist/conformance.d.ts.map +1 -1
  21. package/dist/conformance.js +20 -1
  22. package/dist/conformance.js.map +1 -1
  23. package/dist/flag-allowlists.d.ts.map +1 -1
  24. package/dist/flag-allowlists.js +4 -0
  25. package/dist/flag-allowlists.js.map +1 -1
  26. package/dist/main.js +17 -2
  27. package/dist/main.js.map +1 -1
  28. package/dist/ownerops.d.ts +17 -0
  29. package/dist/ownerops.d.ts.map +1 -1
  30. package/dist/ownerops.js +25 -9
  31. package/dist/ownerops.js.map +1 -1
  32. package/dist/provision.d.ts.map +1 -1
  33. package/dist/provision.js +6 -1
  34. package/dist/provision.js.map +1 -1
  35. package/dist/remote.d.ts +20 -0
  36. package/dist/remote.d.ts.map +1 -1
  37. package/dist/remote.js +38 -0
  38. package/dist/remote.js.map +1 -1
  39. package/dist/signer.d.ts.map +1 -1
  40. package/dist/signer.js +4 -1
  41. package/dist/signer.js.map +1 -1
  42. package/package.json +6 -6
  43. package/skill/SKILL.md +9 -2
  44. package/skill/reference/decisions.md +2 -2
  45. package/skill/reference/hosting.md +12 -3
  46. package/skill/reference/operating.md +21 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,128 @@
1
1
  # @artblocks/abx-cli
2
2
 
3
+ ## 0.1.0-alpha.26
4
+
5
+ ### Patch Changes
6
+
7
+ - 77a6248: Fixes from the 2026-08-18 eight-room agent sweep of the content-addressed lanes (ipfs · arweave ·
8
+ preferred gateways). The v11 gateway projection worked end to end on a live testnet round trip — bare
9
+ CID on chain, one `set-gateway` tx, byte-identical content id before and after — but the surfaces
10
+ around it lied, hid, or degraded in five ways that cold agents hit immediately.
11
+
12
+ **Both `AbxGenerator` addresses in the manifest had a broken EIP-55 checksum.** The addresses were
13
+ right; the casing was mangled in transcription. viem validates checksums, so
14
+ `readContract`/`writeContract` against the recorded value threw `Address "0x2c1b7Cf6…" is invalid` —
15
+ `abx verify` could not run its on-chain-URI check on **either** testnet. Corrected in
16
+ `deployments.ts` and the docs mirror, with the code at both fixed addresses re-confirmed on chain
17
+ (identical bytecode, as CREATE2 requires). The per-entry equality tests stayed green through all of
18
+ it because they compared against the same mangled string, so the manifest now carries a **property
19
+ test**: every recorded address must be a valid checksum.
20
+
21
+ **A deploy narrated the upload gateway as if it were the served URL.** With
22
+ `--onchain-uri --backend ipfs`, the progress line printed the backend's own locator
23
+ (`https://gateway.pinata.cloud/ipfs/<cid>/0.png`) while the chain got a bare CID served from
24
+ somewhere else entirely — in one run, from `ipfs.io`, because that is the floor and no preference was
25
+ written. The line now shows the URL the token will actually carry, resolved through the same
26
+ precedence that decides what gets written (`--ipfs-gateway`/`--arweave-gateway` → `--gateway` for the
27
+ backend in use → env → floor), and says whether that prefix is the project's choice or the public
28
+ default filling a silence.
29
+
30
+ **`--ipfs-gateway` / `--arweave-gateway` were absent from every deploy command's `--help`.** They
31
+ appeared only in `set-gateway --help` and the skill's reference pages, so an agent reading the CLI
32
+ alone could not find the flags the CLI itself tells you to use. All three deploy commands now name
33
+ them, with the floors (`https://ipfs.io/ipfs/`, `https://arweave.net/`) and the upload-vs-serving
34
+ distinction stated where the decision is made.
35
+
36
+ **`abx storage upload` handed `abx attach` a locator that silently downgraded the attachment.** It
37
+ printed `abx attach <address> <key> https://gateway.pinata.cloud/ipfs/<cid>/file.png` — and `attach`
38
+ picks the on-chain representation from the scheme, so an `https://` locator stores a plain `url` with
39
+ the gateway host welded into the value: no `set-gateway` repoint, exactly the coupling the
40
+ content-addressed representations exist to remove. Following the command's own printed next step was
41
+ the wrong move — and the skill had promised the scheme form all along, so the doc was right and the
42
+ command was wrong. It now hands back `ipfs://<cid>/file.png` / `ar://<txid>/file.png` (both in the prose
43
+ hint and as `attachLocator` in `--json`), keeps the https URL as the browsable one, and says why they
44
+ differ.
45
+
46
+ **`.abx-self-host/` is now self-ignoring.** It holds this node's projection and, for the Arweave
47
+ backend, a signing-capable key that carries prepaid upload credits. This repo gitignores that
48
+ directory and the skill said so — but a _creator's_ repo does not, so a first `--backend arweave` run
49
+ could leave a key staged for commit with nothing having said a word. The CLI writes a `.gitignore`
50
+ containing `*` inside the directory before anything sensitive lands there: it ignores the whole tree
51
+ regardless of the enclosing repo's config, needs no edit to a file we don't own, and never overwrites
52
+ one that already exists.
53
+
54
+ The **local-gateway warning** also stopped over-claiming. It said a `127.0.0.1` gateway means "the
55
+ served image URL resolves only on THIS machine" — true when the gateway host was welded into the
56
+ field, false now that the field holds a bare CID, and it aimed the creator at the wrong repair. It now
57
+ names the damage that is still real: bytes pinned only to a local node cannot be retrieved by anyone,
58
+ and no gateway can serve content that was never pinned publicly.
59
+
60
+ Also: `abx storage status --json` no longer warns `unrecognized flag(s), ignored: --json` about a flag
61
+ its own usage documents and that visibly works (a readout contradicting itself is worse than no
62
+ readout), and the `--unsigned` epilogue names `abx add <address>` rather than `abx index <address>`,
63
+ which fails on a node that never registered the project — the common case for a tx handed to someone
64
+ else's signer.
65
+
66
+ - 77a6248: Fixes from the 2026-08-18 six-room agent sweep of the hosted-services lane (managed provider ·
67
+ self-hosting · conformance). Three surfaces reported a credential problem as something else.
68
+
69
+ **`abx remote --conformance` blamed the service for our key.** With a rejected token it correctly
70
+ reported `the provided token was rejected (401)` — and then ran the authed-tier probes anyway. Each
71
+ one 401s, and each asserts on a 400, so one stale key produced four further failures reading
72
+ `bytes for a REFERENCED output (image) → 401 (expected 400; accepting this is how a resolver becomes
73
+ an object store)`. That is an accusation against the operator, and it is the exact inverse of what
74
+ this command is for: conformance is meant to be checkable from OUTSIDE, before you sign up. A cold
75
+ agent hit it and had to choose between believing five ✗ marks and explaining them away — it chose to
76
+ explain them away and told the creator the service was trustworthy. Now a rejected token skips the
77
+ authed tiers with one note (naming the descriptor's own signup URL), the public tier still runs in
78
+ full, and the run reports the one failure that is real. 401 is also handled like 403 inside the probe
79
+ helper, which already knew a credential problem is not a conformance verdict.
80
+
81
+ **`abx doctor` reported a dead credential as configured.** It printed `remotes: meridian` for a token
82
+ the service rejects, because it only checked that the variable was _present_. Doctor is the command a
83
+ creator is told to run first, so the 401 surfaced much later, from `abx remote <name>`, after that
84
+ line had already been trusted. Same class as an RPC that answers `[]` because it pruned its logs:
85
+ presence is not capability. It now makes one cheap authed call per named remote and reports
86
+ `✓ good · 1 project(s) visible` or `✗ meridian — token rejected (401) — fix or rotate
87
+ ABX_REMOTE_MERIDIAN_TOKEN`. A short timeout with no backoff keeps it quick, a 403 stays a note
88
+ (provider scoping is not a misconfiguration), and an unreachable provider is a soft note rather than
89
+ a ✗ — nothing here can fail doctor for a reason the creator cannot act on.
90
+
91
+ **`abx deploy-effects` told operators to set a variable that is never read.** The Fly scaffold's
92
+ storage-secrets block emitted `fly secrets set ABX_ARWEAVE_KEY=…`; no such variable exists anywhere in
93
+ the toolkit. A hosted runner cannot use the CLI's managed key file either (that path is on the
94
+ operator's machine), so the line now names `ARWEAVE_JWK` with the JWK inline, which is the form that
95
+ actually works remotely.
96
+
97
+ **A remote register on a self-resolving project claimed a win it did not deliver.** `abx add --remote`
98
+ printed its successes and stopped. But a project whose `tokenURIRenderer` is set answers `tokenURI`
99
+ from the chain, so marketplaces and wallets read that document and never touch the service — the
100
+ registration is still worth having (indexing, the live view, managed rendering) and changes nothing a
101
+ collector sees. A cold agent, told "put it on a hosted service so it shows up properly", had to
102
+ reconstruct that from `state` → `tokenuri` → `contracturi` → the docs → a raw curl before it could
103
+ answer honestly. The register now says it, and the skill states the inverse rule the reference pages
104
+ never had: a resolver adds nothing marketplace-facing to a project that already resolves on-chain.
105
+
106
+ `abx verify`'s help also stopped contradicting itself — "no server needed" read as "needs nothing"
107
+ while the command refuses until the project is registered locally with `abx add`. It now says "no
108
+ resolver in the path" and names the prerequisite.
109
+
110
+ Skill: stop asserting third-party prices and free tiers. Two rooms in one sweep quoted plan costs to a
111
+ creator — one lifted "free tier" from our own `hosting.md` (Fly's has since changed), the other
112
+ invented a monthly Pinata figure out of nothing. We cannot keep another company's pricing current, so
113
+ the skill now says to name the provider and point at its pricing page, and to compare _shapes_
114
+ (pay-once vs. monthly; lapses vs. nothing-to-renew) which stay true. Turbo's under-100 KB free tier
115
+ stays, because the CLI enforces and prints it. The never-read-`.env` rule also moved to the top of
116
+ SKILL.md: an agent listed and read files while orienting, before it reached that rule twenty lines
117
+ down, and printed credentials into its own transcript.
118
+
119
+ - Updated dependencies [77a6248]
120
+ - Updated dependencies [77a6248]
121
+ - @artblocks/abx-sdk@0.1.0-alpha.18
122
+ - @artblocks/abx-indexer@0.1.0-alpha.19
123
+ - @artblocks/abx-storage@0.1.0-alpha.18
124
+ - @artblocks/abx-token-api@0.1.0-alpha.21
125
+
3
126
  ## 0.1.0-alpha.25
4
127
 
5
128
  ### Minor Changes
@@ -110,7 +110,8 @@ export type RemoteEthUpload = {
110
110
  export declare function prepareContent(imagePath: string | undefined, clone: Address, overrides: StorageOverrides, store?: boolean, // false for --dry-run: compute the hash but don't custody bytes
111
111
  onChain?: boolean, // true (--onchain-uri): put the image ON-CHAIN (inline SVG) so it self-resolves
112
112
  remoteEth?: RemoteEthUpload, // wallet-lane Turbo uploads: sign+pay with the connected browser wallet
113
- walletAddr?: string): Promise<{
113
+ walletAddr?: string, // the deployer wallet — checked for existing Turbo credits if the managed key is short
114
+ gatewayFlags?: Flags): Promise<{
114
115
  tokenFields: OnChainFieldInput[];
115
116
  contentNote: string;
116
117
  }>;
@@ -122,9 +123,16 @@ walletAddr?: string): Promise<{
122
123
  export declare function parseDeployTraits(flags: Flags): OpenSeaAttribute[];
123
124
  /** Encode creator traits as the on-chain `attributes` field (inline JSON bytes) — for `--traits-onchain`. */
124
125
  export declare const attributesInlineField: (attrs: OpenSeaAttribute[]) => OnChainFieldInput;
125
- /** Warn when IPFS/Arweave custody is pointed at a LOCAL gateway: the served image URL
126
- * (`<gateway>/ipfs/<cid>`) would resolve only on this machine, so marketplaces/wallets can't
127
- * load it — a pinning service + a PUBLIC gateway is part of operating off-chain custody. */
126
+ /**
127
+ * Warn when IPFS/Arweave custody is pointed at a LOCAL gateway.
128
+ *
129
+ * Two distinct problems ride on one flag, and the warning names the one that actually applies. The
130
+ * bytes are pinned only to a node on this machine, so nothing off it can retrieve them — that is the
131
+ * real damage and it survives any later `set-gateway`. It ALSO used to weld that localhost host into
132
+ * the on-chain value; since the field holds a bare CID it no longer does (the serving prefix is the
133
+ * collection's preference), so promising "the served URL resolves only on THIS machine" would now be
134
+ * false and would point the creator at the wrong repair.
135
+ */
128
136
  export declare function localGatewayWarning(flags: Flags): string | null;
129
137
  /** A readout line for an optional creator text field — states exactly what's written (and where),
130
138
  * or that NOTHING is, so the deploy never silently invents one. */
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,7 @@ import { isEditionContract } from '../kind.js';
26
26
  import { jsonSafe, withJson } from '../jsonout.js';
27
27
  import { planOnChainScript } from '../script-chunks.js';
28
28
  import { bold, c, dim, ensureFactory, ensureRenderer, ensureSeedSource, ensureSeriesCodeFactory, ensureSeriesFactory, ensureOneOfOneEditionFactory, ensureEditionFactory, ensureEditionCodeFactory, g, info, keepAlive, ok, p, portInUse, printServing, registerAndIndexLocally, reindexAfterDeploy, step, warn, } from '../output.js';
29
- import { AUTHORSHIP_DEPLOY_FIELDS, ONCHAIN_PROJECT_SOFT_LIMIT, ONCHAIN_READ_WARN_BYTES, tokenUriGasEstimate, authorshipContractFields, gatewayContractFields, computeContentPlan, envStagingSender, parseCompress, parseSeedSourceValue, canonicalSeedSource, refuseUnusableSeedSource, parseTransferValidatorValue, guardOnChainSize, previewImageStaging, refusePrewrappedImage, sessionStagingSender, stageImageField, stageImageFieldsBatch, } from '../ownerops.js';
29
+ import { AUTHORSHIP_DEPLOY_FIELDS, ONCHAIN_PROJECT_SOFT_LIMIT, ONCHAIN_READ_WARN_BYTES, tokenUriGasEstimate, authorshipContractFields, gatewayContractFields, servingGateway, computeContentPlan, envStagingSender, parseCompress, parseSeedSourceValue, canonicalSeedSource, refuseUnusableSeedSource, parseTransferValidatorValue, guardOnChainSize, previewImageStaging, refusePrewrappedImage, sessionStagingSender, stageImageField, stageImageFieldsBatch, } from '../ownerops.js';
30
30
  import { canonicalLabel } from '../remote.js';
31
31
  import { assertLaneCanSign, confirmSend, gatedSend, laneFromFlags } from '../riskgate.js';
32
32
  import { describeSchema, editionSchemaAdvisory, parseSchemaSpecs } from '../schema.js';
@@ -356,6 +356,29 @@ export const imageContentAddressedField = (network, contentId) => ({
356
356
  * `cloud` and friends keep the plain `url` / `url-template` they always had: an https CDN locator IS
357
357
  * the address, with no identity underneath to separate out.
358
358
  */
359
+ /**
360
+ * The URL a creator's token will actually carry, for a locator a durable backend just produced.
361
+ *
362
+ * For `ipfs`/`arweave` the backend's locator is an UPLOAD-gateway URL, and the on-chain field holds
363
+ * only the bare CID/txid — so narrating the locator verbatim told the creator a host their token
364
+ * does not use (a live deploy printed `gateway.pinata.cloud/…` while committing a CID served from
365
+ * `ipfs.io`). Rebuild it under the serving preference instead, and say which one that is, since
366
+ * "the floor is filling a silence" and "you chose this" have different futures.
367
+ *
368
+ * Every other backend is returned verbatim: an https CDN locator IS the address.
369
+ */
370
+ function servedImageUrl(backendId, locator, flags) {
371
+ if (backendId !== 'ipfs' && backendId !== 'arweave')
372
+ return { url: locator, note: '' };
373
+ const contentId = contentIdFromLocator(backendId, locator);
374
+ if (!contentId)
375
+ return { url: locator, note: '' };
376
+ const { prefix, chosen } = servingGateway(backendId, flags);
377
+ return {
378
+ url: `${prefix}${contentId}`,
379
+ note: chosen ? `gateway: yours, written on-chain` : `gateway: public default — repoint any time with ${bold('abx set-gateway')}`,
380
+ };
381
+ }
359
382
  /** How a lane should describe what it just committed, so the narration matches the field written. */
360
383
  function describeLocatorField(backendId) {
361
384
  return backendId === 'ipfs' || backendId === 'arweave'
@@ -422,7 +445,8 @@ export function imageEndsUpOnChain(flags, onchainImage) {
422
445
  export async function prepareContent(imagePath, clone, overrides, store = true, // false for --dry-run: compute the hash but don't custody bytes
423
446
  onChain = false, // true (--onchain-uri): put the image ON-CHAIN (inline SVG) so it self-resolves
424
447
  remoteEth, // wallet-lane Turbo uploads: sign+pay with the connected browser wallet
425
- walletAddr) {
448
+ walletAddr, // the deployer wallet — checked for existing Turbo credits if the managed key is short
449
+ gatewayFlags = {}) {
426
450
  if (!imagePath) {
427
451
  // demo default = generative SVG. On-chain mode inlines it (self-resolving, no custody);
428
452
  // off-chain mode commits its keccak and regenerates/serves it.
@@ -503,7 +527,10 @@ walletAddr) {
503
527
  // Keep the bytes under their hash too: `abx verify` can then still prove the served image
504
528
  // matches what was uploaded, even though the on-chain field addresses it by URL.
505
529
  await backend.put(hash, { bytes, contentType });
506
- ok(`image ${url} ${dim(`(${backend.id}; baked on-chain, no server)`)}`);
530
+ const served = servedImageUrl(backend.id, url, gatewayFlags);
531
+ ok(`image → ${served.url} ${dim(`(${backend.id}; baked on-chain, no server)`)}`);
532
+ if (served.note)
533
+ info(dim(` ${served.note}`));
507
534
  return {
508
535
  tokenFields: [imageLocatorField(backend.id, url)],
509
536
  contentNote: `content: ${basename(path)} (${bytes.length} bytes, ${contentType}) on ${backend.id} · ON-CHAIN image ${describeLocatorField(backend.id)}`,
@@ -538,16 +565,24 @@ export const attributesInlineField = (attrs) => ({
538
565
  representation: encodeTag(R.inline),
539
566
  value: toHex(JSON.stringify(attrs)),
540
567
  });
541
- /** Warn when IPFS/Arweave custody is pointed at a LOCAL gateway: the served image URL
542
- * (`<gateway>/ipfs/<cid>`) would resolve only on this machine, so marketplaces/wallets can't
543
- * load it — a pinning service + a PUBLIC gateway is part of operating off-chain custody. */
568
+ /**
569
+ * Warn when IPFS/Arweave custody is pointed at a LOCAL gateway.
570
+ *
571
+ * Two distinct problems ride on one flag, and the warning names the one that actually applies. The
572
+ * bytes are pinned only to a node on this machine, so nothing off it can retrieve them — that is the
573
+ * real damage and it survives any later `set-gateway`. It ALSO used to weld that localhost host into
574
+ * the on-chain value; since the field holds a bare CID it no longer does (the serving prefix is the
575
+ * collection's preference), so promising "the served URL resolves only on THIS machine" would now be
576
+ * false and would point the creator at the wrong repair.
577
+ */
544
578
  export function localGatewayWarning(flags) {
545
579
  const opts = storageOptions(storageOverrides(flags));
546
580
  const gateway = opts.backend === 'ipfs' ? opts.ipfs?.gateway : opts.backend === 'arweave' ? opts.arweave?.gateway : undefined;
547
581
  if (gateway && /^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)\b/i.test(gateway)) {
548
- return (`${opts.backend} gateway is ${gateway} — a LOCAL gateway. The served image URL resolves only on THIS machine; ` +
549
- `marketplaces and wallets won't load it. Pin to a service with a PUBLIC gateway (e.g. a Pinata dedicated gateway) ` +
550
- `via --gateway https://… or ABX_IPFS_GATEWAY.`);
582
+ return (`${opts.backend} gateway is ${gateway} — a LOCAL gateway, so the bytes would be pinned only to a node on THIS ` +
583
+ `machine and nobody else could retrieve them. The on-chain field holds the bare content id (a gateway change is ` +
584
+ `later just ${bold('abx set-gateway')}), but no gateway can serve content that was never pinned publicly. Pin to a ` +
585
+ `service with a PUBLIC gateway (e.g. a Pinata dedicated gateway) via --gateway https://… or ABX_IPFS_GATEWAY.`);
551
586
  }
552
587
  return null;
553
588
  }
@@ -889,7 +924,7 @@ export async function cmdDeployBody(flags, serveAfter, emit) {
889
924
  ? { tokenFields: [bakedImage], contentNote: 'content: image staged ON-CHAIN via reader (self-resolving, no custody)' }
890
925
  : onchainImage
891
926
  ? { tokenFields: [], contentNote: 'content: image would be staged ON-CHAIN via reader (chunk store) — dry run skips the staging write' }
892
- : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri, uploadRemoteEth, deployer);
927
+ : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri, uploadRemoteEth, deployer, flags);
893
928
  // Put the description ON-CHAIN (inline) when asked, or always under --onchain-uri
894
929
  // (the on-chain renderer can only emit on-chain fields, so an off-chain-only
895
930
  // description would simply be omitted). On-chain wins at resolve either way.
@@ -1390,7 +1425,7 @@ export async function cmdDeployOneOfOneEditionBody(flags, emit) {
1390
1425
  ? { tokenFields: [bakedImage], contentNote: 'content: image staged ON-CHAIN via reader (self-resolving, no custody)' }
1391
1426
  : onchainImage
1392
1427
  ? { tokenFields: [], contentNote: 'content: image would be staged ON-CHAIN via reader (chunk store) — dry run skips the staging write' }
1393
- : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri);
1428
+ : await prepareContent(flags.image, clone, storageOverrides(flags), !dryRun, onChainUri, undefined, undefined, flags);
1394
1429
  if (flags.description && (onChainUri || flags['description-onchain'])) {
1395
1430
  tokenFields.push({ field: encodeTag(F.description), representation: encodeTag(R.inline), value: toHex(flags.description) });
1396
1431
  }
@@ -1801,6 +1836,14 @@ export async function cmdDeploySeriesBody(flags, emit) {
1801
1836
  if (uniform) {
1802
1837
  contractFields = [imageLocatorField(backendId, `<${backendId}-dir>/{id}${exts[0]}`, true)];
1803
1838
  info(`would upload ${tokenPaths.length} file(s) as ONE ${backendId} directory → collection image <${backendId}-dir>/{id}${exts[0]} (O(1); ${describeLocatorField(backendId)})`);
1839
+ // Name the SERVING prefix in the plan too. Without it a preview says "the gateway is the
1840
+ // collection's preference" and never says what that preference resolves to, so a reader
1841
+ // fills the blank with the upload gateway they just typed — the same confusion the live
1842
+ // narration used to cause outright.
1843
+ if (backendId === 'ipfs' || backendId === 'arweave') {
1844
+ const { prefix, chosen } = servingGateway(backendId, flags);
1845
+ info(`served from ${bold(prefix)} ${dim(chosen ? '(your --' + backendId + '-gateway, written on-chain)' : `(public default — nothing written; repoint any time with ${bold('abx set-gateway')})`)}`);
1846
+ }
1804
1847
  }
1805
1848
  else {
1806
1849
  tokenFields = tokenPaths.map(({ tokenId }) => tokenFieldOf(tokenId, imageLocatorField(backendId, `<${backendId}-url-${tokenId}>`)));
@@ -1816,7 +1859,10 @@ export async function cmdDeploySeriesBody(flags, emit) {
1816
1859
  const template = `${base}/{id}${exts[0]}`;
1817
1860
  contractFields = [imageLocatorField(backendId, template, true)];
1818
1861
  info(`uploaded ${entries.length} file(s) as one ${backendId} directory`);
1819
- info(`collection image: ${template} ${dim(`— one field covers every token (O(1); ${describeLocatorField(backendId)})`)}`);
1862
+ const servedTemplate = servedImageUrl(backendId, template, flags);
1863
+ info(`collection image: ${servedTemplate.url} ${dim(`— one field covers every token (O(1); ${describeLocatorField(backendId)})`)}`);
1864
+ if (servedTemplate.note)
1865
+ info(dim(` ${servedTemplate.note}`));
1820
1866
  }
1821
1867
  else {
1822
1868
  // mixed extensions (or no directory support): per-token url fields (O(N)).
@@ -1828,7 +1874,7 @@ export async function cmdDeploySeriesBody(flags, emit) {
1828
1874
  if (!locator)
1829
1875
  throw new Error(`backend ${backendId} returned no public locator for token ${tokenId} — a durable backend (ipfs/arweave) is required for --onchain-uri image hosting`);
1830
1876
  tokenFields.push(tokenFieldOf(tokenId, imageLocatorField(backendId, locator)));
1831
- info(`token ${tokenId} ← ${fname} → ${locator}`);
1877
+ info(`token ${tokenId} ← ${fname} → ${servedImageUrl(backendId, locator, flags).url}`);
1832
1878
  }
1833
1879
  info(`mixed file extensions → per-token image fields (O(N)); a uniform extension enables the O(1) directory template`);
1834
1880
  }
@@ -2335,6 +2381,14 @@ export async function cmdDeployEditionImageBody(flags, emit) {
2335
2381
  if (uniform) {
2336
2382
  imageContractFields = [imageLocatorField(backendId, `<${backendId}-dir>/{id}${exts[0]}`, true)];
2337
2383
  info(`would upload ${tokenPaths.length} file(s) as ONE ${backendId} directory → collection image <${backendId}-dir>/{id}${exts[0]} (O(1); ${describeLocatorField(backendId)})`);
2384
+ // Name the SERVING prefix in the plan too. Without it a preview says "the gateway is the
2385
+ // collection's preference" and never says what that preference resolves to, so a reader
2386
+ // fills the blank with the upload gateway they just typed — the same confusion the live
2387
+ // narration used to cause outright.
2388
+ if (backendId === 'ipfs' || backendId === 'arweave') {
2389
+ const { prefix, chosen } = servingGateway(backendId, flags);
2390
+ info(`served from ${bold(prefix)} ${dim(chosen ? '(your --' + backendId + '-gateway, written on-chain)' : `(public default — nothing written; repoint any time with ${bold('abx set-gateway')})`)}`);
2391
+ }
2338
2392
  }
2339
2393
  else {
2340
2394
  for (const { tokenId } of tokenPaths)