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.
Files changed (128) hide show
  1. package/README.md +3 -3
  2. package/ROADMAP.md +4 -4
  3. package/dist/{chamber-Cm7_vz_U.js → chamber-CesaYQmb.js} +83 -103
  4. package/dist/chamber-CesaYQmb.js.map +1 -0
  5. package/dist/{chamber-B_ff1-af.js → chamber-ayzW3B-v.js} +84 -103
  6. package/dist/chamber-ayzW3B-v.js.map +1 -0
  7. package/dist/{chamber-vapor-CrDvj19S.js → chamber-vapor-CqMH_L-d.js} +7 -42
  8. package/dist/chamber-vapor-CqMH_L-d.js.map +1 -0
  9. package/dist/{chamber-vapor-Bc-A5SID.js → chamber-vapor-Djf77X57.js} +8 -42
  10. package/dist/chamber-vapor-Djf77X57.js.map +1 -0
  11. package/dist/chamber-vapor.d.ts +22 -0
  12. package/dist/chamber-vapor.d.ts.map +1 -1
  13. package/dist/chamber.d.ts +43 -7
  14. package/dist/chamber.d.ts.map +1 -1
  15. package/dist/{signal-pT4BgmiH.js → command-bus-DNHnswE_.js} +113 -237
  16. package/dist/command-bus-DNHnswE_.js.map +1 -0
  17. package/dist/{command-bus-DA3nlrS6.js → command-bus-nxA-KYSC.js} +44 -107
  18. package/dist/command-bus-nxA-KYSC.js.map +1 -0
  19. package/dist/command-bus.d.ts +11 -0
  20. package/dist/command-bus.d.ts.map +1 -1
  21. package/dist/directives.js +1 -1
  22. package/dist/iife.js +4 -4
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +116 -124
  26. package/dist/index.js.map +1 -1
  27. package/dist/plugins-extra.d.ts.map +1 -1
  28. package/dist/plugins-io.d.ts +1 -1
  29. package/dist/plugins-io.d.ts.map +1 -1
  30. package/dist/plugins-schema.js +1 -1
  31. package/dist/transitions.js +1 -1
  32. package/dist/{transports-CMcmqEN-.js → transports-BSfLx9oG.js} +6 -22
  33. package/dist/transports-BSfLx9oG.js.map +1 -0
  34. package/dist/{transports-BuSZVG89.js → transports-Bnz6r6x5.js} +19 -25
  35. package/dist/transports-Bnz6r6x5.js.map +1 -0
  36. package/dist/transports.d.ts.map +1 -1
  37. package/dist/transports.js +2 -2
  38. package/dist/vapor-chamber-core.iife.js +93 -198
  39. package/dist/vapor-chamber-core.iife.js.map +1 -1
  40. package/dist/vapor-chamber-core.iife.min.js +1 -1
  41. package/dist/vapor-chamber-elements.iife.js +95 -200
  42. package/dist/vapor-chamber-elements.iife.js.map +1 -1
  43. package/dist/vapor-chamber-elements.iife.min.js +1 -1
  44. package/dist/vapor-chamber.iife.js +142 -267
  45. package/dist/vapor-chamber.iife.js.map +1 -1
  46. package/dist/vapor-chamber.iife.min.js +1 -1
  47. package/package.json +2 -2
  48. package/scripts/check-size.mjs +3 -3
  49. package/dist/chamber-BHo2PZnx.js +0 -1297
  50. package/dist/chamber-BHo2PZnx.js.map +0 -1
  51. package/dist/chamber-BLvYXQR8.js +0 -518
  52. package/dist/chamber-BLvYXQR8.js.map +0 -1
  53. package/dist/chamber-BUgOYOAc.js +0 -1293
  54. package/dist/chamber-BUgOYOAc.js.map +0 -1
  55. package/dist/chamber-B_ff1-af.js.map +0 -1
  56. package/dist/chamber-BmLw2FDU.js +0 -420
  57. package/dist/chamber-BmLw2FDU.js.map +0 -1
  58. package/dist/chamber-BwyEE9vP.js +0 -1320
  59. package/dist/chamber-BwyEE9vP.js.map +0 -1
  60. package/dist/chamber-C0xS5NDI.js +0 -420
  61. package/dist/chamber-C0xS5NDI.js.map +0 -1
  62. package/dist/chamber-C1q3L1oU.js +0 -420
  63. package/dist/chamber-C1q3L1oU.js.map +0 -1
  64. package/dist/chamber-Cm7_vz_U.js.map +0 -1
  65. package/dist/chamber-CoO1CLDg.js +0 -518
  66. package/dist/chamber-CoO1CLDg.js.map +0 -1
  67. package/dist/chamber-Vn0IZVna.js +0 -518
  68. package/dist/chamber-Vn0IZVna.js.map +0 -1
  69. package/dist/chamber-iK4VO3lw.js +0 -420
  70. package/dist/chamber-iK4VO3lw.js.map +0 -1
  71. package/dist/chamber-vapor-8R6iwINH.js +0 -540
  72. package/dist/chamber-vapor-8R6iwINH.js.map +0 -1
  73. package/dist/chamber-vapor-B5KwDQXN.js +0 -539
  74. package/dist/chamber-vapor-B5KwDQXN.js.map +0 -1
  75. package/dist/chamber-vapor-BNIYoRME.js +0 -540
  76. package/dist/chamber-vapor-BNIYoRME.js.map +0 -1
  77. package/dist/chamber-vapor-BYdGCAVC.js +0 -540
  78. package/dist/chamber-vapor-BYdGCAVC.js.map +0 -1
  79. package/dist/chamber-vapor-Bc-A5SID.js.map +0 -1
  80. package/dist/chamber-vapor-CQWCByx-.js +0 -525
  81. package/dist/chamber-vapor-CQWCByx-.js.map +0 -1
  82. package/dist/chamber-vapor-CrDvj19S.js.map +0 -1
  83. package/dist/chamber-vapor-D7WY8gpo.js +0 -540
  84. package/dist/chamber-vapor-D7WY8gpo.js.map +0 -1
  85. package/dist/chamber-vapor-DzhknTIy.js +0 -540
  86. package/dist/chamber-vapor-DzhknTIy.js.map +0 -1
  87. package/dist/chamber-vapor-EH9hhveO.js +0 -540
  88. package/dist/chamber-vapor-EH9hhveO.js.map +0 -1
  89. package/dist/chamber-vapor-IpqC6fgk.js +0 -540
  90. package/dist/chamber-vapor-IpqC6fgk.js.map +0 -1
  91. package/dist/chamber-vapor-i1EIsWOg.js +0 -540
  92. package/dist/chamber-vapor-i1EIsWOg.js.map +0 -1
  93. package/dist/chamber-vapor-isZkw0sf.js +0 -525
  94. package/dist/chamber-vapor-isZkw0sf.js.map +0 -1
  95. package/dist/command-bus-DA3nlrS6.js.map +0 -1
  96. package/dist/signal-BEmakAvP.js +0 -913
  97. package/dist/signal-BEmakAvP.js.map +0 -1
  98. package/dist/signal-C0JQhs2G.js +0 -926
  99. package/dist/signal-C0JQhs2G.js.map +0 -1
  100. package/dist/signal-C7iO4lNJ.js +0 -957
  101. package/dist/signal-C7iO4lNJ.js.map +0 -1
  102. package/dist/signal-CBFIjSiL.js +0 -951
  103. package/dist/signal-CBFIjSiL.js.map +0 -1
  104. package/dist/signal-D1SPpDTh.js +0 -952
  105. package/dist/signal-D1SPpDTh.js.map +0 -1
  106. package/dist/signal-eHOL-GNS.js +0 -926
  107. package/dist/signal-eHOL-GNS.js.map +0 -1
  108. package/dist/signal-pT4BgmiH.js.map +0 -1
  109. package/dist/transports-BHQkkVjt.js +0 -699
  110. package/dist/transports-BHQkkVjt.js.map +0 -1
  111. package/dist/transports-Bd_fqFva.js +0 -732
  112. package/dist/transports-Bd_fqFva.js.map +0 -1
  113. package/dist/transports-BhJ56Fgx.js +0 -699
  114. package/dist/transports-BhJ56Fgx.js.map +0 -1
  115. package/dist/transports-BuSZVG89.js.map +0 -1
  116. package/dist/transports-CMcmqEN-.js.map +0 -1
  117. package/dist/transports-Ckkspzeb.js +0 -700
  118. package/dist/transports-Ckkspzeb.js.map +0 -1
  119. package/dist/transports-CtFiD_mr.js +0 -699
  120. package/dist/transports-CtFiD_mr.js.map +0 -1
  121. package/dist/transports-D4_d3u_d.js +0 -699
  122. package/dist/transports-D4_d3u_d.js.map +0 -1
  123. package/dist/transports-DKop5_zi.js +0 -700
  124. package/dist/transports-DKop5_zi.js.map +0 -1
  125. package/dist/transports-DN6DzZTU.js +0 -732
  126. package/dist/transports-DN6DzZTU.js.map +0 -1
  127. package/dist/transports-DTNi1DT6.js +0 -732
  128. 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 gzipped. Vue 3.6 Vapor aligned. Optional DevTools integration.
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
- - **~2 KB gzipped** — zero runtime dependencies
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 Vapor aligned** — signals, `onScopeDispose`, alien-signals internals
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.11** (released 2026-05-07).
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.11"`. The lib supports
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.11 (generics inference, emits/attrs split,
18
- custom-element fallback in shadowRoot:false trees). The lib's wrappers are
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 { a as createCommandBus } from "./command-bus-DA3nlrS6.js";
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.onUnmounted === "function") {
24
- _vueOnUnmounted = vue.onUnmounted;
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
- try {
113
- _vueOnScopeDispose(disposeFn);
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 or component instance found. Call dispose() manually or use this composable inside setup() / effectScope()."
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 (_vueOnDeactivated) {
136
- try {
137
- _vueOnDeactivated(onPause);
138
- } catch {
139
- }
140
- }
141
- if (_vueOnActivated) {
142
- try {
143
- _vueOnActivated(onResume);
144
- } catch {
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
- loading.value = true;
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
- loading.value = true;
395
- lastError.value = null;
396
- let result;
397
- try {
398
- result = bus.query(action, target, payload);
399
- } catch (e) {
400
- loading.value = false;
401
- const error = e;
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
- useCommandBus as a,
500
- useCommandError as b,
501
- useCommandGroup as c,
502
- useCommandHistory as d,
503
- useCommandQuery as e,
504
- useCommandState as f,
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
- useSharedCommandState as h,
485
+ useCommandBus as h,
507
486
  isVaporAvailable as i,
508
- getVaporInteropRef as j,
509
- getVaporAppFn as k,
510
- getDefineVaporCustomElementFn as l,
511
- getDefineVaporComponentFn as m,
512
- getDefineVaporAsyncComponentFn as n,
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-Cm7_vz_U.js.map
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 { s as signal, a as createCommandBus, e as configureSignal } from "./signal-CBFIjSiL.js";
2
- let _vueOnUnmounted = null;
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.onUnmounted === "function") {
23
- _vueOnUnmounted = vue.onUnmounted;
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
- try {
112
- _vueOnScopeDispose(disposeFn);
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 or component instance found. Call dispose() manually or use this composable inside setup() / effectScope()."
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 (_vueOnDeactivated) {
135
- try {
136
- _vueOnDeactivated(onPause);
137
- } catch {
138
- }
139
- }
140
- if (_vueOnActivated) {
141
- try {
142
- _vueOnActivated(onResume);
143
- } catch {
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
- loading.value = true;
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
- loading.value = true;
394
- lastError.value = null;
395
- let result;
396
- try {
397
- result = bus.query(action, target, payload);
398
- } catch (e) {
399
- loading.value = false;
400
- const error = e;
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
- useCommandBus as a,
499
- useCommandError as b,
500
- useCommandGroup as c,
501
- useCommandHistory as d,
502
- useCommandQuery as e,
503
- useCommandState as f,
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
- useSharedCommandState as h,
485
+ useCommandBus as h,
506
486
  isVaporAvailable as i,
507
- getVaporInteropRef as j,
508
- getVaporAppFn as k,
509
- getDefineVaporCustomElementFn as l,
510
- getDefineVaporComponentFn as m,
511
- getDefineVaporAsyncComponentFn as n,
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-B_ff1-af.js.map
499
+ //# sourceMappingURL=chamber-ayzW3B-v.js.map