@pyreon/store 0.0.1

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.
@@ -0,0 +1,37 @@
1
+ //#region src/registry.ts
2
+ const _defaultRegistry = /* @__PURE__ */ new Map();
3
+ let _registryProvider = () => _defaultRegistry;
4
+ function getRegistry() {
5
+ return _registryProvider();
6
+ }
7
+
8
+ //#endregion
9
+ //#region src/devtools.ts
10
+ /**
11
+ * @pyreon/store devtools introspection API.
12
+ * Import: `import { ... } from "@pyreon/store/devtools"`
13
+ */
14
+ const _listeners = /* @__PURE__ */ new Set();
15
+ /** @internal — called by defineStore/resetStore to notify devtools. */
16
+ function _notifyChange() {
17
+ for (const listener of _listeners) listener();
18
+ }
19
+ /** Get all registered store IDs. */
20
+ function getRegisteredStores() {
21
+ return [...getRegistry().keys()];
22
+ }
23
+ /** Get a store API by ID (or undefined if not registered). */
24
+ function getStoreById(id) {
25
+ return getRegistry().get(id);
26
+ }
27
+ /** Subscribe to store registry changes (store added/removed). Returns unsubscribe. */
28
+ function onStoreChange(listener) {
29
+ _listeners.add(listener);
30
+ return () => {
31
+ _listeners.delete(listener);
32
+ };
33
+ }
34
+
35
+ //#endregion
36
+ export { _notifyChange, getRegisteredStores, getStoreById, onStoreChange };
37
+ //# sourceMappingURL=devtools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.js","names":[],"sources":["../src/registry.ts","../src/devtools.ts"],"sourcesContent":["// ─── Registry ─────────────────────────────────────────────────────────────────\n\n// Default: module-level singleton (CSR and single-threaded SSR).\n// For concurrent SSR, @pyreon/runtime-server replaces this with an\n// AsyncLocalStorage-backed provider via setRegistryProvider().\nconst _defaultRegistry = new Map<string, unknown>()\nlet _registryProvider: () => Map<string, unknown> = () => _defaultRegistry\n\n/**\n * Override the store registry provider.\n * Called by @pyreon/runtime-server to inject a per-request isolated registry,\n * preventing store state from leaking between concurrent SSR requests.\n *\n * @example\n * import { AsyncLocalStorage } from \"node:async_hooks\"\n * const als = new AsyncLocalStorage<Map<string, unknown>>()\n * setRegistryProvider(() => als.getStore() ?? new Map())\n * // Then wrap each request: als.run(new Map(), () => renderToString(app))\n */\nexport function setRegistryProvider(fn: () => Map<string, unknown>): void {\n _registryProvider = fn\n}\n\nexport function getRegistry(): Map<string, unknown> {\n return _registryProvider()\n}\n","/**\n * @pyreon/store devtools introspection API.\n * Import: `import { ... } from \"@pyreon/store/devtools\"`\n */\n\nimport { getRegistry } from './registry'\n\nconst _listeners = new Set<() => void>()\n\n/** @internal — called by defineStore/resetStore to notify devtools. */\nexport function _notifyChange(): void {\n for (const listener of _listeners) listener()\n}\n\n/** Get all registered store IDs. */\nexport function getRegisteredStores(): string[] {\n return [...getRegistry().keys()]\n}\n\n/** Get a store API by ID (or undefined if not registered). */\nexport function getStoreById(\n id: string,\n): import('./index').StoreApi<Record<string, unknown>> | undefined {\n return getRegistry().get(id) as\n | import('./index').StoreApi<Record<string, unknown>>\n | undefined\n}\n\n/** Subscribe to store registry changes (store added/removed). Returns unsubscribe. */\nexport function onStoreChange(listener: () => void): () => void {\n _listeners.add(listener)\n return () => {\n _listeners.delete(listener)\n }\n}\n"],"mappings":";AAKA,MAAM,mCAAmB,IAAI,KAAsB;AACnD,IAAI,0BAAsD;AAiB1D,SAAgB,cAAoC;AAClD,QAAO,mBAAmB;;;;;;;;;ACjB5B,MAAM,6BAAa,IAAI,KAAiB;;AAGxC,SAAgB,gBAAsB;AACpC,MAAK,MAAM,YAAY,WAAY,WAAU;;;AAI/C,SAAgB,sBAAgC;AAC9C,QAAO,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC;;;AAIlC,SAAgB,aACd,IACiE;AACjE,QAAO,aAAa,CAAC,IAAI,GAAG;;;AAM9B,SAAgB,cAAc,UAAkC;AAC9D,YAAW,IAAI,SAAS;AACxB,cAAa;AACX,aAAW,OAAO,SAAS"}
package/lib/index.js ADDED
@@ -0,0 +1,225 @@
1
+ import { batch, batch as batch$1, computed, effect, signal } from "@pyreon/reactivity";
2
+
3
+ //#region src/registry.ts
4
+ const _defaultRegistry = /* @__PURE__ */ new Map();
5
+ let _registryProvider = () => _defaultRegistry;
6
+ /**
7
+ * Override the store registry provider.
8
+ * Called by @pyreon/runtime-server to inject a per-request isolated registry,
9
+ * preventing store state from leaking between concurrent SSR requests.
10
+ *
11
+ * @example
12
+ * import { AsyncLocalStorage } from "node:async_hooks"
13
+ * const als = new AsyncLocalStorage<Map<string, unknown>>()
14
+ * setRegistryProvider(() => als.getStore() ?? new Map())
15
+ * // Then wrap each request: als.run(new Map(), () => renderToString(app))
16
+ */
17
+ function setRegistryProvider(fn) {
18
+ _registryProvider = fn;
19
+ }
20
+ function getRegistry() {
21
+ return _registryProvider();
22
+ }
23
+
24
+ //#endregion
25
+ //#region src/devtools.ts
26
+ const _listeners = /* @__PURE__ */ new Set();
27
+ /** @internal — called by defineStore/resetStore to notify devtools. */
28
+ function _notifyChange() {
29
+ for (const listener of _listeners) listener();
30
+ }
31
+
32
+ //#endregion
33
+ //#region src/index.ts
34
+ function isSignalLike(v) {
35
+ if (typeof v !== "function") return false;
36
+ const fn = v;
37
+ return typeof fn.set === "function" && typeof fn.peek === "function";
38
+ }
39
+ function isComputedLike(v) {
40
+ if (typeof v !== "function") return false;
41
+ return typeof v.dispose === "function" && !isSignalLike(v);
42
+ }
43
+ const _plugins = [];
44
+ /** Register a global store plugin. Plugins run when a store is first created. */
45
+ function addStorePlugin(plugin) {
46
+ _plugins.push(plugin);
47
+ }
48
+ /**
49
+ * Define a store with a unique id and a setup function.
50
+ * Returns a hook that returns a `StoreApi<T>` with the user's state under `.store`
51
+ * and framework methods (`patch`, `subscribe`, `onAction`, `reset`, `dispose`) at the top level.
52
+ */
53
+ function defineStore(id, setup) {
54
+ return function useStore() {
55
+ const registry = getRegistry();
56
+ if (registry.has(id)) return registry.get(id);
57
+ const raw = setup();
58
+ const signalKeys = [];
59
+ const actionKeys = [];
60
+ const initialValues = /* @__PURE__ */ new Map();
61
+ for (const key of Object.keys(raw)) {
62
+ const val = raw[key];
63
+ if (isSignalLike(val)) {
64
+ signalKeys.push(key);
65
+ initialValues.set(key, val.peek());
66
+ } else if (isComputedLike(val)) {} else if (typeof val === "function") actionKeys.push(key);
67
+ }
68
+ const subscribers = /* @__PURE__ */ new Set();
69
+ let patchInProgress = false;
70
+ let patchEvents = [];
71
+ function getState() {
72
+ const state = {};
73
+ for (const key of signalKeys) state[key] = raw[key].peek();
74
+ return state;
75
+ }
76
+ function notifyDirect(key, oldValue, newValue) {
77
+ if (patchInProgress) {
78
+ patchEvents.push({
79
+ key,
80
+ newValue,
81
+ oldValue
82
+ });
83
+ return;
84
+ }
85
+ if (subscribers.size === 0) return;
86
+ const mutation = {
87
+ storeId: id,
88
+ type: "direct",
89
+ events: [{
90
+ key,
91
+ newValue,
92
+ oldValue
93
+ }]
94
+ };
95
+ const state = getState();
96
+ for (const cb of subscribers) cb(mutation, state);
97
+ }
98
+ const signalUnsubs = [];
99
+ for (const key of signalKeys) {
100
+ const sig = raw[key];
101
+ let prev = sig.peek();
102
+ const unsub = sig.subscribe(() => {
103
+ const next = sig.peek();
104
+ const old = prev;
105
+ prev = next;
106
+ notifyDirect(key, old, next);
107
+ });
108
+ signalUnsubs.push(unsub);
109
+ }
110
+ const actionListeners = /* @__PURE__ */ new Set();
111
+ function wrapAction(key, original) {
112
+ return (...args) => {
113
+ const afterCbs = [];
114
+ const errorCbs = [];
115
+ const context = {
116
+ name: key,
117
+ storeId: id,
118
+ args,
119
+ after: (cb) => afterCbs.push(cb),
120
+ onError: (cb) => errorCbs.push(cb)
121
+ };
122
+ for (const listener of actionListeners) listener(context);
123
+ try {
124
+ const result = original(...args);
125
+ if (result != null && typeof result.then === "function") return result.then((resolved) => {
126
+ for (const cb of afterCbs) cb(resolved);
127
+ return resolved;
128
+ }, (err) => {
129
+ for (const cb of errorCbs) cb(err);
130
+ throw err;
131
+ });
132
+ for (const cb of afterCbs) cb(result);
133
+ return result;
134
+ } catch (err) {
135
+ for (const cb of errorCbs) cb(err);
136
+ throw err;
137
+ }
138
+ };
139
+ }
140
+ const userStore = {};
141
+ for (const key of Object.keys(raw)) if (actionKeys.includes(key)) userStore[key] = wrapAction(key, raw[key]);
142
+ else userStore[key] = raw[key];
143
+ const api = {
144
+ store: userStore,
145
+ id,
146
+ get state() {
147
+ return getState();
148
+ },
149
+ patch(partialOrFn) {
150
+ patchInProgress = true;
151
+ patchEvents = [];
152
+ batch$1(() => {
153
+ if (typeof partialOrFn === "function") {
154
+ const signalMap = {};
155
+ for (const key of signalKeys) signalMap[key] = raw[key];
156
+ partialOrFn(signalMap);
157
+ } else for (const [key, value] of Object.entries(partialOrFn)) {
158
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
159
+ if (signalKeys.includes(key)) raw[key].set(value);
160
+ }
161
+ });
162
+ patchInProgress = false;
163
+ if (subscribers.size > 0 && patchEvents.length > 0) {
164
+ const mutation = {
165
+ storeId: id,
166
+ type: "patch",
167
+ events: patchEvents
168
+ };
169
+ const state = getState();
170
+ for (const cb of subscribers) cb(mutation, state);
171
+ }
172
+ patchEvents = [];
173
+ },
174
+ subscribe(callback, options) {
175
+ subscribers.add(callback);
176
+ if (options?.immediate) callback({
177
+ storeId: id,
178
+ type: "direct",
179
+ events: []
180
+ }, getState());
181
+ return () => {
182
+ subscribers.delete(callback);
183
+ };
184
+ },
185
+ onAction(callback) {
186
+ actionListeners.add(callback);
187
+ return () => {
188
+ actionListeners.delete(callback);
189
+ };
190
+ },
191
+ reset() {
192
+ batch$1(() => {
193
+ for (const [key, initial] of initialValues) raw[key].set(initial);
194
+ });
195
+ },
196
+ dispose() {
197
+ for (const unsub of signalUnsubs) unsub();
198
+ signalUnsubs.length = 0;
199
+ subscribers.clear();
200
+ actionListeners.clear();
201
+ getRegistry().delete(id);
202
+ }
203
+ };
204
+ for (const plugin of _plugins) try {
205
+ plugin(api);
206
+ } catch (_err) {}
207
+ registry.set(id, api);
208
+ _notifyChange();
209
+ return api;
210
+ };
211
+ }
212
+ /** Destroy a store by id so next call to useStore() re-runs setup. */
213
+ function resetStore(id) {
214
+ getRegistry().delete(id);
215
+ _notifyChange();
216
+ }
217
+ /** Destroy all stores — useful for SSR isolation and tests. */
218
+ function resetAllStores() {
219
+ getRegistry().clear();
220
+ _notifyChange();
221
+ }
222
+
223
+ //#endregion
224
+ export { addStorePlugin, batch, computed, defineStore, effect, resetAllStores, resetStore, setRegistryProvider as setStoreRegistryProvider, signal };
225
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/registry.ts","../src/devtools.ts","../src/index.ts"],"sourcesContent":["// ─── Registry ─────────────────────────────────────────────────────────────────\n\n// Default: module-level singleton (CSR and single-threaded SSR).\n// For concurrent SSR, @pyreon/runtime-server replaces this with an\n// AsyncLocalStorage-backed provider via setRegistryProvider().\nconst _defaultRegistry = new Map<string, unknown>()\nlet _registryProvider: () => Map<string, unknown> = () => _defaultRegistry\n\n/**\n * Override the store registry provider.\n * Called by @pyreon/runtime-server to inject a per-request isolated registry,\n * preventing store state from leaking between concurrent SSR requests.\n *\n * @example\n * import { AsyncLocalStorage } from \"node:async_hooks\"\n * const als = new AsyncLocalStorage<Map<string, unknown>>()\n * setRegistryProvider(() => als.getStore() ?? new Map())\n * // Then wrap each request: als.run(new Map(), () => renderToString(app))\n */\nexport function setRegistryProvider(fn: () => Map<string, unknown>): void {\n _registryProvider = fn\n}\n\nexport function getRegistry(): Map<string, unknown> {\n return _registryProvider()\n}\n","/**\n * @pyreon/store devtools introspection API.\n * Import: `import { ... } from \"@pyreon/store/devtools\"`\n */\n\nimport { getRegistry } from './registry'\n\nconst _listeners = new Set<() => void>()\n\n/** @internal — called by defineStore/resetStore to notify devtools. */\nexport function _notifyChange(): void {\n for (const listener of _listeners) listener()\n}\n\n/** Get all registered store IDs. */\nexport function getRegisteredStores(): string[] {\n return [...getRegistry().keys()]\n}\n\n/** Get a store API by ID (or undefined if not registered). */\nexport function getStoreById(\n id: string,\n): import('./index').StoreApi<Record<string, unknown>> | undefined {\n return getRegistry().get(id) as\n | import('./index').StoreApi<Record<string, unknown>>\n | undefined\n}\n\n/** Subscribe to store registry changes (store added/removed). Returns unsubscribe. */\nexport function onStoreChange(listener: () => void): () => void {\n _listeners.add(listener)\n return () => {\n _listeners.delete(listener)\n }\n}\n","/**\n * @pyreon/store — global state management built on @pyreon/reactivity signals.\n *\n * API (composition style):\n *\n * const useCounter = defineStore(\"counter\", () => {\n * const count = signal(0)\n * const double = computed(() => count() * 2)\n * const increment = () => count.update(n => n + 1)\n * return { count, double, increment }\n * })\n *\n * // Inside a component (or anywhere):\n * const { store, patch, subscribe } = useCounter()\n * store.count() // read state\n * store.increment() // call action\n * patch({ count: 5 }) // batch-update\n *\n * Stores are singletons — the setup function runs once per store id.\n * Call `resetStore(id)` or `resetAllStores()` to clear the registry\n * (useful for testing or HMR).\n *\n * For concurrent SSR, call setStoreRegistryProvider() with an\n * AsyncLocalStorage-backed provider so each request gets isolated store state.\n */\n\nexport type { Signal } from '@pyreon/reactivity'\nexport { batch, computed, effect, signal } from '@pyreon/reactivity'\nimport { batch } from '@pyreon/reactivity'\n\nexport { setRegistryProvider as setStoreRegistryProvider } from './registry'\nimport { getRegistry } from './registry'\nimport { _notifyChange } from './devtools'\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface MutationInfo {\n storeId: string\n type: 'direct' | 'patch'\n events: { key: string; newValue: unknown; oldValue: unknown }[]\n}\n\nexport type SubscribeCallback = (\n mutation: MutationInfo,\n state: Record<string, unknown>,\n) => void\n\nexport interface ActionContext {\n name: string\n storeId: string\n args: unknown[]\n after: (cb: (result: unknown) => void) => void\n onError: (cb: (error: unknown) => void) => void\n}\n\nexport type OnActionCallback = (context: ActionContext) => void\n\nexport type StorePlugin = (api: StoreApi<Record<string, unknown>>) => void\n\n/** The structured result returned by every store hook. */\nexport interface StoreApi<T> {\n /** The user-defined store state, computeds, and actions. */\n store: T\n /** Store identifier. */\n id: string\n /** Read-only snapshot of all signal values. */\n readonly state: Record<string, unknown>\n /** Batch-update multiple signals (object form) or direct access (function form). */\n patch(partialState: Record<string, unknown>): void\n patch(fn: (state: Record<string, any>) => void): void\n /** Subscribe to state mutations. Returns an unsubscribe function. */\n subscribe(\n callback: SubscribeCallback,\n options?: { immediate?: boolean },\n ): () => void\n /** Intercept action calls. Returns an unsubscribe function. */\n onAction(callback: OnActionCallback): () => void\n /** Reset all signals to their initial values. */\n reset(): void\n /** Teardown: unsubscribe all listeners and remove from registry. */\n dispose(): void\n}\n\n// ─── Detection helpers ───────────────────────────────────────────────────────\n\n/** Duck-typed signal interface for detection without importing concrete types. */\ninterface SignalLike {\n (): unknown\n set(v: unknown): void\n peek(): unknown\n subscribe(l: () => void): () => void\n}\n\nfunction isSignalLike(v: unknown): v is SignalLike {\n if (typeof v !== 'function') return false\n const fn = v as unknown as Record<string, unknown>\n return typeof fn.set === 'function' && typeof fn.peek === 'function'\n}\n\nfunction isComputedLike(v: unknown): boolean {\n if (typeof v !== 'function') return false\n const fn = v as unknown as Record<string, unknown>\n return typeof fn.dispose === 'function' && !isSignalLike(v)\n}\n\n// ─── Plugin system ───────────────────────────────────────────────────────────\n\nconst _plugins: StorePlugin[] = []\n\n/** Register a global store plugin. Plugins run when a store is first created. */\nexport function addStorePlugin(plugin: StorePlugin): void {\n _plugins.push(plugin)\n}\n\n// ─── defineStore ─────────────────────────────────────────────────────────────\n\n/**\n * Define a store with a unique id and a setup function.\n * Returns a hook that returns a `StoreApi<T>` with the user's state under `.store`\n * and framework methods (`patch`, `subscribe`, `onAction`, `reset`, `dispose`) at the top level.\n */\nexport function defineStore<T extends Record<string, unknown>>(\n id: string,\n setup: () => T,\n): () => StoreApi<T> {\n return function useStore(): StoreApi<T> {\n const registry = getRegistry()\n if (registry.has(id)) return registry.get(id) as StoreApi<T>\n\n const raw = setup()\n\n // Classify properties\n const signalKeys: string[] = []\n const actionKeys: string[] = []\n const initialValues = new Map<string, unknown>()\n\n for (const key of Object.keys(raw)) {\n const val = raw[key]\n if (isSignalLike(val)) {\n signalKeys.push(key)\n initialValues.set(key, val.peek())\n } else if (isComputedLike(val)) {\n // computed — skip, just pass through\n } else if (typeof val === 'function') {\n actionKeys.push(key)\n }\n }\n\n // ─── subscribe infrastructure ───────────────────────────────────────\n const subscribers = new Set<SubscribeCallback>()\n let patchInProgress = false\n let patchEvents: MutationInfo['events'] = []\n\n function getState(): Record<string, unknown> {\n const state: Record<string, unknown> = {}\n for (const key of signalKeys) {\n state[key] = (raw[key] as any).peek()\n }\n return state\n }\n\n function notifyDirect(key: string, oldValue: unknown, newValue: unknown) {\n if (patchInProgress) {\n patchEvents.push({ key, newValue, oldValue })\n return\n }\n if (subscribers.size === 0) return\n const mutation: MutationInfo = {\n storeId: id,\n type: 'direct',\n events: [{ key, newValue, oldValue }],\n }\n const state = getState()\n for (const cb of subscribers) cb(mutation, state)\n }\n\n // Subscribe to each signal for change detection\n const signalUnsubs: (() => void)[] = []\n for (const key of signalKeys) {\n const sig = raw[key] as any\n let prev = sig.peek()\n const unsub = sig.subscribe(() => {\n const next = sig.peek()\n const old = prev\n prev = next\n notifyDirect(key, old, next)\n })\n signalUnsubs.push(unsub)\n }\n\n // ─── onAction infrastructure ────────────────────────────────────────\n const actionListeners = new Set<OnActionCallback>()\n\n // Wrap actions\n function wrapAction(key: string, original: (...args: any[]) => unknown) {\n return (...args: unknown[]) => {\n const afterCbs: ((result: unknown) => void)[] = []\n const errorCbs: ((error: unknown) => void)[] = []\n\n const context: ActionContext = {\n name: key,\n storeId: id,\n args,\n after: (cb) => afterCbs.push(cb),\n onError: (cb) => errorCbs.push(cb),\n }\n\n for (const listener of actionListeners) {\n listener(context)\n }\n\n try {\n const result = original(...args)\n\n // Handle async actions: if the result is a thenable, wait for\n // resolution before calling after/onError callbacks.\n if (result != null && typeof (result as any).then === 'function') {\n return (result as Promise<unknown>).then(\n (resolved) => {\n for (const cb of afterCbs) cb(resolved)\n return resolved\n },\n (err) => {\n for (const cb of errorCbs) cb(err)\n throw err\n },\n )\n }\n\n for (const cb of afterCbs) cb(result)\n return result\n } catch (err) {\n for (const cb of errorCbs) cb(err)\n throw err\n }\n }\n }\n\n // ─── Build user store object ────────────────────────────────────────\n const userStore: Record<string, unknown> = {}\n\n for (const key of Object.keys(raw)) {\n if (actionKeys.includes(key)) {\n userStore[key] = wrapAction(\n key,\n raw[key] as (...args: any[]) => unknown,\n )\n } else {\n userStore[key] = raw[key]\n }\n }\n\n // ─── Build StoreApi ─────────────────────────────────────────────────\n const api: StoreApi<T> = {\n store: userStore as T,\n\n id,\n\n get state() {\n return getState()\n },\n\n patch(\n partialOrFn:\n | Record<string, unknown>\n | ((state: Record<string, any>) => void),\n ) {\n patchInProgress = true\n patchEvents = []\n\n batch(() => {\n if (typeof partialOrFn === 'function') {\n // Functional form: pass an object with the actual signals so user calls .set()\n const signalMap: Record<string, any> = {}\n for (const key of signalKeys) {\n signalMap[key] = raw[key]\n }\n partialOrFn(signalMap)\n } else {\n // Object form: set values directly (skip reserved proto keys)\n for (const [key, value] of Object.entries(partialOrFn)) {\n if (\n key === '__proto__' ||\n key === 'constructor' ||\n key === 'prototype'\n )\n continue\n if (signalKeys.includes(key)) {\n ;(raw[key] as SignalLike).set(value)\n }\n }\n }\n })\n\n patchInProgress = false\n\n // Emit a single notification for the patch\n if (subscribers.size > 0 && patchEvents.length > 0) {\n const mutation: MutationInfo = {\n storeId: id,\n type: 'patch',\n events: patchEvents,\n }\n const state = getState()\n for (const cb of subscribers) cb(mutation, state)\n }\n patchEvents = []\n },\n\n subscribe(\n callback: SubscribeCallback,\n options?: { immediate?: boolean },\n ): () => void {\n subscribers.add(callback)\n if (options?.immediate) {\n const mutation: MutationInfo = {\n storeId: id,\n type: 'direct',\n events: [],\n }\n callback(mutation, getState())\n }\n return () => {\n subscribers.delete(callback)\n }\n },\n\n onAction(callback: OnActionCallback): () => void {\n actionListeners.add(callback)\n return () => {\n actionListeners.delete(callback)\n }\n },\n\n reset() {\n batch(() => {\n for (const [key, initial] of initialValues) {\n ;(raw[key] as any).set(initial)\n }\n })\n },\n\n dispose() {\n for (const unsub of signalUnsubs) unsub()\n signalUnsubs.length = 0\n subscribers.clear()\n actionListeners.clear()\n getRegistry().delete(id)\n },\n }\n\n // Run plugins — errors in one plugin should not break store creation\n for (const plugin of _plugins) {\n try {\n plugin(api as StoreApi<Record<string, unknown>>)\n } catch (_err) {\n // Plugin errors should not break store creation\n }\n }\n\n registry.set(id, api)\n _notifyChange()\n return api\n }\n}\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\n/** Destroy a store by id so next call to useStore() re-runs setup. */\nexport function resetStore(id: string): void {\n getRegistry().delete(id)\n _notifyChange()\n}\n\n/** Destroy all stores — useful for SSR isolation and tests. */\nexport function resetAllStores(): void {\n getRegistry().clear()\n _notifyChange()\n}\n"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ function getRegistry() {
2
+ return _registryProvider();
3
+ }
4
+
5
+ //#endregion
6
+ //#region src/devtools.ts
7
+ /**
8
+ * @pyreon/store devtools introspection API.
9
+ * Import: `import { ... } from "@pyreon/store/devtools"`
10
+ */
11
+
12
+ /** @internal — called by defineStore/resetStore to notify devtools. */
13
+ function _notifyChange() {
14
+ for (const listener of _listeners) listener();
15
+ }
16
+ /** Get all registered store IDs. */
17
+ function getRegisteredStores() {
18
+ return [...getRegistry().keys()];
19
+ }
20
+ /** Get a store API by ID (or undefined if not registered). */
21
+ function getStoreById(id) {
22
+ return getRegistry().get(id);
23
+ }
24
+ /** Subscribe to store registry changes (store added/removed). Returns unsubscribe. */
25
+ function onStoreChange(listener) {
26
+ _listeners.add(listener);
27
+ return () => {
28
+ _listeners.delete(listener);
29
+ };
30
+ }
31
+
32
+ //#endregion
33
+ export { _notifyChange, getRegisteredStores, getStoreById, onStoreChange };
34
+ //# sourceMappingURL=devtools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.d.ts","names":[],"sources":["../../src/registry.ts","../../src/devtools.ts"],"mappings":"AAuBA,SAAgB,WAAA,CAAA,EAAoC;EAClD,OAAO,iBAAA,CAAA,CAAmB;;;;;;;;;;;ACd5B,SAAgB,aAAA,CAAA,EAAsB;EACpC,KAAK,MAAM,QAAA,IAAY,UAAA,EAAY,QAAA,CAAA,CAAU;;;AAI/C,SAAgB,mBAAA,CAAA,EAAgC;EAC9C,OAAO,CAAC,GAAG,WAAA,CAAA,CAAa,CAAC,IAAA,CAAA,CAAM,CAAC;;;AAIlC,SAAgB,YAAA,CACd,EAAA,EACiE;EACjE,OAAO,WAAA,CAAA,CAAa,CAAC,GAAA,CAAI,EAAA,CAAG;;;AAM9B,SAAgB,aAAA,CAAc,QAAA,EAAkC;EAC9D,UAAA,CAAW,GAAA,CAAI,QAAA,CAAS;EACxB,OAAA,MAAa;IACX,UAAA,CAAW,MAAA,CAAO,QAAA,CAAS"}
@@ -0,0 +1,58 @@
1
+ //#region src/index.d.ts
2
+ interface MutationInfo {
3
+ storeId: string;
4
+ type: 'direct' | 'patch';
5
+ events: {
6
+ key: string;
7
+ newValue: unknown;
8
+ oldValue: unknown;
9
+ }[];
10
+ }
11
+ type SubscribeCallback = (mutation: MutationInfo, state: Record<string, unknown>) => void;
12
+ interface ActionContext {
13
+ name: string;
14
+ storeId: string;
15
+ args: unknown[];
16
+ after: (cb: (result: unknown) => void) => void;
17
+ onError: (cb: (error: unknown) => void) => void;
18
+ }
19
+ type OnActionCallback = (context: ActionContext) => void;
20
+ /** The structured result returned by every store hook. */
21
+ interface StoreApi<T> {
22
+ /** The user-defined store state, computeds, and actions. */
23
+ store: T;
24
+ /** Store identifier. */
25
+ id: string;
26
+ /** Read-only snapshot of all signal values. */
27
+ readonly state: Record<string, unknown>;
28
+ /** Batch-update multiple signals (object form) or direct access (function form). */
29
+ patch(partialState: Record<string, unknown>): void;
30
+ patch(fn: (state: Record<string, any>) => void): void;
31
+ /** Subscribe to state mutations. Returns an unsubscribe function. */
32
+ subscribe(callback: SubscribeCallback, options?: {
33
+ immediate?: boolean;
34
+ }): () => void;
35
+ /** Intercept action calls. Returns an unsubscribe function. */
36
+ onAction(callback: OnActionCallback): () => void;
37
+ /** Reset all signals to their initial values. */
38
+ reset(): void;
39
+ /** Teardown: unsubscribe all listeners and remove from registry. */
40
+ dispose(): void;
41
+ }
42
+ //#endregion
43
+ //#region src/devtools.d.ts
44
+ /**
45
+ * @pyreon/store devtools introspection API.
46
+ * Import: `import { ... } from "@pyreon/store/devtools"`
47
+ */
48
+ /** @internal — called by defineStore/resetStore to notify devtools. */
49
+ declare function _notifyChange(): void;
50
+ /** Get all registered store IDs. */
51
+ declare function getRegisteredStores(): string[];
52
+ /** Get a store API by ID (or undefined if not registered). */
53
+ declare function getStoreById(id: string): StoreApi<Record<string, unknown>> | undefined;
54
+ /** Subscribe to store registry changes (store added/removed). Returns unsubscribe. */
55
+ declare function onStoreChange(listener: () => void): () => void;
56
+ //#endregion
57
+ export { _notifyChange, getRegisteredStores, getStoreById, onStoreChange };
58
+ //# sourceMappingURL=devtools2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools2.d.ts","names":[],"sources":["../../src/index.ts","../../src/devtools.ts"],"mappings":";UAoCiB,YAAA;EACf,OAAA;EACA,IAAA;EACA,MAAA;IAAU,GAAA;IAAa,QAAA;IAAmB,QAAA;EAAA;AAAA;AAAA,KAGhC,iBAAA,IACV,QAAA,EAAU,YAAA,EACV,KAAA,EAAO,MAAA;AAAA,UAGQ,aAAA;EACf,IAAA;EACA,OAAA;EACA,IAAA;EACA,KAAA,GAAQ,EAAA,GAAK,MAAA;EACb,OAAA,GAAU,EAAA,GAAK,KAAA;AAAA;AAAA,KAGL,gBAAA,IAAoB,OAAA,EAAS,aAAA;;UAKxB,QAAA;EAMC;EAJhB,KAAA,EAAO,CAAA;EAOW;EALlB,EAAA;EAYmB;EAAA,SAVV,KAAA,EAAO,MAAA;EAUmB;EARnC,KAAA,CAAM,YAAA,EAAc,MAAA;EACpB,KAAA,CAAM,EAAA,GAAK,KAAA,EAAO,MAAA;EAPX;EASP,SAAA,CACE,QAAA,EAAU,iBAAA,EACV,OAAA;IAAY,SAAA;EAAA;EALd;EAQA,QAAA,CAAS,QAAA,EAAU,gBAAA;EARb;EAUN,KAAA;EATkB;EAWlB,OAAA;AAAA;;;;;;AA5CF;;iBC1BgB,aAAA,CAAA;;iBAKA,mBAAA,CAAA;;iBAKA,YAAA,CACd,EAAA,WACkC,QAAA,CAAN,MAAA;;iBAOd,aAAA,CAAc,QAAA"}
@@ -0,0 +1,222 @@
1
+ import { batch, batch as batch$1, computed, effect, signal } from "@pyreon/reactivity";
2
+
3
+ //#region src/registry.ts
4
+
5
+ /**
6
+ * Override the store registry provider.
7
+ * Called by @pyreon/runtime-server to inject a per-request isolated registry,
8
+ * preventing store state from leaking between concurrent SSR requests.
9
+ *
10
+ * @example
11
+ * import { AsyncLocalStorage } from "node:async_hooks"
12
+ * const als = new AsyncLocalStorage<Map<string, unknown>>()
13
+ * setRegistryProvider(() => als.getStore() ?? new Map())
14
+ * // Then wrap each request: als.run(new Map(), () => renderToString(app))
15
+ */
16
+ function setRegistryProvider(fn) {
17
+ _registryProvider = fn;
18
+ }
19
+ function getRegistry() {
20
+ return _registryProvider();
21
+ }
22
+
23
+ //#endregion
24
+ //#region src/devtools.ts
25
+
26
+ /** @internal — called by defineStore/resetStore to notify devtools. */
27
+ function _notifyChange() {
28
+ for (const listener of _listeners) listener();
29
+ }
30
+
31
+ //#endregion
32
+ //#region src/index.ts
33
+ function isSignalLike(v) {
34
+ if (typeof v !== "function") return false;
35
+ const fn = v;
36
+ return typeof fn.set === "function" && typeof fn.peek === "function";
37
+ }
38
+ function isComputedLike(v) {
39
+ if (typeof v !== "function") return false;
40
+ return typeof v.dispose === "function" && !isSignalLike(v);
41
+ }
42
+ /** Register a global store plugin. Plugins run when a store is first created. */
43
+ function addStorePlugin(plugin) {
44
+ _plugins.push(plugin);
45
+ }
46
+ /**
47
+ * Define a store with a unique id and a setup function.
48
+ * Returns a hook that returns a `StoreApi<T>` with the user's state under `.store`
49
+ * and framework methods (`patch`, `subscribe`, `onAction`, `reset`, `dispose`) at the top level.
50
+ */
51
+ function defineStore(id, setup) {
52
+ return function useStore() {
53
+ const registry = getRegistry();
54
+ if (registry.has(id)) return registry.get(id);
55
+ const raw = setup();
56
+ const signalKeys = [];
57
+ const actionKeys = [];
58
+ const initialValues = /* @__PURE__ */new Map();
59
+ for (const key of Object.keys(raw)) {
60
+ const val = raw[key];
61
+ if (isSignalLike(val)) {
62
+ signalKeys.push(key);
63
+ initialValues.set(key, val.peek());
64
+ } else if (isComputedLike(val)) {} else if (typeof val === "function") actionKeys.push(key);
65
+ }
66
+ const subscribers = /* @__PURE__ */new Set();
67
+ let patchInProgress = false;
68
+ let patchEvents = [];
69
+ function getState() {
70
+ const state = {};
71
+ for (const key of signalKeys) state[key] = raw[key].peek();
72
+ return state;
73
+ }
74
+ function notifyDirect(key, oldValue, newValue) {
75
+ if (patchInProgress) {
76
+ patchEvents.push({
77
+ key,
78
+ newValue,
79
+ oldValue
80
+ });
81
+ return;
82
+ }
83
+ if (subscribers.size === 0) return;
84
+ const mutation = {
85
+ storeId: id,
86
+ type: "direct",
87
+ events: [{
88
+ key,
89
+ newValue,
90
+ oldValue
91
+ }]
92
+ };
93
+ const state = getState();
94
+ for (const cb of subscribers) cb(mutation, state);
95
+ }
96
+ const signalUnsubs = [];
97
+ for (const key of signalKeys) {
98
+ const sig = raw[key];
99
+ let prev = sig.peek();
100
+ const unsub = sig.subscribe(() => {
101
+ const next = sig.peek();
102
+ const old = prev;
103
+ prev = next;
104
+ notifyDirect(key, old, next);
105
+ });
106
+ signalUnsubs.push(unsub);
107
+ }
108
+ const actionListeners = /* @__PURE__ */new Set();
109
+ function wrapAction(key, original) {
110
+ return (...args) => {
111
+ const afterCbs = [];
112
+ const errorCbs = [];
113
+ const context = {
114
+ name: key,
115
+ storeId: id,
116
+ args,
117
+ after: cb => afterCbs.push(cb),
118
+ onError: cb => errorCbs.push(cb)
119
+ };
120
+ for (const listener of actionListeners) listener(context);
121
+ try {
122
+ const result = original(...args);
123
+ if (result != null && typeof result.then === "function") return result.then(resolved => {
124
+ for (const cb of afterCbs) cb(resolved);
125
+ return resolved;
126
+ }, err => {
127
+ for (const cb of errorCbs) cb(err);
128
+ throw err;
129
+ });
130
+ for (const cb of afterCbs) cb(result);
131
+ return result;
132
+ } catch (err) {
133
+ for (const cb of errorCbs) cb(err);
134
+ throw err;
135
+ }
136
+ };
137
+ }
138
+ const userStore = {};
139
+ for (const key of Object.keys(raw)) if (actionKeys.includes(key)) userStore[key] = wrapAction(key, raw[key]);else userStore[key] = raw[key];
140
+ const api = {
141
+ store: userStore,
142
+ id,
143
+ get state() {
144
+ return getState();
145
+ },
146
+ patch(partialOrFn) {
147
+ patchInProgress = true;
148
+ patchEvents = [];
149
+ batch$1(() => {
150
+ if (typeof partialOrFn === "function") {
151
+ const signalMap = {};
152
+ for (const key of signalKeys) signalMap[key] = raw[key];
153
+ partialOrFn(signalMap);
154
+ } else for (const [key, value] of Object.entries(partialOrFn)) {
155
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
156
+ if (signalKeys.includes(key)) raw[key].set(value);
157
+ }
158
+ });
159
+ patchInProgress = false;
160
+ if (subscribers.size > 0 && patchEvents.length > 0) {
161
+ const mutation = {
162
+ storeId: id,
163
+ type: "patch",
164
+ events: patchEvents
165
+ };
166
+ const state = getState();
167
+ for (const cb of subscribers) cb(mutation, state);
168
+ }
169
+ patchEvents = [];
170
+ },
171
+ subscribe(callback, options) {
172
+ subscribers.add(callback);
173
+ if (options?.immediate) callback({
174
+ storeId: id,
175
+ type: "direct",
176
+ events: []
177
+ }, getState());
178
+ return () => {
179
+ subscribers.delete(callback);
180
+ };
181
+ },
182
+ onAction(callback) {
183
+ actionListeners.add(callback);
184
+ return () => {
185
+ actionListeners.delete(callback);
186
+ };
187
+ },
188
+ reset() {
189
+ batch$1(() => {
190
+ for (const [key, initial] of initialValues) raw[key].set(initial);
191
+ });
192
+ },
193
+ dispose() {
194
+ for (const unsub of signalUnsubs) unsub();
195
+ signalUnsubs.length = 0;
196
+ subscribers.clear();
197
+ actionListeners.clear();
198
+ getRegistry().delete(id);
199
+ }
200
+ };
201
+ for (const plugin of _plugins) try {
202
+ plugin(api);
203
+ } catch (_err) {}
204
+ registry.set(id, api);
205
+ _notifyChange();
206
+ return api;
207
+ };
208
+ }
209
+ /** Destroy a store by id so next call to useStore() re-runs setup. */
210
+ function resetStore(id) {
211
+ getRegistry().delete(id);
212
+ _notifyChange();
213
+ }
214
+ /** Destroy all stores — useful for SSR isolation and tests. */
215
+ function resetAllStores() {
216
+ getRegistry().clear();
217
+ _notifyChange();
218
+ }
219
+
220
+ //#endregion
221
+ export { addStorePlugin, batch, computed, defineStore, effect, resetAllStores, resetStore, setRegistryProvider as setStoreRegistryProvider, signal };
222
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/registry.ts","../../src/devtools.ts","../../src/index.ts"],"mappings":";;;;;;;;;;;;;;;AAmBA,SAAgB,mBAAA,CAAoB,EAAA,EAAsC;EACxE,iBAAA,GAAoB,EAAA;;AAGtB,SAAgB,WAAA,CAAA,EAAoC;EAClD,OAAO,iBAAA,CAAA,CAAmB;;;;;;;ACd5B,SAAgB,aAAA,CAAA,EAAsB;EACpC,KAAK,MAAM,QAAA,IAAY,UAAA,EAAY,QAAA,CAAA,CAAU;;;;;ACkF/C,SAAS,YAAA,CAAa,CAAA,EAA6B;EACjD,IAAI,OAAO,CAAA,KAAM,UAAA,EAAY,OAAO,KAAA;EACpC,MAAM,EAAA,GAAK,CAAA;EACX,OAAO,OAAO,EAAA,CAAG,GAAA,KAAQ,UAAA,IAAc,OAAO,EAAA,CAAG,IAAA,KAAS,UAAA;;AAG5D,SAAS,cAAA,CAAe,CAAA,EAAqB;EAC3C,IAAI,OAAO,CAAA,KAAM,UAAA,EAAY,OAAO,KAAA;EAEpC,OAAO,OADI,CAAA,CACM,OAAA,KAAY,UAAA,IAAc,CAAC,YAAA,CAAa,CAAA,CAAE;;;AAQ7D,SAAgB,cAAA,CAAe,MAAA,EAA2B;EACxD,QAAA,CAAS,IAAA,CAAK,MAAA,CAAO;;;;;;;AAUvB,SAAgB,WAAA,CACd,EAAA,EACA,KAAA,EACmB;EACnB,OAAO,SAAS,QAAA,CAAA,EAAwB;IACtC,MAAM,QAAA,GAAW,WAAA,CAAA,CAAa;IAC9B,IAAI,QAAA,CAAS,GAAA,CAAI,EAAA,CAAG,EAAE,OAAO,QAAA,CAAS,GAAA,CAAI,EAAA,CAAG;IAE7C,MAAM,GAAA,GAAM,KAAA,CAAA,CAAO;IAGnB,MAAM,UAAA,GAAuB,EAAE;IAC/B,MAAM,UAAA,GAAuB,EAAE;IAC/B,MAAM,aAAA,GAAA,eAAgB,IAAI,GAAA,CAAA,CAAsB;IAEhD,KAAK,MAAM,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,EAAE;MAClC,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,CAAA;MAChB,IAAI,YAAA,CAAa,GAAA,CAAI,EAAE;QACrB,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI;QACpB,aAAA,CAAc,GAAA,CAAI,GAAA,EAAK,GAAA,CAAI,IAAA,CAAA,CAAM,CAAC;iBACzB,cAAA,CAAe,GAAA,CAAI,EAAE,CAAA,CAAA,MAAA,IAErB,OAAO,GAAA,KAAQ,UAAA,EACxB,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI;;IAKxB,MAAM,WAAA,GAAA,eAAc,IAAI,GAAA,CAAA,CAAwB;IAChD,IAAI,eAAA,GAAkB,KAAA;IACtB,IAAI,WAAA,GAAsC,EAAE;IAE5C,SAAS,QAAA,CAAA,EAAoC;MAC3C,MAAM,KAAA,GAAiC,CAAA,CAAE;MACzC,KAAK,MAAM,GAAA,IAAO,UAAA,EAChB,KAAA,CAAM,GAAA,CAAA,GAAQ,GAAA,CAAI,GAAA,CAAA,CAAa,IAAA,CAAA,CAAM;MAEvC,OAAO,KAAA;;IAGT,SAAS,YAAA,CAAa,GAAA,EAAa,QAAA,EAAmB,QAAA,EAAmB;MACvE,IAAI,eAAA,EAAiB;QACnB,WAAA,CAAY,IAAA,CAAK;UAAE,GAAA;UAAK,QAAA;UAAU;SAAU,CAAC;QAC7C;;MAEF,IAAI,WAAA,CAAY,IAAA,KAAS,CAAA,EAAG;MAC5B,MAAM,QAAA,GAAyB;QAC7B,OAAA,EAAS,EAAA;QACT,IAAA,EAAM,QAAA;QACN,MAAA,EAAQ,CAAC;UAAE,GAAA;UAAK,QAAA;UAAU;SAAU;OACrC;MACD,MAAM,KAAA,GAAQ,QAAA,CAAA,CAAU;MACxB,KAAK,MAAM,EAAA,IAAM,WAAA,EAAa,EAAA,CAAG,QAAA,EAAU,KAAA,CAAM;;IAInD,MAAM,YAAA,GAA+B,EAAE;IACvC,KAAK,MAAM,GAAA,IAAO,UAAA,EAAY;MAC5B,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,CAAA;MAChB,IAAI,IAAA,GAAO,GAAA,CAAI,IAAA,CAAA,CAAM;MACrB,MAAM,KAAA,GAAQ,GAAA,CAAI,SAAA,CAAA,MAAgB;QAChC,MAAM,IAAA,GAAO,GAAA,CAAI,IAAA,CAAA,CAAM;QACvB,MAAM,GAAA,GAAM,IAAA;QACZ,IAAA,GAAO,IAAA;QACP,YAAA,CAAa,GAAA,EAAK,GAAA,EAAK,IAAA,CAAK;QAC5B;MACF,YAAA,CAAa,IAAA,CAAK,KAAA,CAAM;;IAI1B,MAAM,eAAA,GAAA,eAAkB,IAAI,GAAA,CAAA,CAAuB;IAGnD,SAAS,UAAA,CAAW,GAAA,EAAa,QAAA,EAAuC;MACtE,OAAA,CAAQ,GAAG,IAAA,KAAoB;QAC7B,MAAM,QAAA,GAA0C,EAAE;QAClD,MAAM,QAAA,GAAyC,EAAE;QAEjD,MAAM,OAAA,GAAyB;UAC7B,IAAA,EAAM,GAAA;UACN,OAAA,EAAS,EAAA;UACT,IAAA;UACA,KAAA,EAAQ,EAAA,IAAO,QAAA,CAAS,IAAA,CAAK,EAAA,CAAG;UAChC,OAAA,EAAU,EAAA,IAAO,QAAA,CAAS,IAAA,CAAK,EAAA;SAChC;QAED,KAAK,MAAM,QAAA,IAAY,eAAA,EACrB,QAAA,CAAS,OAAA,CAAQ;QAGnB,IAAI;UACF,MAAM,MAAA,GAAS,QAAA,CAAS,GAAG,IAAA,CAAK;UAIhC,IAAI,MAAA,IAAU,IAAA,IAAQ,OAAQ,MAAA,CAAe,IAAA,KAAS,UAAA,EACpD,OAAQ,MAAA,CAA4B,IAAA,CACjC,QAAA,IAAa;YACZ,KAAK,MAAM,EAAA,IAAM,QAAA,EAAU,EAAA,CAAG,QAAA,CAAS;YACvC,OAAO,QAAA;aAER,GAAA,IAAQ;YACP,KAAK,MAAM,EAAA,IAAM,QAAA,EAAU,EAAA,CAAG,GAAA,CAAI;YAClC,MAAM,GAAA;YAET;UAGH,KAAK,MAAM,EAAA,IAAM,QAAA,EAAU,EAAA,CAAG,MAAA,CAAO;UACrC,OAAO,MAAA;iBACA,GAAA,EAAK;UACZ,KAAK,MAAM,EAAA,IAAM,QAAA,EAAU,EAAA,CAAG,GAAA,CAAI;UAClC,MAAM,GAAA;;;;IAMZ,MAAM,SAAA,GAAqC,CAAA,CAAE;IAE7C,KAAK,MAAM,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,EAChC,IAAI,UAAA,CAAW,QAAA,CAAS,GAAA,CAAI,EAC1B,SAAA,CAAU,GAAA,CAAA,GAAO,UAAA,CACf,GAAA,EACA,GAAA,CAAI,GAAA,CAAA,CACL,CAAA,KAED,SAAA,CAAU,GAAA,CAAA,GAAO,GAAA,CAAI,GAAA,CAAA;IAKzB,MAAM,GAAA,GAAmB;MACvB,KAAA,EAAO,SAAA;MAEP,EAAA;MAEA,IAAI,KAAA,CAAA,EAAQ;QACV,OAAO,QAAA,CAAA,CAAU;;MAGnB,KAAA,CACE,WAAA,EAGA;QACA,eAAA,GAAkB,IAAA;QAClB,WAAA,GAAc,EAAE;QAEhB,OAAA,CAAA,MAAY;UACV,IAAI,OAAO,WAAA,KAAgB,UAAA,EAAY;YAErC,MAAM,SAAA,GAAiC,CAAA,CAAE;YACzC,KAAK,MAAM,GAAA,IAAO,UAAA,EAChB,SAAA,CAAU,GAAA,CAAA,GAAO,GAAA,CAAI,GAAA,CAAA;YAEvB,WAAA,CAAY,SAAA,CAAU;iBAGtB,KAAK,MAAM,CAAC,GAAA,EAAK,KAAA,CAAA,IAAU,MAAA,CAAO,OAAA,CAAQ,WAAA,CAAY,EAAE;YACtD,IACE,GAAA,KAAQ,WAAA,IACR,GAAA,KAAQ,aAAA,IACR,GAAA,KAAQ,WAAA,EAER;YACF,IAAI,UAAA,CAAW,QAAA,CAAS,GAAA,CAAI,EACxB,GAAA,CAAI,GAAA,CAAA,CAAoB,GAAA,CAAI,KAAA,CAAM;;UAI1C;QAEF,eAAA,GAAkB,KAAA;QAGlB,IAAI,WAAA,CAAY,IAAA,GAAO,CAAA,IAAK,WAAA,CAAY,MAAA,GAAS,CAAA,EAAG;UAClD,MAAM,QAAA,GAAyB;YAC7B,OAAA,EAAS,EAAA;YACT,IAAA,EAAM,OAAA;YACN,MAAA,EAAQ;WACT;UACD,MAAM,KAAA,GAAQ,QAAA,CAAA,CAAU;UACxB,KAAK,MAAM,EAAA,IAAM,WAAA,EAAa,EAAA,CAAG,QAAA,EAAU,KAAA,CAAM;;QAEnD,WAAA,GAAc,EAAE;;MAGlB,SAAA,CACE,QAAA,EACA,OAAA,EACY;QACZ,WAAA,CAAY,GAAA,CAAI,QAAA,CAAS;QACzB,IAAI,OAAA,EAAS,SAAA,EAMX,QAAA,CAL+B;UAC7B,OAAA,EAAS,EAAA;UACT,IAAA,EAAM,QAAA;UACN,MAAA,EAAQ;SACT,EACkB,QAAA,CAAA,CAAU,CAAC;QAEhC,OAAA,MAAa;UACX,WAAA,CAAY,MAAA,CAAO,QAAA,CAAS;;;MAIhC,QAAA,CAAS,QAAA,EAAwC;QAC/C,eAAA,CAAgB,GAAA,CAAI,QAAA,CAAS;QAC7B,OAAA,MAAa;UACX,eAAA,CAAgB,MAAA,CAAO,QAAA,CAAS;;;MAIpC,KAAA,CAAA,EAAQ;QACN,OAAA,CAAA,MAAY;UACV,KAAK,MAAM,CAAC,GAAA,EAAK,OAAA,CAAA,IAAY,aAAA,EACzB,GAAA,CAAI,GAAA,CAAA,CAAa,GAAA,CAAI,OAAA,CAAQ;UAEjC;;MAGJ,OAAA,CAAA,EAAU;QACR,KAAK,MAAM,KAAA,IAAS,YAAA,EAAc,KAAA,CAAA,CAAO;QACzC,YAAA,CAAa,MAAA,GAAS,CAAA;QACtB,WAAA,CAAY,KAAA,CAAA,CAAO;QACnB,eAAA,CAAgB,KAAA,CAAA,CAAO;QACvB,WAAA,CAAA,CAAa,CAAC,MAAA,CAAO,EAAA,CAAG;;KAE3B;IAGD,KAAK,MAAM,MAAA,IAAU,QAAA,EACnB,IAAI;MACF,MAAA,CAAO,GAAA,CAAyC;aACzC,IAAA,EAAM,CAAA;IAKjB,QAAA,CAAS,GAAA,CAAI,EAAA,EAAI,GAAA,CAAI;IACrB,aAAA,CAAA,CAAe;IACf,OAAO,GAAA;;;;AAOX,SAAgB,UAAA,CAAW,EAAA,EAAkB;EAC3C,WAAA,CAAA,CAAa,CAAC,MAAA,CAAO,EAAA,CAAG;EACxB,aAAA,CAAA,CAAe;;;AAIjB,SAAgB,cAAA,CAAA,EAAuB;EACrC,WAAA,CAAA,CAAa,CAAC,KAAA,CAAA,CAAO;EACrB,aAAA,CAAA,CAAe"}