@artblocks/abx-token-api 0.1.0-alpha.32 → 0.1.0-alpha.34

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