@artblocks/abx-storage 0.1.0-alpha.2 → 0.1.0-alpha.21

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/CHANGELOG.md ADDED
@@ -0,0 +1,552 @@
1
+ # @artblocks/abx-storage
2
+
3
+ ## 0.1.0-alpha.21
4
+
5
+ ### Patch Changes
6
+
7
+ - c9f7aeb: Fold the burn, and make "canonically ABX v2" sayable — from abx-services' 2026-08-20 reply
8
+ (`reviews/2026-08/services-reply-docs-23.md`). All off-chain: no contract changed, no address moved.
9
+
10
+ **SDK — `foldSpine` now folds an ERC-721 burn, and `TokenState.minted` is replaced by `lifecycle`
11
+ (BREAKING).** A burn wrote the zero address into `TokenState.owner` — where nothing downstream could
12
+ tell it from a holder — and `minted` latched `true` at mint and was never recomputed, so a burned
13
+ token reconstructed as live. `lifecycle: 'unminted' | 'live' | 'burned' | 'no-live-copies'` replaces it,
14
+ and `owner` is `null` for a burned id rather than a sentinel. An enum rather than the `minted` +
15
+ `burned` pair the report asked for: a boolean whose `false` has two meanings leaves the burn case one
16
+ forgotten field away from rendering as "not yet minted", which is exactly what our own CLI did.
17
+
18
+ **`'burned'` is terminal and ERC-721-only; an edition at zero live copies is `'no-live-copies'`.** The
19
+ first cut of this enum shared `'burned'` across both standards, on the grounds that "one vocabulary on
20
+ both lanes" was the honest shape. It wasn't: the correct _response_ to destruction differs by standard
21
+ (a 721 id is gone forever and must `410`; an edition id can mint again and must not), so a shared word
22
+ put every consumer one forgotten `contractType` branch away from serving `410 Gone` for a token the
23
+ contract still resolves — and our own migration note told the first consumer to map the shared word
24
+ straight onto their `410` sites. abx-services caught it in review before it published. Splitting the
25
+ word moves the rule out of prose and into the type: **`lifecycle === 'burned'` is safe to treat as
26
+ permanent on either standard, with no carve-out**, which let the reference resolver's `isEditionState`
27
+ guard go away entirely. Pinned from both ends — no edition history can fold to `'burned'`, and the
28
+ route asserts its own standard-blindness.
29
+
30
+ **The two lanes now agree id-for-id.** The same review found `TokenRow.lifecycle` (head reads) reporting
31
+ `'unknown'` for a fully-burned edition id while the fold reported `'burned'` for that same id — under a
32
+ docstring claiming the two lanes used the same words. That is the sibling-drift class this repo treats
33
+ as a bug (see `TokenState.maxSupply`'s note, the last time one field name carried two meanings). Both
34
+ lanes now answer `'no-live-copies'` there: the fold _could_ distinguish never-minted from fully-burned
35
+ and deliberately does not, because the distinction has no consumer. `'unknown'` survives for the one
36
+ case where a head read genuinely cannot say — a 1/1 has no mint frontier, so a reverting `ownerOf`
37
+ there is evidence of nothing.
38
+
39
+ What the latched boolean was costing, all in our own tree: the effects harness re-rendered destroyed
40
+ tokens on every sweep, forever; `onchain-uri`'s probe reads the LOWEST live id, so burning token 0 made
41
+ a healthy collection's on-chain-URI lane report as **broken**; the resolver served metadata — and the
42
+ pre-mint _warming placeholder_, i.e. "still loading" forever — for ids the contract disowns; `mintedCount`
43
+ never went down; and `abx state` printed "not yet minted" for a token that had been destroyed.
44
+
45
+ **SDK — `BurnConfigured` and `MaxRoyaltyBpsUpdated` fold into `ProjectState.burnable` /
46
+ `.maxRoyaltyBps`.** Both events shipped in the ABI and in `SPINE_EVENT_DOC` and reached no field of
47
+ state; the upgrade memo then told consumers the doc entry _was_ the fold, which it has never been (it
48
+ supplies `register`/`what` on the event record, full stop). Both are tri-state: `null` means the spine
49
+ never stated it — an implementation with no `burn` entrypoint and an unpublished ceiling — which is not
50
+ `false`, and not 10%. The ceiling is deliberately not nested inside `royalty`, since clearing a royalty
51
+ nulls that field while the ceiling stays binding on chain.
52
+
53
+ **SDK — a fold-coverage guard, because this was the second instance in four days.** `DefaultMaxSupplySet`
54
+ did the same thing on 2026-08-17. `SPINE_EVENT_NO_FOLD` now lists the events that deliberately reach no
55
+ state _and why_ (a ping whose value is a head read, a factory's own log, a minter sibling, an allowance),
56
+ and `spine-fold-coverage.test.ts` asserts every decodable event is either folded or excused. A new event
57
+ is unfolded and unexcused until someone decides which.
58
+
59
+ **SDK — a burned 1/1 no longer vanishes from `listTokens`.** The id range fell back to `totalSupply`
60
+ (live: mints − burns) when a token type exposes no `nextTokenId`, so burning a 1/1's only token made the
61
+ listing enumerate ZERO ids — `abx tokens` printed nothing at all, indistinguishable from a collection
62
+ with no tokens. A 1/1's id space is `{0}` forever regardless of what is live. Found by burning a real
63
+ token on Sepolia rather than by any fixture, which is the only way this one surfaces.
64
+
65
+ **SDK — head reads can now say `burned`.** `nextTokenId` is a mint frontier that only rises, so an id
66
+ below it whose `ownerOf` reverts was minted and destroyed. `TokenRow.lifecycle` (`'live'` / `'burned'` /
67
+ `'unminted'` / `'unknown'`) and `TokenListing.burnedCount` (`nextTokenId − totalSupply`) drop out of that,
68
+ with no event log. `'unknown'` stays a real member where the chain declines to say: a 1/1 has no frontier,
69
+ and an edition's `supply == 0` cannot distinguish never-minted from fully-burned.
70
+
71
+ **SDK — `burned` joins `ServiceErrorCode`, paired with `410 Gone`.** A remote token API had nothing
72
+ honest to say about a destroyed id and was sending `410` with `code: 'not_registered'` — a statement
73
+ about the _contract_. The rule behind the pairing is the general one: **a resolver answers what the
74
+ contract's own URI getter answers.** A burned 721's `tokenURI` reverts `NonexistentToken`, so serving a
75
+ document would contradict the contract; an ERC-1155's `uri(id)` has no existence gate and a zero-supply
76
+ id can mint again, so **an edition never 410s** — it serves, with `supply: 0`.
77
+
78
+ **SDK — `readCollectionPolicy`, `canonicalFactories`, `verifyProvenance`: protocol knowledge moves out
79
+ of the CLI.** The CLI was declaring its own ABI fragments for `burnable`/`maxRoyaltyBps` and reading
80
+ them itself in two places, so no other integrator could reach either fact. `canonicalFactories(chainId)`
81
+ replaces two copies of the six-anchor enumeration inside `anchors.ts` — the list whose completeness _is_
82
+ the trust model. `verifyCanonical` gains `opts.factories`, which **replaces** the manifest set rather
83
+ than appending to it, so a multi-tenant operator's pinned allowlist can drive the gate without silently
84
+ widening it.
85
+
86
+ **SDK — anchor generations: "canonically ABX v2", not a bare `false`.** `verifyCanonical` reported
87
+ "deployed by an ABX factory since replaced" and "deployed outside the toolkit entirely" identically —
88
+ its own docstring admitted it — and the first is a perfectly good collection. `ANCHOR_GENERATIONS` keys
89
+ each generation of the six trust anchors by the **on-chain core version** its clones report, and
90
+ `verifyProvenance` returns `{canonical, generation: 'current' | 'prior' | null, coreVersion, factory,
91
+ anchorsAnswered}`. The version is on the clone itself, so the answer is chain-verified rather than a
92
+ manifest claim, and it keeps working after a factory retires. Retired generations never feed
93
+ `verifyCanonical`: provenance is not trust — a superseded generation can predate a security remediation.
94
+ Pre-launch testnet generations are deliberately not backfilled.
95
+
96
+ **Redeploy process — a token-layer runtime change is a new anchor generation.** It bumps
97
+ `AbxVersion.CORE_VERSION` and moves the SDK's `isCurrent*` probes in lockstep. That is now a checklist
98
+ step (`contracts/README.md`, `CLAUDE.md`) _enforced by_ `deployments.test.ts`: recorded generations must
99
+ have unique, increasing core versions and the newest must match the constant in `AbxVersion.sol`, so a
100
+ batch cannot record a generation without bumping or bump without recording. The gap that prompted it: the
101
+ 2026-08-20 batch added `burn()`, `burnable()`, `maxRoyaltyBps()` and `reduceMaxRoyaltyBps()` to the CORE
102
+ base — burn is not an extension, so no extension version moved either — and left the constant at 2, so
103
+ `abxVersion() == 2` cannot tell a burn-capable token from a pre-burn one.
104
+
105
+ **CLI — the royalty ceiling is shown with its rate, and headroom is named.** A ceiling above the live
106
+ rate is royalty the owner can add unilaterally, and a listing page never shows it. `abx state` prints the
107
+ pair and, when there is headroom, says the useful thing: reducing the cap **to** the current rate is what
108
+ turns "5% today" into "5%, provably, forever". (Named by abx-services as their `royalty-headroom` flag —
109
+ a marketplace can compute it, so a creator should hear it from us first.)
110
+
111
+ **Reference stack — the same fixes, so the reference is exemplary rather than the counter-example.**
112
+ `mintedCount` keeps its name and counts LIVE ids, with `burnedCount` added only when non-zero (so a
113
+ project with no burns serves byte-identical JSON, and a consumer's fixtures keep telling the truth);
114
+ the indexer projection carries `lifecycle`; the effects status route and the render sweep skip destroyed
115
+ ids; the dashboard badges a burned token instead of calling it minted; and `abx verify` / the migrate and
116
+ re-point probes never choose a burned token as their subject.
117
+
118
+ **CLI — `--send` is accepted on the deploy paths, and two lane flags is refused.** Every deploy's help
119
+ advertises the signing lanes as `--send hot/env key · --sign wallet page · --unsigned print tx`, in 25
120
+ places, and `--send` was the one of the three the deploy allowlist rejected: typing what the help showed
121
+ produced `unrecognized flag(s): --send` from the guard whose whole purpose is catching flags that would
122
+ be silently ignored — the guard firing on the tool's own documentation. Found by using the CLI as a cold
123
+ reader of its own `--help` while setting up an on-chain test. While there, lane resolution moved from
124
+ truthiness to **presence** (`--sign=` parses to `''`, which is falsy, so a caller who explicitly named
125
+ the wallet lane was routed to the unattended env key — the one direction of that bug that costs
126
+ something), and naming two lanes at once now refuses instead of resolving by an undocumented precedence.
127
+
128
+ **Packaging — every published tarball ships its CHANGELOG.** `files` was `['dist', 'LICENSE']` on the
129
+ SDK, indexer, storage, effects and token-api, so the only package whose release notes reached consumers
130
+ was the CLI. A downstream team upgrading the SDK had no CHANGELOG in the tarball and diffed two `dist/`
131
+ trees to find out what moved — then reported the release notes as missing, which cost a whole exchange
132
+ to adjudicate. One line each.
133
+
134
+ **Docs + spec.** The event spine gains a Burn section and the `MaxRoyaltyBpsUpdated` row, both with the
135
+ fold rules an indexer relies on; three stale deploy-event-order lists are corrected; the remote-services
136
+ error taxonomy gains the `410 burned` row and the edition carve-out; `owner-powers` explains headroom and
137
+ burn permanence; and `indexing-notes` states plainly that documenting an event is not folding it.
138
+
139
+ - Updated dependencies [c9f7aeb]
140
+ - @artblocks/abx-sdk@0.1.0-alpha.21
141
+
142
+ ## 0.1.0-alpha.20
143
+
144
+ ### Patch Changes
145
+
146
+ - Updated dependencies [84ca9dd]
147
+ - Updated dependencies [84ca9dd]
148
+ - @artblocks/abx-sdk@0.1.0-alpha.20
149
+
150
+ ## 0.1.0-alpha.19
151
+
152
+ ### Patch Changes
153
+
154
+ - Updated dependencies [b1c333d]
155
+ - Updated dependencies [b1c333d]
156
+ - @artblocks/abx-sdk@0.1.0-alpha.19
157
+
158
+ ## 0.1.0-alpha.18
159
+
160
+ ### Patch Changes
161
+
162
+ - Updated dependencies [77a6248]
163
+ - Updated dependencies [77a6248]
164
+ - @artblocks/abx-sdk@0.1.0-alpha.18
165
+
166
+ ## 0.1.0-alpha.17
167
+
168
+ ### Patch Changes
169
+
170
+ - Updated dependencies [c5b8ec3]
171
+ - Updated dependencies [5b29f53]
172
+ - @artblocks/abx-sdk@0.1.0-alpha.17
173
+
174
+ ## 0.1.0-alpha.16
175
+
176
+ ### Patch Changes
177
+
178
+ - Updated dependencies [9c287c0]
179
+ - Updated dependencies [b5744a1]
180
+ - Updated dependencies [9c287c0]
181
+ - @artblocks/abx-sdk@0.1.0-alpha.16
182
+
183
+ ## 0.1.0-alpha.15
184
+
185
+ ### Patch Changes
186
+
187
+ - Updated dependencies [7fec2d7]
188
+ - @artblocks/abx-sdk@0.1.0-alpha.15
189
+
190
+ ## 0.1.0-alpha.14
191
+
192
+ ### Patch Changes
193
+
194
+ - Updated dependencies [1b6b741]
195
+ - Updated dependencies [1b6b741]
196
+ - Updated dependencies [1b6b741]
197
+ - Updated dependencies [1b6b741]
198
+ - Updated dependencies [1b6b741]
199
+ - Updated dependencies [1b6b741]
200
+ - Updated dependencies [f64a31f]
201
+ - Updated dependencies [1b6b741]
202
+ - Updated dependencies [1b6b741]
203
+ - Updated dependencies [1b6b741]
204
+ - Updated dependencies [1b6b741]
205
+ - Updated dependencies [1b6b741]
206
+ - Updated dependencies [1b6b741]
207
+ - Updated dependencies [1b6b741]
208
+ - Updated dependencies [1b6b741]
209
+ - Updated dependencies [1b6b741]
210
+ - Updated dependencies [1b6b741]
211
+ - @artblocks/abx-sdk@0.1.0-alpha.14
212
+
213
+ ## 0.1.0-alpha.13
214
+
215
+ ### Patch Changes
216
+
217
+ - Updated dependencies [528c6c6]
218
+ - @artblocks/abx-sdk@0.1.0-alpha.13
219
+
220
+ ## 0.1.0-alpha.12
221
+
222
+ ### Patch Changes
223
+
224
+ - Updated dependencies [afa9dd4]
225
+ - Updated dependencies [8c254d5]
226
+ - @artblocks/abx-sdk@0.1.0-alpha.12
227
+
228
+ ## 0.1.0-alpha.11
229
+
230
+ ### Patch Changes
231
+
232
+ - d40caf4: Requested by an integrator (abx-services) — the conformance surface now lives in the neutral
233
+ layer. Five pieces that only token-api or storage exposed before, and that any third-party
234
+ resolver needs to reproduce the reference behavior byte-for-byte, move into `@artblocks/abx-sdk`:
235
+
236
+ - **The generator-document family** (`ABX_JS`, `escapeInlineScript`/`escapeInlineJson`,
237
+ `buildGeneratorDocument`, `injectTokenDataIntoHtml` — new `src/generator-document.ts`): pure
238
+ string operations with no resolver-specific behavior, so the SDK, `abx preview`, and any
239
+ third-party provider now share one definition instead of the CLI importing token-api just for
240
+ this.
241
+ - **The registry-dependency family** (`DEPENDENCY_REGISTRY_ABI`, `activeRegistry`,
242
+ `resolveRegistryDep`, `registryDepUrl`, `dependencyScriptTags`, `URL_BUDGET_BYTES`), merged into
243
+ the SDK's existing `deps.ts` alongside its registry-pointer logic. `node:zlib` can't come along
244
+ — SDK core has to stay reachable from a browser bundle — so decompression is now an INJECTED
245
+ `inflate?: (bytes: Uint8Array) => Uint8Array` threaded through `resolveRegistryDep`/
246
+ `dependencyScriptTags`; omitting it when a resolved dep actually needs decompressing throws a
247
+ new typed `InflateRequiredError` naming the fix, rather than crashing opaquely or silently
248
+ degrading. `@artblocks/abx-sdk/node` gains `nodeInflate` (a one-line `gunzipSync` wrapper) so a
249
+ Node host wires it in one line; a browser host passes a `DecompressionStream`-based
250
+ implementation instead. (Merge note: the prior `dependencyRegistryReadAbi` and token-api's
251
+ `DEPENDENCY_REGISTRY_ABI` declared the identical `getDependencyDetails` entry twice — deduped
252
+ into one array that also carries `getDependencyScript`.)
253
+ - **`contentTypeFromPath`** (new `src/mime.ts`): the MIME extension-map lookup, verbatim.
254
+ - **Gateway resolution, split pure/env** (new `src/gateways.ts`): `resolveGatewayBase` is now PURE
255
+ (no env read — takes resolved `{ipfs?, arweave?}` overrides) and `gatewayUrlFor` moves alongside
256
+ it; `gatewayConfigFromEnv()` is the one place that reads `ABX_IPFS_GATEWAY`/
257
+ `ABX_ARWEAVE_GATEWAY`, kept separate so a host with its own gateway config never has to touch
258
+ `process.env` through this module at all.
259
+ - **`exponentialBackoffDelay(attempt, baseMs, capMs)`** (`util.ts`): `min(baseMs * 2^(attempt-1),
260
+ capMs)`, 1-indexed like the existing `linearBackoffDelay`. Prefer it for a sustained rate limit
261
+ or an overloaded upstream; `linearBackoffDelay` stays right for a one-off transient failure.
262
+ `service.ts`'s own retry ladder is unchanged (still linear — its rationale comment stands).
263
+
264
+ Token-api and storage keep every existing export working, re-exported from the SDK where the
265
+ implementation moved — no removals, and token-api's own `nodeInflate`-pre-wired wrappers mean its
266
+ internal call sites (`code.ts`'s document assembly, `deps.ts`'s `depStatusReport`) needed no
267
+ signature changes at all. The browser-bundle test (`packages/sdk/test/browser-bundle.test.ts`)
268
+ stays green with all of this now exported from the core index — proof that the injected-`inflate`
269
+ design actually keeps `node:zlib` out of the bundle.
270
+
271
+ - Updated dependencies [d40caf4]
272
+ - Updated dependencies [d40caf4]
273
+ - @artblocks/abx-sdk@0.1.0-alpha.11
274
+
275
+ ## 0.1.0-alpha.10
276
+
277
+ ### Minor Changes
278
+
279
+ - 11fa933: The extraction phase of the simplification refactor: business logic that lived only inside the CLI
280
+ is now importable — the CLI calls the same functions you can.
281
+
282
+ **Into the SDK:** the five trust-anchor bootstraps (`ensureFactory`, `ensureSeriesFactory`,
283
+ `ensureSeriesCodeFactory`, `ensureRenderer`, `ensureSeedSource` — `anchors.ts`, on the same
284
+ injected-`send` + `onEvent` pattern as `ensureChunkStore`, with a typed `AnchorUnavailableError`),
285
+ `detectCanonicalFactory`/`resolveScanFloor`, the on-chain-URI setup composer (`onchain-uri.ts`),
286
+ interrupted-deploy resume planning (`resume.ts`), migration plan/parity reconciliation
287
+ (`migrate.ts`), the `abx.js` static analyzer (`inspect.ts`), dependency setup legs (`deps.ts`),
288
+ content-staging plans (`staging.ts` — `planStagedContent`, `stageFieldContent` with `StagingEvent`),
289
+ `mintedTokenIds`, and a typed `readSaleConfig` for the fixed-price minter.
290
+
291
+ **Into storage:** `uploadAndLocate`, `repinNodeCustody` (the byte-custody half of migration),
292
+ `decideImageContentLane`, `assessStorageReadiness`/`assessTurboFunds` (the Arweave/Turbo funding
293
+ math), and `awaitLocatorReady` (poll a locator until it serves).
294
+
295
+ **CLI hardening that fell out of the dedup:** one risk gate (`gatedSend`) now guards every write —
296
+ `--dry-run` and `--confirm` mean the same thing on every command, all owner-ops gain `--confirm`,
297
+ and a write reaching the send lane under `--dry-run` is structurally impossible (grep-enforced by
298
+ test). One `CHAIN` source of truth; one memoized local-indexer accessor.
299
+
300
+ ### Patch Changes
301
+
302
+ - 11fa933: The remaining phases of the simplification refactor that hadn't yet gotten a changeset: the CLI's
303
+ internal module split, the token-api/effects/mint-page convergence on the SDK, the shipped skill's
304
+ rewrite for the simplified surface, and a new SDK README.
305
+
306
+ - **`abx`'s `main.ts` split into domain command modules** (`commands/{deploy,project,reads,service,
307
+ scaffold,storage}.ts`, shared `output.ts`/`errors.ts`), with one exit-discipline rule
308
+ (`process.exitCode` + return, or a typed `CliError`, everywhere — bare `process.exit` only at the
309
+ entry guard, the top-level catch, and the keep-alive SIGINT handler). Purely internal: a 207-fixture
310
+ byte-diff matrix (every help text, dry-run, error path, and exit code) confirmed identical output
311
+ before and after.
312
+ - **token-api / effects / mint-page converge on the SDK**: `@artblocks/abx-storage` gains one
313
+ `resolveGatewayBase` (`readiness.ts`), replacing three near-identical copies (two in token-api, one
314
+ inline in storage itself); token-api exports `buildGeneratorDocument` so the CLI's `abx preview`
315
+ consumes the real generator-document assembler instead of a hand-kept duplicate; the effects runner
316
+ now resolves its config via the SDK's `readEnv` and gets a `makePublicClient` fallback transport, so
317
+ `ABX_RPC_URL` accepts a comma-separated failover list like every other RPC var; the scaffolded
318
+ mint-page app now imports ABIs from `@artblocks/abx-sdk/abi` and a browser-safe `makePublicClient` +
319
+ typed `readSaleConfig` instead of hand-rolled fetch/decode, and pins its generated `package.json` to
320
+ the SDK's _resolved_ version via a new `@artblocks/abx-sdk/package.json` export (alpha version
321
+ counters diverge per package under changesets, so pinning the CLI's own number could produce an
322
+ unsatisfiable range).
323
+ - **The shipped skill (`.claude/skills/abx-self-host/`) is rewritten for the surface phases 0–5
324
+ actually shipped**: every warning made obsolete by an enforcement is deleted rather than softened —
325
+ predict-only deploy-preview addresses, the `approvals N` line, the single `ABX_REMOTE_SELF_*`
326
+ credential grammar, `doctor`'s version/provenance ladder, `storage show --check`, the render/storage
327
+ combo validator's dry-run row, and `ABX_DEPLOYER_PK` as the only key name. Retired names swept from
328
+ `dev-loop-test`, the agent-eval scenarios, and spec prose. The skill ships bundled inside this CLI
329
+ package (co-versioned via `SKILL.md` frontmatter), so it rides this same patch.
330
+ - **New `packages/sdk/README.md`**: what the SDK is, the send-injection model (`PreparedTx` +
331
+ `SendTx`, `makeHotSender` for a hot key, bring-your-own for a wallet/multisig), a complete
332
+ deploy → upload → mint → read walkthrough against real exports, and browser-use notes (explicit
333
+ `rpcUrls`, no env, the `/node` subpath is Node-only). Included in the npm tarball automatically
334
+ (README is one of the files npm always packs, regardless of the `files` allowlist).
335
+
336
+ - 11fa933: Phase 5 interface unifications: the self resolver becomes a named remote, doctor absorbs the
337
+ version/install/provenance ladder, deploy previews stop showing addresses they can't keep,
338
+ approvals are counted honestly, render×storage combos are validated once, and storage config gets
339
+ a real probe.
340
+
341
+ - **Self resolver is a named remote (breaking, client-side only)**: the CLIENT credential for the
342
+ local/self resolver moves from `ABX_RESOLVER_ADMIN_TOKEN` to the named-remote grammar
343
+ (`ABX_REMOTE_SELF_URL` / `ABX_REMOTE_SELF_TOKEN` — "self" is just a conventional remote name, zero
344
+ special-casing). The SERVER side (token-api control-plane auth, `provision.ts`, the Fly.io secret)
345
+ keeps its old name — it's the service's own config, not a client credential, so deployed resolvers
346
+ need no change. The old client var, if still set, is now a pointed `CliError` naming both new vars
347
+ (no silent fallback); `abx doctor` flags it too, and the near-miss `_KEY`-vs-`_TOKEN` detector keeps
348
+ working under the unified grammar.
349
+ - **`abx doctor` absorbs the version/install/provenance ladder** the skill used to only teach in
350
+ prose: one new ✓/✗ block for binary provenance (source checkout / npm install / npx — the silent-
351
+ stale-npx-cache trap), npm currency (reuses the existing cached update check), and skill↔CLI
352
+ version match (reuses `abx skill`'s own discovery). Each row names the exact fix.
353
+ - **Deploy previews stop showing addresses they can't keep**: `--dry-run` (`deploy` /
354
+ `deploy-series` / `deploy-code`) **without `--salt`** no longer prints a "deterministic address" —
355
+ that salt was just freshly, randomly reserved, so the address was real for that one preview and
356
+ never reproducible by a plain re-run. It now prints the salt itself, prominently, plus how to pin
357
+ it: re-run with `--salt <shown>` (guaranteed same address), or `abx predict --salt <shown> --for
358
+ <signer>`. **With `--salt`, the address prints exactly as before** (it IS stable) — `abx predict`
359
+ is unchanged. The same rule applies to `--json`: without `--salt`, `address` reports `null` rather
360
+ than a value the real deploy won't land at (`saltPinned` still says why).
361
+ - **`approvals` — a labeled, honest signature count**: every deploy-family `--dry-run` preview and
362
+ `--confirm` summary now carries one uniform `approvals N wallet approval(s)` line/clause — the
363
+ number of **wallet TX signatures** the real run will ask for (a connected-wallet storage upload,
364
+ e.g. Arweave via `--storage-signer eth`, is a message signature, not a transaction, and stays
365
+ listed separately, as it already was). It's derived from the exact same staging/setup-multicall
366
+ math that sizes the wallet-lane session's own `total`, so the two can never disagree — this caught
367
+ (and fixed) `deploy-code`'s wallet-lane session `total` being hardcoded to `2` even on the 1-tx path
368
+ (no chunks/schema/deps/on-chain-uri legs/setup-carried mints), which would have shown "transaction
369
+ 1 of 2" and then silently never asked for a second.
370
+ - **One validator for render×storage combos**: `@artblocks/abx-storage` gains
371
+ `validateRenderStorageCombo()` (`content-plan.ts`) — the single source of truth for two known-bad
372
+ configurations, each checked against the ACTUAL fact that makes it bad (not against an unrelated
373
+ flag): (1) `--image-base` needs a backend that can overwrite a stable per-token key in place; an
374
+ ipfs/arweave-_shaped URL_ is refused regardless of this deploy's own `--backend`, because those are
375
+ content-addressed — a re-upload gets a new address, so no fixed URL can point at it. (2) publishing
376
+ a render to a resolver that doesn't share this machine's disk needs a backend that can hand back a
377
+ public URL at all — `fs` (or `cloud` with no public base) can't. `deploy-code` wires this into BOTH
378
+ its real-run refusal (`--image-base`) and a new `render/storage ✓|✗ <reason>` dry-run row;
379
+ `requirePublishableBackend` (the existing `abx render --remote` / `abx effects` guard) now consults
380
+ the same validator for its ok/not-ok decision, so the two surfaces can't drift apart.
381
+ - **`abx storage show --check`**: a real read/write against the resolved storage config, not just
382
+ "is it configured." `cloud` PUTs a tiny object through the signed API and GETs it back over the
383
+ PUBLIC base with a plain unsigned fetch — the only check that catches the R2/S3
384
+ endpoint-vs-public-base trap (`health()` alone only proves the API credentials work); on failure
385
+ both URLs print, so the mismatch is visible. `ipfs`/`fs` reuse their existing `health()` verbatim
386
+ (gateway/API reachability, dir writability — no upload, no pin — reused, not reimplemented).
387
+ `arweave` adds an identity+balance READ, never a paid upload. Exit code is meaningful (0 ok / 1 any
388
+ ✗) so a script can gate a launch on it. `abx doctor`'s storage row now runs the same fuller probe
389
+ (bounded to 1.5s, matching its other fast network checks) instead of a bare `health()` call.
390
+
391
+ - Updated dependencies [11fa933]
392
+ - Updated dependencies [11fa933]
393
+ - Updated dependencies [11fa933]
394
+ - @artblocks/abx-sdk@0.1.0-alpha.10
395
+
396
+ ## 0.1.0-alpha.9
397
+
398
+ ### Patch Changes
399
+
400
+ - df298d8: `abx storage status <locator>` — is it retrievable yet, or only accepted?
401
+
402
+ Backlog B21, and the second half of a gap two independent integrations hit eight days apart. An upload
403
+ service answers "accepted" the moment it holds your bytes; a gateway serves them only once they
404
+ propagate, and on Arweave that runs to minutes. Nothing in the upload result distinguished the two, so
405
+ the natural implementation — upload during a mint, write the locator into the token — mints a token
406
+ that renders broken for the first minutes of its life.
407
+
408
+ The first reporter rebuilt this layer themselves (ranged GETs, a propagating/ready model, retry ladders
409
+ lengthened after measuring real times) and concluded "every serious integrator will rebuild some
410
+ version of this." The second published 32 renders and found **32/32 404ing on `arweave.net` while 22/32
411
+ already served from `permagate.io` and `vilenarios.com`**, with the uploader reporting `CONFIRMED`
412
+ throughout — and the expensive part is what a creator does next, since a placeholder on a fresh drop
413
+ reads as a failed render, so you re-run `abx render --force` and re-upload everything for nothing.
414
+
415
+ That second observation shapes the design: propagation is **per-gateway**, so the check probes the
416
+ gateway your project actually uses _plus two others_, which buys a third verdict the reporters' own
417
+ two-state model couldn't express.
418
+
419
+ - **`ready`** — your gateway serves the bytes. Safe to reference.
420
+ - **`propagating`** — another gateway serves them, so the data **provably exists** on the network and
421
+ yours is merely behind. Waiting is the fix, and the command says plainly not to re-upload.
422
+ - **`unreachable`** — nothing probed serves them. Deliberately _not_ called propagating: from outside,
423
+ a locator that is still settling and one that is simply wrong look identical, and reporting the
424
+ friendlier of the two is how a tool teaches someone to ignore it. When every gateway rejects the id
425
+ itself (a 4xx that isn't 404) rather than just missing it, that _is_ evidence, and the output says
426
+ "malformed locator, waiting will not fix it" — the inverse mistake of waiting out a typo costs more
427
+ than a needless re-upload.
428
+
429
+ Accepts every form a locator arrives in (`ar://`, `ipfs://`, a gateway URL, a bare txid/CID, with a
430
+ directory path suffix), reads **headers only** via a ranged request with the body cancelled — so
431
+ checking a 40 MB asset doesn't download it — and **exits non-zero unless ready**, which makes waiting a
432
+ one-liner instead of a retry ladder: `until abx storage status <loc> --json; do sleep 10; done`.
433
+
434
+ The primitive is `locatorStatus()` in `@artblocks/abx-storage`, not CLI-only (per B20): anything
435
+ programmatic should call it in-process rather than spawning the CLI per check. `abx render`'s existing
436
+ propagation note now points at the command, so the advisory has an answer attached.
437
+
438
+ - Updated dependencies [df298d8]
439
+ - Updated dependencies [df298d8]
440
+ - @artblocks/abx-sdk@0.1.0-alpha.9
441
+
442
+ ## 0.1.0-alpha.8
443
+
444
+ ### Patch Changes
445
+
446
+ - Updated dependencies [e325b46]
447
+ - @artblocks/abx-sdk@0.1.0-alpha.8
448
+
449
+ ## 0.1.0-alpha.7
450
+
451
+ ### Patch Changes
452
+
453
+ - 1b50f9d: Fixes from an integrator batch: a machine-readable `tokenuri`, one Arweave identity across CLI and SDK, a correct OpenSea refresh, and attach telling the truth.
454
+
455
+ **`abx tokenuri --json`.** The command abbreviated long values (`… (382 chars)`) with no way to turn it
456
+ off, so for a token whose whole point is on-chain content it returned something that _looked_ like the
457
+ metadata and wasn't. An integrator scraped it, stored a `data:` URI cut to 96 characters, and only
458
+ found out in production; they abandoned the CLI as a read path and reimplemented `eth_call`. `--json`
459
+ now emits the verbatim decoded document — no banner, no ANSI, no truncation — so
460
+ `abx tokenuri <addr> --json | jq` is a supported read path. The human view still abbreviates, and now
461
+ says `[--json for the full value]`.
462
+
463
+ **One Arweave identity, resolved in one place.** `arweaveConfigFromEnv()` read `ARWEAVE_JWK` and
464
+ nothing else, while the CLI mints and manages `.abx-self-host/arweave-key.json`. Porting a working CLI
465
+ flow to the SDK — same machine, minutes later — failed every upload with "Arweave via Turbo needs an
466
+ identity", a message that says storage was never configured when the truth was that two layers
467
+ disagreed about where the identity lives. `@artblocks/abx-storage` now exports `resolveArweaveJwk()`
468
+ (env → managed key file) and the CLI delegates to it. Its diagnostics come with it: an empty key file
469
+ now reports the **path** and the remedy instead of `Unexpected end of JSON input`, and a corrupt one
470
+ says the same.
471
+
472
+ **`abx refresh` on the default chain.** The OpenSea slug map held only `sepolia` and `mainnet`, so
473
+ `base-sepolia` — the CLI's own default — fell through to the raw key: the refresh POST went to a slug
474
+ OpenSea doesn't know, and the printed link pointed at **mainnet** `opensea.io` for a testnet token.
475
+ Slugs are now correct (`base_sepolia`), `testnet` comes from the chain registry rather than a second
476
+ hand-maintained set, and a chain with no known slug produces **no link** instead of a wrong one. Same
477
+ shape as the hardcoded explorer table that once sent every Base Sepolia link to Etherscan.
478
+
479
+ **`abx attach` names its dependency.** Attaching artifacts to a project that resolves on-chain now
480
+ warns, before the send, that they will **not** appear in `tokenURI` — the on-chain renderer carries
481
+ reserved fields only, and the artifacts manifest comes from a resolver. A team attached five audio
482
+ stems to a fully-on-chain token and found them "paid for, stored on-chain, and invisible"; the note
483
+ that existed was one dim line that read as a footnote rather than as a missing service.
484
+
485
+ **`ensureChunkStore` moved to the SDK.** The bootstrap every on-chain-content path needs existed only
486
+ inside the CLI, so an SDK integrator got `resolveChunkStore()` (may return undefined) plus a separate
487
+ `storeSupportsWriteContent()` they had to remember — forget it and an incapable store fails _deep
488
+ inside a mint, after transactions have landed_. One team hand-rolled the guard for exactly that reason.
489
+ `ensureChunkStore(publicClient, send, {chainId, override, onEvent})` is now exported; the SDK reports
490
+ progress through `onEvent` instead of printing, and the CLI keeps its narration.
491
+
492
+ **`abx storage upload --json`.** The locator as data. They scraped this line, captured its ANSI colour
493
+ codes along with the URL, wrote the result into a _stored_ player URL, and found out when it 404'd in
494
+ production. In `--json` mode stdout carries the JSON and nothing else; progress moves to stderr.
495
+
496
+ **`--backend ipfs` no longer hides a missing credential.** Without `PINATA_JWT` the backend resolves to
497
+ **kubo against a local node**, so a dry run looked fine and the real upload failed for anyone not running
498
+ one. The preview now says so. Related correction: the skill claimed "a backend missing its secret falls
499
+ back to `fs`" — it does not. `cloud` refuses up front naming the missing values, and `ipfs` goes to the
500
+ local node; nothing silently degrades to local disk. Both sides now say the same thing.
501
+
502
+ Reported in the 2026-08-03 MXRR integration batch (feedback 869f27b1, a256217f, 119d7e8e, 975c363e,
503
+ e38216db, e267078b).
504
+
505
+ - Updated dependencies [1b50f9d]
506
+ - Updated dependencies [1b50f9d]
507
+ - @artblocks/abx-sdk@0.1.0-alpha.7
508
+
509
+ ## 0.1.0-alpha.6
510
+
511
+ ### Patch Changes
512
+
513
+ - Updated dependencies [1158420]
514
+ - Updated dependencies [1158420]
515
+ - Updated dependencies [1158420]
516
+ - @artblocks/abx-sdk@0.1.0-alpha.6
517
+
518
+ ## 0.1.0-alpha.5
519
+
520
+ ### Patch Changes
521
+
522
+ - Updated dependencies [feba8c2]
523
+ - @artblocks/abx-sdk@0.1.0-alpha.5
524
+
525
+ ## 0.1.0-alpha.4
526
+
527
+ ### Patch Changes
528
+
529
+ - Updated dependencies [67b686b]
530
+ - @artblocks/abx-sdk@0.1.0-alpha.4
531
+
532
+ ## 0.1.0-alpha.3
533
+
534
+ ### Patch Changes
535
+
536
+ - Updated dependencies [a72723d]
537
+ - @artblocks/abx-sdk@0.1.0-alpha.3
538
+
539
+ ## 0.1.0-alpha.2
540
+
541
+ ### Patch Changes
542
+
543
+ - Updated dependencies [3745bd3]
544
+ - Updated dependencies [3745bd3]
545
+ - @artblocks/abx-sdk@0.1.0-alpha.2
546
+
547
+ ## 0.1.0-alpha.1
548
+
549
+ ### Patch Changes
550
+
551
+ - Updated dependencies [4074766]
552
+ - @artblocks/abx-sdk@0.1.0-alpha.1
package/dist/arweave.d.ts CHANGED
@@ -256,4 +256,18 @@ export declare class ArweaveBackend implements StorageBackend {
256
256
  * secrets). `ABX_ARWEAVE_ETH_SIGNER_KEY` selects an EVM Turbo identity (the CLI usually sets this
257
257
  * from the resolved signing key instead). */
258
258
  export declare function arweaveConfigFromEnv(): ArweaveConfig;
259
+ /** Where the CLI keeps the Turbo identity it creates and manages on first upload. */
260
+ export declare function arweaveKeyFilePath(): string;
261
+ /**
262
+ * The ONE place either layer resolves an Arweave identity: `ARWEAVE_JWK` (an explicit, inline
263
+ * secret) if set, else the CLI-managed key file.
264
+ *
265
+ * That fallback is the whole point. The CLI mints and manages `.abx-self-host/arweave-key.json` on
266
+ * first upload, but this function used to read `ARWEAVE_JWK` and nothing else — so an integrator
267
+ * porting a working CLI flow to the SDK, on the same machine, minutes later, had every upload fail
268
+ * with "Arweave via Turbo needs an identity". The message said storage was never configured; the
269
+ * truth was that two layers disagreed about where the identity lives, and it named neither the file
270
+ * nor the mismatch. They reimplemented this lookup themselves to get moving.
271
+ */
272
+ export declare function resolveArweaveJwk(): ArweaveJwk | undefined;
259
273
  //# sourceMappingURL=arweave.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"arweave.d.ts","sourceRoot":"","sources":["../src/arweave.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"arweave.d.ts","sourceRoot":"","sources":["../src/arweave.ts"],"names":[],"mappings":"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"}
package/dist/arweave.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve as resolvePath } from 'node:path';
1
3
  import { privateKeyToAccount } from 'viem/accounts';
2
4
  import { ContentIndex } from './content-index.js';
3
5
  import { arweaveAddress } from './arweave-identity.js';
@@ -440,10 +442,47 @@ export function arweaveConfigFromEnv() {
440
442
  provider: process.env.ABX_ARWEAVE_PROVIDER,
441
443
  uploadUrl: process.env.ABX_ARWEAVE_UPLOAD_URL,
442
444
  token: process.env.ARWEAVE_UPLOAD_TOKEN,
443
- jwk: parseJwkEnv(process.env.ARWEAVE_JWK),
445
+ jwk: resolveArweaveJwk(),
444
446
  ethSignerKey: process.env.ABX_ARWEAVE_ETH_SIGNER_KEY,
445
447
  };
446
448
  }
449
+ /** Where the CLI keeps the Turbo identity it creates and manages on first upload. */
450
+ export function arweaveKeyFilePath() {
451
+ const dataDir = process.env.ABX_DATA_DIR ?? resolvePath(process.cwd(), '.abx-self-host');
452
+ return process.env.ABX_ARWEAVE_KEY_FILE ?? resolvePath(dataDir, 'arweave-key.json');
453
+ }
454
+ /**
455
+ * The ONE place either layer resolves an Arweave identity: `ARWEAVE_JWK` (an explicit, inline
456
+ * secret) if set, else the CLI-managed key file.
457
+ *
458
+ * That fallback is the whole point. The CLI mints and manages `.abx-self-host/arweave-key.json` on
459
+ * first upload, but this function used to read `ARWEAVE_JWK` and nothing else — so an integrator
460
+ * porting a working CLI flow to the SDK, on the same machine, minutes later, had every upload fail
461
+ * with "Arweave via Turbo needs an identity". The message said storage was never configured; the
462
+ * truth was that two layers disagreed about where the identity lives, and it named neither the file
463
+ * nor the mismatch. They reimplemented this lookup themselves to get moving.
464
+ */
465
+ export function resolveArweaveJwk() {
466
+ const fromEnv = parseJwkEnv(process.env.ARWEAVE_JWK);
467
+ if (fromEnv)
468
+ return fromEnv;
469
+ const file = arweaveKeyFilePath();
470
+ if (!existsSync(file))
471
+ return undefined;
472
+ const raw = readFileSync(file, 'utf8');
473
+ if (raw.trim() === '') {
474
+ // An empty key file is a real state (an interrupted first upload), and the bare parser error it
475
+ // used to produce — "Unexpected end of JSON input" from `abx doctor` — pointed at a parser
476
+ // rather than the file or the remedy.
477
+ throw new Error(`Arweave key file ${file} is empty — delete it and re-run; the CLI mints a fresh managed identity on the next upload.`);
478
+ }
479
+ try {
480
+ return JSON.parse(raw);
481
+ }
482
+ catch {
483
+ throw new Error(`Arweave key file ${file} is not valid JSON — delete it to regenerate, or point ABX_ARWEAVE_KEY_FILE at a valid JWK.`);
484
+ }
485
+ }
447
486
  function parseJwkEnv(raw) {
448
487
  if (!raw)
449
488
  return undefined;