vapor-chamber 1.0.0 → 1.1.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.
@@ -1,8 +1,11 @@
1
1
  /**
2
2
  * vapor-chamber — Vue 3.6+ Vapor-specific API
3
3
  *
4
- * createVaporChamberApp, getVaporInteropPlugin, defineVaporCommand,
5
- * useVaporCommand
4
+ * v1.1.0 — Added: defineVaporCustomElement, defineVaporComponent,
5
+ * defineVaporAsyncComponent wrappers (Vue 3.6.0-beta.10+);
6
+ * useVaporAsyncCommand for Suspense-aware async dispatch.
7
+ * v0.6.0 — Added: useVaporCommand composable.
8
+ * v0.4.0 — Added: createVaporChamberApp, getVaporInteropPlugin, defineVaporCommand.
6
9
  *
7
10
  * Separated from chamber.ts to keep the core composable module CDCC-compliant.
8
11
  */
@@ -28,6 +31,57 @@ export declare function createVaporChamberApp(rootComponent: any, rootProps?: an
28
31
  * if (plugin) createApp(App).use(plugin).mount('#app');
29
32
  */
30
33
  export declare function getVaporInteropPlugin(): any | null;
34
+ /**
35
+ * defineVaporCustomElement — create a custom element backed by Vapor rendering.
36
+ *
37
+ * Wraps Vue 3.6.0-beta.10's `defineVaporCustomElement()`. The generated custom
38
+ * element uses Vapor's compiler-optimized rendering instead of the VDOM, giving
39
+ * zero-overhead DOM updates inside shadow DOM.
40
+ *
41
+ * SSR runtime is automatically tree-shaken from the generated code (beta.10 fix).
42
+ *
43
+ * Returns null if Vue 3.6.0-beta.10+ is not detected — check before calling
44
+ * `customElements.define()`.
45
+ *
46
+ * @example
47
+ * import { defineVaporCustomElement } from 'vapor-chamber';
48
+ * const MyEl = defineVaporCustomElement({
49
+ * props: { label: String },
50
+ * setup(props) { return () => h('span', props.label); }
51
+ * });
52
+ * if (MyEl) customElements.define('my-el', MyEl);
53
+ */
54
+ export declare function defineVaporCustomElement(options: any, extraOptions?: any): any | null;
55
+ /**
56
+ * defineVaporComponent — define a Vapor component with proper type inference.
57
+ *
58
+ * Wraps Vue 3.6.0-beta.10's `defineVaporComponent()`. Use this to get full
59
+ * TypeScript inference for props, emits, and slots in Vapor components.
60
+ *
61
+ * Returns null if Vue 3.6.0-beta.10+ is not detected.
62
+ *
63
+ * @example
64
+ * import { defineVaporComponent } from 'vapor-chamber';
65
+ * const Comp = defineVaporComponent({
66
+ * props: { count: Number },
67
+ * setup(props) { return () => h('div', `Count: ${props.count}`); }
68
+ * });
69
+ */
70
+ export declare function defineVaporComponent(options: any): any | null;
71
+ /**
72
+ * defineVaporAsyncComponent — define an async Vapor component for lazy loading.
73
+ *
74
+ * Wraps Vue 3.6.0-beta.10's `defineVaporAsyncComponent()`. Async Vapor
75
+ * components are properly cached by VaporKeepAlive and hydrate under VDOM
76
+ * Suspense boundaries (beta.10 fix).
77
+ *
78
+ * Returns null if Vue 3.6.0-beta.10+ is not detected.
79
+ *
80
+ * @example
81
+ * import { defineVaporAsyncComponent } from 'vapor-chamber';
82
+ * const AsyncPanel = defineVaporAsyncComponent(() => import('./Panel.vue'));
83
+ */
84
+ export declare function defineVaporAsyncComponent(loader: any): any | null;
31
85
  /**
32
86
  * defineVaporCommand — zero-overhead command for hot paths in Vapor mode.
33
87
  *
@@ -62,9 +116,37 @@ export declare function defineVaporCommand(action: string, handler: Handler, opt
62
116
  * dispatch('cartAdd', { id: product.id });
63
117
  */
64
118
  export declare function useVaporCommand(): {
65
- dispatch: (action: string, target: any, payload?: any) => CommandResult;
119
+ dispatch: (action: string, target: any, payload?: any) => CommandResult | Promise<CommandResult>;
66
120
  register: (action: string, handler: Handler, opts?: RegisterOptions) => () => void;
67
121
  on: (pattern: string, listener: (cmd: Command, result: CommandResult) => void) => () => void;
122
+ emit: (event: string, data?: any) => void;
123
+ loading: import("./chamber").Signal<boolean>;
124
+ lastError: import("./chamber").Signal<Error | null>;
125
+ dispose: () => void;
126
+ };
127
+ /**
128
+ * useVaporAsyncCommand — async-aware command dispatch for Vapor components
129
+ * used inside Suspense boundaries.
130
+ *
131
+ * Vue 3.6.0-beta.10 introduced proper async component hydration under VDOM
132
+ * Suspense. This composable wraps an AsyncCommandBus dispatch with reactive
133
+ * loading/error state, making it safe for `<script setup vapor>` components
134
+ * that await async operations.
135
+ *
136
+ * The dispatch function returns a Promise<CommandResult>, matching the
137
+ * AsyncCommandBus interface. Use this when your commands hit async transports
138
+ * (HTTP bridge, WS bridge) and you need awaitable results.
139
+ *
140
+ * @example
141
+ * // In a <script setup vapor> component under <Suspense>:
142
+ * import { useVaporAsyncCommand } from 'vapor-chamber';
143
+ * const { dispatch, loading, lastError } = useVaporAsyncCommand(asyncBus);
144
+ * const result = await dispatch('orderCreate', { items: cart });
145
+ */
146
+ export declare function useVaporAsyncCommand(asyncBus?: {
147
+ dispatch: (action: string, target: any, payload?: any) => Promise<CommandResult>;
148
+ }): {
149
+ dispatch: (action: string, target: any, payload?: any) => Promise<CommandResult>;
68
150
  loading: import("./chamber").Signal<boolean>;
69
151
  lastError: import("./chamber").Signal<Error | null>;
70
152
  dispose: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"chamber-vapor.d.ts","sourceRoot":"","sources":["../src/chamber-vapor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEtF;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,OASxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,IAAI,GAAG,GAAG,IAAI,CAElD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,eAAe;uBAKC,GAAG,YAAY,GAAG,KAAG,aAAa;;EAS7D;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe;uBAMH,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,aAAa;uBASlD,MAAM,WAAW,OAAO,SAAS,eAAe,KAAG,MAAM,IAAI;kBAMlE,MAAM,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,KAAK,IAAI,KAAG,MAAM,IAAI;;;;EAclG"}
1
+ {"version":3,"file":"chamber-vapor.d.ts","sourceRoot":"","sources":["../src/chamber-vapor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,OAAO,KAAK,EAAE,OAAO,EAAgB,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEpG;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,OASxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,IAAI,GAAG,GAAG,IAAI,CAElD;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAIrF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAI7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAIjE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,eAAe;uBAKC,GAAG,YAAY,GAAG,KAAG,aAAa;;EAS7D;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe;uBAMH,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;uBA0B3E,MAAM,WAAW,OAAO,SAAS,eAAe,KAAG,MAAM,IAAI;kBAMlE,MAAM,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,KAAK,IAAI,KAAG,MAAM,IAAI;kBAO5E,MAAM,SAAS,GAAG,KAAG,IAAI;;;;EAY/C;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE;IAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;CAAE;uBAMlG,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,OAAO,CAAC,aAAa,CAAC;;;;EAwB5F"}
@@ -1,12 +1,15 @@
1
1
  /**
2
2
  * vapor-chamber — Vue 3.6+ Vapor-specific API
3
3
  *
4
- * createVaporChamberApp, getVaporInteropPlugin, defineVaporCommand,
5
- * useVaporCommand
4
+ * v1.1.0 — Added: defineVaporCustomElement, defineVaporComponent,
5
+ * defineVaporAsyncComponent wrappers (Vue 3.6.0-beta.10+);
6
+ * useVaporAsyncCommand for Suspense-aware async dispatch.
7
+ * v0.6.0 — Added: useVaporCommand composable.
8
+ * v0.4.0 — Added: createVaporChamberApp, getVaporInteropPlugin, defineVaporCommand.
6
9
  *
7
10
  * Separated from chamber.ts to keep the core composable module CDCC-compliant.
8
11
  */
9
- import { getCommandBus, signal, tryAutoCleanup, getVaporAppFn, getVaporInteropRef, } from './chamber';
12
+ import { getCommandBus, signal, tryAutoCleanup, getVaporAppFn, getVaporInteropRef, getDefineVaporCustomElementFn, getDefineVaporComponentFn, getDefineVaporAsyncComponentFn, } from './chamber';
10
13
  /**
11
14
  * Create a Vapor app instance with vapor-chamber ready.
12
15
  * Requires Vue 3.6+. Throws if Vapor is not available.
@@ -37,6 +40,78 @@ export function createVaporChamberApp(rootComponent, rootProps) {
37
40
  export function getVaporInteropPlugin() {
38
41
  return getVaporInteropRef();
39
42
  }
43
+ // ---------------------------------------------------------------------------
44
+ // Vue 3.6.0-beta.10+ Vapor Custom Elements
45
+ // ---------------------------------------------------------------------------
46
+ /**
47
+ * defineVaporCustomElement — create a custom element backed by Vapor rendering.
48
+ *
49
+ * Wraps Vue 3.6.0-beta.10's `defineVaporCustomElement()`. The generated custom
50
+ * element uses Vapor's compiler-optimized rendering instead of the VDOM, giving
51
+ * zero-overhead DOM updates inside shadow DOM.
52
+ *
53
+ * SSR runtime is automatically tree-shaken from the generated code (beta.10 fix).
54
+ *
55
+ * Returns null if Vue 3.6.0-beta.10+ is not detected — check before calling
56
+ * `customElements.define()`.
57
+ *
58
+ * @example
59
+ * import { defineVaporCustomElement } from 'vapor-chamber';
60
+ * const MyEl = defineVaporCustomElement({
61
+ * props: { label: String },
62
+ * setup(props) { return () => h('span', props.label); }
63
+ * });
64
+ * if (MyEl) customElements.define('my-el', MyEl);
65
+ */
66
+ export function defineVaporCustomElement(options, extraOptions) {
67
+ const fn = getDefineVaporCustomElementFn();
68
+ if (!fn)
69
+ return null;
70
+ return extraOptions !== undefined ? fn(options, extraOptions) : fn(options);
71
+ }
72
+ /**
73
+ * defineVaporComponent — define a Vapor component with proper type inference.
74
+ *
75
+ * Wraps Vue 3.6.0-beta.10's `defineVaporComponent()`. Use this to get full
76
+ * TypeScript inference for props, emits, and slots in Vapor components.
77
+ *
78
+ * Returns null if Vue 3.6.0-beta.10+ is not detected.
79
+ *
80
+ * @example
81
+ * import { defineVaporComponent } from 'vapor-chamber';
82
+ * const Comp = defineVaporComponent({
83
+ * props: { count: Number },
84
+ * setup(props) { return () => h('div', `Count: ${props.count}`); }
85
+ * });
86
+ */
87
+ export function defineVaporComponent(options) {
88
+ const fn = getDefineVaporComponentFn();
89
+ if (!fn)
90
+ return null;
91
+ return fn(options);
92
+ }
93
+ /**
94
+ * defineVaporAsyncComponent — define an async Vapor component for lazy loading.
95
+ *
96
+ * Wraps Vue 3.6.0-beta.10's `defineVaporAsyncComponent()`. Async Vapor
97
+ * components are properly cached by VaporKeepAlive and hydrate under VDOM
98
+ * Suspense boundaries (beta.10 fix).
99
+ *
100
+ * Returns null if Vue 3.6.0-beta.10+ is not detected.
101
+ *
102
+ * @example
103
+ * import { defineVaporAsyncComponent } from 'vapor-chamber';
104
+ * const AsyncPanel = defineVaporAsyncComponent(() => import('./Panel.vue'));
105
+ */
106
+ export function defineVaporAsyncComponent(loader) {
107
+ const fn = getDefineVaporAsyncComponentFn();
108
+ if (!fn)
109
+ return null;
110
+ return fn(loader);
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // defineVaporCommand
114
+ // ---------------------------------------------------------------------------
40
115
  /**
41
116
  * defineVaporCommand — zero-overhead command for hot paths in Vapor mode.
42
117
  *
@@ -87,7 +162,21 @@ export function useVaporCommand() {
87
162
  function dispatch(action, target, payload) {
88
163
  loading.value = true;
89
164
  lastError.value = null;
90
- const result = bus.dispatch(action, target, payload);
165
+ let result;
166
+ try {
167
+ result = bus.dispatch(action, target, payload);
168
+ }
169
+ catch (e) {
170
+ loading.value = false;
171
+ const error = e;
172
+ lastError.value = error;
173
+ return { ok: false, error };
174
+ }
175
+ // Handle async results (when using async bus or async transport plugins)
176
+ if (result && typeof result.then === 'function') {
177
+ return result.then((r) => { loading.value = false; if (!r.ok)
178
+ lastError.value = r.error ?? null; return r; }, (e) => { loading.value = false; lastError.value = e; return { ok: false, error: e }; });
179
+ }
91
180
  loading.value = false;
92
181
  if (!result.ok)
93
182
  lastError.value = result.error ?? null;
@@ -103,10 +192,66 @@ export function useVaporCommand() {
103
192
  listeners.push(unsub);
104
193
  return unsub;
105
194
  }
195
+ /** Fire a domain event — notifies on() listeners, no handler required, no result. */
196
+ function emit(event, data) {
197
+ bus.emit(event, data);
198
+ }
199
+ function dispose() {
200
+ listeners.forEach(fn => fn());
201
+ listeners.length = 0;
202
+ }
203
+ tryAutoCleanup(dispose);
204
+ return { dispatch, register, on, emit, loading, lastError, dispose };
205
+ }
206
+ // ---------------------------------------------------------------------------
207
+ // useVaporAsyncCommand
208
+ // ---------------------------------------------------------------------------
209
+ /**
210
+ * useVaporAsyncCommand — async-aware command dispatch for Vapor components
211
+ * used inside Suspense boundaries.
212
+ *
213
+ * Vue 3.6.0-beta.10 introduced proper async component hydration under VDOM
214
+ * Suspense. This composable wraps an AsyncCommandBus dispatch with reactive
215
+ * loading/error state, making it safe for `<script setup vapor>` components
216
+ * that await async operations.
217
+ *
218
+ * The dispatch function returns a Promise<CommandResult>, matching the
219
+ * AsyncCommandBus interface. Use this when your commands hit async transports
220
+ * (HTTP bridge, WS bridge) and you need awaitable results.
221
+ *
222
+ * @example
223
+ * // In a <script setup vapor> component under <Suspense>:
224
+ * import { useVaporAsyncCommand } from 'vapor-chamber';
225
+ * const { dispatch, loading, lastError } = useVaporAsyncCommand(asyncBus);
226
+ * const result = await dispatch('orderCreate', { items: cart });
227
+ */
228
+ export function useVaporAsyncCommand(asyncBus) {
229
+ const bus = asyncBus ?? getCommandBus();
230
+ const loading = signal(false);
231
+ const lastError = signal(null);
232
+ const listeners = [];
233
+ async function dispatch(action, target, payload) {
234
+ loading.value = true;
235
+ lastError.value = null;
236
+ try {
237
+ const result = await bus.dispatch(action, target, payload);
238
+ if (!result.ok)
239
+ lastError.value = result.error ?? null;
240
+ return result;
241
+ }
242
+ catch (e) {
243
+ const error = e;
244
+ lastError.value = error;
245
+ return { ok: false, error };
246
+ }
247
+ finally {
248
+ loading.value = false;
249
+ }
250
+ }
106
251
  function dispose() {
107
252
  listeners.forEach(fn => fn());
108
253
  listeners.length = 0;
109
254
  }
110
255
  tryAutoCleanup(dispose);
111
- return { dispatch, register, on, loading, lastError, dispose };
256
+ return { dispatch, loading, lastError, dispose };
112
257
  }
package/dist/chamber.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * vapor-chamber - Vue Vapor integration
3
3
  *
4
+ * v1.1.0 — Vue 3.6.0-beta.10 alignment: defineVaporCustomElement, defineVaporComponent,
5
+ * defineVaporAsyncComponent detection; improved hydration interop.
4
6
  * v0.4.1 — Added: useCommandGroup (namespace isolation), useCommandError (error boundary).
5
7
  * v0.4.0 — Vue 3.6 Vapor alignment: onScopeDispose, Vapor detection,
6
8
  * defineVaporCommand, createVaporChamberApp.
@@ -43,6 +45,12 @@ export declare function isVaporAvailable(): boolean;
43
45
  export declare function getVaporAppFn(): any;
44
46
  /** @internal — for chamber-vapor.ts use only */
45
47
  export declare function getVaporInteropRef(): any;
48
+ /** @internal — for chamber-vapor.ts use only */
49
+ export declare function getDefineVaporCustomElementFn(): any;
50
+ /** @internal — for chamber-vapor.ts use only */
51
+ export declare function getDefineVaporComponentFn(): any;
52
+ /** @internal — for chamber-vapor.ts use only */
53
+ export declare function getDefineVaporAsyncComponentFn(): any;
46
54
  export declare function getCommandBus(): CommandBus;
47
55
  export declare function setCommandBus(bus: CommandBus): void;
48
56
  /**
@@ -61,13 +69,23 @@ export declare function resetCommandBus(): void;
61
69
  * No-ops entirely if not inside a Vue context.
62
70
  */
63
71
  export declare function tryAutoCleanup(disposeFn: () => void): void;
72
+ /**
73
+ * Register KeepAlive lifecycle hooks to pause/resume bus subscriptions.
74
+ *
75
+ * When a component is deactivated by KeepAlive, `onPause` is called.
76
+ * When reactivated, `onResume` is called. No-ops if not inside a
77
+ * KeepAlive-wrapped component or if Vue is not available.
78
+ *
79
+ * @internal — used by composables that manage bus subscriptions.
80
+ */
81
+ export declare function tryKeepAliveHooks(onPause: () => void, onResume: () => void): void;
64
82
  /**
65
83
  * useCommand - dispatch commands with reactive loading/error state
66
84
  *
67
85
  * Auto-cleanup on Vue component unmount or scope disposal.
68
86
  */
69
87
  export declare function useCommand(): {
70
- dispatch: (action: string, target: any, payload?: any) => CommandResult;
88
+ dispatch: (action: string, target: any, payload?: any) => CommandResult | Promise<CommandResult>;
71
89
  loading: Signal<boolean>;
72
90
  lastError: Signal<Error | null>;
73
91
  };
@@ -105,6 +123,27 @@ export declare function useCommandHistory(options?: {
105
123
  clear: () => void;
106
124
  dispose: () => void;
107
125
  };
126
+ /**
127
+ * useCommandQuery — CQRS read-side composable with reactive state.
128
+ *
129
+ * Wraps bus.query() with reactive `data`, `loading`, and `lastError` signals.
130
+ * query() skips onBefore hooks (no auth gates, no loading spinners for reads)
131
+ * but runs plugins, handlers, and afterHooks.
132
+ *
133
+ * Supports both sync and async buses — if the result is a Promise, loading
134
+ * stays true until it resolves.
135
+ *
136
+ * @example
137
+ * const { query, data, loading, lastError } = useCommandQuery();
138
+ * const result = query('getUser', { id: 42 });
139
+ * // data.value = result.value after query completes
140
+ */
141
+ export declare function useCommandQuery(): {
142
+ query: (action: string, target: any, payload?: any) => CommandResult | Promise<CommandResult>;
143
+ data: Signal<any>;
144
+ loading: Signal<boolean>;
145
+ lastError: Signal<Error | null>;
146
+ };
108
147
  /**
109
148
  * useCommandGroup — namespace isolation for large apps and multi-team projects.
110
149
  *
@@ -125,6 +164,8 @@ export declare function useCommandHistory(options?: {
125
164
  */
126
165
  export declare function useCommandGroup(namespace: string): {
127
166
  dispatch: (action: string, target: any, payload?: any) => CommandResult;
167
+ query: (action: string, target: any, payload?: any) => CommandResult;
168
+ emit: (event: string, data?: any) => void;
128
169
  register: (action: string, handler: Handler, opts?: RegisterOptions) => () => void;
129
170
  use: (plugin: Plugin) => () => void;
130
171
  on: (pattern: string, listener: Listener) => () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"chamber.d.ts","sourceRoot":"","sources":["../src/chamber.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAoB,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMpK,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AACrC,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AAwFxD;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAGzD;AAoBD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAEtD;AAED,eAAO,MAAM,MAAM,EAAE,YAAoD,CAAC;AAM1E;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,gDAAgD;AAChD,wBAAgB,aAAa,IAAI,GAAG,CAA8B;AAClE,gDAAgD;AAChD,wBAAgB,kBAAkB,IAAI,GAAG,CAAmC;AAQ5E,wBAAgB,aAAa,IAAI,UAAU,CAK1C;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAEnD;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAMD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,IAAI,GAAG,IAAI,CAoC1D;AAMD;;;;GAIG;AACH,wBAAgB,UAAU;uBAKE,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,aAAa;;;EAU7E;AAMD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,EAAE,CAAC,EACV,QAAQ,EAAE;IACR,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,KAAK,CAAC,CAAC;CACjD;;;EAuBF;AAMD;;GAEG;AACH,wBAAgB,aAAa,mDAE5B;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;CAC/B;;;;;gBAoBa,OAAO,GAAG,SAAS;gBAsBnB,OAAO,GAAG,SAAS;;;EAmCrC;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM;uBAQrB,MAAM,UAAU,GAAG,YAAY,GAAG,KAAG,aAAa;uBAIlD,MAAM,WAAW,OAAO,SAAS,eAAe,KAAG,MAAM,IAAI;kBAMlE,MAAM,KAAG,MAAM,IAAI;kBAMnB,MAAM,YAAY,QAAQ,KAAG,MAAM,IAAI;;;EAgB7D;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE;IACvC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;CAC/B;;aAIqB,OAAO;eAAS,KAAK;mBAAa,MAAM;;;;;EAyBlE"}
1
+ {"version":3,"file":"chamber.d.ts","sourceRoot":"","sources":["../src/chamber.ts"],"names":[],"mappings":"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"}
package/dist/chamber.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * vapor-chamber - Vue Vapor integration
3
3
  *
4
+ * v1.1.0 — Vue 3.6.0-beta.10 alignment: defineVaporCustomElement, defineVaporComponent,
5
+ * defineVaporAsyncComponent detection; improved hydration interop.
4
6
  * v0.4.1 — Added: useCommandGroup (namespace isolation), useCommandError (error boundary).
5
7
  * v0.4.0 — Vue 3.6 Vapor alignment: onScopeDispose, Vapor detection,
6
8
  * defineVaporCommand, createVaporChamberApp.
@@ -22,11 +24,17 @@ let _vueRef = null;
22
24
  let _vueOnUnmounted = null;
23
25
  let _vueOnScopeDispose = null;
24
26
  let _vueGetCurrentInstance = null;
27
+ let _vueOnActivated = null;
28
+ let _vueOnDeactivated = null;
25
29
  let _vueProbed = false;
26
30
  // Vue 3.6+ Vapor detection
27
31
  let _hasVapor = false;
28
32
  let _createVaporAppFn = null;
29
33
  let _vaporInteropPluginRef = null;
34
+ // Vue 3.6.0-beta.10+ Vapor APIs
35
+ let _defineVaporCustomElementFn = null;
36
+ let _defineVaporComponentFn = null;
37
+ let _defineVaporAsyncComponentFn = null;
30
38
  /** Promise that resolves once Vue detection is complete. Await this in composables
31
39
  * that need Vue APIs to be available before first use. */
32
40
  let _probePromise = null;
@@ -44,6 +52,13 @@ function applyVueModule(vue) {
44
52
  if (vue && typeof vue.getCurrentInstance === 'function') {
45
53
  _vueGetCurrentInstance = vue.getCurrentInstance;
46
54
  }
55
+ // KeepAlive lifecycle hooks (Vue 3.x)
56
+ if (vue && typeof vue.onActivated === 'function') {
57
+ _vueOnActivated = vue.onActivated;
58
+ }
59
+ if (vue && typeof vue.onDeactivated === 'function') {
60
+ _vueOnDeactivated = vue.onDeactivated;
61
+ }
47
62
  // Vue 3.6+ Vapor detection
48
63
  if (vue && typeof vue.createVaporApp === 'function') {
49
64
  _hasVapor = true;
@@ -52,6 +67,16 @@ function applyVueModule(vue) {
52
67
  if (vue && typeof vue.vaporInteropPlugin !== 'undefined') {
53
68
  _vaporInteropPluginRef = vue.vaporInteropPlugin;
54
69
  }
70
+ // Vue 3.6.0-beta.10+: Vapor custom elements and component definitions
71
+ if (vue && typeof vue.defineVaporCustomElement === 'function') {
72
+ _defineVaporCustomElementFn = vue.defineVaporCustomElement;
73
+ }
74
+ if (vue && typeof vue.defineVaporComponent === 'function') {
75
+ _defineVaporComponentFn = vue.defineVaporComponent;
76
+ }
77
+ if (vue && typeof vue.defineVaporAsyncComponent === 'function') {
78
+ _defineVaporAsyncComponentFn = vue.defineVaporAsyncComponent;
79
+ }
55
80
  }
56
81
  function probeVue() {
57
82
  if (_vueProbed)
@@ -141,6 +166,12 @@ export function isVaporAvailable() {
141
166
  export function getVaporAppFn() { return _createVaporAppFn; }
142
167
  /** @internal — for chamber-vapor.ts use only */
143
168
  export function getVaporInteropRef() { return _vaporInteropPluginRef; }
169
+ /** @internal — for chamber-vapor.ts use only */
170
+ export function getDefineVaporCustomElementFn() { return _defineVaporCustomElementFn; }
171
+ /** @internal — for chamber-vapor.ts use only */
172
+ export function getDefineVaporComponentFn() { return _defineVaporComponentFn; }
173
+ /** @internal — for chamber-vapor.ts use only */
174
+ export function getDefineVaporAsyncComponentFn() { return _defineVaporAsyncComponentFn; }
144
175
  // ---------------------------------------------------------------------------
145
176
  // Shared command bus instance
146
177
  // ---------------------------------------------------------------------------
@@ -209,6 +240,33 @@ export function tryAutoCleanup(disposeFn) {
209
240
  }
210
241
  }
211
242
  // ---------------------------------------------------------------------------
243
+ // KeepAlive pause/resume support
244
+ // ---------------------------------------------------------------------------
245
+ /**
246
+ * Register KeepAlive lifecycle hooks to pause/resume bus subscriptions.
247
+ *
248
+ * When a component is deactivated by KeepAlive, `onPause` is called.
249
+ * When reactivated, `onResume` is called. No-ops if not inside a
250
+ * KeepAlive-wrapped component or if Vue is not available.
251
+ *
252
+ * @internal — used by composables that manage bus subscriptions.
253
+ */
254
+ export function tryKeepAliveHooks(onPause, onResume) {
255
+ probeVue();
256
+ if (_vueOnDeactivated) {
257
+ try {
258
+ _vueOnDeactivated(onPause);
259
+ }
260
+ catch { /* not in component context */ }
261
+ }
262
+ if (_vueOnActivated) {
263
+ try {
264
+ _vueOnActivated(onResume);
265
+ }
266
+ catch { /* not in component context */ }
267
+ }
268
+ }
269
+ // ---------------------------------------------------------------------------
212
270
  // useCommand
213
271
  // ---------------------------------------------------------------------------
214
272
  /**
@@ -223,7 +281,21 @@ export function useCommand() {
223
281
  function dispatch(action, target, payload) {
224
282
  loading.value = true;
225
283
  lastError.value = null;
226
- const result = bus.dispatch(action, target, payload);
284
+ let result;
285
+ try {
286
+ result = bus.dispatch(action, target, payload);
287
+ }
288
+ catch (e) {
289
+ loading.value = false;
290
+ const error = e;
291
+ lastError.value = error;
292
+ return { ok: false, error };
293
+ }
294
+ // Handle async results (when using async bus or async transport plugins)
295
+ if (result && typeof result.then === 'function') {
296
+ return result.then((r) => { loading.value = false; if (!r.ok)
297
+ lastError.value = r.error ?? null; return r; }, (e) => { loading.value = false; lastError.value = e; return { ok: false, error: e }; });
298
+ }
227
299
  loading.value = false;
228
300
  if (!result.ok)
229
301
  lastError.value = result.error ?? null;
@@ -282,7 +354,10 @@ export function useCommandHistory(options = {}) {
282
354
  const future = signal([]);
283
355
  const canUndo = signal(false);
284
356
  const canRedo = signal(false);
357
+ let paused = false;
285
358
  const unsubscribe = bus.onAfter((cmd, result) => {
359
+ if (paused)
360
+ return;
286
361
  if (result.ok && (!filter || filter(cmd))) {
287
362
  const newPast = [...past.value, cmd];
288
363
  if (newPast.length > maxSize)
@@ -293,6 +368,8 @@ export function useCommandHistory(options = {}) {
293
368
  canRedo.value = false;
294
369
  }
295
370
  });
371
+ // KeepAlive: pause tracking when deactivated, resume when activated
372
+ tryKeepAliveHooks(() => { paused = true; }, () => { paused = false; });
296
373
  function undo() {
297
374
  const p = [...past.value];
298
375
  const cmd = p.pop();
@@ -319,6 +396,17 @@ export function useCommandHistory(options = {}) {
319
396
  const cmd = f.pop();
320
397
  if (cmd) {
321
398
  future.value = f;
399
+ // Pause tracking so the re-dispatch doesn't double-record
400
+ paused = true;
401
+ try {
402
+ bus.dispatch(cmd.action, cmd.target, cmd.payload);
403
+ }
404
+ catch (e) {
405
+ console.error(`[vapor-chamber] Redo dispatch error for "${cmd.action}":`, e);
406
+ }
407
+ finally {
408
+ paused = false;
409
+ }
322
410
  past.value = [...past.value, cmd];
323
411
  canUndo.value = true;
324
412
  canRedo.value = f.length > 0;
@@ -347,6 +435,62 @@ export function useCommandHistory(options = {}) {
347
435
  };
348
436
  }
349
437
  // ---------------------------------------------------------------------------
438
+ // useCommandQuery
439
+ // ---------------------------------------------------------------------------
440
+ /**
441
+ * useCommandQuery — CQRS read-side composable with reactive state.
442
+ *
443
+ * Wraps bus.query() with reactive `data`, `loading`, and `lastError` signals.
444
+ * query() skips onBefore hooks (no auth gates, no loading spinners for reads)
445
+ * but runs plugins, handlers, and afterHooks.
446
+ *
447
+ * Supports both sync and async buses — if the result is a Promise, loading
448
+ * stays true until it resolves.
449
+ *
450
+ * @example
451
+ * const { query, data, loading, lastError } = useCommandQuery();
452
+ * const result = query('getUser', { id: 42 });
453
+ * // data.value = result.value after query completes
454
+ */
455
+ export function useCommandQuery() {
456
+ const bus = getCommandBus();
457
+ const data = signal(null);
458
+ const loading = signal(false);
459
+ const lastError = signal(null);
460
+ function query(action, target, payload) {
461
+ loading.value = true;
462
+ lastError.value = null;
463
+ let result;
464
+ try {
465
+ result = bus.query(action, target, payload);
466
+ }
467
+ catch (e) {
468
+ loading.value = false;
469
+ const error = e;
470
+ lastError.value = error;
471
+ return { ok: false, error };
472
+ }
473
+ // Handle async results
474
+ if (result && typeof result.then === 'function') {
475
+ return result.then((r) => {
476
+ loading.value = false;
477
+ if (r.ok)
478
+ data.value = r.value;
479
+ else
480
+ lastError.value = r.error ?? null;
481
+ return r;
482
+ }, (e) => { loading.value = false; lastError.value = e; return { ok: false, error: e }; });
483
+ }
484
+ loading.value = false;
485
+ if (result.ok)
486
+ data.value = result.value;
487
+ else
488
+ lastError.value = result.error ?? null;
489
+ return result;
490
+ }
491
+ return { query, data, loading, lastError };
492
+ }
493
+ // ---------------------------------------------------------------------------
350
494
  // useCommandGroup
351
495
  // ---------------------------------------------------------------------------
352
496
  /**
@@ -376,6 +520,14 @@ export function useCommandGroup(namespace) {
376
520
  function dispatch(action, target, payload) {
377
521
  return bus.dispatch(prefixed(action), target, payload);
378
522
  }
523
+ /** Read-only dispatch — skips onBefore hooks, runs handler + plugins, fires afterHooks. */
524
+ function query(action, target, payload) {
525
+ return bus.query(prefixed(action), target, payload);
526
+ }
527
+ /** Fire a namespaced domain event — notifies on() listeners, no handler required. */
528
+ function emit(event, data) {
529
+ bus.emit(prefixed(event), data);
530
+ }
379
531
  function register(action, handler, opts) {
380
532
  const unregister = bus.register(prefixed(action), handler, opts);
381
533
  cleanups.push(unregister);
@@ -398,7 +550,7 @@ export function useCommandGroup(namespace) {
398
550
  cleanups.length = 0;
399
551
  }
400
552
  tryAutoCleanup(dispose);
401
- return { dispatch, register, use, on, namespace, dispose };
553
+ return { dispatch, query, emit, register, use, on, namespace, dispose };
402
554
  }
403
555
  // ---------------------------------------------------------------------------
404
556
  // useCommandError
@@ -420,7 +572,10 @@ export function useCommandError(options = {}) {
420
572
  const bus = getCommandBus();
421
573
  const errors = signal([]);
422
574
  const latestError = signal(null);
575
+ let paused = false;
423
576
  const unsubscribe = bus.onAfter((cmd, result) => {
577
+ if (paused)
578
+ return;
424
579
  if (!result.ok && result.error) {
425
580
  if (!filter || filter(cmd)) {
426
581
  latestError.value = result.error;
@@ -428,6 +583,8 @@ export function useCommandError(options = {}) {
428
583
  }
429
584
  }
430
585
  });
586
+ // KeepAlive: pause error capture when deactivated, resume when activated
587
+ tryKeepAliveHooks(() => { paused = true; }, () => { paused = false; });
431
588
  function clearErrors() {
432
589
  errors.value = [];
433
590
  latestError.value = null;
@@ -1 +1 @@
1
- {"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../src/directives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAqHH;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI;IAAE,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAA;CAAE,CA8FnE"}
1
+ {"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../src/directives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAqHH;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI;IAAE,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAA;CAAE,CAiGnE"}