vapor-chamber 1.26.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +280 -215
  3. package/ROADMAP.md +497 -497
  4. package/bin/vc-vitest-mcp.mjs +3 -3
  5. package/dist/LICENSE.txt +3 -3
  6. package/dist/action-filter.d.ts +37 -0
  7. package/dist/action-filter.d.ts.map +1 -0
  8. package/dist/applied-remotely.d.ts +28 -0
  9. package/dist/applied-remotely.d.ts.map +1 -0
  10. package/dist/{library-names.js → applied-remotely.js} +3 -1
  11. package/dist/applied-remotely.js.map +1 -0
  12. package/dist/bounds.d.ts +2 -2
  13. package/dist/bounds.js.map +1 -1
  14. package/dist/chamber-vapor.js +1 -1
  15. package/dist/chamber.d.ts +3 -3
  16. package/dist/chamber.d.ts.map +1 -1
  17. package/dist/chamber.js +44 -34
  18. package/dist/chamber.js.map +1 -1
  19. package/dist/command-bus.d.ts +125 -27
  20. package/dist/command-bus.d.ts.map +1 -1
  21. package/dist/command-bus.js +289 -133
  22. package/dist/command-bus.js.map +1 -1
  23. package/dist/devtools.d.ts +22 -7
  24. package/dist/devtools.d.ts.map +1 -1
  25. package/dist/devtools.js +24 -4
  26. package/dist/devtools.js.map +1 -1
  27. package/dist/directives2.js +1 -1
  28. package/dist/failure.d.ts +18 -5
  29. package/dist/failure.d.ts.map +1 -1
  30. package/dist/failure.js +22 -5
  31. package/dist/failure.js.map +1 -1
  32. package/dist/http-cache.d.ts +4 -3
  33. package/dist/http-cache.d.ts.map +1 -1
  34. package/dist/http-errors.d.ts +4 -4
  35. package/dist/http.d.ts +11 -7
  36. package/dist/http.d.ts.map +1 -1
  37. package/dist/http.js +89 -22
  38. package/dist/http.js.map +1 -1
  39. package/dist/idb.d.ts +30 -0
  40. package/dist/idb.d.ts.map +1 -0
  41. package/dist/idb.js +46 -0
  42. package/dist/idb.js.map +1 -0
  43. package/dist/iife-core.js +1 -1
  44. package/dist/iife-elements.js +1 -1
  45. package/dist/iife.js +1 -1
  46. package/dist/index.d.ts +5 -3
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +167 -92
  49. package/dist/index.js.map +1 -1
  50. package/dist/ledger.d.ts.map +1 -1
  51. package/dist/ledger.js +8 -4
  52. package/dist/ledger.js.map +1 -1
  53. package/dist/mcp.d.ts +30 -20
  54. package/dist/mcp.d.ts.map +1 -1
  55. package/dist/mcp.js +23 -16
  56. package/dist/mcp.js.map +1 -1
  57. package/dist/outbox.d.ts +16 -11
  58. package/dist/outbox.d.ts.map +1 -1
  59. package/dist/outbox.js +17 -41
  60. package/dist/outbox.js.map +1 -1
  61. package/dist/plugins-core.d.ts +15 -7
  62. package/dist/plugins-core.d.ts.map +1 -1
  63. package/dist/plugins-core.js +18 -15
  64. package/dist/plugins-core.js.map +1 -1
  65. package/dist/plugins-extra.d.ts +45 -25
  66. package/dist/plugins-extra.d.ts.map +1 -1
  67. package/dist/plugins-io.d.ts +29 -5
  68. package/dist/plugins-io.d.ts.map +1 -1
  69. package/dist/plugins-io.js +48 -22
  70. package/dist/plugins-io.js.map +1 -1
  71. package/dist/plugins-schema.js +1 -1
  72. package/dist/plugins.d.ts +1 -1
  73. package/dist/plugins.d.ts.map +1 -1
  74. package/dist/poll-with.d.ts +6 -3
  75. package/dist/poll-with.d.ts.map +1 -1
  76. package/dist/router/engine.d.ts +1 -1
  77. package/dist/router/engine.d.ts.map +1 -1
  78. package/dist/router/facts.d.ts +43 -0
  79. package/dist/router/facts.d.ts.map +1 -0
  80. package/dist/router/history.d.ts +2 -1
  81. package/dist/router/history.d.ts.map +1 -1
  82. package/dist/router/index.d.ts +2 -0
  83. package/dist/router/index.d.ts.map +1 -1
  84. package/dist/router/index.js +2 -2
  85. package/dist/router/router-type.d.ts +3 -1
  86. package/dist/router/router-type.d.ts.map +1 -1
  87. package/dist/router/table.d.ts.map +1 -1
  88. package/dist/router-fetch/index.js +1 -1
  89. package/dist/router.js +62 -38
  90. package/dist/router.js.map +1 -1
  91. package/dist/schema.d.ts +43 -9
  92. package/dist/schema.d.ts.map +1 -1
  93. package/dist/shared-bus.js +1 -1
  94. package/dist/ssr.d.ts +2 -2
  95. package/dist/ssr.d.ts.map +1 -1
  96. package/dist/ssr2.js +6 -5
  97. package/dist/ssr2.js.map +1 -1
  98. package/dist/store/core.d.ts +1 -1
  99. package/dist/store/core.d.ts.map +1 -1
  100. package/dist/store/core.js.map +1 -1
  101. package/dist/store-base.d.ts +38 -7
  102. package/dist/store-base.d.ts.map +1 -1
  103. package/dist/store-base.js +135 -30
  104. package/dist/store-base.js.map +1 -1
  105. package/dist/store.d.ts +4 -4
  106. package/dist/store.d.ts.map +1 -1
  107. package/dist/store.js.map +1 -1
  108. package/dist/testing.d.ts +1 -1
  109. package/dist/testing.d.ts.map +1 -1
  110. package/dist/transports.d.ts +25 -12
  111. package/dist/transports.d.ts.map +1 -1
  112. package/dist/transports2.js +64 -23
  113. package/dist/transports2.js.map +1 -1
  114. package/dist/utilities.d.ts +13 -12
  115. package/dist/utilities.d.ts.map +1 -1
  116. package/dist/vapor-chamber-core.iife.js +482 -201
  117. package/dist/vapor-chamber-core.iife.js.map +1 -1
  118. package/dist/vapor-chamber-core.iife.min.js +1 -1
  119. package/dist/vapor-chamber-elements.iife.js +482 -201
  120. package/dist/vapor-chamber-elements.iife.js.map +1 -1
  121. package/dist/vapor-chamber-elements.iife.min.js +1 -1
  122. package/dist/vapor-chamber.iife.js +654 -321
  123. package/dist/vapor-chamber.iife.js.map +1 -1
  124. package/dist/vapor-chamber.iife.min.js +1 -1
  125. package/dist/vitest-mcp.d.ts +6 -5
  126. package/dist/vitest-mcp.d.ts.map +1 -1
  127. package/dist/vitest-mcp.js +5 -5
  128. package/dist/vitest-mcp.js.map +1 -1
  129. package/dist/vitest-pure.d.ts +5 -5
  130. package/dist/vitest-pure.d.ts.map +1 -1
  131. package/dist/vitest-pure.js.map +1 -1
  132. package/package.json +1 -1
  133. package/scripts/check-console-shape.mjs +1 -1
  134. package/scripts/check-size.mjs +111 -3
  135. package/src/action-filter.ts +85 -0
  136. package/src/applied-remotely.ts +25 -0
  137. package/src/bounds.ts +2 -2
  138. package/src/chamber.ts +55 -41
  139. package/src/command-bus.ts +437 -144
  140. package/src/devtools.ts +41 -8
  141. package/src/failure.ts +48 -9
  142. package/src/http-cache.ts +16 -15
  143. package/src/http-errors.ts +4 -4
  144. package/src/http.ts +148 -38
  145. package/src/idb.ts +71 -0
  146. package/src/index.ts +8 -1
  147. package/src/ledger.ts +10 -2
  148. package/src/mcp.ts +58 -38
  149. package/src/outbox.ts +31 -51
  150. package/src/plugins-core.ts +38 -19
  151. package/src/plugins-extra.ts +104 -47
  152. package/src/plugins-io.ts +83 -29
  153. package/src/plugins.ts +1 -0
  154. package/src/poll-with.ts +12 -4
  155. package/src/router/engine.ts +50 -50
  156. package/src/router/facts.ts +45 -0
  157. package/src/router/history.ts +4 -3
  158. package/src/router/index.ts +13 -9
  159. package/src/router/router-type.ts +3 -1
  160. package/src/router/table.ts +4 -2
  161. package/src/schema.ts +64 -16
  162. package/src/ssr.ts +10 -6
  163. package/src/store/core.ts +1 -1
  164. package/src/store-base.ts +243 -55
  165. package/src/store.ts +4 -4
  166. package/src/testing.ts +47 -37
  167. package/src/transports.ts +96 -35
  168. package/src/utilities.ts +27 -16
  169. package/src/vitest-mcp.ts +10 -9
  170. package/src/vitest-pure.ts +5 -5
  171. package/dist/library-names.js.map +0 -1
  172. package/dist/settled.js +0 -31
  173. package/dist/settled.js.map +0 -1
  174. package/dist/store-core.d.ts +0 -4
  175. package/dist/store-core.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,87 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## v1.28.0 - 2026-10-07
6
+
7
+ - Fixed `createRouter()` throwing a TypeError on a route row whose `params` is `null`. The row now compiles as one without param types.
8
+ - Added `headers` to a batched result and a WebSocket frame, as OData's JSON batch response has them. Their `Retry-After` sets the wait as a response's does, so an idempotent batched command now waits and is sent again.
9
+ - Changed the reference Laravel controller's `batch()` to send each result the headers its own response would have had, such as `Retry-After: 1` on `in_progress`.
10
+ - Improved the development message when a store or history from a second copy of vapor-chamber registers on a bus. It now names the two copies instead of asking the app to rename the action.
11
+ - Fixed the README schema example, which imported `CommandsOf`. The type is `InferMap`.
12
+ - Added `plugins` to `inspectBus()`: each installed plugin's declared `id`, `priority`, `actions`, whether it has an `actionFilter`, and whether it is a `transport`, in execution order. A hand-built `BusInspection` now needs the field.
13
+ - Fixed `persist` failing every dispatch with `persist:failed:plugin` when the browser blocks site data, so reading `localStorage` throws. It now warns and the dispatch succeeds, and `load()` returns null instead of throwing.
14
+ - Fixed a before- or after-hook that unsubscribes itself, or another hook, during a dispatch skipping the next hook. In `onBefore` the dispatch also failed with `core:refused:hook` and its handler never ran. Hooks now follow the listeners' rule: a dispatch runs the hooks that existed when it started and skips one removed during it, on both buses and in `createTestBus()`. Calling one unsubscribe twice now removes only its own subscription.
15
+ - Fixed a navigation failing with `router:failed:guard` when one guard removed itself and a later guard, and the same case in `afterEach` logging a TypeError. Calling one unsubscribe twice now removes only its own guard or hook. A guard added during a navigation still runs in it.
16
+ - Changed the development check of `undo: true` stores to compare the two reducer runs without serializing the whole state. A part the reducer left unchanged is not read, and the same states warn as before. Production builds are unchanged.
17
+ - Added `actions` and `actionFilter` to `persist`, as on other plugins. The bus then runs it only for those actions: `actions: ['cart*']` saves on `cartAdd`, `cart$reset` and an undo of `cartAdd`. Without them it saves after every successful dispatch, as before.
18
+ - Added `indexedDbStorage()` and `persist().hydrate()`. `persist({ storage: indexedDbStorage() })` saves to IndexedDB, and `await hydrate()` reads the saved state from any storage. `load()` still reads a synchronous storage, and throws a TypeError naming `hydrate()` on one that answers promises. The outbox's `indexedDbOutbox` uses the same code, with unchanged behaviour.
19
+ - Changed `PersistOptions.storage` to `PersistStorage`, whose three methods may answer promises. `localStorage`, `sessionStorage` and any storage typed against 1.27 still fit.
20
+ - Added `routerFacts(router, bus)` to `vapor-chamber/router`. It emits `routerNavigated` after a committed navigation and `routerFailed` after a failed one, so bus listeners see navigations. It never dispatches.
21
+ - Added the `facts` option to `setupDevtools`, which shows the named emitted facts on a Facts timeline layer, such as `{ facts: ['router*'] }`.
22
+ - Improved the wording and order of the README, CONTRIBUTING and the store, router, performance, V8 rules and whitepaper docs, with no fact removed. The router guide now counts six loader rules, not five, and CONTRIBUTING no longer allows emoji in docs, which the ASCII check rejects.
23
+
24
+ ## v1.27.0 - 2026-10-06
25
+
26
+ - Added `createActionFilter(expressions)`, which compiles CloudEvents filter expressions (`exact`, `prefix`, `suffix`, `all`, `any`, `not`) into an action-name predicate. It throws `core:invalid:filter` on what the spec rejects.
27
+ - Added the `actionFilter` option to every plugin that takes `actions` and to `PluginParts`. Given both, both must match, and `actions` is unchanged.
28
+ - Added `ActionScope`, the type of a plugin's `actions` filter, where absent or `[]` is every action, as before. It and `ActionList` are `string[]`, so code typed against 1.26 compiles unchanged.
29
+ - Added `ActionList`, the type of the mandatory list of `debounce`, `throttle` and `optimisticUndo`, where `[]` is none.
30
+ - Changed the store option `actions` to `reducers`, as in `defineChamberStore(id, { state, reducers: { add: (s, id) => ... } })`. Each key names an action, so `add` on store `cart` is `cart.add` and `cartAdd`.
31
+ - Changed `ChamberStoreOptions` to hold the map under `reducers`. Rename the key in typed options.
32
+ - Changed `StoreAction` to `StoreReducer`.
33
+ - Fixed `debounce([])`, `throttle([])` and `optimisticUndo(bus, [])` acting on every action since v1.26.0. An empty list acts on none again, as in 1.25.
34
+ - Fixed `cache`, `idempotent` and `debounce` answering a `$` command, such as `store.$reset()` or an undo, from memory. `throttle`, `rateLimit` and `circuitBreaker` may still refuse one, as before.
35
+ - Updated `RegisterOptions.undo` to state that the original command it receives carries that dispatch's signal, which `supersede` may have aborted.
36
+ - Fixed the Vue todo example giving a todo a new id on redo. The id is now sent with the command.
37
+ - Fixed an abort of a dispatch having three shapes. A handler or plugin that rethrows the signal's reason now gets `core:aborted:dispatch`, not the raw DOMException or `plugin:failed:plugin`, and every abort is a BusError named `AbortError` with the reason as `cause`. Code that checked `instanceof DOMException` after a mid-flight abort reads `e.cause`.
38
+ - Fixed a transactional batch rolling back a copy of each command instead of the command that ran. A store with `undo: true` in the batch now returns to its state before the batch, where before the command object became its state, and the `$undo` command's `causationId` names the command that ran.
39
+ - Fixed an `undo: true` store erasing every later write when an older step is rolled back, as `optimisticUndo` and a failed batch do. The store now re-applies the later steps, writes from other tabs included.
40
+ - Fixed an undo for a step a store does not hold writing a command object into its state. It now changes nothing.
41
+ - Fixed a redo of an `undo: true` store step running the reducer again, so a minted id came back different. The store now writes the state the action produced, the same object.
42
+ - Fixed history undoing locally a command a bridge sent, and sending it again on redo. Such a step now reads `canUndo` false. Reverse a server write with a compensating command.
43
+ - Added a development check to `undo: true` stores: each reducer runs twice, and two different results warn once per action. Mint ids and times in the call.
44
+ - Updated `RegisterOptions.canUndo` to state that a rollback, by `optimisticUndo` or a transactional batch, does not consult it.
45
+ - Fixed the async bus and the HTTP client re-sending a write when nothing identifies it, after no reply, a 502 or 504, or a verdict with `Retry-After`. It now fails once, no reply marked `context.outcome: 'unknown'` with a development warning. Key the command or declare the action idempotent to keep the re-send. The client also waits the `RateLimit` header's `t` when a policy has no quota left.
46
+ - Fixed a request header sent in two spellings, such as an app `idempotency-key` beside the bridge's `Idempotency-Key`, going out once with both values joined. Each name now goes out once, under its first spelling with the last value, and a FormData upload or a 419 refresh deletes a name in every spelling.
47
+ - Fixed a `share` store opened later losing its first writes to a tab that had written before. A tab now asks for the current state when it opens, and its next write builds on it.
48
+ - Security: fixed `authGuard({ protected: ['admin*'] })` protecting nothing. A trailing `*` now reads as the prefix it names, and `'*'` protects every action.
49
+ - Fixed one idempotency key standing for two requests. `idempotent()` now adds the payload to its default key, and the outbox gives each queued record its own key, so a second write is never answered or dropped as the first. Keys without a payload, custom keys and stored records are unchanged.
50
+ - Fixed the async bus's `request()` answering two requests with different payloads with one result, and a joined caller waiting on another caller's timeout and abort. Each caller now keeps its own wait, and the responder receives the command the plugins saw.
51
+ - Fixed the batching bridge sending a dispatch aborted while it waited for its window, and reporting it `ok`. An aborted dispatch now settles `core:aborted:dispatch` at once and is never sent, and a sent batch is cancelled once every command in it has aborted.
52
+ - Fixed a GET made after a write to its URL joining a read already in flight from before the write. A write, or `invalidateCache`, again stops new reads joining it.
53
+ - Fixed `circuitBreaker` opening on the caller's own cancels, such as `supersede` cancelling a search. An abort no longer counts as a backend failure.
54
+ - Fixed `createReaction`'s `maxHops` missing an indirect cycle such as `a -> b` plus `b -> a`. Every reaction on a bus now shares one hop count.
55
+ - Fixed the MCP handler against the 2025-06-18 spec: `initialize` answers only a version it speaks, an unknown or not allowed tool is the JSON-RPC error -32602 instead of an `isError` result, and a request with `id: null` gets -32600. In tests, `mcpClient().call` of an unlisted tool now rejects with `code: -32602`.
56
+ - Fixed `useCommandError` and `useCommandHistory` throwing on a sealed bus. Like `useSharedCommandState`, they now observe it, and the bus stays sealed.
57
+ - Fixed a `NaN` option failing open in `rateLimit` (`max`, `window`), `createReaction` (`maxHops`), `pollWith` (`interval`, `maxWait`), `useCommandError` and `useSharedCommandState` (`maxSize`) and `createSSRPlugin` (`maxSize`). A `NaN` now behaves like the missing option.
58
+ - Fixed a schema key written as `cart_add` typing only that name while the bus validates and lists `cartAdd`. The camelCase name is now a typed name too, the raw one still compiles, and the development warning says to use the camelCase name. It no longer prints in production.
59
+ - Fixed `createTestBus().dispatchBatch` ignoring `transactional` and `continueOnError`. It now runs the bus's own batch rule, rollback included.
60
+ - Changed `optimisticUndo` to accept an async bus in its types, as its example and `history()` do. Fixed the docs of `ErrorCodeEntry.retryable`, the `inspectBus` example and a test-helper example to say what the code does.
61
+ - Added `ActionSchema.annotations`, MCP's `ToolAnnotations` (`readOnlyHint`, `idempotentHint`, `destructiveHint`, `openWorldHint`, `title`). The MCP handler lists them on each tool, and `readOnlyHint` or `idempotentHint` makes the async bus treat the action as idempotent when `retry` is unset.
62
+ - Changed the async bus's `retry: { actions }` to `retry: { actionPolicies }`, and `RetryDeclaration` to `RetryPolicy`. The most specific match now wins (an exact name, then the longest prefix, then `*`), whatever the written order, so `cartAdd: false` is never re-sent because of an earlier `'cart*'`. Rename the key and the type.
63
+ - Changed `createMcpHandler`'s allowlist from `actions` to `actionFilter`, its one selection. Replace `actions: ['cart*']` with `actionFilter: createActionFilter([{ prefix: { action: 'cart' } }])`, and `['*']` with `createActionFilter([])`. To expose nothing, do not mount the handler. A leftover `actions` is ignored, so every schema action is exposed.
64
+ - Fixed a redo doing nothing when `cache` or `idempotent` had kept the command's first answer: the store stayed undone and history read it as redone. Once an undo lands, the bus calls the new `PluginParts.forget(cmd)` on every plugin, and those two drop that answer.
65
+ - Fixed a custom `key` on `cache` or `idempotent` answering a `$` command, such as `store.$reset()`, with an app command's stored answer when the two keys matched. A `$` command now always takes the default key.
66
+ - Fixed `idempotent` joining a second `$reset` or undo to the first one still in flight, so the second never ran. A `$` command now always runs.
67
+ - Added the store option `answer(state, value, cmd)`: a bridged store action writes the server's answer as one step of that command. Without it, nothing changes.
68
+ - Added `RegisterOptions.answer(cmd, value)`, called when a transport answered in place of the handler, before the plugins outside it.
69
+ - Added the store option `version(state)`: an answer older than the held state is not written. An answer with no `state` writes nothing.
70
+ - Added `stores` to the wire answer, store states by store id: `{ state, stores: { cart: {...} } }`. Each store with that id takes its state, over its own `answer`. A state that is not an object is not written. The Laravel example controller returns it.
71
+ - Fixed the HTTP client serving a stale GET after a write named that URL in `Location` or `Content-Location`. A write now drops those URLs too, on its own origin only.
72
+ - Changed `idempotent`'s `maxKeys` to `maxSize`.
73
+ - Changed `metrics`' `maxEntries` to `maxSize`.
74
+ - Changed `createOutbox`'s `maxQueue` to `maxSize`.
75
+ - Changed `createSSRPlugin`'s `maxCommands` to `maxSize`.
76
+ - Changed `errorCap` to `maxSize` on `useCommandError` and `useSharedCommandState`.
77
+ - Changed the bus option `bufferLimit` to `maxBufferSize`.
78
+ - Changed `teardown()` to `dispose()` on `createSseBridge` and `createEchoBridge`.
79
+ - Changed `createChannel()`'s `close()` to `dispose()`.
80
+ - Changed `destroy()` to `dispose()` on the router and its history.
81
+ - Changed `VitestMcpServer.close()` to `disposeAsync()`.
82
+ - Fixed the README's `optimisticUndo` example calling the server from its inverse. The inverse now reverses the local change only.
83
+ - Fixed docs that named what the code lacks: an `onReceive` hook on `createWsBridge`, an LRU in `matchesPattern`, and a `vitest-pure` subpath (it is `vitest/pure`).
84
+ - Improved a sync `dispatch` on a bus with no plugin, hook or listener: 7 to 12 ns faster, it no longer allocates a meta nothing reads. A dispatch through plugins or listeners measures about 3 ns slower.
85
+
5
86
  ## v1.26.0 - 2026-10-04
6
87
 
7
88
  ### Fixed (the 1.26 evaluation's bug list)