vapor-chamber 1.28.0 → 1.29.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.
- package/CHANGELOG.md +14 -0
- package/README.md +61 -29
- package/dist/LICENSE.txt +3 -2
- package/dist/chamber-vapor.d.ts +6 -3
- package/dist/chamber-vapor.d.ts.map +1 -1
- package/dist/chamber-vapor.js +4 -4
- package/dist/chamber-vapor.js.map +1 -1
- package/dist/chamber.d.ts +16 -21
- package/dist/chamber.d.ts.map +1 -1
- package/dist/chamber.js +20 -19
- package/dist/chamber.js.map +1 -1
- package/dist/command-bus.d.ts +2 -0
- package/dist/command-bus.d.ts.map +1 -1
- package/dist/command-bus.js +5 -1
- package/dist/command-bus.js.map +1 -1
- package/dist/directives2.js +1 -1
- package/dist/iife-core.js +1 -1
- package/dist/iife-elements.js +1 -1
- package/dist/iife.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2034
- package/dist/ledger.js +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +3 -3
- package/dist/mcp.js.map +1 -1
- package/dist/outbox.js +1 -1
- package/dist/plugins-core.js +1 -1
- package/dist/plugins-extra.d.ts +14 -0
- package/dist/plugins-extra.d.ts.map +1 -1
- package/dist/plugins-io.js +1 -1
- package/dist/plugins-schema.js +1 -1
- package/dist/shared-bus.d.ts +21 -1
- package/dist/shared-bus.d.ts.map +1 -1
- package/dist/shared-bus.js +5 -2
- package/dist/shared-bus.js.map +1 -1
- package/dist/signal.d.ts +5 -2
- package/dist/signal.d.ts.map +1 -1
- package/dist/signal.js.map +1 -1
- package/dist/src.js +2036 -0
- package/dist/src.js.map +1 -0
- package/dist/ssr.d.ts +20 -19
- package/dist/ssr.d.ts.map +1 -1
- package/dist/ssr2.js +1 -1
- package/dist/ssr2.js.map +1 -1
- package/dist/transitions/vapor.js +2 -2
- package/dist/transitions/vapor.js.map +1 -1
- package/dist/transitions.d.ts.map +1 -1
- package/dist/transitions2.js +2 -2
- package/dist/transitions2.js.map +1 -1
- package/dist/transports2.js +1 -1
- package/dist/vapor-chamber-core.iife.js.map +1 -1
- package/dist/vapor-chamber-elements.iife.js +3 -2
- package/dist/vapor-chamber-elements.iife.js.map +1 -1
- package/dist/vapor-chamber-elements.iife.min.js +1 -1
- package/dist/vapor-chamber.iife.js +34 -17
- package/dist/vapor-chamber.iife.js.map +1 -1
- package/dist/vapor-chamber.iife.min.js +1 -1
- package/dist/vapor.d.ts +13 -16
- package/dist/vapor.d.ts.map +1 -1
- package/dist/vapor.js +16 -2
- package/dist/vapor.js.map +1 -1
- package/dist/vite-hmr.d.ts +7 -9
- package/dist/vite-hmr.d.ts.map +1 -1
- package/dist/vite-hmr.js.map +1 -1
- package/dist/vue.d.ts +8 -6
- package/dist/vue.d.ts.map +1 -1
- package/dist/vue.js +17 -2
- package/dist/vue.js.map +1 -1
- package/package.json +5 -3
- package/scripts/check-size.mjs +22 -2
- package/scripts/generate-api-docs.mjs +43 -4
- package/src/chamber-vapor.ts +13 -8
- package/src/chamber.ts +59 -45
- package/src/command-bus.ts +6 -0
- package/src/index.ts +3 -0
- package/src/mcp.ts +1 -1
- package/src/plugins-extra.ts +14 -0
- package/src/shared-bus.ts +27 -1
- package/src/signal.ts +5 -2
- package/src/ssr.ts +20 -19
- package/src/transitions/vapor.ts +2 -2
- package/src/transitions.ts +4 -3
- package/src/vapor.ts +13 -16
- package/src/vite-hmr.ts +7 -9
- package/src/vue.ts +15 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## v1.29.0 - 2026-10-08
|
|
6
|
+
|
|
7
|
+
- Added the root's whole surface to `vapor-chamber/vue` and `vapor-chamber/vapor`: the bus, plugins, transports and the HTTP client. A Vue app now imports from one entry, `import { createCommandBus, useCommand } from 'vapor-chamber/vue'`. They are the root's own functions, so code that imports the bus from the root is unchanged and shares the same bus.
|
|
8
|
+
- Fixed a bundle that inlines Vue and runs in Node, such as a Vite SSR build with `ssr.noExternal`. The root's runtime lookup loaded a second Vue and replaced what `vapor-chamber/vue` wired at build time. Composables lost reactivity and cleanup, and `untracked()` went back to tracking. Composables on a bundled page with an import map for `vue` hit the same. The lookup now wires only the Vue the app already has, and keeps what `vapor-chamber/vue` wired.
|
|
9
|
+
- Fixed the README's elements IIFE example, which registered no widget: it now hands Vue over with `configureVue` first. The README names one entry per kind of app, and says that `untracked()` cannot suspend tracking on a page with no build step.
|
|
10
|
+
- Fixed the store guide on ordering a store's answers with `serialize`. Its default key is the action, so two different actions of one store were both in flight. One lane per store, keyed to the commands that reach the server, now orders the store's writes and its reads. The guide and `serialize`'s docblock say to key the store's local reducers to `null`: in the lane, a read that awaits one waits for ever. They also say that a command waiting in the lane already reads as loading in `isLoading()`.
|
|
11
|
+
- Vue 3.5 is now tested on every run. Every entry that uses Vue loads and works on it, except `vapor-chamber/vapor`, `vapor-chamber/transitions/vapor` and `vapor-chamber/router/vapor`, which need Vue 3.6.
|
|
12
|
+
- Fixed `useSharedCommandState().dispatch` throwing when a subscriber of `inFlight` or `isAnyLoading` throws. `isAnyLoading` then stayed true for every reader. The dispatch now fails with that error and the count returns to 0, as `useCommand`'s does.
|
|
13
|
+
- Changed `dispatch` and `query` of `useCommand`, `useCommandQuery`, `useCommandGroup`, `useSharedCommandState` and `defineVaporCommand` to be typed by the bus they run on. A sync bus gives a `CommandResult`, an async one a promise of it, and the shared bus a `CommandResult`. A cast or a narrowing written for the old types can go. On an async bus, `useCommand`'s `dispatch` now returns a promise even when a subscriber throws.
|
|
14
|
+
- Added `bus` to the options of `useCommand`, `useCommandState`, `useCommandHistory`, `useCommandQuery`, `useCommandGroup`, `useCommandError`, `defineVaporCommand` and `useDeepCommandState`. Each runs on the bus it is given, sync or async. A concurrent SSR server can now pass a bus per request, as `setCommandBus` advises. Without it they use the shared bus, as before. `useSharedCommandState` now accepts an async bus too.
|
|
15
|
+
- Fixed the retry example, which stated the rule from before 1.27. Fixed the README row for `isLoading()`, which left out when counting starts and stops.
|
|
16
|
+
- Fixed three docs. The SSR examples set the shared bus per request, which their own warning calls unsafe: they now give each request its own bus. `src/signal.ts` and the whitepaper now say what a read of `__VUE__` finds. The whitepaper's script-tag recipe loaded the core IIFE, which never reads the parked Vue: it now loads the full IIFE.
|
|
17
|
+
- Fixed the examples to match this release. The Vue examples import from `vapor-chamber/vue` alone, and drop an `instanceof Promise` check on a dispatch result. Two retry comments now state the current rule. `feature-vite-wire.ts` says a root-only app needs the plugin on Vite.
|
|
18
|
+
|
|
5
19
|
## v1.28.0 - 2026-10-07
|
|
6
20
|
|
|
7
21
|
- Fixed `createRouter()` throwing a TypeError on a route row whose `params` is `null`. The row now compiles as one without param types.
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ so each action has one place to read and to test.
|
|
|
43
43
|
- **Vue <!-- vc:vueAligned -->3.6.0-rc.10<!-- /vc:vueAligned --> aligned**: signals, `onScopeDispose`, `getCurrentScope`, alien-signals internals. Tracked per release in the [CHANGELOG](CHANGELOG.md)
|
|
44
44
|
- **No runtime dependency**. `alien-signals` is an optional peer, installed only by apps that use the `vapor-chamber/alien-signals` connector. Unimported modules tree-shake to zero
|
|
45
45
|
- **ESM-only**, plus three IIFE `<script>` drop-ins for no-bundler pages
|
|
46
|
-
- **<!-- vc:covStatements -->100.0<!-- /vc:covStatements -->% coverage on all four axes** - statements, branches, functions and lines, across **<!-- vc:tests -->
|
|
46
|
+
- **<!-- vc:covStatements -->100.0<!-- /vc:covStatements -->% coverage on all four axes** - statements, branches, functions and lines, across **<!-- vc:tests -->3572<!-- /vc:tests --> tests** in <!-- vc:testFiles -->326<!-- /vc:testFiles --> files ([full table](docs/COVERAGE.md)). Every branch in the measured surface is taken by a test
|
|
47
47
|
|
|
48
48
|
## Contents
|
|
49
49
|
|
|
@@ -156,20 +156,23 @@ A misspelled action or field in a component is a compile error, before any reque
|
|
|
156
156
|
</details>
|
|
157
157
|
|
|
158
158
|
<details>
|
|
159
|
-
<summary><b>Gotcha:</b> in a Vue app, import
|
|
159
|
+
<summary><b>Gotcha:</b> in a Vue app, import from <code>vapor-chamber/vue</code>, not the root</summary>
|
|
160
160
|
|
|
161
|
-
Import the
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
Import from the static entry, `vapor-chamber/vue` (or `vapor-chamber/vapor` when the app calls the
|
|
162
|
+
library's Vapor API, such as `createVaporChamberApp`). It
|
|
163
|
+
carries the composables (`useCommand`, `useCommandState`, `signal`, ...) and the root's whole
|
|
164
|
+
surface: the bus, plugins, transports. The static entry hands Vue to the library at build time, the
|
|
165
|
+
moment it is imported, so even module-scope state is reactive:
|
|
165
166
|
|
|
166
167
|
```ts
|
|
167
|
-
import { createCommandBus, setCommandBus } from 'vapor-chamber';
|
|
168
|
-
import { useCommand, signal } from 'vapor-chamber/vue'; // composables: Vue wired
|
|
168
|
+
import { createCommandBus, setCommandBus, useCommand, signal } from 'vapor-chamber/vue';
|
|
169
169
|
|
|
170
170
|
export const count = signal(0); // reactive, no waiting
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
+
They are the root's own functions, so code that still takes the bus from the root shares the same
|
|
174
|
+
bus.
|
|
175
|
+
|
|
173
176
|
The root has to work with no Vue in the tree, so it can only look for Vue at runtime. It does so
|
|
174
177
|
through a bare `import('vue')` that resolves under a dev server and **fails in a production
|
|
175
178
|
bundle**. There, composables imported from the root get plain `{ value }` state (no reactivity),
|
|
@@ -1101,8 +1104,7 @@ re-run. Every composable here suspends reactive tracking around its bus call. If
|
|
|
1101
1104
|
**raw bus** inside an effect, wrap it:
|
|
1102
1105
|
|
|
1103
1106
|
```ts
|
|
1104
|
-
import { getCommandBus } from 'vapor-chamber';
|
|
1105
|
-
import { untracked } from 'vapor-chamber/vue'; // untracked() from the Vue entry
|
|
1107
|
+
import { getCommandBus, untracked } from 'vapor-chamber/vue';
|
|
1106
1108
|
|
|
1107
1109
|
watchEffect(() => {
|
|
1108
1110
|
// without untracked(), anything the HANDLER reads becomes a dependency of
|
|
@@ -1111,11 +1113,27 @@ watchEffect(() => {
|
|
|
1111
1113
|
});
|
|
1112
1114
|
```
|
|
1113
1115
|
|
|
1116
|
+
On a page with no build step (a `<script>` tag or an import map), `untracked()` cannot suspend
|
|
1117
|
+
tracking: Vue's browser builds do not export what it needs. See
|
|
1118
|
+
[whitepaper 9.6](docs/whitepaper.md#96-blade--cdn-zero-build).
|
|
1119
|
+
|
|
1114
1120
|
</details>
|
|
1115
1121
|
|
|
1116
1122
|
<details>
|
|
1117
1123
|
<summary><b>Which entry to import from</b> - <code>/vapor</code>, <code>/vue</code>, or the package root, and what each one wires</summary>
|
|
1118
1124
|
|
|
1125
|
+
One entry per kind of app, measured on built apps of each kind (log s35.231). `/vue` and `/vapor`
|
|
1126
|
+
carry the bus too.
|
|
1127
|
+
|
|
1128
|
+
| App | Import from | Build step |
|
|
1129
|
+
|---|---|---|
|
|
1130
|
+
| App that calls the library's Vapor API (`createVaporChamberApp`, `defineVaporComponent`, `defineVaporAsyncComponent`, `defineVaporCustomElement`, `getVaporInteropPlugin`) | `vapor-chamber/vapor` | Optional, drops the runtime lookup: `vaporChamberWire({ entry: 'vapor' })` on Vite, the define below elsewhere |
|
|
1131
|
+
| Any other Vue app, vDOM or Vapor, including one that uses only Vue's own Vapor APIs or `vapor-chamber/router/vapor` | `vapor-chamber/vue` | Optional, the same: `vaporChamberWire()` on Vite, the define elsewhere |
|
|
1132
|
+
| Server build (SSR) | `vapor-chamber/vue` | Optional: the define drops the runtime lookup from the server bundle |
|
|
1133
|
+
| App that imports only the root | the root | Needed on Vite: `vaporChamberWire()`. Other bundlers have none, so import from a subpath |
|
|
1134
|
+
| `<script>`-tag page | `VaporChamber.configureVue(Vue)` | None. `untracked()` is not available |
|
|
1135
|
+
| ESM page with an import map | `configureVue(Vue)` | None. `untracked()` cannot suspend tracking |
|
|
1136
|
+
|
|
1119
1137
|
**Import from `vapor-chamber/vue` in a Vue app.** The Gotcha above says why. The root can only
|
|
1120
1138
|
look for Vue at runtime, and that lookup fails in a production bundle. So `untracked()` silently
|
|
1121
1139
|
becomes a pass-through there. The static entry resolves Vue at build time, and re-exports the
|
|
@@ -1128,7 +1146,8 @@ in a page where DEV is on. That is a page served by Vite's dev server (measured
|
|
|
1128
1146
|
on Vite 8), or a test runner with a DOM. A production build drops it, from every chunk. A server never
|
|
1129
1147
|
shows it: Node resolves that lookup in production too (measured), so the advice would be wrong there.
|
|
1130
1148
|
|
|
1131
|
-
**
|
|
1149
|
+
**When the app calls the library's Vapor API, import from `vapor-chamber/vapor` instead.** It needs
|
|
1150
|
+
Vue 3.6. It is a superset of
|
|
1132
1151
|
`vapor-chamber/vue`, with the same composables and the same tracking fix. It also wires Vue's
|
|
1133
1152
|
Vapor APIs statically. So there is no `configureVue()` call to write and no runtime probe to
|
|
1134
1153
|
depend on:
|
|
@@ -1173,12 +1192,12 @@ import vue from '@vitejs/plugin-vue';
|
|
|
1173
1192
|
import { vaporChamberWire } from 'vapor-chamber/vite';
|
|
1174
1193
|
|
|
1175
1194
|
export default defineConfig({
|
|
1176
|
-
plugins: [vue(), vaporChamberWire()], // { entry: 'vapor' } when the app
|
|
1195
|
+
plugins: [vue(), vaporChamberWire()], // { entry: 'vapor' } when the app calls the library's Vapor API
|
|
1177
1196
|
});
|
|
1178
1197
|
```
|
|
1179
1198
|
|
|
1180
|
-
`'vapor'` is your call, not a guess. It wires
|
|
1181
|
-
|
|
1199
|
+
`'vapor'` is your call, not a guess. It wires Vue's Vapor app and component helpers into the bundle,
|
|
1200
|
+
which an app that does not call the library's Vapor API should not pay for.
|
|
1182
1201
|
|
|
1183
1202
|
The redirect runs in builds only. The dev server resolves the runtime lookup by itself. A
|
|
1184
1203
|
redirect there, over a pre-bundled install, would put two copies of the library in the page
|
|
@@ -1204,8 +1223,13 @@ new webpack.DefinePlugin({ __VC_WIRED_BUILD__: 'true' })
|
|
|
1204
1223
|
Leave it out only for an app that imports the composables from the root and wires nothing: there
|
|
1205
1224
|
the lookup is what finds Vue (`tests/root-probe-builds.test.ts`).
|
|
1206
1225
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1226
|
+
A Vite app that imports from the subpath, with neither `vaporChamberWire()` nor the define, still
|
|
1227
|
+
ships the lookup as dead code: +2,589 B raw, +932 B brotli on a vDOM app (measured 2026-10-08, log
|
|
1228
|
+
s35.231). Either one removes it.
|
|
1229
|
+
|
|
1230
|
+
Both entries also carry the bus itself (`createCommandBus`, `getCommandBus`, plugins, transports),
|
|
1231
|
+
so a Vue app imports one entry. An app with no Vue imports the bus from the package root, which
|
|
1232
|
+
works with no Vue in the tree.
|
|
1209
1233
|
|
|
1210
1234
|
</details>
|
|
1211
1235
|
|
|
@@ -1333,7 +1357,7 @@ Minified, comment-free, brotli q=11. Always-current per-export table:
|
|
|
1333
1357
|
on any regression past budget.
|
|
1334
1358
|
|
|
1335
1359
|
The two that matter: the dispatch core is **<!-- vc:sizeCore -->4.7<!-- /vc:sizeCore --> KB** and the import-everything barrel is
|
|
1336
|
-
<!-- vc:sizeBarrel -->32.
|
|
1360
|
+
<!-- vc:sizeBarrel -->32.3<!-- /vc:sizeBarrel --> KB. The main entries, and why the numbers are
|
|
1337
1361
|
machine-stamped rather than retyped:
|
|
1338
1362
|
|
|
1339
1363
|
<details>
|
|
@@ -1342,14 +1366,14 @@ machine-stamped rather than retyped:
|
|
|
1342
1366
|
| Entry | brotli |
|
|
1343
1367
|
|---|--:|
|
|
1344
1368
|
| dispatch core (`createCommandBus`, tree-shaken) | **<!-- vc:sizeCore -->4.7<!-- /vc:sizeCore --> KB** |
|
|
1345
|
-
| `vapor-chamber` (main barrel, import-*everything*) | <!-- vc:sizeBarrel -->32.
|
|
1369
|
+
| `vapor-chamber` (main barrel, import-*everything*) | <!-- vc:sizeBarrel -->32.3<!-- /vc:sizeBarrel --> KB |
|
|
1346
1370
|
| `vapor-chamber/router` | <!-- vc:sizeRouter -->10.6<!-- /vc:sizeRouter --> KB |
|
|
1347
1371
|
| `vapor-chamber/router/vdom` | <!-- vc:sizeRouterVdom -->0.7<!-- /vc:sizeRouterVdom --> KB |
|
|
1348
1372
|
| `vapor-chamber/router/vapor` | <!-- vc:sizeRouterVapor -->0.7<!-- /vc:sizeRouterVapor --> KB |
|
|
1349
1373
|
| `vapor-chamber/router/remote` | <!-- vc:sizeRouterRemote -->5.3<!-- /vc:sizeRouterRemote --> KB |
|
|
1350
1374
|
| `vapor-chamber/router-fetch` | <!-- vc:sizeRouterFetch -->5.6<!-- /vc:sizeRouterFetch --> KB |
|
|
1351
|
-
| `vapor-chamber/vue` | <!-- vc:sizeVue -->
|
|
1352
|
-
| `vapor-chamber/vapor` | <!-- vc:sizeVapor -->
|
|
1375
|
+
| `vapor-chamber/vue` (with the root's surface, import-*everything*) | <!-- vc:sizeVue -->32.3<!-- /vc:sizeVue --> KB |
|
|
1376
|
+
| `vapor-chamber/vapor` (the same) | <!-- vc:sizeVapor -->32.5<!-- /vc:sizeVapor --> KB |
|
|
1353
1377
|
| `vapor-chamber/reactive` | <!-- vc:sizeReactive -->6.1<!-- /vc:sizeReactive --> KB |
|
|
1354
1378
|
| `vapor-chamber/transports` | <!-- vc:sizeTransports -->5.8<!-- /vc:sizeTransports --> KB |
|
|
1355
1379
|
| `vapor-chamber/outbox` | <!-- vc:sizeOutbox -->2.7<!-- /vc:sizeOutbox --> KB |
|
|
@@ -1358,6 +1382,9 @@ machine-stamped rather than retyped:
|
|
|
1358
1382
|
| `vapor-chamber/store` | <!-- vc:sizeStore -->2.2<!-- /vc:sizeStore --> KB |
|
|
1359
1383
|
|
|
1360
1384
|
**Rows are not additive** - every row includes the shared core, which your bundle carries once.
|
|
1385
|
+
The `/vue` and `/vapor` rows include the whole root they carry. An app pays only for what it
|
|
1386
|
+
imports: one import from `/vapor` builds `examples/vapor-sfc` to the same bytes as two (log
|
|
1387
|
+
s35.236).
|
|
1361
1388
|
`vapor-chamber` is the barrel measured import-everything. Your bundler drops what you don't use.
|
|
1362
1389
|
|
|
1363
1390
|
These figures are **machine-stamped** from [docs/BUNDLE-SIZES.md](./docs/BUNDLE-SIZES.md). The
|
|
@@ -1374,8 +1401,8 @@ Three `<script>`-tag drop-ins. Pick by audience, not feature checklist.
|
|
|
1374
1401
|
| Variant | Audience | Min | Brotli | Gzip |
|
|
1375
1402
|
|---|---|--:|--:|--:|
|
|
1376
1403
|
| **core** | Sprinkled JS on server-rendered pages (Blade, Rails, Django, WordPress). You dispatch user actions to a backend over HTTP. | <!-- vc:sizeIifeCoreRaw -->32.4<!-- /vc:sizeIifeCoreRaw --> KB | <!-- vc:sizeIifeCore -->10.2<!-- /vc:sizeIifeCore --> KB | <!-- vc:sizeIifeCoreGzip -->11.2<!-- /vc:sizeIifeCoreGzip --> KB |
|
|
1377
|
-
| **elements** | Embeddable widgets (chat bubbles, checkout buttons, third-party drop-ins). You ship a `<vc-widget>` custom element. | <!-- vc:sizeIifeElementsRaw -->34.0<!-- /vc:sizeIifeElementsRaw --> KB | <!-- vc:sizeIifeElements -->10.
|
|
1378
|
-
| **full** | SPAs that grew big enough to want everything (realtime, undo/redo, persistence, full Vapor surface). | <!-- vc:sizeIifeFullRaw -->46.
|
|
1404
|
+
| **elements** | Embeddable widgets (chat bubbles, checkout buttons, third-party drop-ins). You ship a `<vc-widget>` custom element. | <!-- vc:sizeIifeElementsRaw -->34.0<!-- /vc:sizeIifeElementsRaw --> KB | <!-- vc:sizeIifeElements -->10.7<!-- /vc:sizeIifeElements --> KB | <!-- vc:sizeIifeElementsGzip -->11.7<!-- /vc:sizeIifeElementsGzip --> KB |
|
|
1405
|
+
| **full** | SPAs that grew big enough to want everything (realtime, undo/redo, persistence, full Vapor surface). | <!-- vc:sizeIifeFullRaw -->46.9<!-- /vc:sizeIifeFullRaw --> KB | <!-- vc:sizeIifeFull -->14.7<!-- /vc:sizeIifeFull --> KB | <!-- vc:sizeIifeFullGzip -->16.2<!-- /vc:sizeIifeFullGzip --> KB |
|
|
1379
1406
|
|
|
1380
1407
|
<details>
|
|
1381
1408
|
<summary><b>What's in each variant</b>, plus drop-in examples</summary>
|
|
@@ -1405,7 +1432,10 @@ Three `<script>`-tag drop-ins. Pick by audience, not feature checklist.
|
|
|
1405
1432
|
```html
|
|
1406
1433
|
<!-- elements: register a custom-element widget in one call -->
|
|
1407
1434
|
<script src=".../vapor-chamber-elements.iife.min.js"></script>
|
|
1408
|
-
<script>
|
|
1435
|
+
<script type="module">
|
|
1436
|
+
// Needed: without Vue's Vapor build handed over, defineWidget returns false.
|
|
1437
|
+
const Vue = await import('.../vue.runtime-with-vapor.esm-browser.prod.js');
|
|
1438
|
+
VaporChamber.configureVue(Vue);
|
|
1409
1439
|
VaporChamber.defineWidget('vc-cart', {
|
|
1410
1440
|
props: { sku: String },
|
|
1411
1441
|
// A Vapor setup() returns a BLOCK - real DOM nodes. There is no compiler
|
|
@@ -1491,8 +1521,8 @@ Everything else is optional and tree-shaken when unimported.
|
|
|
1491
1521
|
form.ts, schema.ts, devtools.ts, directives.ts, vite-hmr.ts
|
|
1492
1522
|
```
|
|
1493
1523
|
|
|
1494
|
-
**Coverage:** <!-- vc:covStatements -->100.0<!-- /vc:covStatements -->% statements, <!-- vc:covBranches -->100.0<!-- /vc:covBranches -->% branches, <!-- vc:covFunctions -->100.0<!-- /vc:covFunctions -->% functions, <!-- vc:covLines -->100.0<!-- /vc:covLines -->% lines across **<!-- vc:tests -->
|
|
1495
|
-
(<!-- vc:testFiles -->
|
|
1524
|
+
**Coverage:** <!-- vc:covStatements -->100.0<!-- /vc:covStatements -->% statements, <!-- vc:covBranches -->100.0<!-- /vc:covBranches -->% branches, <!-- vc:covFunctions -->100.0<!-- /vc:covFunctions -->% functions, <!-- vc:covLines -->100.0<!-- /vc:covLines -->% lines across **<!-- vc:tests -->3572<!-- /vc:tests --> tests**
|
|
1525
|
+
(<!-- vc:testFiles -->326<!-- /vc:testFiles --> files). Per-file table:
|
|
1496
1526
|
[docs/COVERAGE.md](docs/COVERAGE.md). Run `npm run test:coverage` for live numbers.
|
|
1497
1527
|
|
|
1498
1528
|
## Testing
|
|
@@ -1625,12 +1655,12 @@ on a Facts layer: `setupDevtools(bus, app, { facts: ['router*'] })`.
|
|
|
1625
1655
|
|
|
1626
1656
|
| Composable | Description |
|
|
1627
1657
|
|------------|-------------|
|
|
1628
|
-
| `useCommand()` | Vapor-safe: dispatch + register/on/emit + reactive loading/error, auto-cleanup |
|
|
1629
|
-
| `useSharedCommandState(options?)` | Aggregate `isAnyLoading` + `errors` ring buffer, **shared** across subscribers on the same bus. For toolbars, status bars, global spinners. `isLoading(action, target?)` answers "is THIS one in flight?" per `commandKey(action, target)`, bus-wide, as its own reactive flag - a reader re-runs only on its key |
|
|
1658
|
+
| `useCommand(options?)` | Vapor-safe: dispatch + register/on/emit + reactive loading/error, auto-cleanup |
|
|
1659
|
+
| `useSharedCommandState(options?)` | Aggregate `isAnyLoading` + `errors` ring buffer, **shared** across subscribers on the same bus. For toolbars, status bars, global spinners. `isLoading(action, target?)` answers "is THIS one in flight?" per `commandKey(action, target)`, bus-wide, as its own reactive flag - a reader re-runs only on its key. Counting starts at the bus's first `isLoading()` call and stops when its last holder leaves with nothing in flight. A dispatch already in flight when counting starts reads `false` |
|
|
1630
1660
|
| `defineVaporCommand(action, handler, options?)` | Zero-overhead dispatch for hot paths |
|
|
1631
|
-
| `useCommandState(initial, handlers)` | State managed by commands |
|
|
1661
|
+
| `useCommandState(initial, handlers, options?)` | State managed by commands |
|
|
1632
1662
|
| `useCommandHistory(options?)` | Reactive undo/redo |
|
|
1633
|
-
| `useCommandGroup(namespace)` | Namespace isolation - prefixes all calls in camelCase |
|
|
1663
|
+
| `useCommandGroup(namespace, options?)` | Namespace isolation - prefixes all calls in camelCase |
|
|
1634
1664
|
| `useCommandError(options?)` | Reactive error boundary for failed dispatches |
|
|
1635
1665
|
| `getCommandBus()` | Get the shared bus |
|
|
1636
1666
|
| `untracked(fn)` | Run a **raw-bus** dispatch without its handler's reads becoming dependencies of the surrounding effect. The composables above already do this - you only need it when calling `getCommandBus()` directly from inside a `watchEffect` / `computed`. No-op without Vue. **Import from `vapor-chamber/vue`** in a Vue app: from the package root it degrades to a pass-through in a production build |
|
|
@@ -1641,6 +1671,8 @@ on a Facts layer: `setupDevtools(bus, app, { facts: ['router*'] })`.
|
|
|
1641
1671
|
| `getVaporInteropPlugin()` | `vaporInteropPlugin` for mixed trees |
|
|
1642
1672
|
| `setupDevtools(bus, app, { facts? })` | Connect bus to Vue DevTools (`vapor-chamber/devtools`) |
|
|
1643
1673
|
|
|
1674
|
+
Every composable above takes `bus` in its options, sync or async. Without it, it uses the shared bus.
|
|
1675
|
+
|
|
1644
1676
|
**Router** - see [docs/router.md](docs/router.md) for the full surface:
|
|
1645
1677
|
`createRouter`, `useRouter`, `useRoute`, `useQueryParam`, `useRouteData`, `useRouteError`,
|
|
1646
1678
|
`useMenu`, `useBreadcrumbs`, `usePagination`, `onBeforeLeave`, `RouterOutlet`.
|
package/dist/LICENSE.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
vapor-chamber v1.
|
|
1
|
+
vapor-chamber v1.29.0 - licence information for the distributed JavaScript
|
|
2
2
|
==============================================================================
|
|
3
3
|
|
|
4
4
|
Every JavaScript file in this directory carries the one-line reference
|
|
5
5
|
"/*! See LICENSE.txt */". This file is that reference.
|
|
6
6
|
|
|
7
|
-
These
|
|
7
|
+
These 62 files:
|
|
8
8
|
|
|
9
9
|
a11y.js
|
|
10
10
|
alien-signals.js
|
|
@@ -44,6 +44,7 @@ These 61 files:
|
|
|
44
44
|
router/vdom.js
|
|
45
45
|
shared-bus.js
|
|
46
46
|
signal.js
|
|
47
|
+
src.js
|
|
47
48
|
ssr.js
|
|
48
49
|
ssr2.js
|
|
49
50
|
store-base.js
|
package/dist/chamber-vapor.d.ts
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Separated from chamber.ts to keep the core composable module CDCC-compliant.
|
|
12
12
|
*/
|
|
13
|
-
import type { Handler, RegisterOptions, CommandResult } from './command-bus';
|
|
13
|
+
import type { BaseBus, CommandBus, Handler, RegisterOptions, CommandResult } from './command-bus';
|
|
14
|
+
import { type BusOption, type ResultOn } from './shared-bus';
|
|
14
15
|
/**
|
|
15
16
|
* Create a Vapor app instance with vapor-chamber ready.
|
|
16
17
|
* Requires Vue 3.6+. Throws if Vapor is not available.
|
|
@@ -117,6 +118,8 @@ export declare function defineVaporComponent<T = any>(options: object): T | null
|
|
|
117
118
|
* const AsyncPanel = defineVaporAsyncComponent(() => import('./Panel.vue'));
|
|
118
119
|
*/
|
|
119
120
|
export declare function defineVaporAsyncComponent<T = any>(loader: (() => Promise<unknown>) | object): T | null;
|
|
121
|
+
/** `defineVaporCommand`'s options: how the handler registers, and on which bus. */
|
|
122
|
+
export type VaporCommandOptions<B extends BaseBus = BaseBus> = RegisterOptions & BusOption<B>;
|
|
120
123
|
/**
|
|
121
124
|
* defineVaporCommand - zero-overhead command for hot paths in Vapor mode.
|
|
122
125
|
*
|
|
@@ -132,8 +135,8 @@ export declare function defineVaporAsyncComponent<T = any>(loader: (() => Promis
|
|
|
132
135
|
* });
|
|
133
136
|
* dispatch({ name: 'page_view', params: { page: '/landing' } });
|
|
134
137
|
*/
|
|
135
|
-
export declare function defineVaporCommand(action: string, handler: Handler, options?:
|
|
136
|
-
dispatch: (target: any, payload?: any) =>
|
|
138
|
+
export declare function defineVaporCommand<B extends BaseBus = CommandBus>(action: string, handler: Handler, options?: VaporCommandOptions<B>): {
|
|
139
|
+
dispatch: (target: any, payload?: any) => ResultOn<B>;
|
|
137
140
|
dispose: () => void;
|
|
138
141
|
};
|
|
139
142
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chamber-vapor.d.ts","sourceRoot":"","sources":["../src/chamber-vapor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"chamber-vapor.d.ts","sourceRoot":"","sources":["../src/chamber-vapor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGlG,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAyBzE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,GAAG,GAAG,EAC9C,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,IAAI,CAaN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,IAAI,GAAG,GAAG,IAAI,CAElD;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAOlG;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAOvE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,GAAG,GAAG,EAC/C,MAAM,EAAE,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,MAAM,GACxC,CAAC,GAAG,IAAI,CAOV;AAMD,mFAAmF;AACnF,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI,eAAe,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;AAE9F;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,OAAO,GAAG,UAAU,EAC/D,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC;uBAcN,GAAG,YAAY,GAAG,KAAG,QAAQ,CAAC,CAAC,CAAC;;EAS3D;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE;IAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;CAAE;uBAUlG,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,OAAO,CAAC,aAAa,CAAC;;;;EAgC5F"}
|
package/dist/chamber-vapor.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*! See LICENSE.txt */
|
|
2
|
-
import {
|
|
2
|
+
import { S as errResult } from "./command-bus.js";
|
|
3
3
|
import { a as getDefineVaporComponentFn, b as vueDetectionHint, c as getVaporInteropRef, d as tryAutoCleanup, f as untracked, i as getDefineVaporAsyncComponentFn, o as getDefineVaporCustomElementFn, s as getVaporAppFn } from "./chamber.js";
|
|
4
4
|
import { n as signal } from "./signal.js";
|
|
5
|
-
import {
|
|
5
|
+
import { r as resolveBus } from "./shared-bus.js";
|
|
6
6
|
var DEV = typeof process !== "undefined" || import.meta.env?.DEV ? process.env.NODE_ENV !== "production" : false;
|
|
7
7
|
function devWarnNoVapor(api) {
|
|
8
8
|
console.warn(`[vapor-chamber] ${api}() returned null - Vue 3.6+ with Vapor mode was not detected, so the component was NOT created. ${vueDetectionHint()} For VDOM mode use the matching define* helper from vue instead.`);
|
|
@@ -40,7 +40,7 @@ function defineVaporAsyncComponent(loader) {
|
|
|
40
40
|
return fn(loader);
|
|
41
41
|
}
|
|
42
42
|
function defineVaporCommand(action, handler, options) {
|
|
43
|
-
const bus =
|
|
43
|
+
const bus = resolveBus(options?.bus);
|
|
44
44
|
const unregister = bus.register(action, handler, options);
|
|
45
45
|
function dispatch(target, payload) {
|
|
46
46
|
return untracked(() => bus.dispatch(action, target, payload));
|
|
@@ -55,7 +55,7 @@ function defineVaporCommand(action, handler, options) {
|
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
function useVaporAsyncCommand(asyncBus) {
|
|
58
|
-
const bus = asyncBus
|
|
58
|
+
const bus = resolveBus(asyncBus);
|
|
59
59
|
const loading = signal(false);
|
|
60
60
|
const lastError = signal(null);
|
|
61
61
|
async function dispatch(action, target, payload) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chamber-vapor.js","names":["_errResult"],"sources":["../src/chamber-vapor.ts"],"sourcesContent":["/**\n * vapor-chamber - Vue 3.6+ Vapor-specific API\n *\n * This file renders nothing: it forwards Vue's own define* functions, so\n * rendering-side work (attrs fallthrough, interop, hydration) lands below it.\n * The wrappers and createVaporChamberApp take an opt-in return generic\n * (`<T = any>`) and `object`-typed options: importing Vue's Vapor types here\n * would put a hard `vue` type dependency on the main barrel and break Vue-less\n * command-bus consumers, so callers opt in: `defineVaporComponent<MyComp>(opts)`.\n *\n * Separated from chamber.ts to keep the core composable module CDCC-compliant.\n */\n\nimport {\n getCommandBus,\n signal,\n tryAutoCleanup,\n untracked,\n getVaporAppFn,\n getVaporInteropRef,\n getDefineVaporCustomElementFn,\n getDefineVaporComponentFn,\n getDefineVaporAsyncComponentFn,\n vueDetectionHint,\n} from './chamber';\nimport type { Handler, RegisterOptions, CommandResult, CommandMap } from './command-bus';\nimport { _errResult } from './command-bus';\nimport { DEV } from './dev';\n\n/**\n * Why the `defineVapor*` wrappers warn instead of just returning null.\n *\n * Each returns `null` when the Vapor runtime is absent, and callers are\n * documented to check. But a bare `null` is the same failure shape that hid a\n * real bug for several releases: `tryKeepAliveHooks` guarded on an accessor\n * that silently answers \"no\" under Vapor, so a feature was inert with nothing\n * to see (rc.4 cycle - see tests/keepalive-input-scope-fixture.test.ts). Silent\n * negatives are how detection bugs survive.\n *\n * So the null stays - throwing would break the documented contract and the\n * tests that assert it - but it is not quiet. The call sites gate on\n * `DEV`, so the whole call (and every byte of message text) folds out of the\n * production IIFE builds; this helper is then unreferenced and tree-shaken.\n */\nfunction devWarnNoVapor(api: string): void {\n console.warn(\n `[vapor-chamber] ${api}() returned null - Vue 3.6+ with Vapor mode was not detected, ` +\n `so the component was NOT created. ${vueDetectionHint()} ` +\n 'For VDOM mode use the matching define* helper from vue instead.',\n );\n}\n\n/**\n * Create a Vapor app instance with vapor-chamber ready.\n * Requires Vue 3.6+. Throws if Vapor is not available.\n *\n * Pass-through over Vue's createVaporApp - scope-ID handling, HMR app-instance\n * refresh, and setup() error recovery are Vue runtime behavior (per-beta detail:\n * CHANGELOG / whitepaper alignment log).\n *\n * `rootProps` are Vue's raw props, passed through unchanged: a plain value is\n * the value, and a FUNCTION is a getter that Vue calls for the value. So a\n * callback is wrapped, `{ onSave: () => onSave }`; passed bare it is called\n * and the component receives what it returned. (A function set on a\n * `defineWidget` element property is the opposite: it arrives as itself.)\n * Pinned by tests/vapor/vapor-subpath-wiring.test.ts.\n *\n * @example\n * import { createVaporChamberApp } from 'vapor-chamber';\n * import App from './App.vue';\n * createVaporChamberApp(App).mount('#app');\n *\n * @example Root props\n * createVaporChamberApp(App, { title: 'Cart', onSave: () => onSave }).mount('#app');\n */\nexport function createVaporChamberApp<TApp = any>(\n rootComponent: object,\n rootProps?: Record<string, unknown>,\n): TApp {\n const fn = getVaporAppFn();\n if (!fn) {\n // The bare \"Vapor required\" message was the same whether Vue was absent,\n // present-without-Vapor, or present-but-unreachable - three different\n // problems with three different fixes. vueDetectionHint() names which.\n throw new Error(\n // The diagnosis ships (vueDetectionHint says why); the advice is DEV's.\n `[vapor-chamber] Vue 3.6+ with Vapor mode required. ${vueDetectionHint()}` +\n (DEV ? ' For VDOM mode, use createApp() from vue instead.' : '')\n );\n }\n return fn(rootComponent, rootProps) as TApp;\n}\n\n/**\n * Returns the vaporInteropPlugin if available (Vue 3.6+).\n * Use this to enable mixed Vapor/VDOM component trees.\n *\n * Pass-through over Vue's plugin. The returned reference is safe to hold\n * across HMR cycles (Vue does not mutate the bridge).\n *\n * @example\n * import { createApp } from 'vue';\n * import { getVaporInteropPlugin } from 'vapor-chamber';\n * const plugin = getVaporInteropPlugin();\n * if (plugin) createApp(App).use(plugin).mount('#app');\n */\nexport function getVaporInteropPlugin(): any | null {\n return getVaporInteropRef();\n}\n\n// ---------------------------------------------------------------------------\n// Vapor Custom Elements (Vue 3.6 - defineVaporCustomElement introduced in 3.6.0-alpha.4, #14017)\n// ---------------------------------------------------------------------------\n\n/**\n * defineVaporCustomElement - create a custom element backed by Vapor rendering.\n *\n * Wraps Vue's `defineVaporCustomElement()` (introduced in 3.6.0-alpha.4, #14017). The generated custom\n * element uses Vapor's compiler-optimized rendering instead of the VDOM, giving\n * zero-overhead DOM updates inside shadow DOM. Safe to call with a reused\n * options object, and children re-render on reactive prop changes (beta.14+;\n * per-beta detail: CHANGELOG / whitepaper alignment log).\n *\n * Returns null if the Vapor runtime (Vue 3.6+) is not detected - check before calling\n * `customElements.define()`.\n *\n * @example\n * import { defineVaporCustomElement } from 'vapor-chamber';\n * const MyEl = defineVaporCustomElement({\n * props: { label: String },\n * // A Vapor setup() returns a BLOCK - real DOM nodes - not a render\n * // function or h() output. An SFC's compiler builds this from its template.\n * setup(props) {\n * const span = document.createElement('span');\n * span.textContent = String(props.label);\n * return span;\n * }\n * });\n * if (MyEl) customElements.define('vc-greeting', MyEl);\n */\nexport function defineVaporCustomElement<T = any>(options: object, extraOptions?: object): T | null {\n const fn = getDefineVaporCustomElementFn();\n if (!fn) {\n if (DEV) devWarnNoVapor(\"defineVaporCustomElement\");\n return null;\n }\n return (extraOptions !== undefined ? fn(options, extraOptions) : fn(options)) as T;\n}\n\n/**\n * defineVaporComponent - define a Vapor component with proper type inference.\n *\n * Wraps Vue's `defineVaporComponent()` (typed since 3.6.0-alpha.5, #13831). Use this to get full\n * TypeScript inference for props, emits, and slots in Vapor components.\n * Pass-through - emits/$attrs routing, v-once interop, scope IDs, and the\n * compiler optimizations are Vue behavior (per-beta detail: CHANGELOG /\n * whitepaper alignment log).\n *\n * Returns null if the Vapor runtime (Vue 3.6+) is not detected.\n *\n * @example\n * import { defineVaporComponent } from 'vapor-chamber';\n * const Comp = defineVaporComponent({\n * props: { count: Number },\n * emits: ['change'],\n * // Returns DOM nodes (a block), not h(): see defineVaporCustomElement above.\n * setup(props) {\n * const div = document.createElement('div');\n * div.textContent = `Count: ${props.count}`;\n * return div;\n * }\n * });\n */\nexport function defineVaporComponent<T = any>(options: object): T | null {\n const fn = getDefineVaporComponentFn();\n if (!fn) {\n if (DEV) devWarnNoVapor(\"defineVaporComponent\");\n return null;\n }\n return fn(options) as T;\n}\n\n/**\n * defineVaporAsyncComponent - define an async Vapor component for lazy loading.\n *\n * Wraps Vue's `defineVaporAsyncComponent()` (introduced in 3.6.0-alpha.3, #13059). Async Vapor\n * components are cached by VaporKeepAlive and hydrate under VDOM Suspense.\n * The loading placeholder receives the deferred component's props and slots\n * (beta.14+) - render a skeleton matching the final shape. Per-beta detail:\n * CHANGELOG / whitepaper alignment log.\n *\n * Returns null if the Vapor runtime (Vue 3.6+) is not detected.\n *\n * @example\n * import { defineVaporAsyncComponent } from 'vapor-chamber';\n * const AsyncPanel = defineVaporAsyncComponent(() => import('./Panel.vue'));\n */\nexport function defineVaporAsyncComponent<T = any>(\n loader: (() => Promise<unknown>) | object,\n): T | null {\n const fn = getDefineVaporAsyncComponentFn();\n if (!fn) {\n if (DEV) devWarnNoVapor(\"defineVaporAsyncComponent\");\n return null;\n }\n return fn(loader) as T;\n}\n\n// ---------------------------------------------------------------------------\n// defineVaporCommand\n// ---------------------------------------------------------------------------\n\n/**\n * defineVaporCommand - zero-overhead command for hot paths in Vapor mode.\n *\n * Unlike useCommand(), this skips reactive loading/error signal creation.\n * Ideal for high-frequency, fire-and-forget patterns where reactive\n * loading/error state isn't needed: scroll-position tracking, mousemove\n * sampling, telemetry / metrics events, debounced search, autosave.\n *\n * @example\n * const { dispatch } = defineVaporCommand('telemetryEvent', (cmd) => {\n * // forward to whatever metrics / analytics SDK you use\n * sendMetric(cmd.target.name, cmd.target.params);\n * });\n * dispatch({ name: 'page_view', params: { page: '/landing' } });\n */\nexport function defineVaporCommand(\n action: string,\n handler: Handler,\n options?: RegisterOptions\n) {\n const bus = getCommandBus<CommandMap>();\n const unregister = bus.register(action, handler, options);\n\n // `untracked`, like every other composable's dispatch. This one was the gap,\n // and the worst place for it: a dispatch is an ACTION, not a read, and this\n // helper is documented for hot paths in Vapor mode - i.e. the call most\n // likely to be made from inside a render effect, where the handler's reads\n // become that effect's dependencies and the component re-renders on state it\n // never mentions. Pass-through when Vue is absent, so the \"zero reactive\n // overhead\" claim above is unaffected for non-Vue consumers.\n function dispatch(target: any, payload?: any): CommandResult {\n return untracked(() => bus.dispatch(action, target, payload));\n }\n\n function dispose() { unregister(); }\n\n tryAutoCleanup(dispose);\n\n return { dispatch, dispose };\n}\n\n// ---------------------------------------------------------------------------\n// useVaporAsyncCommand\n// ---------------------------------------------------------------------------\n\n/**\n * useVaporAsyncCommand - async-aware command dispatch for Vapor components\n * used inside Suspense boundaries.\n *\n * Vue 3.6.0-beta.10 introduced proper async component hydration under VDOM\n * Suspense. This composable wraps an AsyncCommandBus dispatch with reactive\n * loading/error state, making it safe for `<script setup vapor>` components\n * that await async operations. Error-boundary rendering and scheduler-flush\n * behavior around async components are Vue runtime concerns (per-beta detail:\n * CHANGELOG / whitepaper alignment log).\n *\n * The dispatch function returns a Promise<CommandResult>, matching the\n * AsyncCommandBus interface. Use this when your commands hit async transports\n * (HTTP bridge, WS bridge) and you need awaitable results.\n *\n * Vue 3.6.0-rc.8: an awaiting `<script setup vapor>` compiles to an\n * `async setup()` that uses runtime-core's `withAsyncContext` and returns its\n * template as a render closure, and it registers with the NEAREST `<Suspense>`.\n * Composables called after the `await` - this one, `useCommand()` - arm their\n * cleanup on the restored component scope, including when the app unmounts\n * during the await. Pinned by tests/async-vapor-setup-fixture.test.ts.\n *\n * @example\n * // In a <script setup vapor> component under <Suspense>:\n * import { useVaporAsyncCommand } from 'vapor-chamber';\n * const { dispatch, loading, lastError } = useVaporAsyncCommand(asyncBus);\n * const result = await dispatch('orderCreate', { items: cart });\n */\nexport function useVaporAsyncCommand(asyncBus?: { dispatch: (action: string, target: any, payload?: any) => Promise<CommandResult> }) {\n const bus = asyncBus ?? (getCommandBus() as any);\n const loading = signal(false);\n const lastError = signal<Error | null>(null);\n\n // Intentionally hand-rolled, NOT routed through the shared runDispatch() that\n // useCommand / useCommandQuery use. A single async/await is\n // ~1.2x leaner on the dispatch wrapper than runDispatch's .then-chain (measured);\n // this is the awaited HTTP/WS path, so keep it lean. Do not \"consolidate\" into\n // runDispatch - the consistency isn't worth the wrapper overhead here.\n async function dispatch(action: string, target: any, payload?: any): Promise<CommandResult> {\n try {\n // Both opening writes are inside the try: a sync subscriber that throws\n // on either becomes a failed result and `loading` ends false (pinned by\n // tests/vapor-async-throwing-subscriber.test.ts).\n loading.value = true;\n lastError.value = null;\n // Untracked around the SYNCHRONOUS entry only - once the dispatch\n // suspends, the caller's effect has finished and there is no subscriber\n // left to leak into (pinned by the \"synchronous entry is the whole\n // exposure\" test). Same scope as runDispatch's, one call, so the leaner\n // hand-rolled wrapper above stays leaner.\n const result = await untracked(() => bus.dispatch(action, target, payload));\n if (!result.ok) lastError.value = result.error ?? null;\n return result;\n } catch (e) {\n const error = e as Error;\n lastError.value = error;\n return _errResult(error);\n } finally {\n loading.value = false;\n }\n }\n\n // Dispatch-only composable (no register/on, unlike useCommand) - there are no\n // subscriptions to tear down. Kept as a no-op for return-shape symmetry with the\n // other composables (callers may destructure `dispose`).\n function dispose() {}\n\n tryAutoCleanup(dispose);\n\n return { dispatch, loading, lastError, dispose };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAS,eAAe,KAAmB;CACzC,QAAQ,KACN,mBAAmB,IAAI,kGACgB,iBAAiB,EAAE,iEAE5D;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,sBACd,eACA,WACM;CACN,MAAM,KAAK,cAAc;CACzB,IAAI,CAAC,IAIH,MAAM,IAAI,MAER,sDAAsD,iBAAiB,OACtE,MAAM,sDAAsD,GAC/D;CAEF,OAAO,GAAG,eAAe,SAAS;AACpC;;;;;;;;;;;;;;AAeA,SAAgB,wBAAoC;CAClD,OAAO,mBAAmB;AAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,yBAAkC,SAAiB,cAAiC;CAClG,MAAM,KAAK,8BAA8B;CACzC,IAAI,CAAC,IAAI;EACP,IAAI,KAAK,eAAe,0BAA0B;EAClD,OAAO;CACT;CACA,OAAQ,iBAAiB,KAAA,IAAY,GAAG,SAAS,YAAY,IAAI,GAAG,OAAO;AAC7E;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,qBAA8B,SAA2B;CACvE,MAAM,KAAK,0BAA0B;CACrC,IAAI,CAAC,IAAI;EACP,IAAI,KAAK,eAAe,sBAAsB;EAC9C,OAAO;CACT;CACA,OAAO,GAAG,OAAO;AACnB;;;;;;;;;;;;;;;;AAiBA,SAAgB,0BACd,QACU;CACV,MAAM,KAAK,+BAA+B;CAC1C,IAAI,CAAC,IAAI;EACP,IAAI,KAAK,eAAe,2BAA2B;EACnD,OAAO;CACT;CACA,OAAO,GAAG,MAAM;AAClB;;;;;;;;;;;;;;;;AAqBA,SAAgB,mBACd,QACA,SACA,SACA;CACA,MAAM,MAAM,cAA0B;CACtC,MAAM,aAAa,IAAI,SAAS,QAAQ,SAAS,OAAO;CASxD,SAAS,SAAS,QAAa,SAA8B;EAC3D,OAAO,gBAAgB,IAAI,SAAS,QAAQ,QAAQ,OAAO,CAAC;CAC9D;CAEA,SAAS,UAAU;EAAE,WAAW;CAAG;CAEnC,eAAe,OAAO;CAEtB,OAAO;EAAE;EAAU;CAAQ;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgB,qBAAqB,UAAiG;CACpI,MAAM,MAAM,YAAa,cAAc;CACvC,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,YAAY,OAAqB,IAAI;CAO3C,eAAe,SAAS,QAAgB,QAAa,SAAuC;EAC1F,IAAI;GAIF,QAAQ,QAAQ;GAChB,UAAU,QAAQ;GAMlB,MAAM,SAAS,MAAM,gBAAgB,IAAI,SAAS,QAAQ,QAAQ,OAAO,CAAC;GAC1E,IAAI,CAAC,OAAO,IAAI,UAAU,QAAQ,OAAO,SAAS;GAClD,OAAO;EACT,SAAS,GAAG;GACV,MAAM,QAAQ;GACd,UAAU,QAAQ;GAClB,OAAOA,UAAW,KAAK;EACzB,UAAU;GACR,QAAQ,QAAQ;EAClB;CACF;CAKA,SAAS,UAAU,CAAC;CAEpB,eAAe,OAAO;CAEtB,OAAO;EAAE;EAAU;EAAS;EAAW;CAAQ;AACjD"}
|
|
1
|
+
{"version":3,"file":"chamber-vapor.js","names":["_errResult"],"sources":["../src/chamber-vapor.ts"],"sourcesContent":["/**\n * vapor-chamber - Vue 3.6+ Vapor-specific API\n *\n * This file renders nothing: it forwards Vue's own define* functions, so\n * rendering-side work (attrs fallthrough, interop, hydration) lands below it.\n * The wrappers and createVaporChamberApp take an opt-in return generic\n * (`<T = any>`) and `object`-typed options: importing Vue's Vapor types here\n * would put a hard `vue` type dependency on the main barrel and break Vue-less\n * command-bus consumers, so callers opt in: `defineVaporComponent<MyComp>(opts)`.\n *\n * Separated from chamber.ts to keep the core composable module CDCC-compliant.\n */\n\nimport {\n signal,\n tryAutoCleanup,\n untracked,\n getVaporAppFn,\n getVaporInteropRef,\n getDefineVaporCustomElementFn,\n getDefineVaporComponentFn,\n getDefineVaporAsyncComponentFn,\n vueDetectionHint,\n} from './chamber';\nimport type { BaseBus, CommandBus, Handler, RegisterOptions, CommandResult } from './command-bus';\nimport { _errResult } from './command-bus';\nimport { DEV } from './dev';\nimport { resolveBus, type BusOption, type ResultOn } from './shared-bus';\n\n/**\n * Why the `defineVapor*` wrappers warn instead of just returning null.\n *\n * Each returns `null` when the Vapor runtime is absent, and callers are\n * documented to check. But a bare `null` is the same failure shape that hid a\n * real bug for several releases: `tryKeepAliveHooks` guarded on an accessor\n * that silently answers \"no\" under Vapor, so a feature was inert with nothing\n * to see (rc.4 cycle - see tests/keepalive-input-scope-fixture.test.ts). Silent\n * negatives are how detection bugs survive.\n *\n * So the null stays - throwing would break the documented contract and the\n * tests that assert it - but it is not quiet. The call sites gate on\n * `DEV`, so the whole call (and every byte of message text) folds out of the\n * production IIFE builds; this helper is then unreferenced and tree-shaken.\n */\nfunction devWarnNoVapor(api: string): void {\n console.warn(\n `[vapor-chamber] ${api}() returned null - Vue 3.6+ with Vapor mode was not detected, ` +\n `so the component was NOT created. ${vueDetectionHint()} ` +\n 'For VDOM mode use the matching define* helper from vue instead.',\n );\n}\n\n/**\n * Create a Vapor app instance with vapor-chamber ready.\n * Requires Vue 3.6+. Throws if Vapor is not available.\n *\n * Pass-through over Vue's createVaporApp - scope-ID handling, HMR app-instance\n * refresh, and setup() error recovery are Vue runtime behavior (per-beta detail:\n * CHANGELOG / whitepaper alignment log).\n *\n * `rootProps` are Vue's raw props, passed through unchanged: a plain value is\n * the value, and a FUNCTION is a getter that Vue calls for the value. So a\n * callback is wrapped, `{ onSave: () => onSave }`; passed bare it is called\n * and the component receives what it returned. (A function set on a\n * `defineWidget` element property is the opposite: it arrives as itself.)\n * Pinned by tests/vapor/vapor-subpath-wiring.test.ts.\n *\n * @example\n * import { createVaporChamberApp } from 'vapor-chamber';\n * import App from './App.vue';\n * createVaporChamberApp(App).mount('#app');\n *\n * @example Root props\n * createVaporChamberApp(App, { title: 'Cart', onSave: () => onSave }).mount('#app');\n */\nexport function createVaporChamberApp<TApp = any>(\n rootComponent: object,\n rootProps?: Record<string, unknown>,\n): TApp {\n const fn = getVaporAppFn();\n if (!fn) {\n // The bare \"Vapor required\" message was the same whether Vue was absent,\n // present-without-Vapor, or present-but-unreachable - three different\n // problems with three different fixes. vueDetectionHint() names which.\n throw new Error(\n // The diagnosis ships (vueDetectionHint says why); the advice is DEV's.\n `[vapor-chamber] Vue 3.6+ with Vapor mode required. ${vueDetectionHint()}` +\n (DEV ? ' For VDOM mode, use createApp() from vue instead.' : '')\n );\n }\n return fn(rootComponent, rootProps) as TApp;\n}\n\n/**\n * Returns the vaporInteropPlugin if available (Vue 3.6+).\n * Use this to enable mixed Vapor/VDOM component trees.\n *\n * Pass-through over Vue's plugin. The returned reference is safe to hold\n * across HMR cycles (Vue does not mutate the bridge).\n *\n * @example\n * import { createApp } from 'vue';\n * import { getVaporInteropPlugin } from 'vapor-chamber';\n * const plugin = getVaporInteropPlugin();\n * if (plugin) createApp(App).use(plugin).mount('#app');\n */\nexport function getVaporInteropPlugin(): any | null {\n return getVaporInteropRef();\n}\n\n// ---------------------------------------------------------------------------\n// Vapor Custom Elements (Vue 3.6 - defineVaporCustomElement introduced in 3.6.0-alpha.4, #14017)\n// ---------------------------------------------------------------------------\n\n/**\n * defineVaporCustomElement - create a custom element backed by Vapor rendering.\n *\n * Wraps Vue's `defineVaporCustomElement()` (introduced in 3.6.0-alpha.4, #14017). The generated custom\n * element uses Vapor's compiler-optimized rendering instead of the VDOM, giving\n * zero-overhead DOM updates inside shadow DOM. Safe to call with a reused\n * options object, and children re-render on reactive prop changes (beta.14+;\n * per-beta detail: CHANGELOG / whitepaper alignment log).\n *\n * Returns null if the Vapor runtime (Vue 3.6+) is not detected - check before calling\n * `customElements.define()`.\n *\n * @example\n * import { defineVaporCustomElement } from 'vapor-chamber';\n * const MyEl = defineVaporCustomElement({\n * props: { label: String },\n * // A Vapor setup() returns a BLOCK - real DOM nodes - not a render\n * // function or h() output. An SFC's compiler builds this from its template.\n * setup(props) {\n * const span = document.createElement('span');\n * span.textContent = String(props.label);\n * return span;\n * }\n * });\n * if (MyEl) customElements.define('vc-greeting', MyEl);\n */\nexport function defineVaporCustomElement<T = any>(options: object, extraOptions?: object): T | null {\n const fn = getDefineVaporCustomElementFn();\n if (!fn) {\n if (DEV) devWarnNoVapor(\"defineVaporCustomElement\");\n return null;\n }\n return (extraOptions !== undefined ? fn(options, extraOptions) : fn(options)) as T;\n}\n\n/**\n * defineVaporComponent - define a Vapor component with proper type inference.\n *\n * Wraps Vue's `defineVaporComponent()` (typed since 3.6.0-alpha.5, #13831). Use this to get full\n * TypeScript inference for props, emits, and slots in Vapor components.\n * Pass-through - emits/$attrs routing, v-once interop, scope IDs, and the\n * compiler optimizations are Vue behavior (per-beta detail: CHANGELOG /\n * whitepaper alignment log).\n *\n * Returns null if the Vapor runtime (Vue 3.6+) is not detected.\n *\n * @example\n * import { defineVaporComponent } from 'vapor-chamber';\n * const Comp = defineVaporComponent({\n * props: { count: Number },\n * emits: ['change'],\n * // Returns DOM nodes (a block), not h(): see defineVaporCustomElement above.\n * setup(props) {\n * const div = document.createElement('div');\n * div.textContent = `Count: ${props.count}`;\n * return div;\n * }\n * });\n */\nexport function defineVaporComponent<T = any>(options: object): T | null {\n const fn = getDefineVaporComponentFn();\n if (!fn) {\n if (DEV) devWarnNoVapor(\"defineVaporComponent\");\n return null;\n }\n return fn(options) as T;\n}\n\n/**\n * defineVaporAsyncComponent - define an async Vapor component for lazy loading.\n *\n * Wraps Vue's `defineVaporAsyncComponent()` (introduced in 3.6.0-alpha.3, #13059). Async Vapor\n * components are cached by VaporKeepAlive and hydrate under VDOM Suspense.\n * The loading placeholder receives the deferred component's props and slots\n * (beta.14+) - render a skeleton matching the final shape. Per-beta detail:\n * CHANGELOG / whitepaper alignment log.\n *\n * Returns null if the Vapor runtime (Vue 3.6+) is not detected.\n *\n * @example\n * import { defineVaporAsyncComponent } from 'vapor-chamber';\n * const AsyncPanel = defineVaporAsyncComponent(() => import('./Panel.vue'));\n */\nexport function defineVaporAsyncComponent<T = any>(\n loader: (() => Promise<unknown>) | object,\n): T | null {\n const fn = getDefineVaporAsyncComponentFn();\n if (!fn) {\n if (DEV) devWarnNoVapor(\"defineVaporAsyncComponent\");\n return null;\n }\n return fn(loader) as T;\n}\n\n// ---------------------------------------------------------------------------\n// defineVaporCommand\n// ---------------------------------------------------------------------------\n\n/** `defineVaporCommand`'s options: how the handler registers, and on which bus. */\nexport type VaporCommandOptions<B extends BaseBus = BaseBus> = RegisterOptions & BusOption<B>;\n\n/**\n * defineVaporCommand - zero-overhead command for hot paths in Vapor mode.\n *\n * Unlike useCommand(), this skips reactive loading/error signal creation.\n * Ideal for high-frequency, fire-and-forget patterns where reactive\n * loading/error state isn't needed: scroll-position tracking, mousemove\n * sampling, telemetry / metrics events, debounced search, autosave.\n *\n * @example\n * const { dispatch } = defineVaporCommand('telemetryEvent', (cmd) => {\n * // forward to whatever metrics / analytics SDK you use\n * sendMetric(cmd.target.name, cmd.target.params);\n * });\n * dispatch({ name: 'page_view', params: { page: '/landing' } });\n */\nexport function defineVaporCommand<B extends BaseBus = CommandBus>(\n action: string,\n handler: Handler,\n options?: VaporCommandOptions<B>\n) {\n const bus = resolveBus(options?.bus);\n // The options go to register() as they are: it reads the register fields,\n // and an undo's stored copy keeps `bus`, which nothing reads.\n const unregister = bus.register(action, handler, options);\n\n // `untracked`, like every other composable's dispatch. This one was the gap,\n // and the worst place for it: a dispatch is an ACTION, not a read, and this\n // helper is documented for hot paths in Vapor mode - i.e. the call most\n // likely to be made from inside a render effect, where the handler's reads\n // become that effect's dependencies and the component re-renders on state it\n // never mentions. Pass-through when Vue is absent, so the \"zero reactive\n // overhead\" claim above is unaffected for non-Vue consumers.\n function dispatch(target: any, payload?: any): ResultOn<B> {\n return untracked(() => bus.dispatch(action, target, payload)) as ResultOn<B>;\n }\n\n function dispose() { unregister(); }\n\n tryAutoCleanup(dispose);\n\n return { dispatch, dispose };\n}\n\n// ---------------------------------------------------------------------------\n// useVaporAsyncCommand\n// ---------------------------------------------------------------------------\n\n/**\n * useVaporAsyncCommand - async-aware command dispatch for Vapor components\n * used inside Suspense boundaries.\n *\n * Vue 3.6.0-beta.10 introduced proper async component hydration under VDOM\n * Suspense. This composable wraps an AsyncCommandBus dispatch with reactive\n * loading/error state, making it safe for `<script setup vapor>` components\n * that await async operations. Error-boundary rendering and scheduler-flush\n * behavior around async components are Vue runtime concerns (per-beta detail:\n * CHANGELOG / whitepaper alignment log).\n *\n * The dispatch function returns a Promise<CommandResult>, matching the\n * AsyncCommandBus interface. Use this when your commands hit async transports\n * (HTTP bridge, WS bridge) and you need awaitable results.\n *\n * Vue 3.6.0-rc.8: an awaiting `<script setup vapor>` compiles to an\n * `async setup()` that uses runtime-core's `withAsyncContext` and returns its\n * template as a render closure, and it registers with the NEAREST `<Suspense>`.\n * Composables called after the `await` - this one, `useCommand()` - arm their\n * cleanup on the restored component scope, including when the app unmounts\n * during the await. Pinned by tests/async-vapor-setup-fixture.test.ts.\n *\n * @example\n * // In a <script setup vapor> component under <Suspense>:\n * import { useVaporAsyncCommand } from 'vapor-chamber';\n * const { dispatch, loading, lastError } = useVaporAsyncCommand(asyncBus);\n * const result = await dispatch('orderCreate', { items: cart });\n */\nexport function useVaporAsyncCommand(asyncBus?: { dispatch: (action: string, target: any, payload?: any) => Promise<CommandResult> }) {\n const bus: any = resolveBus(asyncBus as BaseBus | undefined);\n const loading = signal(false);\n const lastError = signal<Error | null>(null);\n\n // Intentionally hand-rolled, NOT routed through the shared runDispatch() that\n // useCommand / useCommandQuery use. A single async/await is\n // ~1.2x leaner on the dispatch wrapper than runDispatch's .then-chain (measured);\n // this is the awaited HTTP/WS path, so keep it lean. Do not \"consolidate\" into\n // runDispatch - the consistency isn't worth the wrapper overhead here.\n async function dispatch(action: string, target: any, payload?: any): Promise<CommandResult> {\n try {\n // Both opening writes are inside the try: a sync subscriber that throws\n // on either becomes a failed result and `loading` ends false (pinned by\n // tests/vapor-async-throwing-subscriber.test.ts).\n loading.value = true;\n lastError.value = null;\n // Untracked around the SYNCHRONOUS entry only - once the dispatch\n // suspends, the caller's effect has finished and there is no subscriber\n // left to leak into (pinned by the \"synchronous entry is the whole\n // exposure\" test). Same scope as runDispatch's, one call, so the leaner\n // hand-rolled wrapper above stays leaner.\n const result = await untracked(() => bus.dispatch(action, target, payload));\n if (!result.ok) lastError.value = result.error ?? null;\n return result;\n } catch (e) {\n const error = e as Error;\n lastError.value = error;\n return _errResult(error);\n } finally {\n loading.value = false;\n }\n }\n\n // Dispatch-only composable (no register/on, unlike useCommand) - there are no\n // subscriptions to tear down. Kept as a no-op for return-shape symmetry with the\n // other composables (callers may destructure `dispose`).\n function dispose() {}\n\n tryAutoCleanup(dispose);\n\n return { dispatch, loading, lastError, dispose };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAS,eAAe,KAAmB;CACzC,QAAQ,KACN,mBAAmB,IAAI,kGACgB,iBAAiB,EAAE,iEAE5D;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,sBACd,eACA,WACM;CACN,MAAM,KAAK,cAAc;CACzB,IAAI,CAAC,IAIH,MAAM,IAAI,MAER,sDAAsD,iBAAiB,OACtE,MAAM,sDAAsD,GAC/D;CAEF,OAAO,GAAG,eAAe,SAAS;AACpC;;;;;;;;;;;;;;AAeA,SAAgB,wBAAoC;CAClD,OAAO,mBAAmB;AAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,yBAAkC,SAAiB,cAAiC;CAClG,MAAM,KAAK,8BAA8B;CACzC,IAAI,CAAC,IAAI;EACP,IAAI,KAAK,eAAe,0BAA0B;EAClD,OAAO;CACT;CACA,OAAQ,iBAAiB,KAAA,IAAY,GAAG,SAAS,YAAY,IAAI,GAAG,OAAO;AAC7E;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,qBAA8B,SAA2B;CACvE,MAAM,KAAK,0BAA0B;CACrC,IAAI,CAAC,IAAI;EACP,IAAI,KAAK,eAAe,sBAAsB;EAC9C,OAAO;CACT;CACA,OAAO,GAAG,OAAO;AACnB;;;;;;;;;;;;;;;;AAiBA,SAAgB,0BACd,QACU;CACV,MAAM,KAAK,+BAA+B;CAC1C,IAAI,CAAC,IAAI;EACP,IAAI,KAAK,eAAe,2BAA2B;EACnD,OAAO;CACT;CACA,OAAO,GAAG,MAAM;AAClB;;;;;;;;;;;;;;;;AAwBA,SAAgB,mBACd,QACA,SACA,SACA;CACA,MAAM,MAAM,WAAW,SAAS,GAAG;CAGnC,MAAM,aAAa,IAAI,SAAS,QAAQ,SAAS,OAAO;CASxD,SAAS,SAAS,QAAa,SAA4B;EACzD,OAAO,gBAAgB,IAAI,SAAS,QAAQ,QAAQ,OAAO,CAAC;CAC9D;CAEA,SAAS,UAAU;EAAE,WAAW;CAAG;CAEnC,eAAe,OAAO;CAEtB,OAAO;EAAE;EAAU;CAAQ;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgB,qBAAqB,UAAiG;CACpI,MAAM,MAAW,WAAW,QAA+B;CAC3D,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,YAAY,OAAqB,IAAI;CAO3C,eAAe,SAAS,QAAgB,QAAa,SAAuC;EAC1F,IAAI;GAIF,QAAQ,QAAQ;GAChB,UAAU,QAAQ;GAMlB,MAAM,SAAS,MAAM,gBAAgB,IAAI,SAAS,QAAQ,QAAQ,OAAO,CAAC;GAC1E,IAAI,CAAC,OAAO,IAAI,UAAU,QAAQ,OAAO,SAAS;GAClD,OAAO;EACT,SAAS,GAAG;GACV,MAAM,QAAQ;GACd,UAAU,QAAQ;GAClB,OAAOA,UAAW,KAAK;EACzB,UAAU;GACR,QAAQ,QAAQ;EAClB;CACF;CAKA,SAAS,UAAU,CAAC;CAEpB,eAAe,OAAO;CAEtB,OAAO;EAAE;EAAU;EAAS;EAAW;CAAQ;AACjD"}
|
package/dist/chamber.d.ts
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* composables came from the root with nothing wired. The history is in
|
|
11
11
|
* CHANGELOG.md.
|
|
12
12
|
*/
|
|
13
|
-
import { type CommandBus, type Command, type CommandResult, type CommandMap, type TargetOf, type PayloadOf, type ResultOf, type Handler, type Plugin, type RegisterOptions, type Listener } from './command-bus';
|
|
13
|
+
import { type BaseBus, type CommandBus, type Command, type CommandResult, type CommandMap, type TargetOf, type PayloadOf, type ResultOf, type Handler, type Plugin, type RegisterOptions, type Listener } from './command-bus';
|
|
14
14
|
import { configureSignal, signal } from './signal';
|
|
15
|
-
import { getCommandBus, resetCommandBus, setCommandBus } from './shared-bus';
|
|
15
|
+
import { getCommandBus, resetCommandBus, setCommandBus, type BusOption, type ResultOn } from './shared-bus';
|
|
16
16
|
import type { Signal } from './signal';
|
|
17
17
|
export type { Signal, CreateSignal } from './signal';
|
|
18
18
|
export { configureSignal };
|
|
@@ -153,6 +153,7 @@ export type SharedCommandMap = [keyof GlobalCommands] extends [never] ? CommandM
|
|
|
153
153
|
[K in keyof GlobalCommands]: GlobalCommands[K];
|
|
154
154
|
};
|
|
155
155
|
export { getCommandBus, setCommandBus, resetCommandBus };
|
|
156
|
+
export type { BusOption, ResultOn };
|
|
156
157
|
/**
|
|
157
158
|
* Try to register a cleanup function on the nearest Vue scope/component.
|
|
158
159
|
*
|
|
@@ -230,8 +231,8 @@ export declare function runDispatch(bus: CommandBus, query: boolean, action: str
|
|
|
230
231
|
* register('cartAdd', (cmd) => addToCart(cmd.target));
|
|
231
232
|
* dispatch('cartAdd', { id: product.id });
|
|
232
233
|
*/
|
|
233
|
-
export declare function useCommand(): {
|
|
234
|
-
dispatch: <A extends keyof SharedCommandMap & string>(action: A, target: TargetOf<SharedCommandMap, A>, payload?: PayloadOf<SharedCommandMap, A>) =>
|
|
234
|
+
export declare function useCommand<B extends BaseBus = CommandBus>(options?: BusOption<B>): {
|
|
235
|
+
dispatch: <A extends keyof SharedCommandMap & string>(action: A, target: TargetOf<SharedCommandMap, A>, payload?: PayloadOf<SharedCommandMap, A>) => ResultOn<B, CommandResult<ResultOf<SharedCommandMap, A>>>;
|
|
235
236
|
register: <A extends keyof SharedCommandMap & string>(action: A, handler: (cmd: Command<A, TargetOf<SharedCommandMap, A>, PayloadOf<SharedCommandMap, A>>) => ResultOf<SharedCommandMap, A> | Promise<ResultOf<SharedCommandMap, A>>, opts?: RegisterOptions) => () => void;
|
|
236
237
|
on: (pattern: string, listener: (cmd: Command, result: CommandResult) => void) => () => void;
|
|
237
238
|
emit: (event: string, data?: any) => void;
|
|
@@ -239,18 +240,12 @@ export declare function useCommand(): {
|
|
|
239
240
|
lastError: Signal<Error | null>;
|
|
240
241
|
dispose: () => void;
|
|
241
242
|
};
|
|
242
|
-
export type UseSharedCommandStateOptions = {
|
|
243
|
+
export type UseSharedCommandStateOptions<B extends BaseBus = BaseBus> = BusOption<B> & {
|
|
243
244
|
/**
|
|
244
245
|
* How many recent errors to retain in `errors`. The list is kept
|
|
245
246
|
* newest-last; older entries drop off. Default: 10.
|
|
246
247
|
*/
|
|
247
248
|
maxSize?: number;
|
|
248
|
-
/**
|
|
249
|
-
* Bus to attach to. Defaults to the shared instance from `getCommandBus()`,
|
|
250
|
-
* which matches the single-bus pattern most apps use. Pass an explicit bus
|
|
251
|
-
* to scope shared state to a feature group / island.
|
|
252
|
-
*/
|
|
253
|
-
bus?: CommandBus;
|
|
254
249
|
};
|
|
255
250
|
/**
|
|
256
251
|
* useSharedCommandState - one set of reactive signals shared across every
|
|
@@ -276,10 +271,10 @@ export type UseSharedCommandStateOptions = {
|
|
|
276
271
|
*
|
|
277
272
|
* Auto-cleanup on Vue scope/component disposal via tryAutoCleanup.
|
|
278
273
|
*/
|
|
279
|
-
export declare function useSharedCommandState(options?: UseSharedCommandStateOptions): {
|
|
274
|
+
export declare function useSharedCommandState<B extends BaseBus = CommandBus>(options?: UseSharedCommandStateOptions<B>): {
|
|
280
275
|
dispatch: (action: string, target: any, payload?: any, opts?: {
|
|
281
276
|
signal?: AbortSignal;
|
|
282
|
-
}) =>
|
|
277
|
+
}) => ResultOn<B>;
|
|
283
278
|
/** Reactive per-(action, target) loading flag - see isLoading above. */
|
|
284
279
|
isLoading: (action: string, target?: unknown) => Readonly<Signal<boolean>>;
|
|
285
280
|
/** Number of dispatches currently in flight across all subscribers. */
|
|
@@ -298,7 +293,7 @@ export declare function useSharedCommandState(options?: UseSharedCommandStateOpt
|
|
|
298
293
|
* hooks Vue's scope/unmount lifecycle. */
|
|
299
294
|
dispose: () => void;
|
|
300
295
|
};
|
|
301
|
-
export type UseCommandStateOptions = {
|
|
296
|
+
export type UseCommandStateOptions = BusOption & {
|
|
302
297
|
/**
|
|
303
298
|
* When true, multiple synchronous dispatches within the same microtask are
|
|
304
299
|
* accumulated and the signal is written once via `queueMicrotask`. Pairs with
|
|
@@ -359,7 +354,7 @@ export declare function _createCommandState<T>(initial: T, handlers: {
|
|
|
359
354
|
export declare function useCommandHistory(options?: {
|
|
360
355
|
maxSize?: number;
|
|
361
356
|
filter?: (cmd: Command) => boolean;
|
|
362
|
-
}): {
|
|
357
|
+
} & BusOption): {
|
|
363
358
|
past: Signal<Command[]>;
|
|
364
359
|
future: Signal<Command[]>;
|
|
365
360
|
canUndo: Signal<boolean>;
|
|
@@ -384,8 +379,8 @@ export declare function useCommandHistory(options?: {
|
|
|
384
379
|
* const result = query('getUser', { id: 42 });
|
|
385
380
|
* // data.value = result.value after query completes
|
|
386
381
|
*/
|
|
387
|
-
export declare function useCommandQuery(): {
|
|
388
|
-
query: (action: string, target: any, payload?: any) =>
|
|
382
|
+
export declare function useCommandQuery<B extends BaseBus = CommandBus>(options?: BusOption<B>): {
|
|
383
|
+
query: (action: string, target: any, payload?: any) => ResultOn<B>;
|
|
389
384
|
data: Signal<any>;
|
|
390
385
|
loading: Signal<boolean>;
|
|
391
386
|
lastError: Signal<Error | null>;
|
|
@@ -408,9 +403,9 @@ export declare function useCommandQuery(): {
|
|
|
408
403
|
* const orders = useCommandGroup('orders')
|
|
409
404
|
* orders.dispatch('cancel', { id }) // dispatches 'ordersCancel'
|
|
410
405
|
*/
|
|
411
|
-
export declare function useCommandGroup(namespace: string): {
|
|
412
|
-
dispatch: (action: string, target: any, payload?: any) =>
|
|
413
|
-
query: (action: string, target: any, payload?: any) =>
|
|
406
|
+
export declare function useCommandGroup<B extends BaseBus = CommandBus>(namespace: string, options?: BusOption<B>): {
|
|
407
|
+
dispatch: (action: string, target: any, payload?: any) => ResultOn<B>;
|
|
408
|
+
query: (action: string, target: any, payload?: any) => ResultOn<B>;
|
|
414
409
|
emit: (event: string, data?: any) => void;
|
|
415
410
|
register: (action: string, handler: Handler, opts?: RegisterOptions) => () => void;
|
|
416
411
|
use: (plugin: Plugin) => () => void;
|
|
@@ -434,7 +429,7 @@ export declare function useCommandError(options?: {
|
|
|
434
429
|
filter?: (cmd: Command) => boolean;
|
|
435
430
|
/** Max errors retained - oldest are dropped first (ring buffer). Default: 50. */
|
|
436
431
|
maxSize?: number;
|
|
437
|
-
}): {
|
|
432
|
+
} & BusOption): {
|
|
438
433
|
errors: Signal<{
|
|
439
434
|
cmd: Command;
|
|
440
435
|
error: Error;
|
package/dist/chamber.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chamber.d.ts","sourceRoot":"","sources":["../src/chamber.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"chamber.d.ts","sourceRoot":"","sources":["../src/chamber.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAyE,KAAK,OAAO,EAAE,KAAK,UAAU,EAAC,KAAK,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrS,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAc,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAgDxH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAgBvC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;AA4IlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAI9C;AAsBD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE,UAAU,UAAQ,GAAG,IAAI,CAI3F;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAY3C;AAmND;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AASD;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAkBzC;AAED,gDAAgD;AAChD,wBAAgB,aAAa,IAAI,GAAG,CAA8B;AAClE,gDAAgD;AAChD,wBAAgB,kBAAkB,IAAI,GAAG,CAAmC;AAC5E,gDAAgD;AAChD,wBAAgB,6BAA6B,IAAI,GAAG,CAAwC;AAC5F,gDAAgD;AAChD,wBAAgB,yBAAyB,IAAI,GAAG,CAAoC;AACpF,gDAAgD;AAChD,wBAAgB,8BAA8B,IAAI,GAAG,CAAyC;AAC9F;wEACwE;AACxE,wBAAgB,eAAe,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC,GAAG,IAAI,CAA0B;AAM/F;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,cAAc;CAAG;AAElC;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,GACjE,UAAU,GACV;KAAG,CAAC,IAAI,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC;CAAE,CAAC;AAGvD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AAMpC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,IAAI,GAAG,IAAI,CAwB1D;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAOjF;AAqBD,gBAAgB;AAChB,wBAAgB,WAAW,CACzB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,EACxB,SAAS,EAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,EAC/B,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAC/B,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAmDxC;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,OAAO,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;eAS7D,CAAC,SAAS,MAAM,gBAAgB,GAAG,MAAM,UACjD,CAAC,UACD,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,YAC3B,SAAS,CAAC,gBAAgB,EAAE,CAAC,CAAC,KACvC,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;eAI1C,CAAC,SAAS,MAAM,gBAAgB,GAAG,MAAM,UACjD,CAAC,WACA,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,SAC5J,eAAe,KACrB,MAAM,IAAI;kBAeQ,MAAM,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,KAAK,IAAI,KAAG,MAAM,IAAI;kBAO5E,MAAM,SAAS,GAAG,KAAG,IAAI;;;;EA6B/C;AAgJD,MAAM,MAAM,4BAA4B,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG;IACrF;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,OAAO,GAAG,UAAU,EAAE,OAAO,GAAE,4BAA4B,CAAC,CAAC,CAAM;uBA+GvG,MAAM,UACN,GAAG,YACD,GAAG,SACN;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,KAC9B,QAAQ,CAAC,CAAC,CAAC;IA4EZ,wEAAwE;wBAtB/C,MAAM,WAAW,OAAO,KAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAwB7E,uEAAuE;;IAEvE,+DAA+D;;IAE/D,kDAAkD;;IAElD,sEAAsE;;IAEtE,2CAA2C;;IAE3C,+BAA+B;iBAtDf,IAAI;IAwDpB;+CAC2C;mBA1BzB,IAAI;EA6BzB;AAMD,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG;IAC/C;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,EAAE,CAAC,EACV,QAAQ,EAAE;IACR,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,KAAK,CAAC,CAAC;CACjD,EACD,OAAO,GAAE,sBAA2B;;aAoBN,MAAM,IAAI;EAjBzC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,OAAO,EAAE,CAAC,EACV,QAAQ,EAAE;IACR,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,KAAK,CAAC,CAAC;CACjD,EACD,OAAO,EAAE,sBAAsB,EAC/B,YAAY,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,GACnC;IAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAuC3C;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;CACpC,GAAG,SAAc;;;;;gBAqCC,OAAO,GAAG,SAAS;gBACnB,OAAO,GAAG,SAAS;iBAClB,IAAI;;EAkBvB;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;oBAU7D,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,QAAQ,CAAC,CAAC,CAAC;;;;EAKxE;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;uBAmC7E,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,QAAQ,CAAC,CAAC,CAAC;oBAKnD,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,QAAQ,CAAC,CAAC,CAAC;kBAKlD,MAAM,SAAS,GAAG,KAAG,IAAI;uBAIpB,MAAM,WAAW,OAAO,SAAS,eAAe,KAAG,MAAM,IAAI;kBAMlE,MAAM,KAAG,MAAM,IAAI;kBAMnB,MAAM,YAAY,QAAQ,KAAG,MAAM,IAAI;;;EAe7D;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE;IACvC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACnC,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,SAAc;;aAKS,OAAO;eAAS,KAAK;mBAAa,MAAM;;;;;EAoClE"}
|