@artblocks/abx-token-api 0.1.0-alpha.31 → 0.1.0-alpha.33

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 CHANGED
@@ -1,1249 +1,15 @@
1
1
  # @artblocks/abx-token-api
2
2
 
3
- ## 0.1.0-alpha.31
3
+ ## 0.1.0-alpha.33
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - c5e0d84: Published package `homepage` and `bugs` fields now point at docs.abx.io instead of a private GitHub
8
- repo that 404s. File reports with `abx feedback`; `npm bugs` no longer names a repository the public
9
- cannot open.
7
+ - 64248d9: Establish the public source baseline and refresh dependency constraints.
8
+ - Updated dependencies [64248d9]
9
+ - @artblocks/abx-indexer@0.1.0-alpha.31
10
+ - @artblocks/abx-sdk@0.1.0-alpha.30
11
+ - @artblocks/abx-storage@0.1.0-alpha.30
10
12
 
11
- Reported in the 2026-08-27 tester batch (feedback 40142396).
13
+ ## Unreleased
12
14
 
13
- - Updated dependencies [c5e0d84]
14
- - Updated dependencies [c5e0d84]
15
- - @artblocks/abx-sdk@0.1.0-alpha.28
16
- - @artblocks/abx-indexer@0.1.0-alpha.29
17
- - @artblocks/abx-storage@0.1.0-alpha.28
18
-
19
- ## 0.1.0-alpha.30
20
-
21
- ### Patch Changes
22
-
23
- - Updated dependencies [4072f0c]
24
- - @artblocks/abx-sdk@0.1.0-alpha.27
25
- - @artblocks/abx-indexer@0.1.0-alpha.28
26
- - @artblocks/abx-storage@0.1.0-alpha.27
27
-
28
- ## 0.1.0-alpha.29
29
-
30
- ### Patch Changes
31
-
32
- - Updated dependencies [b182f23]
33
- - @artblocks/abx-sdk@0.1.0-alpha.26
34
- - @artblocks/abx-indexer@0.1.0-alpha.27
35
- - @artblocks/abx-storage@0.1.0-alpha.26
36
-
37
- ## 0.1.0-alpha.28
38
-
39
- ### Patch Changes
40
-
41
- - Updated dependencies [8f2f78a]
42
- - @artblocks/abx-sdk@0.1.0-alpha.25
43
- - @artblocks/abx-indexer@0.1.0-alpha.26
44
- - @artblocks/abx-storage@0.1.0-alpha.25
45
-
46
- ## 0.1.0-alpha.27
47
-
48
- ### Patch Changes
49
-
50
- - Updated dependencies [61503c3]
51
- - @artblocks/abx-sdk@0.1.0-alpha.24
52
- - @artblocks/abx-indexer@0.1.0-alpha.25
53
- - @artblocks/abx-storage@0.1.0-alpha.24
54
-
55
- ## 0.1.0-alpha.26
56
-
57
- ### Patch Changes
58
-
59
- - bd77ba2: Correct the Node floor to 22.13, and refuse to start with a remedy instead of a stack trace.
60
-
61
- Every package declared `engines.node: ">=22.5.0"` — the version `node:sqlite` was **added**, not the
62
- version it became usable. It shipped in v22.5.0 behind `--experimental-sqlite` and lost the flag in
63
- v22.13.0 / v23.4.0. So `npm i -g @artblocks/abx-cli` on Node 22.5 installed silently (the engine
64
- range was satisfied) and then `abx doctor` — the first command we tell everyone to run — died with a
65
- raw `ERR_UNKNOWN_BUILTIN_MODULE: No such built-in module: node:sqlite` stack trace naming neither
66
- abx nor a fix. Reported 2026-08-24; the floor is now `>=22.13.0` everywhere, so npm warns at install
67
- time.
68
-
69
- The crash happened while ESM _linked_ `main.ts`'s import graph (`output.ts` →
70
- `@artblocks/abx-indexer` → `node:sqlite`), before any of our code ran, so no guard inside the CLI
71
- could have caught it. The published binary is now a deliberately import-free shim (`dist/bin.js`)
72
- that probes for `node:sqlite` and hands off to `main.js` — it prints the running version, the real
73
- floor, and the upgrade command. It probes the **capability**, not the version number: an old Node
74
- launched with `NODE_OPTIONS=--experimental-sqlite` genuinely works, and refusing that would be a
75
- false negative. `engines` states what we support; the guard blocks only what is actually broken.
76
-
77
- `abx doctor`'s header now also reports the running Node, since its output is what people paste when
78
- something is wrong.
79
-
80
- - Updated dependencies [bd77ba2]
81
- - @artblocks/abx-indexer@0.1.0-alpha.24
82
- - @artblocks/abx-storage@0.1.0-alpha.23
83
- - @artblocks/abx-sdk@0.1.0-alpha.23
84
-
85
- ## 0.1.0-alpha.25
86
-
87
- ### Patch Changes
88
-
89
- - 549a32d: The live-view route (`/a/:chainId/:address/:id`) tells the truth for renderer-only projects and for
90
- ERC-1155 editions. Two inverse bugs in one branch:
91
-
92
- - **A renderer-only code project answered `503 + Retry-After` forever.** `deploy-code --image-renderer
93
- … --onchain-uri` with no `--script` has no program and never will — image and traits are computed in
94
- Solidity. The route told callers to keep retrying for content that does not exist. It is now the
95
- terminal 404, which is the honest answer: there is no live view here, by design.
96
- - **`edition-code` was missing from the code-contract check**, so an EditionCode whose chunks had not
97
- been folded in yet answered the _terminal_ 404 instead of the retryable 503 — the exact inverse
98
- failure the mid-index case was written to prevent, on the ERC-1155 lane.
99
-
100
- The two are separated by `script.chunkCount`, which is a head read: a number is what the chain says
101
- right now, so `0` means there is nothing to wait for, while `null` means nobody has asked yet and the
102
- honest answer to unknown stays the retryable one.
103
-
104
- Newly relevant because `deploy-code --copies --image-renderer` now makes a fully on-chain ERC-1155 a
105
- supported lane, and every project on it is renderer-only.
106
-
107
- - Updated dependencies [993e095]
108
- - @artblocks/abx-sdk@0.1.0-alpha.22
109
- - @artblocks/abx-indexer@0.1.0-alpha.23
110
- - @artblocks/abx-storage@0.1.0-alpha.22
111
-
112
- ## 0.1.0-alpha.24
113
-
114
- ### Patch Changes
115
-
116
- - Updated dependencies [c9f7aeb]
117
- - @artblocks/abx-sdk@0.1.0-alpha.21
118
- - @artblocks/abx-storage@0.1.0-alpha.21
119
- - @artblocks/abx-indexer@0.1.0-alpha.22
120
-
121
- ## 0.1.0-alpha.23
122
-
123
- ### Patch Changes
124
-
125
- - Updated dependencies [84ca9dd]
126
- - Updated dependencies [84ca9dd]
127
- - @artblocks/abx-sdk@0.1.0-alpha.20
128
- - @artblocks/abx-indexer@0.1.0-alpha.21
129
- - @artblocks/abx-storage@0.1.0-alpha.20
130
-
131
- ## 0.1.0-alpha.22
132
-
133
- ### Patch Changes
134
-
135
- - Updated dependencies [b1c333d]
136
- - Updated dependencies [b1c333d]
137
- - @artblocks/abx-sdk@0.1.0-alpha.19
138
- - @artblocks/abx-indexer@0.1.0-alpha.20
139
- - @artblocks/abx-storage@0.1.0-alpha.19
140
-
141
- ## 0.1.0-alpha.21
142
-
143
- ### Patch Changes
144
-
145
- - Updated dependencies [77a6248]
146
- - Updated dependencies [77a6248]
147
- - @artblocks/abx-sdk@0.1.0-alpha.18
148
- - @artblocks/abx-indexer@0.1.0-alpha.19
149
- - @artblocks/abx-storage@0.1.0-alpha.18
150
-
151
- ## 0.1.0-alpha.20
152
-
153
- ### Minor Changes
154
-
155
- - c5b8ec3: `ipfs` and `arweave` metadata fields now resolve on both planes, through a gateway the collection
156
- chooses — renderer **spec v11**.
157
-
158
- These are the two representations that are content-addressed, the two where the locator IS the
159
- integrity hash, and the two this protocol tells creators to prefer. They were also the two the
160
- on-chain renderer could not serve. So `abx deploy --onchain-uri --backend ipfs|arweave` worked around
161
- it by baking a gateway HOST into a `url` field, which welded a hostname the creator could never
162
- migrate and made `abx_provenance` report `source: url` for bytes that live on IPFS.
163
-
164
- The fix separates the two facts that the baked URL had fused. The CID/txid stays in the field, as
165
- identity, under that field's own lock. The HTTPS prefix becomes a project-wide preference in two
166
- reserved collection-scope fields, `abx_gateway_ipfs` / `abx_gateway_arweave`, with `https://ipfs.io/ipfs/`
167
- and `https://arweave.net/` as floors. The renderer, the canonical generator, and the off-chain
168
- resolver all read those two fields and apply the same wrap, so a token served from the chain and from
169
- a resolver produces the same URL.
170
-
171
- A dead or slow gateway is now a **repoint**, not a rewrite:
172
-
173
- ```bash
174
- abx set-gateway 0xYourContract --ipfs https://your-dedicated.mypinata.cloud/ipfs/
175
- ```
176
-
177
- One transaction, every token, no re-upload — and it works on fields you have already locked, because
178
- the locked value is the CID and the gateway was never in it.
179
-
180
- **What changes for you**
181
-
182
- - `--onchain-uri --backend ipfs|arweave` writes the bare CID (or `cid/{id}.ext` for the O(1) directory)
183
- as an `ipfs`/`arweave` field instead of a gateway URL as `url`/`url-template`. `--backend cloud` is
184
- unchanged — an HTTPS CDN locator _is_ the address.
185
- - New `abx set-gateway <addr> [--ipfs <prefix>] [--arweave <prefix>]` (`none` clears to the public
186
- default). Two flags, so a project can pay for a dedicated IPFS gateway and leave Arweave public.
187
- - New `--ipfs-gateway` / `--arweave-gateway` on every deploy command. Plain `--gateway` (the
188
- storage/upload gateway) seeds the preference for the backend in use, so passing it still does what
189
- you meant. Nothing is written when no gateway is named — silence keeps the floor live.
190
- - `abx set-field` refuses the two gateway keys and points at `set-gateway`, which validates the
191
- prefix, the scope and the representation. Every way to set them by hand fails silently.
192
- - The `display.gateway` contract param is **superseded and no longer read**. It could name only one
193
- prefix for both schemes and existed only on code projects.
194
- - SDK: `projectGatewayPrefix`, `projectGatewayUrl`, `gatewayPrefixFrom`, `contentIdFromLocator`,
195
- `GATEWAY_FIELD`, `GATEWAY_FLOOR`. For a host running its own resolver, `ABX_IPFS_GATEWAY` /
196
- `ABX_ARWEAVE_GATEWAY` are now a **floor**: a project that stated a preference on chain gets that
197
- preference from every conforming resolver, and host config only fills a silence.
198
-
199
- **New canonical addresses** (both testnets; nothing else moved — no token implementation, factory, or
200
- `initialize` ABI changed):
201
-
202
- | Contract | Address |
203
- | -------------------------------- | -------------------------------------------- |
204
- | `AbxMetadataRenderer` (spec v11) | `0x85C1aE1F076d808fF7c1729F21B85038Fa16105E` |
205
- | `AbxGenerator` (Sepolia) | `0xb7104AdFa6Fb5615e46E2a681A2Ff043B08fADB5` |
206
- | `AbxGenerator` (Base Sepolia) | `0x2c1b7Cf6C54E4acBcB54FCc395f7Af88eB4fC8Ce` |
207
-
208
- Also fixes a crash on `abx deploy-code --copies`: an undefined `bytes` reference threw a
209
- `ReferenceError` at the end of the dry-run plan and, worse, at the confirmation prompt of a real
210
- deploy.
211
-
212
- ### Patch Changes
213
-
214
- - 5b29f53: Drop-in for every reconstruct caller; new exports for hosted/self-host watch loops so they stop
215
- reimplementing `eth_getLogs` chunking and a second per-project fetch.
216
-
217
- **`getLogsAdaptive` is public and accepts `Address | Address[]`.** Address-list chunking defaults to
218
- 1000 (ordinary RPC tier cap) via `addressBatch` — an RPC opinion, not a protocol constant; `0`
219
- disables splitting. Per-tick block windows stay with the watcher (the reference one still uses 5000).
220
-
221
- **`reconstructFromLogs(client, prior, logs, {toBlock})`** is the fold / head-read half of
222
- `reconstructIncremental` given logs the caller already holds. `toBlock` is the inclusive scan head
223
- those logs cover, so a capped window cannot stamp past the last block actually scanned.
224
- `reconstructIncremental` is now a getLogs + that function.
225
-
226
- **A Transfer no longer re-downloads every on-chain script chunk.** Chunk content has no log;
227
- `ScriptUpdated` is the ping. `applyHeadReads` keeps the prior digest unless that ping is in `fresh`
228
- (or the prior digest is missing). Same change helps the single-address path.
229
-
230
- The reference token-api watcher now calls `getLogsAdaptive` for the registered set and hands each
231
- touched project's logs to `reindex({logs, toBlock})`, so the watch tick is the only getLogs.
232
-
233
- - Updated dependencies [c5b8ec3]
234
- - Updated dependencies [5b29f53]
235
- - @artblocks/abx-sdk@0.1.0-alpha.17
236
- - @artblocks/abx-indexer@0.1.0-alpha.18
237
- - @artblocks/abx-storage@0.1.0-alpha.17
238
-
239
- ## 0.1.0-alpha.19
240
-
241
- ### Patch Changes
242
-
243
- - Updated dependencies [9c287c0]
244
- - Updated dependencies [b5744a1]
245
- - Updated dependencies [9c287c0]
246
- - @artblocks/abx-sdk@0.1.0-alpha.16
247
- - @artblocks/abx-indexer@0.1.0-alpha.17
248
- - @artblocks/abx-storage@0.1.0-alpha.16
249
-
250
- ## 0.1.0-alpha.18
251
-
252
- ### Minor Changes
253
-
254
- - 7fec2d7: Off chain, `animation_url` is now a link to this node's route instead of an inlined `data:` URI
255
-
256
- The two URI-valued keys disagreed about the same thing. For on-chain **content**, `image` has always
257
- been served as a link to the resolver's route — bytes should not ride inside a JSON document that
258
- marketplaces re-fetch on every view — while `animation_url` was inlined as
259
- `data:text/html;base64,…`. That is backwards on the rule's own logic: `animation_url` is usually the
260
- _larger_ asset.
261
-
262
- Worse, a reserved key's resolved value is repeated verbatim into the `artifacts` listing, so an
263
- inlined document shipped **twice** in one response. A 3 MB on-chain HTML artwork meant roughly 8 MB of
264
- JSON per metadata fetch, of which the sibling `image` — the small one — contributed a single line.
265
-
266
- And the inline form was already the exception rather than the rule: a code project's `animation_url`
267
- has always been the live-view route. Only a project with an explicit `animation` field holding
268
- on-chain content took the `data:` path.
269
-
270
- ```jsonc
271
- // before // after
272
- "image": "http://node/…/7/image", "image": "http://node/…/7/image",
273
- "animation_url": "data:text/html;base64,PGh0…", "animation_url": "http://node/…/7/data/animation_url",
274
- "artifacts": [ "artifacts": [
275
- {"key":"image", "uri":"http://…"}, {"key":"image", "uri":"http://…"},
276
- {"key":"animation_url", "uri":"data:text/…"} {"key":"animation_url", "uri":"http://…/data/animation_url"}
277
- ] ]
278
- ```
279
-
280
- - **The bytes are unchanged and still on chain.** `abx_provenance` still reports
281
- `source: inline`/`reader`/`renderer` with `status: 'on-chain'` — the route changes where the bytes
282
- ride, not where they live. The route (`/…/data/{field}`, the data plane's own serving route) returns
283
- them with the declared Content-Type, and 302s to a durable locator when one exists.
284
- - **Locators are untouched.** `url`, `url-template`, and a computed `text/uri-list` still land verbatim
285
- on both planes: they are already URIs, and re-hosting one would hide it.
286
- - **The on-chain renderer is unchanged** — a contract has no URL space, so `tokenURI` still inlines the
287
- document, and that self-contained form is the durability floor. **No contract changed and no address
288
- moved.**
289
- - **`abx inspect`'s on-chain readout is unaffected**; it reads the contract's `tokenURI`, not this
290
- document.
291
-
292
- Adopts the position the abx-services team argued while upgrading their resolver — theirs already served
293
- the route form, so this closes the divergence in their favor and the reference is what changed. The
294
- class was invisible to the cross-implementation parity audit, whose fixtures are client-free while the
295
- `renderer` representation needs a live `eth_call`; a new `animation-route.test.ts` boots a real server
296
- on a real socket and follows the link, because a value promising bytes at a URL is a dead link if
297
- nothing serves that URL.
298
-
299
- - 7fec2d7: An edition's per-id cap now folds from the log, so a capped edition stops reporting itself as open
300
-
301
- `DefaultMaxSupplySet` — added in the contract-audit release precisely so the log could tell an open
302
- edition from a capped one — reached the ABI and stopped there. `reconstruct.ts` had no fold case, so
303
- the collection-wide default never landed in `ProjectState`, and **the common shape was the broken
304
- one**: `--copies N` sets the cap at `initialize` and never calls `setMaxSupply`, so no id has a
305
- `MaxSupplyUpdated` of its own and every capped edition ever deployed folded as _uncapped_. The
306
- head-read lane (`listTokens`, which calls `maxSupply(id)`) said `N` the whole time — one field name,
307
- two answers, on the value that decides whether a buy button renders. Found by the abx-services team
308
- while upgrading their resolver/indexer to this release.
309
-
310
- - **`ProjectState.defaultMaxSupply`** — the collection-wide per-id default (`'0'` = open; `null` ⇒ not
311
- an edition). The 1155 analogue of `maxInvocations`.
312
- - **`TokenState.maxSupply` is now the _effective_ cap** — an id's own override, else that default —
313
- and so equals `maxSupply(id)` on chain and its head-read twin `TokenRow.maxSupply`. Previously it
314
- was the override alone, and absent otherwise.
315
- - **`TokenState.maxSupplyOverridden`** — whether this id has ever been explicitly overridden. The
316
- distinction the on-chain getter cannot express (`maxSupply(id)` returns `0` for both "never capped"
317
- and "deliberately closed") and the log now can, plus a signal that the monotonic never-increase rule
318
- is in force for that id.
319
- - **`editionCapOf(token)`** — new SDK export returning `{kind:'open'} | {kind:'capped', cap} |
320
- {kind:'closed'}`, so nothing re-derives the rule. Used by the dashboard and `abx tokens`; pass a
321
- head-read row and a `'0'` cap reads `open`, which is all a state read can honestly say.
322
- - **The dashboard stops lying twice.** It tested `maxSupply` for truthiness: a `--copies 10` id read
323
- "(open)", and — because `'0'` is a non-empty string — an id deliberately closed would have read
324
- "12 / 0". It now reads "12 / 10" and "12 (closed — no more can be minted)".
325
- - **Projection columns**: `projects.default_max_supply`, `tokens.max_supply_overridden` (migration-added,
326
- so an existing store keeps working; NULL stays NULL rather than becoming a fabricated `0`).
327
-
328
- Also in this pass, from the same review:
329
-
330
- - **`SPINE_EVENT_DOC` had drifted to 41 of 52 events**, so eleven folded events carried an empty
331
- human description and defaulted to Register 2 — including `TransferValidatorUpdated`, which belongs
332
- to Register 1, and the factory's `Deployed`. All eleven are described, and a new
333
- `spine-doc-coverage.test.ts` fails the build if the table and the spine ABI drift apart again in
334
- either direction.
335
- - **One provenance body in the resolver's `renderer` branch.** The `text/uri-list` arm hand-built an
336
- object byte-identical to `onChainProv(field, 'renderer', …)` — same keys, same order, the note string
337
- typed a second time — so the only thing that branch could do was drift from `sourceNote`.
338
- - **Dead `abx_params`-era test scaffolding deleted** (a `paramsOf(json) => json.abx_params` reader, an
339
- RPC stub, a schema factory), including an import of a `ParamMember` type that no longer exists —
340
- which nothing caught, because `tsconfig` includes only `src`, so test files are never typechecked.
341
-
342
- ### Patch Changes
343
-
344
- - Updated dependencies [7fec2d7]
345
- - @artblocks/abx-sdk@0.1.0-alpha.15
346
- - @artblocks/abx-indexer@0.1.0-alpha.16
347
- - @artblocks/abx-storage@0.1.0-alpha.15
348
-
349
- ## 0.1.0-alpha.17
350
-
351
- ### Minor Changes
352
-
353
- - 1b6b741: Rename "artist" to "creator" throughout, including the protocol vocabulary
354
-
355
- ABX is a tool for creators generally. Art remains a first-class use case, but it should not be baked
356
- into the product's framing — and it was, down to the on-chain identifiers.
357
-
358
- **Breaking, and deliberately a clean break** (pre-launch, folded into the one redeploy that four
359
- rounds of security remediation already required — deferring would have meant either living with the
360
- old vocabulary permanently or spending a second deployment on a word):
361
-
362
- - `AuthOption` is now `Creator`, `TokenOwner`, `Address`, `CreatorOrTokenOwner`, `CreatorOrAddress`,
363
- `TokenOwnerOrAddress`, `CreatorOrTokenOwnerOrAddress`. Order is unchanged, so the `uint8` values
364
- are identical — only the names moved. Users type these: `--schema key:Type:Creator`.
365
- - The on-chain collection metadata field keys `artist` / `artist_links` are now `creator` /
366
- `creator_links`. These are `bytes32` keys written on-chain and emitted verbatim into every
367
- collection's `contractURI` JSON.
368
- - CLI flags `--artist` / `--artist-links` are now `--creator` / `--creator-links`. No aliases.
369
- - `@artblocks/abx-token-api` renames its `art` module to `content`: `generateArt` →
370
- `generateContent`, `artContentHash` → `contentHash`.
371
- - `AbxMetadataRenderer.SPEC_VERSION` is **7**, and `isCurrentRenderer` gates on it. A v6 renderer
372
- emits a different member key, so it is genuinely behind, not cosmetically so.
373
-
374
- Package CHANGELOGs are left alone on purpose: they record what past alpha versions actually shipped,
375
- and rewriting them would make the release history lie about flag names that really were `--artist`.
376
-
377
- - 1b6b741: Renderer spec v10 projects four long-reserved keys; edition trust anchors move
378
-
379
- **Renderer spec v10.** Four keys the spec reserved from the start were projected on chain by nothing:
380
- `background_color` and `youtube_url` (token), `banner_image` and `featured_image` (collection). A
381
- documented reserved key that no surface emits is a hole rather than a saved byte — a creator sets it,
382
- observes nothing, and cannot tell whether the tool or the marketplace is at fault. All four now project
383
- when their representation is chain-reachable, and are omitted when unset. `isCurrentRenderer` gates on
384
- 10; a v9 renderer silently drops them.
385
-
386
- **`collaborators` is no longer a reserved key.** It was in the registry, projected by neither plane, and
387
- because reserved keys are excluded from the resolver's `artifacts` listing, setting it on chain did
388
- nothing observable anywhere. It is now an ordinary creator key — which means it **does** list in
389
- `artifacts`. Put a collaborator list in a named artifact (`abx attach`) or in `description`.
390
-
391
- **The resolver's two collection image keys are now symmetric with the renderer.** `featured_image` is a
392
- top-level `contractURI` key instead of artifacts-only, and `banner_image` projects for every
393
- chain-reachable representation instead of only `url` (an `inline` or `reader` banner used to vanish).
394
-
395
- **Docs now carry the three-list split** — which keys both planes project, which are the off-chain
396
- resolver's alone by design (`abx_provenance.status`, operator overlay, effects/live-view, the
397
- `artifacts` listing, collection `image` courtesy, `image_data`, off-chain-decode values), and which are
398
- not reserved at all. That split is the thing to read before adding a key to either surface: drift on a
399
- key both planes _can_ emit is what produced three earlier remediations.
400
-
401
- **Addresses.** The three edition factories move (trust anchors) along with their implementations, and
402
- the renderer moves. `AbxEditionLib`, `AbxMetadataLib`, `AbxCodeLib`, `AbxParamsLib`, all three ERC-721
403
- factories, the chunk store, the seed source, both minters and both generators keep their addresses.
404
- Existing clones keep running their frozen implementations; re-point a live collection at the new
405
- renderer with `abx set-renderer` rather than redeploying it.
406
-
407
- - 1b6b741: Independent-audit remediation: `abx_provenance` reshaped, `abx_params` removed, hook ABI widened
408
-
409
- An independent adversarial audit of the contracts found no Critical or High issue, no theft path and
410
- no cross-project reach — but four Mediums, eight Lows and five architectural notes. Everything is
411
- addressed. Consumer-visible changes:
412
-
413
- **`abx_provenance` entries are now `{field, source, note}`.** They lost `onChain`, which was wrong in
414
- both directions — a `url` reported `false` although the URL string is stored on chain, while an
415
- `inline` value of `"https://…"` reported `true` for a pure pointer — and `verifiedAgainstChain`,
416
- which was hardcoded `null` on every entry. `source` says where the bytes came from; whether a value
417
- resolves on chain is visible in the value, and that judgment belongs to the reader. The off-chain
418
- resolver drops `onChain` for the same reason (it was exactly `status === 'on-chain'`) and keeps
419
- `status`, which it can genuinely compute.
420
-
421
- **`abx_params` no longer appears in `tokenURI`.** It was emitted by the on-chain renderer AND the
422
- resolver and parsed back by nobody. Params enumerate directly from the contract — `tokenParamKeys`,
423
- `tokenParam`, `paramSchemaKeys` — which is canonical, needs no indexer, and is what a chain-only
424
- reader should use; a code project's script still receives them through `tokenData`. Traits for
425
- marketplaces belong in `attributes`, unchanged.
426
-
427
- **A computed `image` locator now lands verbatim.** A field renderer returning
428
- `("text/uri-list", "ipfs://…")` was being data-wrapped into `data:text/uri-list;base64,…`, which no
429
- marketplace dereferences. `image` and `animation_url` now share one implementation of the rule.
430
-
431
- **`IAbxTransferHook.onTokenTransfer` gains `operator` and `amount`.** Without them a hook on a
432
- shared-supply ERC-1155 cannot tell a real transfer from a zero-amount no-op — which let any address
433
- fire the param lifecycle for an id it held no copy of. The token also refuses to notify on
434
- zero-amount and self-transfers.
435
-
436
- **`pingURI` is owner-only**, and `paramSchemaHead` / `selectOption` are new: resolving one selected
437
- option no longer copies the whole option table on every render.
438
-
439
- `AbxMetadataRenderer.SPEC_VERSION` is 8. Every canonical address moves — every token type is now
440
- library-linked, including the two ERC-721 image factories, because the metadata field store was
441
- externalized into the new `AbxMetadataLib` to restore EIP-170 headroom before any fix was stacked on
442
- top of 187 bytes of margin.
443
-
444
- The CLI now warns when `--copies` meets a holder-writable `--schema`: on an edition, params belong to
445
- the id, so every holder shares one value and the last writer wins.
446
-
447
- - 1b6b741: Upgrading from alpha.12/alpha.13 — what breaks, in one place
448
-
449
- This release lands the contract-audit branch. It is a **compatibility break with earlier alphas**, which
450
- is fine at this stage (greenfield alpha, no backwards-compatibility promise) but is worth having in one
451
- list rather than spread across a dozen changesets. Nothing here is a deprecation with a migration
452
- window; the old shapes are gone.
453
-
454
- **Every canonical address moved**, and four manifest fields are new (`metadataLib`, `paramsLib`,
455
- `codeLib`, `editionLib` — the delegatecalled write-path libraries). Resolve through `getDeployment` and
456
- the upgrade is transparent; anything you have _stored_ keyed by a factory address is not. A project
457
- indexed from a superseded anchor reads `isCanonical: false` against the new manifest — correct, since it
458
- is what a creator sees if they don't redeploy, but it is a data question, not a version bump.
459
-
460
- **The metadata document changed: renderer spec v4 → v9.** If you assemble or assert on it:
461
-
462
- - `abx_provenance` entries lost `onChain` (it was exactly `status === 'on-chain'`, and wrong in both
463
- directions) and `verifiedAgainstChain` (hardcoded `null` on every entry). `source` and `status` stay.
464
- - The `abx_params` block is gone from **both** lanes. Params enumerate from the contract —
465
- `tokenParamKeys` / `tokenParam` / `paramSchemaKeys` — which is canonical and needs no indexer; a code
466
- project's script still receives them through `tokenData`.
467
- - `artist` / `artist_links` are now `creator` / `creator_links` (reserved on-chain collection field
468
- keys), and `AuthOption.Artist*` is `AuthOption.Creator*` (numeric values unchanged).
469
- - A computed `image` locator (`text/uri-list`) lands **verbatim** instead of being wrapped into a
470
- `data:` URI no marketplace dereferences.
471
- - The on-chain renderer no longer duplicates a computed image into `artifacts`. The off-chain resolver
472
- still emits the complete listing — that asymmetry is specified, not a bug.
473
- - Four long-reserved keys now project on chain: `background_color`, `youtube_url` (token) and
474
- `banner_image`, `featured_image` (collection). `featured_image` also becomes a top-level resolver key
475
- instead of artifacts-only, and `banner_image` projects for every chain-reachable representation
476
- rather than `url` alone.
477
- - `collaborators` is **no longer reserved** — projected by neither plane and excluded from `artifacts`
478
- by its own reserved-ness, so it did nothing. It is now an ordinary creator key that does list.
479
-
480
- **`tokenData` divergences fixed, so rendered output can change:** a contract-scope `seed` no longer
481
- leaks into a token's `tokenData` (the on-chain generator never read one), `seed`'s wire format is always
482
- raw 32-byte hex regardless of schema, and `</script` escaping is case-insensitive to match the on-chain
483
- generator. Cached renders for affected code projects should be re-derived.
484
-
485
- **Removed:** `paramKeysOf`, `paramSchemaOf`, `paramDataOf` on `AbxMetadataRenderer` — orphaned when
486
- params left `tokenURI`. Read the token directly instead.
487
-
488
- **Two hook interfaces widened** (`ConfigurableParams` is extension **v3**; a hook built for the old
489
- signature reverts against a v3 token): `IAbxTransferHook.onTokenTransfer` gained `operator` + `amount`;
490
- `IAbxConfigureHook.onParamConfigured` gained `dataLength` + `dataBlobAddress`.
491
-
492
- **Additive:** `ParamHooksFrozen` folds into `ParamHooks.locked`; `paramSchemaHead` + `selectOption`
493
- replace pulling a whole option table to resolve one index; `readParamHooks`; `abxJs()` / `gunzipScript()`
494
- on the generator for piecewise document assembly; and the three ERC-1155 ABIs now carry
495
- `MetadataUpdate` / `BatchMetadataUpdate` / `DefaultMaxSupplySet`, which were emitted but not decodable.
496
-
497
- ### Patch Changes
498
-
499
- - Updated dependencies [1b6b741]
500
- - Updated dependencies [1b6b741]
501
- - Updated dependencies [1b6b741]
502
- - Updated dependencies [1b6b741]
503
- - Updated dependencies [1b6b741]
504
- - Updated dependencies [1b6b741]
505
- - Updated dependencies [f64a31f]
506
- - Updated dependencies [1b6b741]
507
- - Updated dependencies [1b6b741]
508
- - Updated dependencies [1b6b741]
509
- - Updated dependencies [1b6b741]
510
- - Updated dependencies [1b6b741]
511
- - Updated dependencies [1b6b741]
512
- - Updated dependencies [1b6b741]
513
- - Updated dependencies [1b6b741]
514
- - Updated dependencies [1b6b741]
515
- - Updated dependencies [1b6b741]
516
- - @artblocks/abx-sdk@0.1.0-alpha.14
517
- - @artblocks/abx-indexer@0.1.0-alpha.15
518
- - @artblocks/abx-storage@0.1.0-alpha.14
519
-
520
- ## 0.1.0-alpha.16
521
-
522
- ### Patch Changes
523
-
524
- - Updated dependencies [528c6c6]
525
- - @artblocks/abx-sdk@0.1.0-alpha.13
526
- - @artblocks/abx-indexer@0.1.0-alpha.14
527
- - @artblocks/abx-storage@0.1.0-alpha.13
528
-
529
- ## 0.1.0-alpha.15
530
-
531
- ### Minor Changes
532
-
533
- - afa9dd4: ERC-1155 editions ship with full parity: a Series is many unique tokens (721); an **Edition** is
534
- many copies of a token (1155). The creator's word is **copies** — `abx deploy img.png --copies 100`
535
- (a single-artwork edition, `open` = uncapped), `abx deploy-series ./art --copies 50` (each image an
536
- edition), `abx deploy-code sketch.js --copies 25` (code editions). Without `--copies`, the 721
537
- lanes are unchanged.
538
-
539
- Three new canonical contracts twin the 721 lineup — `OneOfOneEdition`, `EditionImage`,
540
- `EditionCode` — plus `AbxFixedPriceMinter1155`, a per-id fixed-price sale singleton
541
- (`minter configure/buy --token-id [--quantity]`). New owner ops: `mint --token-id --amount`,
542
- `transfer --amount`, `set-max-supply` (per-id cap, only ever decreases), `ping-uri` (re-emit the
543
- native `URI` event after a re-point). ERC-1155C creator-token enforcement is the same `--721c`
544
- opt-in (same validator registry and ERC-165 ids as 721C). Editions announce one new extension
545
- (`abx.extension.edition-supply`, per-id supply/cap); everything else — metadata fields, params,
546
- royalties, renderer, storage, effects — is the same protocol surface on both standards.
547
-
548
- **Integrator surface (audience line):** additive only. `ProjectState.contractType` gains
549
- `'1of1-edition' | 'edition' | 'edition-code'`; `TokenState` gains `supply`/`maxSupply`/`holders`
550
- (editions only; `minted` means supply > 0 there); the spine ABI now decodes
551
- `TransferSingle`/`TransferBatch`/`URI`/`MaxSupplyUpdated`; `ChainDeployment` gains the four
552
- edition anchors (recorded for Sepolia + Base Sepolia, CREATE2-identical); token-api summaries gain
553
- an optional `copies` field. No existing export, route, column, or event shape changed.
554
-
555
- ### Patch Changes
556
-
557
- - Updated dependencies [afa9dd4]
558
- - Updated dependencies [8c254d5]
559
- - @artblocks/abx-sdk@0.1.0-alpha.12
560
- - @artblocks/abx-indexer@0.1.0-alpha.13
561
- - @artblocks/abx-storage@0.1.0-alpha.12
562
-
563
- ## 0.1.0-alpha.14
564
-
565
- ### Patch Changes
566
-
567
- - d40caf4: Requested by an integrator (abx-services) — the conformance surface now lives in the neutral
568
- layer. Five pieces that only token-api or storage exposed before, and that any third-party
569
- resolver needs to reproduce the reference behavior byte-for-byte, move into `@artblocks/abx-sdk`:
570
-
571
- - **The generator-document family** (`ABX_JS`, `escapeInlineScript`/`escapeInlineJson`,
572
- `buildGeneratorDocument`, `injectTokenDataIntoHtml` — new `src/generator-document.ts`): pure
573
- string operations with no resolver-specific behavior, so the SDK, `abx preview`, and any
574
- third-party provider now share one definition instead of the CLI importing token-api just for
575
- this.
576
- - **The registry-dependency family** (`DEPENDENCY_REGISTRY_ABI`, `activeRegistry`,
577
- `resolveRegistryDep`, `registryDepUrl`, `dependencyScriptTags`, `URL_BUDGET_BYTES`), merged into
578
- the SDK's existing `deps.ts` alongside its registry-pointer logic. `node:zlib` can't come along
579
- — SDK core has to stay reachable from a browser bundle — so decompression is now an INJECTED
580
- `inflate?: (bytes: Uint8Array) => Uint8Array` threaded through `resolveRegistryDep`/
581
- `dependencyScriptTags`; omitting it when a resolved dep actually needs decompressing throws a
582
- new typed `InflateRequiredError` naming the fix, rather than crashing opaquely or silently
583
- degrading. `@artblocks/abx-sdk/node` gains `nodeInflate` (a one-line `gunzipSync` wrapper) so a
584
- Node host wires it in one line; a browser host passes a `DecompressionStream`-based
585
- implementation instead. (Merge note: the prior `dependencyRegistryReadAbi` and token-api's
586
- `DEPENDENCY_REGISTRY_ABI` declared the identical `getDependencyDetails` entry twice — deduped
587
- into one array that also carries `getDependencyScript`.)
588
- - **`contentTypeFromPath`** (new `src/mime.ts`): the MIME extension-map lookup, verbatim.
589
- - **Gateway resolution, split pure/env** (new `src/gateways.ts`): `resolveGatewayBase` is now PURE
590
- (no env read — takes resolved `{ipfs?, arweave?}` overrides) and `gatewayUrlFor` moves alongside
591
- it; `gatewayConfigFromEnv()` is the one place that reads `ABX_IPFS_GATEWAY`/
592
- `ABX_ARWEAVE_GATEWAY`, kept separate so a host with its own gateway config never has to touch
593
- `process.env` through this module at all.
594
- - **`exponentialBackoffDelay(attempt, baseMs, capMs)`** (`util.ts`): `min(baseMs * 2^(attempt-1),
595
- capMs)`, 1-indexed like the existing `linearBackoffDelay`. Prefer it for a sustained rate limit
596
- or an overloaded upstream; `linearBackoffDelay` stays right for a one-off transient failure.
597
- `service.ts`'s own retry ladder is unchanged (still linear — its rationale comment stands).
598
-
599
- Token-api and storage keep every existing export working, re-exported from the SDK where the
600
- implementation moved — no removals, and token-api's own `nodeInflate`-pre-wired wrappers mean its
601
- internal call sites (`code.ts`'s document assembly, `deps.ts`'s `depStatusReport`) needed no
602
- signature changes at all. The browser-bundle test (`packages/sdk/test/browser-bundle.test.ts`)
603
- stays green with all of this now exported from the core index — proof that the injected-`inflate`
604
- design actually keeps `node:zlib` out of the bundle.
605
-
606
- - d40caf4: Two first-party consumers adopt the backoff/gateway/data-URI helpers hoisted into `@artblocks/abx-sdk`
607
- last round, and `mint-page` refuses a 1/1 target instead of scaffolding a page that hangs. Drop-in for
608
- everyone — no behavior change in the adoption itself, and the mint-page refusal only fires for a
609
- contract type the page never worked against.
610
-
611
- **`token-api`'s chain watcher now calls `exponentialBackoffDelay`/`linearBackoffDelay` instead of
612
- re-deriving them inline.** `dueForRetry`'s failed-project retry and the tick loop's repeated-failure
613
- delay were the sdk helpers reimplemented by hand; both now call the shared functions, with the exact
614
- index mapping (`min(attempts, 8) + 1` into the 1-indexed exponential helper) that reproduces identical
615
- delays for every `attempts`/`failures` value — proved by an old-formula-vs-sdk-helper equality table
616
- in `packages/token-api/test/watcher-backoff.test.ts` (attempts/failures 0..12, several `baseMs`
617
- values, and the cap boundary explicitly).
618
-
619
- **The `mint-page` template's generated app now reads gateway URLs and `data:` URIs through the sdk**
620
- (`gatewayUrlFor`/`resolveGatewayBase`/`parseDataUri`) instead of a hand-rolled `ipfs://`-slicing
621
- `toGateway` and a hand-parsed comma-split in `fetchJson`. Same output for every input (plain
622
- `https://`, empty string, `ipfs://`, `ar://`, base64 and percent-encoded `data:` bodies) — verified
623
- byte-for-byte before the swap, and pinned by a new mintpage.test.ts assertion that the emitted
624
- `lib/meta.ts` imports the sdk helpers and no longer contains the old hand-rolled body.
625
-
626
- **`mint-page` now refuses a non-Series target.** The generated page reads `maxInvocations`/`paused`
627
- and mints through the shared fixed-price minter — a 1/1 (`OneOfOneImage`) has none of that, so pointing
628
- `mint-page` at one silently wrote a page that sat on "Loading…" forever with no diagnostic. `cmdMintPage`
629
- now probes the same ERC-165 `supportsInterface(IAbxSequentialMint)` `sdk/anchors.ts`'s
630
- `isCurrentSeriesFactory` uses, and refuses with a `CliError` pointing at `abx deploy-series --dir
631
- <folder> --count 1` (matching the existing guidance in `sales.mdx`). A probe that can't run at all (RPC
632
- unreachable) is left undecided and does NOT refuse — scaffolding stays usable offline, same tolerance
633
- the existing best-effort `name()` read already has.
634
-
635
- Also folded in: `PUBLIC_RPC` (the mint-page template's keyless-RPC table) gains `base` and
636
- `base-sepolia` — the toolkit's own default chain was missing from it, so every default-chain deploy
637
- needed a manual `--rpc` just to scaffold its own mint page.
638
-
639
- - Updated dependencies [d40caf4]
640
- - Updated dependencies [d40caf4]
641
- - @artblocks/abx-sdk@0.1.0-alpha.11
642
- - @artblocks/abx-storage@0.1.0-alpha.11
643
- - @artblocks/abx-indexer@0.1.0-alpha.12
644
-
645
- ## 0.1.0-alpha.13
646
-
647
- ### Patch Changes
648
-
649
- - 11fa933: The remaining phases of the simplification refactor that hadn't yet gotten a changeset: the CLI's
650
- internal module split, the token-api/effects/mint-page convergence on the SDK, the shipped skill's
651
- rewrite for the simplified surface, and a new SDK README.
652
-
653
- - **`abx`'s `main.ts` split into domain command modules** (`commands/{deploy,project,reads,service,
654
- scaffold,storage}.ts`, shared `output.ts`/`errors.ts`), with one exit-discipline rule
655
- (`process.exitCode` + return, or a typed `CliError`, everywhere — bare `process.exit` only at the
656
- entry guard, the top-level catch, and the keep-alive SIGINT handler). Purely internal: a 207-fixture
657
- byte-diff matrix (every help text, dry-run, error path, and exit code) confirmed identical output
658
- before and after.
659
- - **token-api / effects / mint-page converge on the SDK**: `@artblocks/abx-storage` gains one
660
- `resolveGatewayBase` (`readiness.ts`), replacing three near-identical copies (two in token-api, one
661
- inline in storage itself); token-api exports `buildGeneratorDocument` so the CLI's `abx preview`
662
- consumes the real generator-document assembler instead of a hand-kept duplicate; the effects runner
663
- now resolves its config via the SDK's `readEnv` and gets a `makePublicClient` fallback transport, so
664
- `ABX_RPC_URL` accepts a comma-separated failover list like every other RPC var; the scaffolded
665
- mint-page app now imports ABIs from `@artblocks/abx-sdk/abi` and a browser-safe `makePublicClient` +
666
- typed `readSaleConfig` instead of hand-rolled fetch/decode, and pins its generated `package.json` to
667
- the SDK's _resolved_ version via a new `@artblocks/abx-sdk/package.json` export (alpha version
668
- counters diverge per package under changesets, so pinning the CLI's own number could produce an
669
- unsatisfiable range).
670
- - **The shipped skill (`.claude/skills/abx-self-host/`) is rewritten for the surface phases 0–5
671
- actually shipped**: every warning made obsolete by an enforcement is deleted rather than softened —
672
- predict-only deploy-preview addresses, the `approvals N` line, the single `ABX_REMOTE_SELF_*`
673
- credential grammar, `doctor`'s version/provenance ladder, `storage show --check`, the render/storage
674
- combo validator's dry-run row, and `ABX_DEPLOYER_PK` as the only key name. Retired names swept from
675
- `dev-loop-test`, the agent-eval scenarios, and spec prose. The skill ships bundled inside this CLI
676
- package (co-versioned via `SKILL.md` frontmatter), so it rides this same patch.
677
- - **New `packages/sdk/README.md`**: what the SDK is, the send-injection model (`PreparedTx` +
678
- `SendTx`, `makeHotSender` for a hot key, bring-your-own for a wallet/multisig), a complete
679
- deploy → upload → mint → read walkthrough against real exports, and browser-use notes (explicit
680
- `rpcUrls`, no env, the `/node` subpath is Node-only). Included in the npm tarball automatically
681
- (README is one of the files npm always packs, regardless of the `files` allowlist).
682
-
683
- - Updated dependencies [11fa933]
684
- - Updated dependencies [11fa933]
685
- - Updated dependencies [11fa933]
686
- - Updated dependencies [11fa933]
687
- - @artblocks/abx-sdk@0.1.0-alpha.10
688
- - @artblocks/abx-storage@0.1.0-alpha.10
689
- - @artblocks/abx-indexer@0.1.0-alpha.11
690
-
691
- ## 0.1.0-alpha.12
692
-
693
- ### Patch Changes
694
-
695
- - df298d8: Fix three ways the reference resolver misreported on-chain state — and the head-read bug underneath one of them
696
-
697
- From an engineering audit by the abx-services team (2026-08-04), who run the same protocol on a
698
- hosted node against real testers and so reach long-tail states a single-node run rarely does. All
699
- three findings reproduced. Verifying the second one turned up a fourth defect that was its actual
700
- cause, and that one is the most consequential of the set.
701
-
702
- **1 · A renderer-computed TEXT field was dropped entirely.** `resolveImage` had an `R.renderer`
703
- branch; `resolveText` did not. So a `renderer`-represented `description`, `external_url`,
704
- `animation_url`, `background_color`, `youtube_url`, or `name` matched no branch and resolved **as if
705
- unset** — silently replaced by the operator's off-chain value with provenance reporting `off-chain`,
706
- or omitted from the metadata altogether. A creator who committed a computed field on-chain got the
707
- operator's version served instead, and nothing errored anywhere.
708
-
709
- `resolveText` now mirrors `AbxMetadataRenderer._appendText`'s `R_RENDERER` arm exactly, because the
710
- two must agree: with `tokenURIRenderer` set the chain assembles this JSON and the resolver merely
711
- re-serves it, so any difference is a resolver contradicting the token's own `tokenURI`. That means
712
- the **declared** contentType is used verbatim (`renderer` is the one representation that types itself
713
- on-chain) rather than an assumed `text/html`, and a `text/uri-list` result (RFC 2483 — the canonical
714
- generator's directory branch) lands as the locator it is, never data-wrapped. This is a deliberate
715
- divergence from the shape the audit recommended (pointing at the node's own `/data/{field}` route):
716
- parity with the on-chain renderer is the stronger constraint here. A field renderer that reverts now
717
- degrades that one field — with provenance saying the on-chain attempt failed, not a clean
718
- `off-chain` — instead of being indistinguishable from an unset field.
719
-
720
- **2 · The `name` fallback asserted an ERC-721 `name()` read it had not performed.** When
721
- `state.name` is null the served value is the raw contract address, and the note still said
722
- `on-chain (ERC-721 name() + #id)`. A hosted node served `"name": "0xb844…c35e56 #0"` beside that note
723
- while the contract's `name()` was `"ABXdoku"`. The wrong name is cosmetic; provenance is the surface
724
- you would point an artist at to audit their own metadata, so a false positive there costs more. The
725
- note is now conditional, and deliberately does not adjudicate _why_ the value was empty — the
726
- projection cannot tell an unnamed contract from a failed read, and guessing is how the original note
727
- came to lie.
728
-
729
- **3 · The live view answered "not a code project" for a code project that was merely mid-index.**
730
- `/a/` collapsed every `resolveLiveView` null into one confident verdict about the **contract**, when
731
- at least one is a statement about the **index**: `chunkCount` is a head read, so a template-mode
732
- project whose chunks have not been folded in yet reads as zero. A tester got
733
- `live · caught up · 127 events · 32 tokens` from the node and this 404, concluded the resolver did
734
- not recognise the SeriesCode factory, and a `--full` re-index did not clear it — the confident
735
- wording sent them looking in the wrong place. The route now consults `contractType` (folded from the
736
- deployed extensions, so it knows before any code lands) and answers **503 + Retry-After** for "not
737
- yet" versus 404 for "not ever". Both verdicts are answered before the chain client is touched, since
738
- neither needs an RPC. The three-way decision is extracted as `liveViewAvailability(state)` so it has
739
- a test seam at all.
740
-
741
- **4 · The head-read multicall failed _whole_ on the flagship lane, and took identity, trust, and the
742
- URI lane with it.** This was not in the audit — it is why finding 2 fires, found by reproducing it
743
- instead of accepting "an RPC hiccup". `applyHeadReads` batched `name`, `symbol`, `owner`,
744
- `contractURI`, `isAbxClone`, `implementation`, the four URI-config getters, and **one `tokenURI` per
745
- token** into a single multicall. A multicall is one `eth_call`: on a fully-on-chain project
746
- `tokenURI(id)` assembles the entire metadata document on-chain, so a handful of those legs exceeds a
747
- public node's budget and _every_ leg in the aggregate reports failure — including legs that answer
748
- fine alone.
749
-
750
- Measured on Base Sepolia `0xB844F4D2137a8Ce785Cbc80D281A36DBD1c35E56` (32 tokens, chain-complete):
751
- 1 tokenURI leg → 5/5 succeeded; **4 legs → 0/8 succeeded**, while `name()` on its own returned
752
- `"ABXdoku"`. Every resolver indexing that collection therefore believed it had no name, no symbol,
753
- no `contractURI`, no canonical proof — and **no `tokenURIRenderer`, i.e. that it was not in the
754
- on-chain-URI lane at all.** Deterministic for any sizable on-chain collection, not a hiccup.
755
-
756
- Reads are now split by cost class: the cheap fixed-size ones that decide a project's identity and
757
- lane go in a batch of their own and can never be collateral damage, while the unbounded ones
758
- (`contractURI`, per-token `tokenURI`, script chunks) read in small chunks through a helper that
759
- re-asks a failed chunk one leg at a time before believing it. After the fix, that same contract
760
- reconstructs with its name, symbol, both URI renderers, and all 32 token URIs intact.
761
-
762
- 12 regression tests across the four, including the null-name case both surfaces missed because every
763
- parity fixture on both sides hardcoded a non-null name.
764
-
765
- - Updated dependencies [df298d8]
766
- - Updated dependencies [df298d8]
767
- - Updated dependencies [df298d8]
768
- - @artblocks/abx-sdk@0.1.0-alpha.9
769
- - @artblocks/abx-storage@0.1.0-alpha.9
770
- - @artblocks/abx-indexer@0.1.0-alpha.10
771
-
772
- ## 0.1.0-alpha.11
773
-
774
- ### Patch Changes
775
-
776
- - Updated dependencies [e325b46]
777
- - @artblocks/abx-sdk@0.1.0-alpha.8
778
- - @artblocks/abx-indexer@0.1.0-alpha.9
779
- - @artblocks/abx-storage@0.1.0-alpha.8
780
-
781
- ## 0.1.0-alpha.10
782
-
783
- ### Patch Changes
784
-
785
- - Updated dependencies [1b50f9d]
786
- - Updated dependencies [1b50f9d]
787
- - @artblocks/abx-sdk@0.1.0-alpha.7
788
- - @artblocks/abx-storage@0.1.0-alpha.7
789
- - @artblocks/abx-indexer@0.1.0-alpha.8
790
-
791
- ## 0.1.0-alpha.9
792
-
793
- ### Patch Changes
794
-
795
- - 1158420: Fixes from a parallel cold-agent sweep: a chain typo no longer crashes every command, and `inspect` stops over-promising on hand-written PRNGs.
796
-
797
- **An unknown `ABX_CHAIN` printed a raw Node stack trace — from every command.** Chain-derived values
798
- were resolved at module scope, in `token-api` (which the CLI imports) and in the CLI itself, so the
799
- throw happened during module evaluation, before `main()` existed to catch it. `ABX_CHAIN=mainnet abx
800
- doctor` dumped an internal source path and exited 1 — including from the one command whose job is to
801
- tell you what is wrong with your environment. Those resolutions are lazy now, and the CLI validates
802
- the variable up front with an answer rather than a crash: unknown values list the shipped chains, and
803
- a mainnet-shaped value says plainly that ABX is testnet-only today.
804
-
805
- **`abx inspect` reported "(no PRNG)" for a hand-written seeded generator — with the _stronger_
806
- reproducibility verdict attached.** The `seeded` check only recognized p5's `randomSeed(`, so a
807
- vanilla LCG or xorshift matched no branch and fell through to "traits look derived from the
808
- seed/params directly". That is the common case, not an edge one — the skill's own canonical
809
- dependency-free example hand-rolls an LCG, and all three sketches written by agents in the sweep hit
810
- it. A hand-rolled generator now gets the `careful` verdict and is told the truth: deterministic and
811
- reproducible on-chain, but only by porting that exact generator and call order into Solidity.
812
-
813
- Also: `--yes` is now documented in `deploy-code --help` (its own placeholder-identity refusal already
814
- told you to pass it), and the `--onchain-uri` raster warning now names the two routes that actually
815
- deliver a no-server image instead of only one.
816
-
817
- Found by the 2026-08-03 parallel sweep (8 cold Sonnet/Haiku agents, isolated sandboxes).
818
-
819
- - Updated dependencies [1158420]
820
- - Updated dependencies [1158420]
821
- - Updated dependencies [1158420]
822
- - @artblocks/abx-sdk@0.1.0-alpha.6
823
- - @artblocks/abx-indexer@0.1.0-alpha.7
824
- - @artblocks/abx-storage@0.1.0-alpha.6
825
-
826
- ## 0.1.0-alpha.8
827
-
828
- ### Minor Changes
829
-
830
- - feba8c2: A resolver is no longer an object store: effect outputs split into **bound** and **referenced**
831
- (`specs/protocol/effects.md → Bound vs referenced`), and the artifact registry enforces the split.
832
-
833
- An output is **bound** iff a binding stitches its _content_ into the metadata JSON (today exactly
834
- `render/traits` → `attributes`); everything else is **referenced** — the projection carries its URL,
835
- or it only appears in the `artifacts` manifest. That one distinction decides who holds the bytes, and
836
- it is now the wire rule rather than a runner constant.
837
-
838
- - **`POST /v1/effect-artifacts` derives the mode from the binding, and refuses both mismatches.**
839
- Bytes for a referenced output → `400` (the resolver redirects either way, so the bytes buy no
840
- capability and cost it storage, retention and egress). A locator for a bound output → `400` (its
841
- content is assembled into `tokenURI`; a pointer there used to be recorded and then silently never
842
- stitch — a wrong answer served confidently). Bound content is capped at **64 KB**, and a locator
843
- that only the producer could resolve (loopback/private host, presigned expiring URL) is rejected.
844
- The resolver never fetches a locator while handling the write, and serves registered locators by
845
- `302` — never by proxying.
846
- - **Bound content moved out of byte custody** into the artifact row (`effect_artifacts.bytes`). Two
847
- distinct rules, deliberately not one: a node **MUST** serve and stitch bound content only at the
848
- token's current settled `inputsHash`, and it **MAY** drop superseded content whenever it likes
849
- (nothing may read it, and it is re-creatable). The reference drops eagerly, on each bound
850
- registration, so it holds at most `64 KB × minted × bound outputs` — but retention is a service
851
- policy, not an obligation. Either way "conforming means holding a bounded amount of JSON in the
852
- database you already run" is now literally true: a resolver in the publish topology needs no object
853
- storage at all.
854
- - **`abx-effects-publish/v1` is gone** (not deprecated): the two routes ride `abx-control-plane/v1`.
855
- Once referenced output is locator-only, accepting a registration is a database insert, so the
856
- capability flag described a distinction that no longer exists. A service that won't take a caller's
857
- artifacts refuses on the credential (`403`) — interfaces describe wire grammar, tokens describe
858
- permission. The interface ids are also explicitly **all-or-nothing**, and the conformance fixture
859
- now checks that every route a declared interface names actually answers.
860
- - **The runner declares bound outputs** (`EffectOutputDecl.bound`), refuses to start when it has a
861
- publish token but a backend that can't name a locator, preflights the descriptor + credential
862
- before spending a render, and **latches** on a permanent (4xx) publish failure instead of
863
- re-rendering every sweep forever. Skips now re-register rows, so a transient publish failure heals
864
- without a re-render.
865
- - **The CLI refuses the impossible combination up front**: `abx render --remote`, `abx effects`
866
- against a remote resolver, and `abx deploy-effects` all require a backend that can name a reachable
867
- URL — `cloud` (S3/R2 + public base), `ipfs`, or `arweave`, named as **peers**. Derived output is
868
- re-creatable, so the protocol has no preference among schemes: a chosen `https://` gateway or
869
- bucket URL is exactly as legitimate as `ipfs://`/`ar://`, and reachability — not durability — is
870
- the requirement. Rendering **co-located** with the resolver remains fully supported on any backend,
871
- including `fs`.
872
-
873
- Breaking for producers that relied on pushing media bytes to a resolver: publish a locator instead,
874
- or co-locate. Breaking for clients that read `abx-effects-publish/v1` from a descriptor.
875
-
876
- ### Patch Changes
877
-
878
- - Updated dependencies [feba8c2]
879
- - @artblocks/abx-sdk@0.1.0-alpha.5
880
- - @artblocks/abx-indexer@0.1.0-alpha.6
881
- - @artblocks/abx-storage@0.1.0-alpha.5
882
-
883
- ## 0.1.0-alpha.7
884
-
885
- ### Minor Changes
886
-
887
- - 67b686b: `abx contracturi`, and the read plane stops answering a bare 404 to three different problems.
888
-
889
- Both halves come from one real failure: an agent driving a hosted resolver wanted collection
890
- metadata, pattern-matched off `/t/{chainId}/{address}/{id}`, dropped the token id, got a bare `404`,
891
- and reported the service as broken. The documented route (`/c/{chainId}/{address}`) was right there —
892
- but there was also no command to just _ask_, and the 404 gave it nothing to correct.
893
-
894
- - **New `abx contracturi <address>`** — the collection-level counterpart of `tokenuri`. Reads
895
- `contractURI()` (ERC-7572) from the contract, **follows it**, and decodes: a `data:` URI inline
896
- (the on-chain lane), an `https://` URL by fetching it (the off-chain lane). A contract commits its
897
- own metadata base on-chain (`contractURIBase`), so the chain — not a doc, not a service
898
- descriptor — is the authoritative answer to where a project's metadata lives. Nobody needs to
899
- hand-build a resolver URL. When the fetch fails, the message says so plainly: the URL came from
900
- the chain, so a bad status is about the _service_ (unregistered project · wrong chain · down),
901
- never a mistyped path.
902
- - **Read-plane responses now carry a machine `code`**, so the three causes of "no metadata came
903
- back" are distinguishable — they were one indistinguishable `{"error": "…"}` `404`:
904
- - `400 invalid_request` — a real route, wrong shape. Names the correct template, and carries
905
- `didYouMean` when the fix is obvious (a `/t/…` missing its token id → `/c/{chainId}/{address}`).
906
- - `404 unknown_route` — this node serves nothing at that path; the body lists what it does serve.
907
- - `404 not_registered` — the path and chain were fine; this node doesn't index that contract.
908
- - `400 unsupported_chain` — wrong chain, plus the `chains` this node does serve. Was a bare `404`;
909
- now matches what the control plane already answered for the same condition.
910
- - `ServiceErrorCode` gains `unknown_route`. The spec's Errors section now covers the read plane too,
911
- with a **MUST** on distinguishing the three misses — and an explicit **MUST NOT** on treating
912
- route templates as per-node discoverable configuration. The route grammar is fixed by the
913
- `abx-token-api/v1` interface; these responses are diagnostics, not a discovery mechanism.
914
- - **The conformance fixture checks all of it** (`pnpm conformance <base-url>`), so any provider can
915
- self-verify in one command. Also fixed: the documented `pnpm conformance -- <base-url>` form
916
- parsed `--` as a flag and swallowed the base URL, printing usage instead of running.
917
-
918
- ### Patch Changes
919
-
920
- - Updated dependencies [67b686b]
921
- - @artblocks/abx-sdk@0.1.0-alpha.4
922
- - @artblocks/abx-indexer@0.1.0-alpha.5
923
- - @artblocks/abx-storage@0.1.0-alpha.4
924
-
925
- ## 0.1.0-alpha.6
926
-
927
- ### Minor Changes
928
-
929
- - a72723d: A standard indexing lifecycle, and registration that no longer blocks on a slow chain RPC
930
- (specs/self-host-toolkit/remote-services.md → The indexing lifecycle).
931
-
932
- - **Fixed: a slow register triggered a retry storm.** The SDK's per-attempt timeout (30s) plus its
933
- retry ladder meant a cold reconstruct that outran one request was **re-POSTed up to four times**,
934
- each starting another full replay against the RPC that was already too slow to answer — and the
935
- caller then saw "nothing responded" even though the registration was durable and indexing was
936
- underway. A timed-out register now asks whether it landed (a status read) instead of re-POSTing, and
937
- the resolver coalesces concurrent catch-ups for one project into a single run.
938
- - **`POST /v1/projects` answers in two conformant shapes, discriminated by HTTP status:** `200` with
939
- the completed summary, or `202` + `{accepted, project: {status}}` when catch-up is deferred. The
940
- registration is normatively **durable before catch-up** and visible on the list immediately, so a
941
- flaky RPC makes for a slower backfill rather than a lost add. No `?wait=`/`Prefer:` negotiation — the
942
- status code is the discriminator, and clients handle both. The reference resolver answers _by
943
- deadline_ (`ABX_REGISTER_DEADLINE_MS`, default 8s): the common case (a fresh deploy) stays
944
- synchronous with real counts; only the pathological case defers.
945
- - **Closed lifecycle enum + error classes, on the status and list routes:**
946
- `queued | backfilling | live | stale | failed`, plus credential-free
947
- `error.class ∈ {rpc_unavailable, rpc_rate_limited, not_abx_contract, internal}` (fixed per-class
948
- messages, never a scrubbed upstream string). Status gains top-level `headBlock` (so lag / % complete
949
- is computable without knowing a service has a watcher) and `attempts`; the list carries `status` +
950
- the error class, so a client renders "3 live, 1 backfilling, 1 failed (rpc_rate_limited)" in one
951
- request. SDK: `IndexStatus`, `IndexErrorClass`, `isAccepted()`, `indexProgress()`,
952
- `classifyIndexError()`, and `AbxServiceClient.awaitIndexed()` — one wait loop for the CLI, the
953
- effects runner, and any hosted agent.
954
- - **The same five words on your own node.** `abx status [address] [--remote [name|url]] [--watch]`:
955
- bare is the node summary (now with each project's state), an address gives lifecycle + scan floor +
956
- blocks-indexed-vs-head + cause, and `--remote` asks a service. (`status` = who is serving it and how
957
- fresh; `state` = what the chain says. Both `--help` texts now say so.)
958
- - **New observability the self-hosted node never had:** the chain watcher marks projects `stale` when
959
- it falls far behind head or its ticks keep failing (previously visible only in the node's log),
960
- re-queues a backfill interrupted by a restart (previously left registered-but-empty until a manual
961
- `abx index`), and retries a `failed` catch-up on exponential backoff instead of hammering a
962
- rate-limited RPC every tick. Lifecycle rows live in their own table: they survive a projection wipe
963
- and are never clobbered by a re-add.
964
- - **CLI:** `abx add|index --remote` prints `registered — backfilling…`, polls to `live`, then prints
965
- the same summary a synchronous service would have given; `--no-wait` returns at the 202 and names
966
- the command to check later. A post-op nudge (`ownerops`) never blocks on someone else's backfill.
967
- A caught-up project with **0 events** now warns instead of printing ✓ (a real ABX clone always emits
968
- a spine, so zero means wrong chain/floor or an RPC that didn't serve the logs).
969
- - **Conformance fixture** accepts either register shape, asserts durable-before-catch-up, lifecycle
970
- membership, `headBlock`, that a deferred catch-up actually reaches `live`, and that no error message
971
- carries a URL.
972
- - Fixed `scripts/mock-remote-service.mts`, which imported the token API by a path that resolved
973
- against `scripts/` and could silently fall back to a _published_ build outside the repo — the
974
- fixture was testing the last release instead of the working tree. The fixture also re-points
975
- scenarios by their fixture header now, so a new one can't keep a dead contract address.
976
-
977
- Found by a cold-agent sweep over the above (10 parallel clean rooms, haiku + sonnet) and fixed here:
978
-
979
- - **`abx status --remote <name>` with no address** parsed the flag itself as the address and sent it
980
- as a URL path segment.
981
- - **A register whose catch-up already failed** was announced as "registered — failed (…is catching
982
- up…)", and with `--no-wait` it exited 0 and then claimed the provider "now serves" the project. A
983
- known failure is now an error in both lanes — there is nothing left to wait for.
984
- - **A `failed` status said what broke but not whose problem it was.** Both the failure error and
985
- `abx status` now carry a per-class action line ("the SERVICE can't reach its chain RPC — not your
986
- key, address, or chain…"), plus a `follow` line naming `--watch`, so a red word isn't a dead end.
987
- - **A `live` project showed a misleading completion percentage.** `toBlock` only advances when a
988
- project has _events_, so a fully current project on a busy chain read as `2/202 (0%)`.
989
- `indexProgress()` now returns a ratio only while `backfilling`; `live` reads "caught up", `stale`
990
- reads "not tracking head right now".
991
- - **`--remote-token` was misattributed on a 401** — the error blamed `ABX_REMOTE_<NAME>_TOKEN` even
992
- when the caller passed an override, making the override look ignored at exactly the moment someone
993
- is testing a replacement key.
994
- - **`not_registered` on a read** (status/reindex) now names the register command instead of echoing a
995
- 404, and a 5xx carrying a failure `class` becomes a wait-vs-broken error.
996
- - **`abx verify`'s summary** read `✓ 0/1 up to date` for a project with no off-chain renders at all —
997
- "zero of one succeeded" to two independent reviewers. It now says "nothing to render for this
998
- project", and otherwise leads with polarity ("N of M token(s) current").
999
- - **`abx doctor` now reports named remotes** and flags a credential stored under a name the CLI does
1000
- not read (`ABX_REMOTE_<NAME>_KEY`). That fault presents as "it acts like I never gave it a key" and
1001
- previously only surfaced from `abx remote <name>` — which a creator reaches _after_ doctor.
1002
- - **Skill: the `npx --no-install abx version` probe was documented as failing cleanly.** It doesn't —
1003
- npm will run any `abx` binary already in the npx cache, which in a real sweep reported a months-old
1004
- build as the project's CLI (and if a plain `npx abx` ever ran on that machine, the bare name is a
1005
- squatted package). The skill now probes `./node_modules/.bin/abx` directly.
1006
- - Also documented: how a multi-word provider name folds into `ABX_REMOTE_<NAME>_*`, and what
1007
- `watching: no` means on a status readout.
1008
-
1009
- A second sweep round over those fixes caught three more, including one the first round's fix created:
1010
-
1011
- - **`abx verify --remote` never checked byte integrity at all** — both of its lanes only ask "is there
1012
- a current render / is this a placeholder", and a green ✓ from that was standing in for "the served
1013
- bytes match the on-chain commitment". A reviewer hit the worst version of this: `--remote` (the form
1014
- the skill tells you to use for a hosted project) reported ✓ on a token whose bytes genuinely did NOT
1015
- hash-match, while bare `abx verify` on the same project reported `✗ keccak256 MISMATCH`. It now calls
1016
- the service's own purpose-built `GET /api/project/:addr/verify` (which holds both the bytes and the
1017
- chain) and reports that verdict separately from the render summary — and when it _can't_ run that
1018
- check (no credential, older node) it says "byte integrity NOT checked" instead of leaving a ✓ to
1019
- imply it passed. The remedy names both real causes (an unbridged durable locator vs. bytes that only
1020
- exist on the creator's machine, which a hosted resolver can never serve).
1021
- - **`abx verify` exited 0 while printing a byte MISMATCH**, in both lanes — nothing could gate on it.
1022
- An integrity mismatch now fails the command; a missing render or placeholder is a normal state and
1023
- still exits 0.
1024
- - **`abx add --dry-run` silently ignored the flag and performed the registration**, local or remote.
1025
- It now refuses and names the read-only commands (`abx state`, `abx status`) instead. Silently doing
1026
- the thing when the caller asked to preview is the one outcome that must never happen.
1027
- - **`PRAGMA busy_timeout` was set third in the store schema**, after the WAL switch it needs to
1028
- protect — so two processes opening the same store at once (parallel CLI runs, or a co-located
1029
- effects runner starting alongside the resolver) could fail outright with `database is locked`
1030
- instead of waiting the moment out. It is now the first statement.
1031
-
1032
- A third round, re-running the scenario that found the verify bug (it now catches it) turned up:
1033
-
1034
- - **`abx add --remote` ended on "it now serves <url>"** — true about indexing, silent about whether
1035
- the bytes are right, and two reviewers stopped there and reported a blank page as fixed. It now names
1036
- the byte check (`abx verify <addr> --remote <name>`) in the same breath.
1037
- - **`canonical:` collapsed a tri-state.** `isCanonical` is `true | false | null`, and both readouts
1038
- printed "unverified" for the last two — so "the chain says this is NOT a clone of the configured
1039
- factory" (a trust finding) looked identical to "the check never ran" (no factory on this chain, normal
1040
- on a dev chain). Two reviewers read the collapsed word as a second failure sitting next to a real one.
1041
- - **`abx verify --remote` gave a bare `fetch failed`** for an endpoint that was down, where
1042
- `abx status --remote` names the host and asks whether it's running. Two commands, one condition, two
1043
- error qualities — now consistent.
1044
- - `abx status <addr>` printed the address twice when the project has no name.
1045
- - Skill: registering with a provider on **their** hostname vs. a domain you control decides whether
1046
- leaving later costs a transaction — now stated in the managed-provider section, before you bake it.
1047
-
1048
- ### Patch Changes
1049
-
1050
- - Updated dependencies [a72723d]
1051
- - @artblocks/abx-sdk@0.1.0-alpha.3
1052
- - @artblocks/abx-indexer@0.1.0-alpha.4
1053
- - @artblocks/abx-storage@0.1.0-alpha.3
1054
-
1055
- ## 0.1.0-alpha.5
1056
-
1057
- ### Minor Changes
1058
-
1059
- - 3745bd3: Remote services are first-class: a provider-neutral control plane, named remotes, and a service
1060
- descriptor (specs/self-host-toolkit/remote-services.md).
1061
-
1062
- - **Control plane moves to `/v1`** (hard cutover; `/admin/*` is gone — redeploy self-hosted nodes):
1063
- `POST/GET /v1/projects`, `DELETE|reindex|status /v1/projects/{chainId}/{address}`,
1064
- `POST /v1/effect-artifacts|effect-status`. `chainId` is explicit and validated everywhere; every
1065
- error carries a machine `code` (`unauthorized` 401 · `forbidden` 403 · `unsupported_chain` ·
1066
- `not_registered` · `disabled`) replacing the old prose-sniffed 404. One bearer guard replaces the
1067
- four inline copies; OPTIONS preflight now answers so browser clients can send `Authorization`.
1068
- - **`GET /.well-known/abx-service`** — the public service descriptor: `interfaces` (present iff
1069
- actually enabled), `chains`, `auth` (with optional provider-set `signupUrl`/`docsUrl` via
1070
- `ABX_SERVICE_*` env), and `render.attached` (managed rendering, probed from the runner's
1071
- `/health`) — so an agent can match a project to a provider before registering.
1072
- - **Named remotes in the CLI**: `--remote <name>` reads `ABX_REMOTE_<NAME>_URL`/`_TOKEN`
1073
- (a managed provider's per-account key — never falls back to `ABX_RESOLVER_ADMIN_TOKEN`);
1074
- `--remote <url> [--remote-token <t>]` for ad-hoc targets; bare `--remote` stays the self-host
1075
- default. New `abx remote [name|url]` inspects a service's descriptor and the projects a token
1076
- sees. `migrate --from/--to` accept names; only the destination needs a credential.
1077
- - **The SDK gains its first HTTP surface**: `AbxServiceClient` (endpoint + injected bearer, retry
1078
- on 5xx/network, immediate typed `AbxServiceError` on 4xx) — shared by the CLI and the effects
1079
- runner's publish lane. `envSuffix()` is the shared env-name normalization.
1080
- - **Conformance fixture**: `pnpm conformance -- <base-url> [--token …]` self-verifies any
1081
- implementation; the e2e suite runs it against the reference container.
1082
-
1083
- ### Patch Changes
1084
-
1085
- - 3745bd3: Membrane fixes found by a 20-run cold-agent regression sweep (sonnet + haiku, black-box clean rooms).
1086
-
1087
- - **A 500 no longer leaks the node's own credentials.** An upstream RPC failure surfaced viem's
1088
- message, which embeds the endpoint URL — and a keyed RPC URL _is_ a credential, so on a
1089
- multi-tenant provider any tenant who could provoke a 500 got the operator's RPC key. The cause now
1090
- goes to the node's log; the wire gets a generic message, an `internal_error` code, and a
1091
- credential-free hint about the failure class. Normative in the remote-services spec.
1092
- - **The service client no longer discards a 5xx body.** The service's own words survive the retry
1093
- ladder, and an exhausted ladder says "failed — last response …" rather than mislabelling a
1094
- server that answered as "unreachable". The descriptor probe drops to 2 attempts, so a typo'd
1095
- provider URL fails in ~1s instead of grinding 5s, with distinct "nothing responded" vs
1096
- "answered, but serves no descriptor" messages.
1097
- - **Conflicting duplicate `.env` keys are reported.** First-wins is unchanged, but a stale second
1098
- `ABX_RPC_URLS_<CHAIN>` line silently pointed the CLI at another network while every check read
1099
- green — the symptom surfaced far away as "no contract at that address". Only genuinely
1100
- _conflicting_ duplicates warn (identical repeats stay quiet).
1101
- - **"No contract at …" errors now name the endpoint they asked** (redacted), because a chain key
1102
- can't distinguish two RPCs that both claim it.
1103
- - **A misnamed remote credential is called out.** `ABX_REMOTE_<NAME>_KEY` (or `_API_KEY`, `_SECRET`)
1104
- is not read, so it previously reported as "no token" while the value sat in `.env`; both
1105
- `abx remote` and the register path now name the near-miss and the correct `_TOKEN` name.
1106
- - **`--dry-run` explains a missing trust anchor instead of crashing.** On a chain where the
1107
- configured factory has no code, `deploy`/`deploy-series` previews died inside
1108
- `predictDeterministicAddress` with a raw `returned no data ("0x")`; they now report it the way
1109
- `abx predict` and a real deploy already did, and name the two ways forward. The keyless
1110
- `--for` requirement also fails fast instead of after several steps of output.
1111
- - **The placeholder-identity guard is one shared predicate** across all three deploy commands
1112
- (it was copy-pasted, and one copy's comment claimed coverage it didn't have), pinned by a new
1113
- regression test: a real send refuses tool defaults, a preview only warns.
1114
- - **The served dashboard's empty state no longer prints `pnpm abx demo`** — a contributor-only
1115
- invocation on a page a published user sees.
1116
-
1117
- - Updated dependencies [3745bd3]
1118
- - Updated dependencies [3745bd3]
1119
- - @artblocks/abx-sdk@0.1.0-alpha.2
1120
- - @artblocks/abx-indexer@0.1.0-alpha.3
1121
- - @artblocks/abx-storage@0.1.0-alpha.2
1122
-
1123
- ## 0.1.0-alpha.4
1124
-
1125
- ### Patch Changes
1126
-
1127
- - 4074766: Fix the dashboard's block-explorer links, which were hardcoded to `https://sepolia.etherscan.io`. Every
1128
- link on the page — contract, owner, implementation, each event's tx — pointed at Ethereum Sepolia no
1129
- matter which chain was being served, so a dashboard for a normal `abx demo` (Base Sepolia by default)
1130
- sent you to an explorer where the contract does not exist. The SDK now derives the explorer from viem's
1131
- own chain metadata (`explorerUrl`/`chainById`), so adding a chain brings its explorer along and no
1132
- hand-maintained table can drift. The CLI's separate copy of that table is collapsed into the same
1133
- helper; `signer.ts` was already doing it correctly.
1134
-
1135
- Drop the demo's opening "trust anchor" step. It asserted that only the canonical factory can make a
1136
- token that _is_ an ABX token, which is false — anything following the protocol's event spine is an ABX
1137
- token, and the factory is one route to that, not the definition. The same overclaim in the index step
1138
- ("verified real") now reports the fact instead: made by the canonical factory, or not. The demo opens
1139
- on the renderer step, and resolving the factory no longer prints a line of its own there.
1140
-
1141
- - Updated dependencies [4074766]
1142
- - @artblocks/abx-sdk@0.1.0-alpha.1
1143
- - @artblocks/abx-indexer@0.1.0-alpha.2
1144
- - @artblocks/abx-storage@0.1.0-alpha.1
1145
-
1146
- ## 0.1.0-alpha.3
1147
-
1148
- ### Patch Changes
1149
-
1150
- - Updated dependencies [c21ea30]
1151
- - @artblocks/abx-indexer@0.1.0-alpha.1
1152
-
1153
- ## 0.1.0-alpha.2
1154
-
1155
- ### Patch Changes
1156
-
1157
- - afb36a3: Fix three bugs that made the documented first run (`abx demo`) look broken.
1158
-
1159
- **A 0-event index was reported as success, and served.** `eth_getLogs` is
1160
- read-after-write inconsistent on load-balanced RPCs: `waitForTransactionReceipt`
1161
- resolves against a node that has the block, then the log query lands on one that
1162
- doesn't yet and returns nothing for a block we _know_ contains our deploy. The CLI
1163
- took that single read at face value, printed `✓ reconstructed 0 events`, stored the
1164
- empty projection and served an empty dashboard — no events, no token, nothing to
1165
- look at. This reproduced 100% of the time against `https://sepolia.base.org`, which
1166
- is the **default endpoint when there is no `.env`** — so the documented first run
1167
- was the path that broke. Every post-deploy index (`deploy`, `demo`, `deploy-series`,
1168
- `deploy-code`, `add`) now re-scans with backoff instead of trusting one read, since
1169
- having just minted means the spine cannot legitimately be empty. If it still comes
1170
- back empty, that is now reported as a failure naming `abx index <addr> --full` as
1171
- the recovery, rather than dressed up as a ✓.
1172
-
1173
- **The demo told you to press a button that does not exist.** It ended with _"Open
1174
- the dashboard, then hit 'Re-index from chain'"_. The dashboard is read-only —
1175
- re-index and verify are admin actions that 404 unless the node has an
1176
- `ABX_RESOLVER_ADMIN_TOKEN` — so that control isn't there to find. It now points at
1177
- the spine table (which _is_ the reconstruction) and at `abx index <addr> --full` to
1178
- replay it. The dashboard's own note also stopped printing a **shortened** address
1179
- inside a copy-pasteable command, and no longer suggests `--remote` for a local node.
1180
-
1181
- **Re-running the demo crashed after spending a transaction.** With port 8787 already
1182
- busy — an `abx demo` or `abx serve` in another terminal, i.e. exactly what happens
1183
- when you run the demo twice — the deploy went through, was paid for, and _then_ the
1184
- serve step died with an unhandled Node `EADDRINUSE` stack trace. The port is now
1185
- preflighted before anything irreversible, so it refuses with "Nothing was deployed"
1186
- and suggests `--port <n+1>`.
1187
-
1188
- **`abx demo` is now a walkthrough rather than a smoke test.** The docs point a
1189
- first-time reader here, but it asserted its interesting claims without ever showing
1190
- them — "reconstructed 9 events — no provider involved" with the events invisible.
1191
- It now teaches, continuously and without pauses (so agents and CI behave
1192
- identically): it explains why the trust anchor is the factory and not a spoofable
1193
- event, names what goes on chain versus what stays a keccak256 commitment, prints
1194
- the reconstructed event spine with what each event told us (tagged ABX vs plain
1195
- ERC-721/7572), then **deletes its own local projection and replays it from the
1196
- deploy block**, comparing a sha256 fingerprint of every chain-derived field to prove
1197
- it lands on identical state. Finally it reads the token back the way a marketplace
1198
- would. `abx deploy` is unchanged — it stays terse.
1199
-
1200
- Adds `Store.dropProjection(address)` / `SelfHostIndexer.dropProjection()`: discard a
1201
- project's reconstructed projection while keeping its registration, so the next index
1202
- rebuilds from the deploy block. That's the primitive the rebuild proof needs, and it
1203
- makes "the projection is a disposable cache" a checkable claim rather than a comment.
1204
-
1205
- ## 0.1.0-alpha.1
1206
-
1207
- ### Patch Changes
1208
-
1209
- - 48d96c5: Add **`abx preview`** — the studio lane for code projects: run the program on
1210
- localhost, live, while it's still being made. No chain, no key, no deploy.
1211
-
1212
- `abx preview --script art.js --schema "palette:HexColor:TokenOwner"` serves a
1213
- studio on `localhost:8788` — shuffle seeds, drive every declared PostParam from a
1214
- real typed input (a color picker for `HexColor`, a dropdown for `Select`), read the
1215
- traits the program actually reported, and `/grid` to see N seeds at once. `/view`
1216
- is the bare document. The program is re-read from disk on every render, so the loop
1217
- is edit-and-refresh with no watcher and no restart.
1218
-
1219
- It serves the **same template-mode document the generator serves** — the real
1220
- `abx.js`, the real canonical `tokenData` shape, the real dependency script tags —
1221
- with a synthetic bytes32 seed in place of a minted one, so what you approve is what
1222
- deploys. There is no second copy of the runtime to drift from. (`@artblocks/abx-token-api`
1223
- now exports `ABX_JS` and the inline-safety escapes so the CLI can build that exact
1224
- document rather than reimplement it.)
1225
-
1226
- `--shoot <dir>` drives the same server headlessly to PNGs plus a `traits.json` and
1227
- exits — that's how an agent, which can't open a browser, sees what the creator sees.
1228
- It also flags the two silent killers: no frame reporting traits (⇒ no marketplace
1229
- `attributes` on any lane) and identical traits across every seed (⇒ the program
1230
- isn't reading `abx.tokenData.seed`, so the drop mints N identical tokens).
1231
-
1232
- Why a live server rather than a screenshot sweep: a still flattens every time-based
1233
- piece, and `abx.done()` exists precisely because stills need a settle point — so a
1234
- proof sheet of an animated piece is a set of arbitrary frozen frames presented as
1235
- the work. Frames render into a fixed 1000×1000 viewport and are scaled to fit their
1236
- slot, so a program that hardcodes its canvas size is never clipped to its own corner.
1237
-
1238
- Skill: add **Phase 0**, an explicit authoring phase that puts every deploy decision
1239
- (hosting, thumbnail, traits, storage, wallet, supply, royalties, name/symbol) off
1240
- the table until the creator says ship, and points at `abx preview` for the loop. The
1241
- skill previously went straight from "the creator brought an idea" to "pick a deploy
1242
- lane", so an agent helping someone _design_ a piece front-loaded infrastructure
1243
- questions while there was still nothing to look at.
1244
-
1245
- Skill: also teach CLI resolution — probe project-local (`npx --no-install abx`)
1246
- before global, install `@artblocks/abx-cli` (not `@artblocks/abx-sdk`, which ships
1247
- no binary), and default to a per-project install. The skill previously assumed `abx`
1248
- was already on PATH and gave no bootstrap path at all, so agents improvised — one
1249
- installed the SDK, then went global unprompted.
15
+ Public release history begins here.