vapor-chamber 1.2.0 → 1.3.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/README.md +3 -3
- package/ROADMAP.md +4 -4
- package/dist/{chamber-Cm7_vz_U.js → chamber-CesaYQmb.js} +83 -103
- package/dist/chamber-CesaYQmb.js.map +1 -0
- package/dist/{chamber-B_ff1-af.js → chamber-ayzW3B-v.js} +84 -103
- package/dist/chamber-ayzW3B-v.js.map +1 -0
- package/dist/{chamber-vapor-CrDvj19S.js → chamber-vapor-CqMH_L-d.js} +7 -42
- package/dist/chamber-vapor-CqMH_L-d.js.map +1 -0
- package/dist/{chamber-vapor-Bc-A5SID.js → chamber-vapor-Djf77X57.js} +8 -42
- package/dist/chamber-vapor-Djf77X57.js.map +1 -0
- package/dist/chamber-vapor.d.ts +22 -0
- package/dist/chamber-vapor.d.ts.map +1 -1
- package/dist/chamber.d.ts +43 -7
- package/dist/chamber.d.ts.map +1 -1
- package/dist/{signal-pT4BgmiH.js → command-bus-DNHnswE_.js} +113 -237
- package/dist/command-bus-DNHnswE_.js.map +1 -0
- package/dist/{command-bus-DA3nlrS6.js → command-bus-nxA-KYSC.js} +44 -107
- package/dist/command-bus-nxA-KYSC.js.map +1 -0
- package/dist/command-bus.d.ts +11 -0
- package/dist/command-bus.d.ts.map +1 -1
- package/dist/directives.js +1 -1
- package/dist/iife.js +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +116 -124
- package/dist/index.js.map +1 -1
- package/dist/plugins-extra.d.ts.map +1 -1
- package/dist/plugins-io.d.ts +1 -1
- package/dist/plugins-io.d.ts.map +1 -1
- package/dist/plugins-schema.js +1 -1
- package/dist/transitions.js +1 -1
- package/dist/{transports-CMcmqEN-.js → transports-BSfLx9oG.js} +6 -22
- package/dist/transports-BSfLx9oG.js.map +1 -0
- package/dist/{transports-BuSZVG89.js → transports-Bnz6r6x5.js} +19 -25
- package/dist/transports-Bnz6r6x5.js.map +1 -0
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +2 -2
- package/dist/vapor-chamber-core.iife.js +93 -198
- package/dist/vapor-chamber-core.iife.js.map +1 -1
- package/dist/vapor-chamber-core.iife.min.js +1 -1
- package/dist/vapor-chamber-elements.iife.js +95 -200
- 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 +142 -267
- package/dist/vapor-chamber.iife.js.map +1 -1
- package/dist/vapor-chamber.iife.min.js +1 -1
- package/package.json +2 -2
- package/scripts/check-size.mjs +3 -3
- package/dist/chamber-BHo2PZnx.js +0 -1297
- package/dist/chamber-BHo2PZnx.js.map +0 -1
- package/dist/chamber-BLvYXQR8.js +0 -518
- package/dist/chamber-BLvYXQR8.js.map +0 -1
- package/dist/chamber-BUgOYOAc.js +0 -1293
- package/dist/chamber-BUgOYOAc.js.map +0 -1
- package/dist/chamber-B_ff1-af.js.map +0 -1
- package/dist/chamber-BmLw2FDU.js +0 -420
- package/dist/chamber-BmLw2FDU.js.map +0 -1
- package/dist/chamber-BwyEE9vP.js +0 -1320
- package/dist/chamber-BwyEE9vP.js.map +0 -1
- package/dist/chamber-C0xS5NDI.js +0 -420
- package/dist/chamber-C0xS5NDI.js.map +0 -1
- package/dist/chamber-C1q3L1oU.js +0 -420
- package/dist/chamber-C1q3L1oU.js.map +0 -1
- package/dist/chamber-Cm7_vz_U.js.map +0 -1
- package/dist/chamber-CoO1CLDg.js +0 -518
- package/dist/chamber-CoO1CLDg.js.map +0 -1
- package/dist/chamber-Vn0IZVna.js +0 -518
- package/dist/chamber-Vn0IZVna.js.map +0 -1
- package/dist/chamber-iK4VO3lw.js +0 -420
- package/dist/chamber-iK4VO3lw.js.map +0 -1
- package/dist/chamber-vapor-8R6iwINH.js +0 -540
- package/dist/chamber-vapor-8R6iwINH.js.map +0 -1
- package/dist/chamber-vapor-B5KwDQXN.js +0 -539
- package/dist/chamber-vapor-B5KwDQXN.js.map +0 -1
- package/dist/chamber-vapor-BNIYoRME.js +0 -540
- package/dist/chamber-vapor-BNIYoRME.js.map +0 -1
- package/dist/chamber-vapor-BYdGCAVC.js +0 -540
- package/dist/chamber-vapor-BYdGCAVC.js.map +0 -1
- package/dist/chamber-vapor-Bc-A5SID.js.map +0 -1
- package/dist/chamber-vapor-CQWCByx-.js +0 -525
- package/dist/chamber-vapor-CQWCByx-.js.map +0 -1
- package/dist/chamber-vapor-CrDvj19S.js.map +0 -1
- package/dist/chamber-vapor-D7WY8gpo.js +0 -540
- package/dist/chamber-vapor-D7WY8gpo.js.map +0 -1
- package/dist/chamber-vapor-DzhknTIy.js +0 -540
- package/dist/chamber-vapor-DzhknTIy.js.map +0 -1
- package/dist/chamber-vapor-EH9hhveO.js +0 -540
- package/dist/chamber-vapor-EH9hhveO.js.map +0 -1
- package/dist/chamber-vapor-IpqC6fgk.js +0 -540
- package/dist/chamber-vapor-IpqC6fgk.js.map +0 -1
- package/dist/chamber-vapor-i1EIsWOg.js +0 -540
- package/dist/chamber-vapor-i1EIsWOg.js.map +0 -1
- package/dist/chamber-vapor-isZkw0sf.js +0 -525
- package/dist/chamber-vapor-isZkw0sf.js.map +0 -1
- package/dist/command-bus-DA3nlrS6.js.map +0 -1
- package/dist/signal-BEmakAvP.js +0 -913
- package/dist/signal-BEmakAvP.js.map +0 -1
- package/dist/signal-C0JQhs2G.js +0 -926
- package/dist/signal-C0JQhs2G.js.map +0 -1
- package/dist/signal-C7iO4lNJ.js +0 -957
- package/dist/signal-C7iO4lNJ.js.map +0 -1
- package/dist/signal-CBFIjSiL.js +0 -951
- package/dist/signal-CBFIjSiL.js.map +0 -1
- package/dist/signal-D1SPpDTh.js +0 -952
- package/dist/signal-D1SPpDTh.js.map +0 -1
- package/dist/signal-eHOL-GNS.js +0 -926
- package/dist/signal-eHOL-GNS.js.map +0 -1
- package/dist/signal-pT4BgmiH.js.map +0 -1
- package/dist/transports-BHQkkVjt.js +0 -699
- package/dist/transports-BHQkkVjt.js.map +0 -1
- package/dist/transports-Bd_fqFva.js +0 -732
- package/dist/transports-Bd_fqFva.js.map +0 -1
- package/dist/transports-BhJ56Fgx.js +0 -699
- package/dist/transports-BhJ56Fgx.js.map +0 -1
- package/dist/transports-BuSZVG89.js.map +0 -1
- package/dist/transports-CMcmqEN-.js.map +0 -1
- package/dist/transports-Ckkspzeb.js +0 -700
- package/dist/transports-Ckkspzeb.js.map +0 -1
- package/dist/transports-CtFiD_mr.js +0 -699
- package/dist/transports-CtFiD_mr.js.map +0 -1
- package/dist/transports-D4_d3u_d.js +0 -699
- package/dist/transports-D4_d3u_d.js.map +0 -1
- package/dist/transports-DKop5_zi.js +0 -700
- package/dist/transports-DKop5_zi.js.map +0 -1
- package/dist/transports-DN6DzZTU.js +0 -732
- package/dist/transports-DN6DzZTU.js.map +0 -1
- package/dist/transports-DTNi1DT6.js +0 -732
- package/dist/transports-DTNi1DT6.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
A lightweight command bus designed for <a href="https://github.com/vuejs/vue-vapor">Vue Vapor</a>. ~2KB
|
|
6
|
+
A lightweight command bus designed for <a href="https://github.com/vuejs/vue-vapor">Vue Vapor</a>. ~6.2KB. Vue 3.6 Vapor aligned. Optional DevTools integration.
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
## What is Vapor Chamber?
|
|
@@ -23,9 +23,9 @@ bus.use(validator({ cartAdd: (cmd) => cmd.target.id ? null : 'Missing ID' }));
|
|
|
23
23
|
const { dispatch, loading, lastError } = useCommand('cartAdd');
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
- **~
|
|
26
|
+
- **~6.7 KB brotli (full IIFE) / ~5.7 KB brotli (ESM tree-shaken)** — zero runtime dependencies
|
|
27
27
|
- **Framework-agnostic core** — the bus itself has no Vue import
|
|
28
|
-
- **Vue 3.6
|
|
28
|
+
- **Vue 3.6.0-beta.12 aligned** — signals, `onScopeDispose`, `getCurrentScope`, alien-signals internals
|
|
29
29
|
- **Full plugin pipeline** — logger, validator, debounce, throttle, retry, persist, sync, and more
|
|
30
30
|
- **Transport layer** — HTTP bridge, WebSocket bridge, SSE bridge
|
|
31
31
|
- **SSR-safe** — per-request bus isolation, no shared singletons
|
package/ROADMAP.md
CHANGED
|
@@ -4,18 +4,18 @@ This project tracks Vue 3.6 while it is in beta. That has direct consequences
|
|
|
4
4
|
for what's stable, what's transitional, and what will change once Vue 3.6
|
|
5
5
|
ships stable. This file is the source of truth for that distinction.
|
|
6
6
|
|
|
7
|
-
Last reviewed against **Vue 3.6.0-beta.
|
|
7
|
+
Last reviewed against **Vue 3.6.0-beta.12** (released 2026-05-15).
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## Current posture: beta territory
|
|
12
12
|
|
|
13
|
-
- **Peer dependency:** `vue: ">=3.5.0 || >=3.6.0-beta.
|
|
13
|
+
- **Peer dependency:** `vue: ">=3.5.0 || >=3.6.0-beta.12"`. The lib supports
|
|
14
14
|
Vue 3.5 (composables only) and Vue 3.6 betas (full Vapor surface).
|
|
15
15
|
- **Vapor APIs are still moving.** `defineVaporCustomElement`, `defineVaporComponent`,
|
|
16
16
|
`defineVaporAsyncComponent` are stable in shape but their underlying behavior
|
|
17
|
-
has shifted between beta.10 and beta.
|
|
18
|
-
|
|
17
|
+
has shifted between beta.10 and beta.12 (generics inference, emits/attrs split,
|
|
18
|
+
VDOM slots interop normalization, error recovery). The lib's wrappers are
|
|
19
19
|
pass-through, so consumers inherit each beta's improvements without code
|
|
20
20
|
changes — but the wrappers themselves exist precisely because the API is
|
|
21
21
|
not yet final.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as createCommandBus } from "./command-bus-DNHnswE_.js";
|
|
2
2
|
import { s as signal, c as configureSignal } from "./signal-DUZrcb-E.js";
|
|
3
|
-
let _vueOnUnmounted = null;
|
|
4
3
|
let _vueOnScopeDispose = null;
|
|
4
|
+
let _vueGetCurrentScope = null;
|
|
5
5
|
let _vueGetCurrentInstance = null;
|
|
6
6
|
let _vueOnActivated = null;
|
|
7
7
|
let _vueOnDeactivated = null;
|
|
@@ -20,8 +20,8 @@ function applyVueModule(vue) {
|
|
|
20
20
|
if (vue && typeof vue.onScopeDispose === "function") {
|
|
21
21
|
_vueOnScopeDispose = vue.onScopeDispose;
|
|
22
22
|
}
|
|
23
|
-
if (vue && typeof vue.
|
|
24
|
-
|
|
23
|
+
if (vue && typeof vue.getCurrentScope === "function") {
|
|
24
|
+
_vueGetCurrentScope = vue.getCurrentScope;
|
|
25
25
|
}
|
|
26
26
|
if (vue && typeof vue.getCurrentInstance === "function") {
|
|
27
27
|
_vueGetCurrentInstance = vue.getCurrentInstance;
|
|
@@ -108,76 +108,60 @@ function resetCommandBus() {
|
|
|
108
108
|
}
|
|
109
109
|
function tryAutoCleanup(disposeFn) {
|
|
110
110
|
probeVue();
|
|
111
|
-
if (_vueOnScopeDispose) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return;
|
|
115
|
-
} catch {
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (_vueOnUnmounted && _vueGetCurrentInstance) {
|
|
119
|
-
try {
|
|
120
|
-
if (_vueGetCurrentInstance()) {
|
|
121
|
-
_vueOnUnmounted(disposeFn);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
} catch {
|
|
125
|
-
}
|
|
111
|
+
if (_vueOnScopeDispose && _vueGetCurrentScope?.()) {
|
|
112
|
+
_vueOnScopeDispose(disposeFn);
|
|
113
|
+
return;
|
|
126
114
|
}
|
|
127
115
|
if (_vueOnScopeDispose && typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
|
|
128
116
|
console.warn(
|
|
129
|
-
"[vapor-chamber] tryAutoCleanup: no Vue scope
|
|
117
|
+
"[vapor-chamber] tryAutoCleanup: no active Vue scope found. Call dispose() manually or use this composable inside setup() / effectScope()."
|
|
130
118
|
);
|
|
131
119
|
}
|
|
132
120
|
}
|
|
133
121
|
function tryKeepAliveHooks(onPause, onResume) {
|
|
134
122
|
probeVue();
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
123
|
+
if (!_vueGetCurrentInstance?.()) return;
|
|
124
|
+
_vueOnDeactivated?.(onPause);
|
|
125
|
+
_vueOnActivated?.(onResume);
|
|
126
|
+
}
|
|
127
|
+
function runDispatch(busCall, loading, lastError, onSuccess) {
|
|
128
|
+
loading.value = true;
|
|
129
|
+
lastError.value = null;
|
|
130
|
+
let result;
|
|
131
|
+
try {
|
|
132
|
+
result = busCall();
|
|
133
|
+
} catch (e) {
|
|
134
|
+
loading.value = false;
|
|
135
|
+
const error = e;
|
|
136
|
+
lastError.value = error;
|
|
137
|
+
return { ok: false, error };
|
|
138
|
+
}
|
|
139
|
+
if (result && typeof result.then === "function") {
|
|
140
|
+
return result.then(
|
|
141
|
+
(r) => {
|
|
142
|
+
loading.value = false;
|
|
143
|
+
if (r.ok) onSuccess?.(r.value);
|
|
144
|
+
else lastError.value = r.error ?? null;
|
|
145
|
+
return r;
|
|
146
|
+
},
|
|
147
|
+
(e) => {
|
|
148
|
+
loading.value = false;
|
|
149
|
+
lastError.value = e;
|
|
150
|
+
return { ok: false, error: e };
|
|
151
|
+
}
|
|
152
|
+
);
|
|
146
153
|
}
|
|
154
|
+
loading.value = false;
|
|
155
|
+
if (result.ok) onSuccess?.(result.value);
|
|
156
|
+
else lastError.value = result.error ?? null;
|
|
157
|
+
return result;
|
|
147
158
|
}
|
|
148
159
|
function useCommand() {
|
|
149
160
|
const bus = getCommandBus();
|
|
150
161
|
const loading = signal(false);
|
|
151
162
|
const lastError = signal(null);
|
|
152
163
|
function dispatch(action, target, payload) {
|
|
153
|
-
|
|
154
|
-
lastError.value = null;
|
|
155
|
-
let result;
|
|
156
|
-
try {
|
|
157
|
-
result = bus.dispatch(action, target, payload);
|
|
158
|
-
} catch (e) {
|
|
159
|
-
loading.value = false;
|
|
160
|
-
const error = e;
|
|
161
|
-
lastError.value = error;
|
|
162
|
-
return { ok: false, error };
|
|
163
|
-
}
|
|
164
|
-
if (result && typeof result.then === "function") {
|
|
165
|
-
return result.then(
|
|
166
|
-
(r) => {
|
|
167
|
-
loading.value = false;
|
|
168
|
-
if (!r.ok) lastError.value = r.error ?? null;
|
|
169
|
-
return r;
|
|
170
|
-
},
|
|
171
|
-
(e) => {
|
|
172
|
-
loading.value = false;
|
|
173
|
-
lastError.value = e;
|
|
174
|
-
return { ok: false, error: e };
|
|
175
|
-
}
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
loading.value = false;
|
|
179
|
-
if (!result.ok) lastError.value = result.error ?? null;
|
|
180
|
-
return result;
|
|
164
|
+
return runDispatch(() => bus.dispatch(action, target, payload), loading, lastError);
|
|
181
165
|
}
|
|
182
166
|
return { dispatch, loading, lastError };
|
|
183
167
|
}
|
|
@@ -278,12 +262,29 @@ function useSharedCommandState(options = {}) {
|
|
|
278
262
|
dispose
|
|
279
263
|
};
|
|
280
264
|
}
|
|
281
|
-
function useCommandState(initial, handlers) {
|
|
265
|
+
function useCommandState(initial, handlers, options = {}) {
|
|
266
|
+
const { coalesce = false } = options;
|
|
282
267
|
const bus = getCommandBus();
|
|
283
268
|
const state = signal(initial);
|
|
284
269
|
const unregisters = [];
|
|
270
|
+
let _pending = initial;
|
|
271
|
+
let _hasPending = false;
|
|
272
|
+
let _scheduled = false;
|
|
285
273
|
for (const [action, handler] of Object.entries(handlers)) {
|
|
286
274
|
const unregister = bus.register(action, (cmd) => {
|
|
275
|
+
if (coalesce) {
|
|
276
|
+
_pending = handler(_hasPending ? _pending : state.value, cmd);
|
|
277
|
+
_hasPending = true;
|
|
278
|
+
if (!_scheduled) {
|
|
279
|
+
_scheduled = true;
|
|
280
|
+
queueMicrotask(() => {
|
|
281
|
+
state.value = _pending;
|
|
282
|
+
_hasPending = false;
|
|
283
|
+
_scheduled = false;
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return _pending;
|
|
287
|
+
}
|
|
287
288
|
state.value = handler(state.value, cmd);
|
|
288
289
|
return state.value;
|
|
289
290
|
});
|
|
@@ -391,36 +392,14 @@ function useCommandQuery() {
|
|
|
391
392
|
const loading = signal(false);
|
|
392
393
|
const lastError = signal(null);
|
|
393
394
|
function query(action, target, payload) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
lastError.value = error;
|
|
403
|
-
return { ok: false, error };
|
|
404
|
-
}
|
|
405
|
-
if (result && typeof result.then === "function") {
|
|
406
|
-
return result.then(
|
|
407
|
-
(r) => {
|
|
408
|
-
loading.value = false;
|
|
409
|
-
if (r.ok) data.value = r.value;
|
|
410
|
-
else lastError.value = r.error ?? null;
|
|
411
|
-
return r;
|
|
412
|
-
},
|
|
413
|
-
(e) => {
|
|
414
|
-
loading.value = false;
|
|
415
|
-
lastError.value = e;
|
|
416
|
-
return { ok: false, error: e };
|
|
417
|
-
}
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
loading.value = false;
|
|
421
|
-
if (result.ok) data.value = result.value;
|
|
422
|
-
else lastError.value = result.error ?? null;
|
|
423
|
-
return result;
|
|
395
|
+
return runDispatch(
|
|
396
|
+
() => bus.query(action, target, payload),
|
|
397
|
+
loading,
|
|
398
|
+
lastError,
|
|
399
|
+
(value) => {
|
|
400
|
+
data.value = value;
|
|
401
|
+
}
|
|
402
|
+
);
|
|
424
403
|
}
|
|
425
404
|
return { query, data, loading, lastError };
|
|
426
405
|
}
|
|
@@ -496,24 +475,25 @@ function useCommandError(options = {}) {
|
|
|
496
475
|
return { errors, latestError, clearErrors, dispose };
|
|
497
476
|
}
|
|
498
477
|
export {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
478
|
+
getDefineVaporAsyncComponentFn as a,
|
|
479
|
+
getDefineVaporComponentFn as b,
|
|
480
|
+
getDefineVaporCustomElementFn as c,
|
|
481
|
+
getVaporAppFn as d,
|
|
482
|
+
getVaporInteropRef as e,
|
|
483
|
+
runDispatch as f,
|
|
505
484
|
getCommandBus as g,
|
|
506
|
-
|
|
485
|
+
useCommandBus as h,
|
|
507
486
|
isVaporAvailable as i,
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
487
|
+
useCommandError as j,
|
|
488
|
+
useCommandGroup as k,
|
|
489
|
+
useCommandHistory as l,
|
|
490
|
+
useCommandQuery as m,
|
|
491
|
+
useCommandState as n,
|
|
492
|
+
useSharedCommandState as o,
|
|
513
493
|
resetCommandBus as r,
|
|
514
494
|
setCommandBus as s,
|
|
515
495
|
tryAutoCleanup as t,
|
|
516
496
|
useCommand as u,
|
|
517
497
|
waitForVueDetection as w
|
|
518
498
|
};
|
|
519
|
-
//# sourceMappingURL=chamber-
|
|
499
|
+
//# sourceMappingURL=chamber-CesaYQmb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chamber-CesaYQmb.js","sources":["../src/chamber.ts"],"sourcesContent":["/**\n * vapor-chamber - Vue Vapor integration\n *\n * v1.3.0 — Vue 3.6.0-beta.12 alignment: error recovery (component context,\n * fallthrough props, render effects restored after setup errors);\n * VDOM slots interop normalization; no code changes needed here.\n * v1.1.0 — Vue 3.6.0-beta.10 alignment: defineVaporCustomElement, defineVaporComponent,\n * defineVaporAsyncComponent detection; improved hydration interop.\n * v0.4.1 — Added: useCommandGroup (namespace isolation), useCommandError (error boundary).\n * v0.4.0 — Vue 3.6 Vapor alignment: onScopeDispose, Vapor detection,\n * defineVaporCommand, createVaporChamberApp.\n * v0.3.0 — Fixed: signal shim, resetCommandBus, auto-cleanup on Vue unmount.\n */\n\nimport { createCommandBus, type CommandBus, type Command, type CommandResult, type Handler, type Plugin, type RegisterOptions, type Listener } from './command-bus';\nimport { configureSignal, signal } from './signal';\nimport type { Signal } from './signal';\n\n// ---------------------------------------------------------------------------\n// Signal abstraction\n// ---------------------------------------------------------------------------\n// The minimal signal API lives in `./signal` (no module-load side effects, so\n// transports / plugins / form can import it without dragging Vue feature\n// detection into ESM consumer bundles). This module adds the heavier behavior:\n// async dynamic import of Vue, lifecycle hook detection, Vapor APIs.\n//\n// When the async probe resolves, applyVueModule() pushes Vue's ref() into the\n// signal module via configureSignal() so SPA consumers eventually use the\n// alien-signals-backed ref for real reactivity.\n\n// Re-export the signal API so existing import paths (`from 'vapor-chamber'`)\n// keep working without source change.\nexport type { Signal, CreateSignal } from './signal';\nexport { configureSignal };\nexport { signal };\n\nlet _vueOnScopeDispose: ((fn: () => void) => void) | null = null;\nlet _vueGetCurrentScope: (() => any) | null = null;\nlet _vueGetCurrentInstance: (() => any) | null = null;\nlet _vueOnActivated: ((fn: () => void) => void) | null = null;\nlet _vueOnDeactivated: ((fn: () => void) => void) | null = null;\nlet _vueProbed = false;\n\n// Vue 3.6+ Vapor detection\nlet _hasVapor = false;\nlet _createVaporAppFn: any = null;\nlet _vaporInteropPluginRef: any = null;\n// Vue 3.6.0-beta.10+ Vapor APIs\nlet _defineVaporCustomElementFn: any = null;\nlet _defineVaporComponentFn: any = null;\nlet _defineVaporAsyncComponentFn: any = null;\n\n/** Promise that resolves once Vue detection is complete. Await this in composables\n * that need Vue APIs to be available before first use. */\nlet _probePromise: Promise<void> | null = null;\n\nfunction applyVueModule(vue: any): void {\n if (vue && typeof vue.ref === 'function') {\n // Push Vue's ref() into the signal module so signal() returns real\n // alien-signals-backed reactives going forward.\n configureSignal(vue.ref);\n }\n\n if (vue && typeof vue.onScopeDispose === 'function') {\n _vueOnScopeDispose = vue.onScopeDispose;\n }\n // getCurrentScope() (Vue 3.2+) — returns the active effect scope or undefined.\n // Used as the guard before calling onScopeDispose, replacing the try/catch pattern.\n if (vue && typeof vue.getCurrentScope === 'function') {\n _vueGetCurrentScope = vue.getCurrentScope;\n }\n if (vue && typeof vue.getCurrentInstance === 'function') {\n _vueGetCurrentInstance = vue.getCurrentInstance;\n }\n\n // KeepAlive lifecycle hooks (Vue 3.x)\n if (vue && typeof vue.onActivated === 'function') {\n _vueOnActivated = vue.onActivated;\n }\n if (vue && typeof vue.onDeactivated === 'function') {\n _vueOnDeactivated = vue.onDeactivated;\n }\n\n // Vue 3.6+ Vapor detection\n if (vue && typeof vue.createVaporApp === 'function') {\n _hasVapor = true;\n _createVaporAppFn = vue.createVaporApp;\n }\n if (vue && typeof vue.vaporInteropPlugin !== 'undefined') {\n _vaporInteropPluginRef = vue.vaporInteropPlugin;\n }\n\n // Vue 3.6.0-beta.10+: Vapor custom elements and component definitions\n if (vue && typeof vue.defineVaporCustomElement === 'function') {\n _defineVaporCustomElementFn = vue.defineVaporCustomElement;\n }\n if (vue && typeof vue.defineVaporComponent === 'function') {\n _defineVaporComponentFn = vue.defineVaporComponent;\n }\n if (vue && typeof vue.defineVaporAsyncComponent === 'function') {\n _defineVaporAsyncComponentFn = vue.defineVaporAsyncComponent;\n }\n}\n\nfunction probeVue(): void {\n if (_vueProbed) return;\n _vueProbed = true;\n\n // 1. Synchronous probe: check globalThis.__VUE__ (set by Vue devtools or bundler)\n // This gives immediate availability for signal() calls at module init time.\n if (typeof globalThis !== 'undefined' && (globalThis as any).__VUE__) {\n try {\n // If Vue is already loaded as a global (common in MPA / server-rendered\n // page setups where Vue ships via a `<script>` tag), use it synchronously.\n const vue = (globalThis as any).__VUE__;\n if (typeof vue.ref === 'function') {\n applyVueModule(vue);\n }\n } catch { /* not available synchronously */ }\n }\n\n // 2. Async probe: dynamic import for ESM / Vite / bundler environments.\n // Resolved by the time user code's first await/tick completes.\n // Variable indirection prevents TS from statically resolving the optional peer dep.\n const vuePkg = 'vue';\n _probePromise = import(/* @vite-ignore */ vuePkg)\n .then((vue: any) => {\n applyVueModule(vue);\n })\n .catch(() => {\n // Vue not available — use plain signals, no auto-cleanup\n });\n}\n\n// Kick off Vue detection at module load time so it's resolved\n// by the time user code calls signal() (typically after a tick).\nprobeVue();\n\n/**\n * Wait for Vue detection to complete. Call this in app setup if you need\n * to guarantee Vue APIs are available before the first signal() call.\n *\n * @example\n * import { waitForVueDetection, signal } from 'vapor-chamber';\n * await waitForVueDetection();\n * const count = signal(0); // guaranteed to use Vue ref() if available\n */\nexport async function waitForVueDetection(): Promise<void> {\n probeVue();\n if (_probePromise) await _probePromise;\n}\n\n// Kick off the async probe on first signal() call from this module's\n// consumers, so SPA tree code paths get full Vue auto-detection. Composables\n// below use signal() and call probeVue() explicitly via tryAutoCleanup.\n\n// ---------------------------------------------------------------------------\n// Vue 3.6+ Vapor detection\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if Vue 3.6+ with Vapor mode support is detected.\n */\nexport function isVaporAvailable(): boolean {\n return _hasVapor;\n}\n\n/** @internal — for chamber-vapor.ts use only */\nexport function getVaporAppFn(): any { return _createVaporAppFn; }\n/** @internal — for chamber-vapor.ts use only */\nexport function getVaporInteropRef(): any { return _vaporInteropPluginRef; }\n/** @internal — for chamber-vapor.ts use only */\nexport function getDefineVaporCustomElementFn(): any { return _defineVaporCustomElementFn; }\n/** @internal — for chamber-vapor.ts use only */\nexport function getDefineVaporComponentFn(): any { return _defineVaporComponentFn; }\n/** @internal — for chamber-vapor.ts use only */\nexport function getDefineVaporAsyncComponentFn(): any { return _defineVaporAsyncComponentFn; }\n\n// ---------------------------------------------------------------------------\n// Shared command bus instance\n// ---------------------------------------------------------------------------\n\nlet sharedBus: CommandBus | null = null;\n\nexport function getCommandBus(): CommandBus {\n if (!sharedBus) {\n sharedBus = createCommandBus();\n }\n return sharedBus;\n}\n\nexport function setCommandBus(bus: CommandBus): void {\n sharedBus = bus;\n}\n\n/**\n * Reset the shared bus to null. Useful in test teardown to prevent\n * handler/hook leaks between test files.\n */\nexport function resetCommandBus(): void {\n sharedBus = null;\n}\n\n// ---------------------------------------------------------------------------\n// Vue lifecycle detection (optional — works without Vue too)\n// ---------------------------------------------------------------------------\n\n/**\n * Try to register a cleanup function on the nearest Vue scope/component.\n *\n * Uses `getCurrentScope()` (Vue 3.2+) to check whether a reactive scope is\n * active before calling `onScopeDispose`. This replaces the earlier try/catch\n * pattern — no exception-as-control-flow, no `onUnmounted` fallback needed.\n *\n * In Vue 3.5+ (the minimum peer dep), every component `setup()` — including\n * Vapor components — is wrapped in an effect scope, so `getCurrentScope()`\n * inside setup always returns something. The `onUnmounted` fallback is\n * unreachable under Vue 3.5+ and has been removed.\n *\n * No-ops entirely when called outside any Vue scope (e.g. module init time,\n * plain async callbacks). Caller is responsible for calling `dispose()` in\n * those cases.\n */\nexport function tryAutoCleanup(disposeFn: () => void): void {\n probeVue();\n\n if (_vueOnScopeDispose && _vueGetCurrentScope?.()) {\n _vueOnScopeDispose(disposeFn);\n return;\n }\n\n if (_vueOnScopeDispose && typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(\n '[vapor-chamber] tryAutoCleanup: no active Vue scope found. ' +\n 'Call dispose() manually or use this composable inside setup() / effectScope().'\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// KeepAlive pause/resume support\n// ---------------------------------------------------------------------------\n\n/**\n * Register KeepAlive lifecycle hooks to pause/resume bus subscriptions.\n *\n * When a component is deactivated by KeepAlive, `onPause` is called.\n * When reactivated, `onResume` is called. No-ops if not inside a\n * KeepAlive-wrapped component or if Vue is not available.\n *\n * `getCurrentInstance()` is the correct guard: `onActivated`/`onDeactivated`\n * throw when called outside a component setup context, so the upfront check\n * replaces the earlier two try/catch blocks.\n *\n * @internal — used by composables that manage bus subscriptions.\n */\nexport function tryKeepAliveHooks(onPause: () => void, onResume: () => void): void {\n probeVue();\n if (!_vueGetCurrentInstance?.()) return;\n _vueOnDeactivated?.(onPause);\n _vueOnActivated?.(onResume);\n}\n\n// ---------------------------------------------------------------------------\n// runDispatch — shared loading/error wrapper used by useCommand, useCommandQuery,\n// and useVaporCommand (chamber-vapor.ts). Accepts a thunk so the bus call is\n// made inside the try block.\n// ---------------------------------------------------------------------------\n\n/** @internal */\nexport function runDispatch(\n busCall: () => any,\n loading: Signal<boolean>,\n lastError: Signal<Error | null>,\n onSuccess?: (value: any) => void,\n): CommandResult | Promise<CommandResult> {\n loading.value = true;\n lastError.value = null;\n let result: any;\n try {\n result = busCall();\n } catch (e) {\n loading.value = false;\n const error = e as Error;\n lastError.value = error;\n return { ok: false, error };\n }\n if (result && typeof result.then === 'function') {\n return (result as Promise<CommandResult>).then(\n (r) => {\n loading.value = false;\n if (r.ok) onSuccess?.(r.value);\n else lastError.value = r.error ?? null;\n return r;\n },\n (e: Error) => { loading.value = false; lastError.value = e; return { ok: false, error: e }; },\n );\n }\n loading.value = false;\n if (result.ok) onSuccess?.(result.value);\n else lastError.value = result.error ?? null;\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// useCommand\n// ---------------------------------------------------------------------------\n\n/**\n * useCommand - dispatch commands with reactive loading/error state\n *\n * Auto-cleanup on Vue component unmount or scope disposal.\n */\nexport function useCommand() {\n const bus = getCommandBus();\n const loading = signal(false);\n const lastError = signal<Error | null>(null);\n\n function dispatch(action: string, target: any, payload?: any): CommandResult | Promise<CommandResult> {\n return runDispatch(() => bus.dispatch(action, target, payload), loading, lastError);\n }\n\n return { dispatch, loading, lastError };\n}\n\n// ---------------------------------------------------------------------------\n// useSharedCommandState\n// ---------------------------------------------------------------------------\n\n/**\n * Shared state attached to one bus. The ref-count tracks how many\n * `useSharedCommandState()` callers are still subscribed; when it hits zero\n * we drop the entry so the WeakMap can collect it (the bus itself is also\n * weakly held).\n */\ntype SharedCommandStateEntry = {\n inFlight: Signal<number>;\n isAnyLoading: Signal<boolean>;\n lastError: Signal<Error | null>;\n errors: Signal<Error[]>;\n errorCount: Signal<number>;\n refCount: number;\n errorCap: number;\n};\n\nconst _sharedStates = new WeakMap<CommandBus, SharedCommandStateEntry>();\n\nexport type UseSharedCommandStateOptions = {\n /**\n * How many recent errors to retain in `errors`. The list is kept\n * newest-last; older entries drop off. Default: 10.\n */\n errorCap?: number;\n /**\n * Bus to attach to. Defaults to the shared instance from `getCommandBus()`,\n * which matches the single-bus pattern most apps use. Pass an explicit bus\n * to scope shared state to a feature group / island.\n */\n bus?: CommandBus;\n};\n\n/**\n * useSharedCommandState — one set of reactive signals shared across every\n * caller, instead of two signals (`loading`, `lastError`) per call.\n *\n * Designed for component-heavy pages where many components need to react to\n * \"is *anything* in flight?\" or \"what was the last error?\". Replaces\n * `N × useCommand()` allocations with a single shared state per bus.\n *\n * Memory math: 50 components × 2 signals each = 100 signal nodes today.\n * With shared state: ~5 signal nodes total + a counter, regardless of\n * subscriber count.\n *\n * @example\n * // Components using this share isAnyLoading, errors, etc.\n * const { dispatch, isAnyLoading, lastError } = useSharedCommandState();\n * await dispatch('cartAdd', product);\n *\n * @example\n * // Disable an entire toolbar while any command is in flight.\n * const { isAnyLoading } = useSharedCommandState();\n * <Button :disabled=\"isAnyLoading.value\">Save</Button>\n *\n * Auto-cleanup on Vue scope/component disposal via tryAutoCleanup.\n */\nexport function useSharedCommandState(options: UseSharedCommandStateOptions = {}) {\n const bus = options.bus ?? getCommandBus();\n const errorCap = options.errorCap ?? 10;\n\n let state = _sharedStates.get(bus);\n if (!state) {\n state = {\n inFlight: signal(0),\n isAnyLoading: signal(false),\n lastError: signal<Error | null>(null),\n errors: signal<Error[]>([]),\n errorCount: signal(0),\n refCount: 0,\n errorCap,\n };\n _sharedStates.set(bus, state);\n } else if (errorCap < state.errorCap) {\n // Tighten the cap if the new caller wants a smaller buffer; never grow\n // it above another caller's request (avoid surprise memory growth).\n state.errorCap = errorCap;\n }\n state.refCount++;\n\n function recordError(err: Error): void {\n state!.lastError.value = err;\n const next = state!.errors.value.slice();\n next.push(err);\n while (next.length > state!.errorCap) next.shift();\n state!.errors.value = next;\n state!.errorCount.value = next.length;\n }\n\n function decrement(): void {\n const n = Math.max(0, state!.inFlight.value - 1);\n state!.inFlight.value = n;\n state!.isAnyLoading.value = n > 0;\n }\n\n function increment(): void {\n state!.inFlight.value++;\n state!.isAnyLoading.value = true;\n }\n\n function dispatch(\n action: string,\n target: any,\n payload?: any,\n opts?: { signal?: AbortSignal },\n ): CommandResult | Promise<CommandResult> {\n increment();\n let result: any;\n try {\n result = bus.dispatch(action, target, payload, opts);\n } catch (e) {\n const error = e as Error;\n recordError(error);\n decrement();\n return { ok: false, error, value: undefined };\n }\n\n if (result && typeof result.then === 'function') {\n return (result as Promise<CommandResult>).then(\n (r) => { if (!r.ok && r.error) recordError(r.error); decrement(); return r; },\n (e: Error) => { recordError(e); decrement(); return { ok: false, error: e, value: undefined }; },\n );\n }\n\n if (!result.ok && result.error) recordError(result.error);\n decrement();\n return result;\n }\n\n /** Wipe accumulated errors. Does not affect in-flight counter. */\n function clear(): void {\n state!.errors.value = [];\n state!.errorCount.value = 0;\n state!.lastError.value = null;\n }\n\n function dispose(): void {\n state!.refCount--;\n if (state!.refCount <= 0) {\n _sharedStates.delete(bus);\n }\n }\n\n tryAutoCleanup(dispose);\n\n return {\n dispatch,\n /** Number of dispatches currently in flight across all subscribers. */\n inFlight: state.inFlight,\n /** True when `inFlight > 0`. Bind to button `disabled` etc. */\n isAnyLoading: state.isAnyLoading,\n /** Most recent error (across all subscribers). */\n lastError: state.lastError,\n /** Ring buffer of recent errors, newest last, capped at `errorCap`. */\n errors: state.errors,\n /** Current size of the `errors` buffer. */\n errorCount: state.errorCount,\n /** Wipe accumulated errors. */\n clear,\n /** Manually unhook. Most callers don't need this — `tryAutoCleanup`\n * hooks Vue's scope/unmount lifecycle. */\n dispose,\n };\n}\n\n// ---------------------------------------------------------------------------\n// useCommandState\n// ---------------------------------------------------------------------------\n\nexport type UseCommandStateOptions = {\n /**\n * When true, multiple synchronous dispatches within the same microtask are\n * accumulated and the signal is written once via `queueMicrotask`. Pairs with\n * Vue 3.6.0-beta.12's v-for source coalescing: our side defers the signal\n * write, Vue's runtime coalesces the resulting DOM update into one pass.\n *\n * Trade-off: 1 microtask of signal latency. Use for arrays consumed by v-for\n * that receive rapid bulk updates (batch dispatch, form field arrays, scroll\n * position lists). Default: false (immediate write per dispatch).\n */\n coalesce?: boolean;\n};\n\n/**\n * useCommandState - create reactive state that updates via commands.\n *\n * Auto-cleanup on Vue component unmount or scope disposal.\n *\n * @example\n * // Immediate mode (default):\n * const { state } = useCommandState([], { cartAdd: (s, cmd) => [...s, cmd.target] });\n *\n * @example\n * // Coalesced mode — batch writes for v-for lists:\n * const { state } = useCommandState([], { cartAdd: (s, cmd) => [...s, cmd.target] }, { coalesce: true });\n */\nexport function useCommandState<T>(\n initial: T,\n handlers: {\n [action: string]: (state: T, cmd: Command) => T;\n },\n options: UseCommandStateOptions = {}\n) {\n const { coalesce = false } = options;\n const bus = getCommandBus();\n const state = signal(initial);\n const unregisters: Array<() => void> = [];\n\n // coalesce bookkeeping — only allocated when coalesce: true\n let _pending: T = initial;\n let _hasPending = false;\n let _scheduled = false;\n\n for (const [action, handler] of Object.entries(handlers)) {\n const unregister = bus.register(action, (cmd) => {\n if (coalesce) {\n _pending = handler(_hasPending ? _pending : state.value, cmd);\n _hasPending = true;\n if (!_scheduled) {\n _scheduled = true;\n queueMicrotask(() => {\n state.value = _pending;\n _hasPending = false;\n _scheduled = false;\n });\n }\n return _pending;\n }\n state.value = handler(state.value, cmd);\n return state.value;\n });\n unregisters.push(unregister);\n }\n\n const dispose = () => {\n unregisters.forEach(fn => fn());\n unregisters.length = 0;\n };\n\n tryAutoCleanup(dispose);\n\n return { state, dispose };\n}\n\n// ---------------------------------------------------------------------------\n// useCommandBus\n// ---------------------------------------------------------------------------\n\n/**\n * useCommandBus - lightweight composable wrapper around the shared bus.\n */\nexport function useCommandBus() {\n return getCommandBus();\n}\n\n// ---------------------------------------------------------------------------\n// useCommandHistory\n// ---------------------------------------------------------------------------\n\n/**\n * useCommandHistory - undo/redo with reactive state\n *\n * Auto-cleanup on Vue component unmount or scope disposal.\n * Undo executes inverse handlers when registered via register(action, handler, { undo }).\n */\nexport function useCommandHistory(options: {\n maxSize?: number;\n filter?: (cmd: Command) => boolean;\n} = {}) {\n const { maxSize = 50, filter } = options;\n const bus = getCommandBus();\n\n const past = signal<Command[]>([]);\n const future = signal<Command[]>([]);\n const canUndo = signal(false);\n const canRedo = signal(false);\n\n let paused = false;\n\n const unsubscribe = bus.onAfter((cmd, result) => {\n if (paused) return;\n if (result.ok && (!filter || filter(cmd))) {\n const newPast = [...past.value, cmd];\n if (newPast.length > maxSize) newPast.shift();\n past.value = newPast;\n future.value = [];\n canUndo.value = true;\n canRedo.value = false;\n }\n });\n\n // KeepAlive: pause tracking when deactivated, resume when activated\n tryKeepAliveHooks(\n () => { paused = true; },\n () => { paused = false; },\n );\n\n function undo(): Command | undefined {\n const p = [...past.value];\n const cmd = p.pop();\n if (cmd) {\n past.value = p;\n future.value = [...future.value, cmd];\n canUndo.value = p.length > 0;\n canRedo.value = true;\n\n // Execute inverse handler if available\n const undoHandler = bus.getUndoHandler(cmd.action);\n if (undoHandler) {\n try {\n undoHandler(cmd);\n } catch (e) {\n console.error(`[vapor-chamber] Undo handler error for \"${cmd.action}\":`, e);\n }\n }\n }\n return cmd;\n }\n\n function redo(): Command | undefined {\n const f = [...future.value];\n const cmd = f.pop();\n if (cmd) {\n future.value = f;\n // Pause tracking so the re-dispatch doesn't double-record\n paused = true;\n try {\n bus.dispatch(cmd.action, cmd.target, cmd.payload);\n } catch (e) {\n console.error(`[vapor-chamber] Redo dispatch error for \"${cmd.action}\":`, e);\n } finally {\n paused = false;\n }\n past.value = [...past.value, cmd];\n canUndo.value = true;\n canRedo.value = f.length > 0;\n }\n return cmd;\n }\n\n function clear() {\n past.value = [];\n future.value = [];\n canUndo.value = false;\n canRedo.value = false;\n }\n\n function dispose() {\n unsubscribe();\n }\n\n tryAutoCleanup(dispose);\n\n return {\n past,\n future,\n canUndo,\n canRedo,\n undo,\n redo,\n clear,\n dispose,\n };\n}\n\n// ---------------------------------------------------------------------------\n// useCommandQuery\n// ---------------------------------------------------------------------------\n\n/**\n * useCommandQuery — CQRS read-side composable with reactive state.\n *\n * Wraps bus.query() with reactive `data`, `loading`, and `lastError` signals.\n * query() skips onBefore hooks (no auth gates, no loading spinners for reads)\n * but runs plugins, handlers, and afterHooks.\n *\n * Supports both sync and async buses — if the result is a Promise, loading\n * stays true until it resolves.\n *\n * @example\n * const { query, data, loading, lastError } = useCommandQuery();\n * const result = query('getUser', { id: 42 });\n * // data.value = result.value after query completes\n */\nexport function useCommandQuery() {\n const bus = getCommandBus();\n const data = signal<any>(null);\n const loading = signal(false);\n const lastError = signal<Error | null>(null);\n\n function query(action: string, target: any, payload?: any): CommandResult | Promise<CommandResult> {\n return runDispatch(\n () => bus.query(action, target, payload),\n loading,\n lastError,\n (value) => { data.value = value; },\n );\n }\n\n return { query, data, loading, lastError };\n}\n\n// ---------------------------------------------------------------------------\n// useCommandGroup\n// ---------------------------------------------------------------------------\n\n/**\n * useCommandGroup — namespace isolation for large apps and multi-team projects.\n *\n * All dispatch/register/on calls are automatically prefixed with the namespace\n * in camelCase. This prevents action name collisions when composing multiple\n * feature modules.\n *\n * @example\n * // Cart feature\n * const cart = useCommandGroup('cart')\n * cart.register('add', handler) // registers 'cartAdd'\n * cart.dispatch('add', product) // dispatches 'cartAdd'\n * cart.on('*', listener) // listens to 'cart*'\n *\n * // Orders feature — completely isolated\n * const orders = useCommandGroup('orders')\n * orders.dispatch('cancel', { id }) // dispatches 'ordersCancel'\n */\nexport function useCommandGroup(namespace: string) {\n const bus = getCommandBus();\n const cleanups: Array<() => void> = [];\n\n function prefixed(action: string): string {\n return namespace + action.charAt(0).toUpperCase() + action.slice(1);\n }\n\n function dispatch(action: string, target: any, payload?: any): CommandResult {\n return bus.dispatch(prefixed(action), target, payload);\n }\n\n /** Read-only dispatch — skips onBefore hooks, runs handler + plugins, fires afterHooks. */\n function query(action: string, target: any, payload?: any): CommandResult {\n return bus.query(prefixed(action), target, payload);\n }\n\n /** Fire a namespaced domain event — notifies on() listeners, no handler required. */\n function emit(event: string, data?: any): void {\n bus.emit(prefixed(event), data);\n }\n\n function register(action: string, handler: Handler, opts?: RegisterOptions): () => void {\n const unregister = bus.register(prefixed(action), handler, opts);\n cleanups.push(unregister);\n return unregister;\n }\n\n function use(plugin: Plugin): () => void {\n const remove = bus.use(plugin);\n cleanups.push(remove);\n return remove;\n }\n\n function on(pattern: string, listener: Listener): () => void {\n // Translate wildcard to namespaced: '*' → 'cart*', 'add' → 'cartAdd'\n const namespacedPattern = pattern === '*' ? `${namespace}*` : prefixed(pattern);\n const unsub = bus.on(namespacedPattern, listener);\n cleanups.push(unsub);\n return unsub;\n }\n\n function dispose() {\n cleanups.forEach(fn => fn());\n cleanups.length = 0;\n }\n\n tryAutoCleanup(dispose);\n\n return { dispatch, query, emit, register, use, on, namespace, dispose };\n}\n\n// ---------------------------------------------------------------------------\n// useCommandError\n// ---------------------------------------------------------------------------\n\n/**\n * useCommandError — component-scoped error boundary for command failures.\n *\n * Subscribes to the bus and captures all failed command results reactively.\n * Optional filter narrows which actions are tracked.\n *\n * @example\n * const { latestError, errors, clearErrors } = useCommandError()\n *\n * // Only watch cart commands\n * const { latestError } = useCommandError({ filter: cmd => cmd.action.startsWith('cart') })\n */\nexport function useCommandError(options: {\n filter?: (cmd: Command) => boolean;\n} = {}) {\n const { filter } = options;\n const bus = getCommandBus();\n\n type ErrorEntry = { cmd: Command; error: Error; timestamp: number };\n const errors = signal<ErrorEntry[]>([]);\n const latestError = signal<Error | null>(null);\n let paused = false;\n\n const unsubscribe = bus.onAfter((cmd, result) => {\n if (paused) return;\n if (!result.ok && result.error) {\n if (!filter || filter(cmd)) {\n latestError.value = result.error;\n errors.value = [...errors.value, { cmd, error: result.error, timestamp: Date.now() }];\n }\n }\n });\n\n // KeepAlive: pause error capture when deactivated, resume when activated\n tryKeepAliveHooks(\n () => { paused = true; },\n () => { paused = false; },\n );\n\n function clearErrors() {\n errors.value = [];\n latestError.value = null;\n }\n\n function dispose() {\n unsubscribe();\n }\n\n tryAutoCleanup(dispose);\n\n return { errors, latestError, clearErrors, dispose };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { f as createCommandBus } from "./command-bus-nxA-KYSC.js";
|
|
2
|
+
import { s as signal, c as configureSignal } from "./signal-DUZrcb-E.js";
|
|
3
3
|
let _vueOnScopeDispose = null;
|
|
4
|
+
let _vueGetCurrentScope = null;
|
|
4
5
|
let _vueGetCurrentInstance = null;
|
|
5
6
|
let _vueOnActivated = null;
|
|
6
7
|
let _vueOnDeactivated = null;
|
|
@@ -19,8 +20,8 @@ function applyVueModule(vue) {
|
|
|
19
20
|
if (vue && typeof vue.onScopeDispose === "function") {
|
|
20
21
|
_vueOnScopeDispose = vue.onScopeDispose;
|
|
21
22
|
}
|
|
22
|
-
if (vue && typeof vue.
|
|
23
|
-
|
|
23
|
+
if (vue && typeof vue.getCurrentScope === "function") {
|
|
24
|
+
_vueGetCurrentScope = vue.getCurrentScope;
|
|
24
25
|
}
|
|
25
26
|
if (vue && typeof vue.getCurrentInstance === "function") {
|
|
26
27
|
_vueGetCurrentInstance = vue.getCurrentInstance;
|
|
@@ -107,76 +108,60 @@ function resetCommandBus() {
|
|
|
107
108
|
}
|
|
108
109
|
function tryAutoCleanup(disposeFn) {
|
|
109
110
|
probeVue();
|
|
110
|
-
if (_vueOnScopeDispose) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return;
|
|
114
|
-
} catch {
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (_vueOnUnmounted && _vueGetCurrentInstance) {
|
|
118
|
-
try {
|
|
119
|
-
if (_vueGetCurrentInstance()) {
|
|
120
|
-
_vueOnUnmounted(disposeFn);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
} catch {
|
|
124
|
-
}
|
|
111
|
+
if (_vueOnScopeDispose && _vueGetCurrentScope?.()) {
|
|
112
|
+
_vueOnScopeDispose(disposeFn);
|
|
113
|
+
return;
|
|
125
114
|
}
|
|
126
115
|
if (_vueOnScopeDispose && typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
|
|
127
116
|
console.warn(
|
|
128
|
-
"[vapor-chamber] tryAutoCleanup: no Vue scope
|
|
117
|
+
"[vapor-chamber] tryAutoCleanup: no active Vue scope found. Call dispose() manually or use this composable inside setup() / effectScope()."
|
|
129
118
|
);
|
|
130
119
|
}
|
|
131
120
|
}
|
|
132
121
|
function tryKeepAliveHooks(onPause, onResume) {
|
|
133
122
|
probeVue();
|
|
134
|
-
if (
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
123
|
+
if (!_vueGetCurrentInstance?.()) return;
|
|
124
|
+
_vueOnDeactivated?.(onPause);
|
|
125
|
+
_vueOnActivated?.(onResume);
|
|
126
|
+
}
|
|
127
|
+
function runDispatch(busCall, loading, lastError, onSuccess) {
|
|
128
|
+
loading.value = true;
|
|
129
|
+
lastError.value = null;
|
|
130
|
+
let result;
|
|
131
|
+
try {
|
|
132
|
+
result = busCall();
|
|
133
|
+
} catch (e) {
|
|
134
|
+
loading.value = false;
|
|
135
|
+
const error = e;
|
|
136
|
+
lastError.value = error;
|
|
137
|
+
return { ok: false, error };
|
|
138
|
+
}
|
|
139
|
+
if (result && typeof result.then === "function") {
|
|
140
|
+
return result.then(
|
|
141
|
+
(r) => {
|
|
142
|
+
loading.value = false;
|
|
143
|
+
if (r.ok) onSuccess?.(r.value);
|
|
144
|
+
else lastError.value = r.error ?? null;
|
|
145
|
+
return r;
|
|
146
|
+
},
|
|
147
|
+
(e) => {
|
|
148
|
+
loading.value = false;
|
|
149
|
+
lastError.value = e;
|
|
150
|
+
return { ok: false, error: e };
|
|
151
|
+
}
|
|
152
|
+
);
|
|
145
153
|
}
|
|
154
|
+
loading.value = false;
|
|
155
|
+
if (result.ok) onSuccess?.(result.value);
|
|
156
|
+
else lastError.value = result.error ?? null;
|
|
157
|
+
return result;
|
|
146
158
|
}
|
|
147
159
|
function useCommand() {
|
|
148
160
|
const bus = getCommandBus();
|
|
149
161
|
const loading = signal(false);
|
|
150
162
|
const lastError = signal(null);
|
|
151
163
|
function dispatch(action, target, payload) {
|
|
152
|
-
|
|
153
|
-
lastError.value = null;
|
|
154
|
-
let result;
|
|
155
|
-
try {
|
|
156
|
-
result = bus.dispatch(action, target, payload);
|
|
157
|
-
} catch (e) {
|
|
158
|
-
loading.value = false;
|
|
159
|
-
const error = e;
|
|
160
|
-
lastError.value = error;
|
|
161
|
-
return { ok: false, error };
|
|
162
|
-
}
|
|
163
|
-
if (result && typeof result.then === "function") {
|
|
164
|
-
return result.then(
|
|
165
|
-
(r) => {
|
|
166
|
-
loading.value = false;
|
|
167
|
-
if (!r.ok) lastError.value = r.error ?? null;
|
|
168
|
-
return r;
|
|
169
|
-
},
|
|
170
|
-
(e) => {
|
|
171
|
-
loading.value = false;
|
|
172
|
-
lastError.value = e;
|
|
173
|
-
return { ok: false, error: e };
|
|
174
|
-
}
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
loading.value = false;
|
|
178
|
-
if (!result.ok) lastError.value = result.error ?? null;
|
|
179
|
-
return result;
|
|
164
|
+
return runDispatch(() => bus.dispatch(action, target, payload), loading, lastError);
|
|
180
165
|
}
|
|
181
166
|
return { dispatch, loading, lastError };
|
|
182
167
|
}
|
|
@@ -277,12 +262,29 @@ function useSharedCommandState(options = {}) {
|
|
|
277
262
|
dispose
|
|
278
263
|
};
|
|
279
264
|
}
|
|
280
|
-
function useCommandState(initial, handlers) {
|
|
265
|
+
function useCommandState(initial, handlers, options = {}) {
|
|
266
|
+
const { coalesce = false } = options;
|
|
281
267
|
const bus = getCommandBus();
|
|
282
268
|
const state = signal(initial);
|
|
283
269
|
const unregisters = [];
|
|
270
|
+
let _pending = initial;
|
|
271
|
+
let _hasPending = false;
|
|
272
|
+
let _scheduled = false;
|
|
284
273
|
for (const [action, handler] of Object.entries(handlers)) {
|
|
285
274
|
const unregister = bus.register(action, (cmd) => {
|
|
275
|
+
if (coalesce) {
|
|
276
|
+
_pending = handler(_hasPending ? _pending : state.value, cmd);
|
|
277
|
+
_hasPending = true;
|
|
278
|
+
if (!_scheduled) {
|
|
279
|
+
_scheduled = true;
|
|
280
|
+
queueMicrotask(() => {
|
|
281
|
+
state.value = _pending;
|
|
282
|
+
_hasPending = false;
|
|
283
|
+
_scheduled = false;
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return _pending;
|
|
287
|
+
}
|
|
286
288
|
state.value = handler(state.value, cmd);
|
|
287
289
|
return state.value;
|
|
288
290
|
});
|
|
@@ -390,36 +392,14 @@ function useCommandQuery() {
|
|
|
390
392
|
const loading = signal(false);
|
|
391
393
|
const lastError = signal(null);
|
|
392
394
|
function query(action, target, payload) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
lastError.value = error;
|
|
402
|
-
return { ok: false, error };
|
|
403
|
-
}
|
|
404
|
-
if (result && typeof result.then === "function") {
|
|
405
|
-
return result.then(
|
|
406
|
-
(r) => {
|
|
407
|
-
loading.value = false;
|
|
408
|
-
if (r.ok) data.value = r.value;
|
|
409
|
-
else lastError.value = r.error ?? null;
|
|
410
|
-
return r;
|
|
411
|
-
},
|
|
412
|
-
(e) => {
|
|
413
|
-
loading.value = false;
|
|
414
|
-
lastError.value = e;
|
|
415
|
-
return { ok: false, error: e };
|
|
416
|
-
}
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
loading.value = false;
|
|
420
|
-
if (result.ok) data.value = result.value;
|
|
421
|
-
else lastError.value = result.error ?? null;
|
|
422
|
-
return result;
|
|
395
|
+
return runDispatch(
|
|
396
|
+
() => bus.query(action, target, payload),
|
|
397
|
+
loading,
|
|
398
|
+
lastError,
|
|
399
|
+
(value) => {
|
|
400
|
+
data.value = value;
|
|
401
|
+
}
|
|
402
|
+
);
|
|
423
403
|
}
|
|
424
404
|
return { query, data, loading, lastError };
|
|
425
405
|
}
|
|
@@ -495,24 +475,25 @@ function useCommandError(options = {}) {
|
|
|
495
475
|
return { errors, latestError, clearErrors, dispose };
|
|
496
476
|
}
|
|
497
477
|
export {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
478
|
+
getDefineVaporAsyncComponentFn as a,
|
|
479
|
+
getDefineVaporComponentFn as b,
|
|
480
|
+
getDefineVaporCustomElementFn as c,
|
|
481
|
+
getVaporAppFn as d,
|
|
482
|
+
getVaporInteropRef as e,
|
|
483
|
+
runDispatch as f,
|
|
504
484
|
getCommandBus as g,
|
|
505
|
-
|
|
485
|
+
useCommandBus as h,
|
|
506
486
|
isVaporAvailable as i,
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
487
|
+
useCommandError as j,
|
|
488
|
+
useCommandGroup as k,
|
|
489
|
+
useCommandHistory as l,
|
|
490
|
+
useCommandQuery as m,
|
|
491
|
+
useCommandState as n,
|
|
492
|
+
useSharedCommandState as o,
|
|
512
493
|
resetCommandBus as r,
|
|
513
494
|
setCommandBus as s,
|
|
514
495
|
tryAutoCleanup as t,
|
|
515
496
|
useCommand as u,
|
|
516
497
|
waitForVueDetection as w
|
|
517
498
|
};
|
|
518
|
-
//# sourceMappingURL=chamber-
|
|
499
|
+
//# sourceMappingURL=chamber-ayzW3B-v.js.map
|