@warp-drive-mirror/experiments 5.10.0-alpha.1 → 5.10.0-alpha.3

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.
@@ -3,7 +3,7 @@ import { n as RequestEventData, t as AbortEventData } from "./types-CRs-Qww6.js"
3
3
  import { CacheHandler as CacheHandler$1, Future } from "@warp-drive-mirror/core/request";
4
4
  import { Store } from "@warp-drive-mirror/core";
5
5
  //#region src/data-worker/worker.d.ts
6
- declare class DataWorker {
6
+ export declare class DataWorker {
7
7
  store: Store;
8
8
  threads: Map<string, MessagePort>;
9
9
  pending: Map<string, Map<number, Future<unknown>>>;
@@ -29,7 +29,6 @@ declare class DataWorker {
29
29
  * with their referenced resources.
30
30
  *
31
31
  */
32
- declare const CacheHandler: CacheHandler$1;
32
+ export declare const CacheHandler: CacheHandler$1;
33
33
  //#endregion
34
- export { CacheHandler, DataWorker };
35
34
  //# sourceMappingURL=data-worker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-worker.d.ts","names":[],"sources":["../src/data-worker/worker.ts","../src/data-worker/cache-handler.ts"],"mappings":";;;;;cASa;EACX,OAAe;EACf,SAAiB,YAAY;EAC7B,SAAiB,YAAY,YAAY;EACzC;EACA;IAAmB;IAAoB;;EACvC,SAAiB;EAEjB,YAAY,kBAAkB,OAAO;IAAY;IAAoB;;EAarE;EAkCA,YAAY,gBAAgB,MAAM;EAqBlC,aAAa,OAAO;EAUpB,QAAc,OAAO,mBAAmB;;;;;;;;;cCnE7B,cAAc"}
1
+ {"version":3,"file":"data-worker.d.ts","names":[],"sources":["../src/data-worker/worker.ts","../src/data-worker/cache-handler.ts"],"mappings":";;;;;qBASa;EACX,OAAe;EACf,SAAiB,YAAY;EAC7B,SAAiB,YAAY,YAAY;EACzC;EACA;IAAmB;IAAoB;;EACvC,SAAiB;EAEjB,YAAY,kBAAkB,OAAO;IAAY;IAAoB;;EAarE;EAkCA,YAAY,gBAAgB,MAAM;EAqBlC,aAAa,OAAO;EAUpB,QAAc,OAAO,mBAAmB;;;;;;;;;qBCnE7B,cAAc"}
@@ -21,7 +21,7 @@ type RequestEventData = {
21
21
  *
22
22
  * @public
23
23
  */
24
- declare class ImageFetch {
24
+ export declare class ImageFetch {
25
25
  worker: Worker | SharedWorker;
26
26
  threadId: string;
27
27
  pending: Map<string, Deferred<string>>;
@@ -56,5 +56,4 @@ declare class ImageFetch {
56
56
  load(url: string): Promise<string>;
57
57
  }
58
58
  //#endregion
59
- export { ImageFetch };
60
59
  //# sourceMappingURL=image-fetch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-fetch.d.ts","names":[],"sources":["../src/image-worker/types.ts","../src/image-worker/fetch.ts"],"mappings":";;;KA8BY;EACV;EACA;EACA;;;;;;;;;;;;;;;;;cCFW;EACX,QAAgB,SAAS;EACzB;EACA,SAAiB,YAAY;EAC7B,SAAiB;EACjB,OAAe;;;;;;EAOf,YAAY,QAAQ,SAAS;EA0C7B,eAAe,cAAc;EAO7B,MAAM,OAAO;;;;;;;;;;;;;;;;;;;EAuBb,KAAK,cAAc"}
1
+ {"version":3,"file":"image-fetch.d.ts","names":[],"sources":["../src/image-worker/types.ts","../src/image-worker/fetch.ts"],"mappings":";;;KA8BY;EACV;EACA;EACA;;;;;;;;;;;;;;;;;qBCFW;EACX,QAAgB,SAAS;EACzB;EACA,SAAiB,YAAY;EAC7B,SAAiB;EACjB,OAAe;;;;;;EAOf,YAAY,QAAQ,SAAS;EA0C7B,eAAe,cAAc;EAO7B,MAAM,OAAO;;;;;;;;;;;;;;;;;;;EAuBb,KAAK,cAAc"}
@@ -18,7 +18,7 @@
18
18
  *
19
19
  * @public
20
20
  */
21
- declare class ImageWorker {
21
+ export declare class ImageWorker {
22
22
  private threads;
23
23
  private pendingImages;
24
24
  private options;
@@ -36,5 +36,4 @@ declare class ImageWorker {
36
36
  private request;
37
37
  }
38
38
  //#endregion
39
- export { ImageWorker };
40
39
  //# sourceMappingURL=image-worker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-worker.d.ts","names":[],"sources":["../src/image-worker/worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;cA+Ba;UACK;UACA;UACA;UACA;UACA;;;;EAKhB,YAAY;IAAY;;UAahB;UAsBA;UA4BA;UAiBM"}
1
+ {"version":3,"file":"image-worker.d.ts","names":[],"sources":["../src/image-worker/worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;qBA+Ba;UACK;UACA;UACA;UACA;UACA;;;;EAKhB,YAAY;IAAY;;UAahB;UAsBA;UA4BA;UAiBM"}
package/dist/storage.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  //#region src/storage/cache.d.ts
2
- declare const DEFAULT_CACHE_ID = "reactive-cache";
3
- interface InternalCacheStorageEvent {
2
+ export declare const DEFAULT_CACHE_ID = "reactive-cache";
3
+ export interface InternalCacheStorageEvent {
4
4
  storageArea: string;
5
5
  key: string | null;
6
6
  oldValue: string | null;
7
7
  newValue: string | null;
8
8
  }
9
- interface CacheStorageEvent {
9
+ export interface CacheStorageEvent {
10
10
  storageArea: CacheStorage;
11
11
  key: string | null;
12
12
  oldValue: string | null;
@@ -18,7 +18,7 @@ interface CacheStorageEvent {
18
18
  * This is a good option for larger data sets than can be efficiently stored in localStorage
19
19
  * but should not be used as a permanent DB or storage solution.
20
20
  */
21
- declare class CacheStorage implements Storage {
21
+ export declare class CacheStorage implements Storage {
22
22
  #private;
23
23
  _data: Map<string, string | null>;
24
24
  _nextUpdate: number | null;
@@ -44,7 +44,7 @@ declare class CacheStorage implements Storage {
44
44
  }
45
45
  //#endregion
46
46
  //#region src/storage/storage.d.ts
47
- interface ReactiveStorageOptions {
47
+ export interface ReactiveStorageOptions {
48
48
  /**
49
49
  * If true, falls back to in-memory storage when the underlying
50
50
  * storage is unavailable (e.g., private browsing mode).
@@ -66,20 +66,39 @@ interface ReactiveStorageOptions {
66
66
  *
67
67
  * If the instance does not already exist, it is created.
68
68
  */
69
- declare function getLocalStorage(): ReactiveStorage;
70
- declare function getSessionStorage(): ReactiveStorage;
71
- declare function getCacheStorage(namespace?: string | null): ReactiveStorage;
69
+ export declare function getLocalStorage(): ReactiveStorage;
70
+ export declare function getSessionStorage(): ReactiveStorage;
71
+ export declare function getCacheStorage(namespace?: string | null): ReactiveStorage;
72
72
  /**
73
73
  * Configure options for the localStorage singleton.
74
74
  * Must be called before getLocalStorage() is first invoked.
75
75
  */
76
- declare function configureLocalStorage(options: ReactiveStorageOptions): void;
76
+ export declare function configureLocalStorage(options: ReactiveStorageOptions): void;
77
77
  /**
78
78
  * Configure options for the sessionStorage singleton.
79
79
  * Must be called before getSessionStorage() is first invoked.
80
80
  */
81
- declare function configureSessionStorage(options: ReactiveStorageOptions): void;
82
- type EffectStorageEvent = CacheStorageEvent | StorageEvent;
81
+ export declare function configureSessionStorage(options: ReactiveStorageOptions): void;
82
+ export type EffectStorageEvent = CacheStorageEvent | StorageEvent;
83
+ /**
84
+ * Subscribes to storage-change events, whether they originate from the
85
+ * native Storage API (a `StorageEvent`, fired cross-tab) or from
86
+ * {@link CacheStorage}'s own same-tab notifications (dispatched as a
87
+ * `CustomEvent` under the same 'storage' name — see `emitStorageEvent`
88
+ * in `./cache.ts`).
89
+ *
90
+ * Returns an unsubscribe function.
91
+ *
92
+ * This can't be expressed by widening the global `WindowEventMap.storage`
93
+ * type: that entry is inherited from `WindowEventHandlersEventMap` as
94
+ * `StorageEvent`, and a declaration-merged override has to stay assignable
95
+ * to the type it's overriding, not the other way around — deliberately
96
+ * reusing this event name for a wider union has no way to satisfy that.
97
+ *
98
+ * Route storage-event subscribers through this helper instead of calling
99
+ * `window.addEventListener('storage', ...)` directly.
100
+ */
101
+ export declare function onStorageEvent(listener: (event: EffectStorageEvent) => void): () => void;
83
102
  /**
84
103
  * A reactive wrapper around the Web Storage API (localStorage/sessionStorage)
85
104
  * that provides signal-based access to storage items and length.
@@ -126,11 +145,11 @@ declare class ReactiveStorage implements Storage {
126
145
  key(index: number): string | null;
127
146
  }
128
147
  //#endregion
129
- //#region src/storage/-private/storage-infra.d.ts
148
+ //#region src/storage/query-params.d.ts
130
149
  /**
131
150
  * Configuration options for fields that are also query parameters
132
151
  */
133
- interface ParamConfig {
152
+ export interface ParamConfig {
134
153
  /**
135
154
  * Convert a value into a string for storage in the URL.
136
155
  * `null` indicates the value should be omitted from the URL.
@@ -152,6 +171,64 @@ interface ParamConfig {
152
171
  */
153
172
  getDefault?: (instance: any) => unknown;
154
173
  }
174
+ /**
175
+ * Creates a {@link ParamConfig} for boolean fields that serialize to '1' or null.
176
+ *
177
+ * @returns ParamConfig for boolean fields
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * @param(BooleanParam())
182
+ * @field
183
+ * myFlag: boolean = false;
184
+ * ```
185
+ */
186
+ export declare function BooleanParam(): ParamConfig;
187
+ /**
188
+ * Creates a {@link ParamConfig} for numeric fields with default value checking.
189
+ *
190
+ * @param precision - When given, the number of digits to serialize after the decimal point
191
+ * @param getDefault - Function to get the default value for comparison
192
+ * @returns ParamConfig for number fields
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * @param(NumberParam(2, function (instance: MyClass) { return instance.defaultZoom; }))
197
+ * @field
198
+ * zoom: number = 12;
199
+ * ```
200
+ */
201
+ export declare function NumberParam(precision?: number, getDefault?: (instance: any) => number | undefined): ParamConfig;
202
+ /**
203
+ * Decorator which marks a field as a query parameter.
204
+ *
205
+ * This decorator only stores metadata - it does not change the property behavior.
206
+ * The field will operate as a normal `@field` until a router integration consumes it.
207
+ *
208
+ * The provided {@link ParamConfig} is used to:
209
+ * - Serialize values for the URL
210
+ * - Deserialize values from the URL
211
+ * - Compare URL and local values
212
+ * - Determine when to include/exclude params from the URL
213
+ *
214
+ * @param config - Configuration for URL serialization/deserialization
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * @SessionResource('map-state')
219
+ * class MapState {
220
+ * @param({
221
+ * serialize: (value: unknown) => (value ? '1' : null),
222
+ * deserialize: (urlValue: string) => urlValue === '1',
223
+ * })
224
+ * @field
225
+ * active: boolean = false;
226
+ * }
227
+ * ```
228
+ */
229
+ export declare function param(config: ParamConfig): PropertyDecorator;
230
+ //#endregion
231
+ //#region src/storage/-private/storage-infra.d.ts
155
232
  interface InternalParamConfig extends ParamConfig {
156
233
  initialized?: boolean;
157
234
  }
@@ -192,6 +269,7 @@ type KeyFn = (obj: any) => string;
192
269
  * @private
193
270
  */
194
271
  declare function initMeta(target: object): StorageResourceMeta;
272
+ declare function initializeFields(instance: object, source: object): void;
195
273
  /**
196
274
  * Get or create the param companion object for a StorageResource instance.
197
275
  *
@@ -227,7 +305,7 @@ declare function getParamCompanion(instance: object, groupControlMap?: Record<st
227
305
  * The function will be called once per instance during
228
306
  * initialization to determine the unique ID for that instance.
229
307
  */
230
- declare function LocalResource(id: string | KeyFn): ClassDecorator;
308
+ export declare function LocalResource(id: string | KeyFn): ClassDecorator;
231
309
  /**
232
310
  * Decorator which transforms a class into a StorageResource
233
311
  * persisted in sessionStorage.
@@ -242,7 +320,7 @@ declare function LocalResource(id: string | KeyFn): ClassDecorator;
242
320
  * The function will be called once per instance during
243
321
  * initialization to determine the unique ID for that instance.
244
322
  */
245
- declare function SessionResource(id: string | KeyFn): ClassDecorator;
323
+ export declare function SessionResource(id: string | KeyFn): ClassDecorator;
246
324
  /**
247
325
  * Decorator which transforms a class into a StorageResource
248
326
  * persisted via the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache).
@@ -262,7 +340,7 @@ declare function SessionResource(id: string | KeyFn): ClassDecorator;
262
340
  * so partitioning can be achieved by using different namespaces for different groups
263
341
  * of data.
264
342
  */
265
- declare function CacheResource(id: string | KeyFn, namespace?: string | null): ClassDecorator;
343
+ export declare function CacheResource(id: string | KeyFn, namespace?: string | null): ClassDecorator;
266
344
  /**
267
345
  * Decorator which marks a property as a field on
268
346
  * a LocalResource or SessionResource
@@ -294,9 +372,9 @@ declare function CacheResource(id: string | KeyFn, namespace?: string | null): C
294
372
  * ```
295
373
  *
296
374
  */
297
- declare function field(type: "local" | "session" | "cache"): PropertyDecorator;
298
- declare function field(target: object, key: string, descriptor?: PropertyDescriptor): void;
299
- declare function input(type: "number" | "boolean" | "float"): PropertyDecorator;
375
+ export declare function field(type: "local" | "session" | "cache"): PropertyDecorator;
376
+ export declare function field(target: object, key: string, descriptor?: PropertyDescriptor): void;
377
+ export declare function input(type: "number" | "boolean" | "float"): PropertyDecorator;
300
378
  /**
301
379
  * Effects are fields that run a side-effecting function.
302
380
  *
@@ -348,7 +426,7 @@ declare function input(type: "number" | "boolean" | "float"): PropertyDecorator;
348
426
  * }
349
427
  * ```
350
428
  */
351
- declare function effect(fn: <K>(update: ValueTransition<K>) => void, type?: "local" | "session"): PropertyDecorator;
429
+ export declare function effect(fn: <K>(update: ValueTransition<K>) => void, type?: "local" | "session"): PropertyDecorator;
352
430
  //#endregion
353
- export { CacheResource, CacheStorage, CacheStorageEvent, DEFAULT_CACHE_ID, EffectStorageEvent, InternalCacheStorageEvent, LocalResource, type ReactiveStorage, ReactiveStorageOptions, SessionResource, getParamCompanion as _getParamCompanion, initMeta as _initMeta, configureLocalStorage, configureSessionStorage, effect, field, getCacheStorage, getLocalStorage, getSessionStorage, input };
431
+ export { type KeyFn, type ReactiveStorage, type ValueTransition, getParamCompanion as _getParamCompanion, initMeta as _initMeta, initializeFields as _initializeFields };
354
432
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","names":[],"sources":["../src/storage/cache.ts","../src/storage/storage.ts","../src/storage/-private/storage-infra.ts","../src/storage/storage-resource.ts"],"mappings":";cAEa;UAKI;EACf;EACA;EACA;EACA;;UAEe;EACf,aAAa;EACb;EACA;EACA;;;;;;;;cAkEW,wBAAwB;;EAInC,OAAO;EACP;EACA,iBAAiB;EAYjB,YAAY;MAMR;EA4BJ;EAKA,QAAQ;EAIR,IAAI;EAgBJ,WAAW;EAQX,QAAQ,aAAa;;;;;SAed,IAAI,mBAAqC,QAAQ;SASjD,YAAY,mBAAqC;;;;;SAYjD;;;;UCtMQ;;;;;EAKf;;;;;EAMA;;;;;EAMA,mBAAmB,aAAa,4BAA4B;;;;;;;iBAgB9C,mBAAmB;iBAOnB,qBAAqB;iBAQrB,gBAAgB,4BAAkC;;;;;iBAelD,sBAAsB,SAAS;;;;;iBAQ/B,wBAAwB,SAAS;KA8BrC,qBAAqB,oBAAoB;;;;;;;cAQ/C,2BAA2B;UACvB;UACA;UACA;UACA;UAEQ;UACA;UAER;EACR,UAAU,aAAa,KAAK,OAAO;EAKnC,YAAY,SAAS,SAAS,UAAS;;;;MA2CnC;;;;EAOJ,SAAS;;;;EAsBT,QAAQ;;;;EAyBR,QAAQ,aAAa;;;;EA2DrB,WAAW;;;;EAsBX;;;;EAeA,IAAI;;;;;;;UC3TW;;;;;EAMf,YAAY,gBAAgB;;;;;EAM5B,cAAc,kBAAkB;;;;;;;;;;EAWhC,cAAc;;UAGN,4BAA4B;EACpC;;UAGe,gBAAgB;EAC/B;EACA,MAAM;EACN,IAAI;;;;;UAMW;EACf;EACA;EACA,MAAM;EACN;EACA,eAAe;EACf,QAAQ,qBAAqB,QAAQ;EACrC,cAAc;EACd,cAAc,YAAY;EAC1B;EACA,WAAW,gBAAgB;;;;;;;;;;;KAajB,SAAS;;;;;;;iBAaL,SAAS,iBAAiB;;;;;;;;;;;;;;;;;;;iBAkT1B,kBAAkB,kBAAkB,kBAAkB;;;;;;;;;;;;;;;;;iBCzWtD,cAAc,aAAa,QAAQ;;;;;;;;;;;;;;;iBAkBnC,gBAAgB,aAAa,QAAQ;;;;;;;;;;;;;;;;;;;;iBAuBrC,cAAc,aAAa,OAAO,4BAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCpE,MAAM,sCAAsC;iBAC5C,MAAM,gBAAgB,aAAa,aAAa;iBAgBhD,MAAM,uCAAuC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoF7C,OAAO,KAAK,GAAG,QAAQ,gBAAgB,aAAa,6BAA6B"}
1
+ {"version":3,"file":"storage.d.ts","names":[],"sources":["../src/storage/cache.ts","../src/storage/storage.ts","../src/storage/query-params.ts","../src/storage/-private/storage-infra.ts","../src/storage/storage-resource.ts"],"mappings":";qBAEa;iBAKI;EACf;EACA;EACA;EACA;;iBAEe;EACf,aAAa;EACb;EACA;EACA;;;;;;;;qBAkEW,wBAAwB;;EAInC,OAAO;EACP;EACA,iBAAiB;EAYjB,YAAY;MAMR;EA4BJ;EAKA,QAAQ;EAIR,IAAI;EAgBJ,WAAW;EAQX,QAAQ,aAAa;;;;;SAed,IAAI,mBAAqC,QAAQ;SASjD,YAAY,mBAAqC;;;;;SAYjD;;;;iBCtMQ;;;;;EAKf;;;;;EAMA;;;;;EAMA,mBAAmB,aAAa,4BAA4B;;;;;;;wBAgB9C,mBAAmB;wBAOnB,qBAAqB;wBAQrB,gBAAgB,4BAAkC;;;;;wBAelD,sBAAsB,SAAS;;;;;wBAQ/B,wBAAwB,SAAS;YA8BrC,qBAAqB,oBAAoB;;;;;;;;;;;;;;;;;;;wBAoBrC,eAAe,WAAW,OAAO;;;;;;;cAe3C,2BAA2B;UACvB;UACA;UACA;UACA;UAEQ;UACA;UAER;EACR,UAAU,aAAa,KAAK,OAAO;EAKnC,YAAY,SAAS,SAAS,UAAS;;;;MAyCnC;;;;EAOJ,SAAS;;;;EAsBT,QAAQ;;;;EAyBR,QAAQ,aAAa;;;;EA2DrB,WAAW;;;;EAsBX;;;;EAeA,IAAI;;;;;;;iBCpVW;;;;;EAKf,YAAY,gBAAgB;;;;;EAK5B,cAAc,kBAAkB;;;;;;;;;;EAUhC,cAAc;;;;;;;;;;;;;;wBAeA,gBAAgB;;;;;;;;;;;;;;;wBAqBhB,YAAY,oBAAoB,cAAc,uCAAuC;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA+CrF,MAAM,QAAQ,cAAc;;;UCzGlC,4BAA4B;EACpC;;UAGe,gBAAgB;EAC/B;EACA,MAAM;EACN,IAAI;;;;;UAMW;EACf;EACA;EACA,MAAM;EACN;EACA,eAAe;EACf,QAAQ,qBAAqB,QAAQ;EACrC,cAAc;EACd,cAAc,YAAY;EAC1B;EACA,WAAW,gBAAgB;;;;;;;;;;;KAajB,SAAS;;;;;;;iBAaL,SAAS,iBAAiB;iBAsG1B,iBAAiB,kBAAkB;;;;;;;;;;;;;;;;;;;iBAgNnC,kBAAkB,kBAAkB,kBAAkB;;;;;;;;;;;;;;;;;wBCjVtD,cAAc,aAAa,QAAQ;;;;;;;;;;;;;;;wBAkBnC,gBAAgB,aAAa,QAAQ;;;;;;;;;;;;;;;;;;;;wBAuBrC,cAAc,aAAa,OAAO,4BAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAmCpE,MAAM,sCAAsC;wBAC5C,MAAM,gBAAgB,aAAa,aAAa;wBAgBhD,MAAM,uCAAuC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAoF7C,OAAO,KAAK,GAAG,QAAQ,gBAAgB,aAAa,6BAA6B"}
package/dist/storage.js CHANGED
@@ -8,6 +8,7 @@ import { defineSignal, entangleSignal, getOrCreateInternalSignal, makeInitialize
8
8
  */
9
9
  var SignalMap = class {
10
10
  _map = {};
11
+ _size = 0;
11
12
  _signals = withSignalStore(this._map);
12
13
  subscribe(key) {
13
14
  macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) && ((test) => {
@@ -15,8 +16,7 @@ var SignalMap = class {
15
16
  })(typeof key === "string");
16
17
  const existing = this._signals.has(key);
17
18
  entangleSignal(this._signals, this._map, key, void 0);
18
- const size = this._size;
19
- this._size = existing ? size : size + 1;
19
+ if (!existing) this._size += 1;
20
20
  return existing;
21
21
  }
22
22
  notify(key) {
@@ -34,7 +34,6 @@ var SignalMap = class {
34
34
  return this._size;
35
35
  }
36
36
  };
37
- defineSignal(SignalMap.prototype, "_size", 0);
38
37
 
39
38
  //#endregion
40
39
  //#region src/storage/cache.ts
@@ -273,6 +272,31 @@ function isStorageUnavailableError(error) {
273
272
  return false;
274
273
  }
275
274
  /**
275
+ * Subscribes to storage-change events, whether they originate from the
276
+ * native Storage API (a `StorageEvent`, fired cross-tab) or from
277
+ * {@link CacheStorage}'s own same-tab notifications (dispatched as a
278
+ * `CustomEvent` under the same 'storage' name — see `emitStorageEvent`
279
+ * in `./cache.ts`).
280
+ *
281
+ * Returns an unsubscribe function.
282
+ *
283
+ * This can't be expressed by widening the global `WindowEventMap.storage`
284
+ * type: that entry is inherited from `WindowEventHandlersEventMap` as
285
+ * `StorageEvent`, and a declaration-merged override has to stay assignable
286
+ * to the type it's overriding, not the other way around — deliberately
287
+ * reusing this event name for a wider union has no way to satisfy that.
288
+ *
289
+ * Route storage-event subscribers through this helper instead of calling
290
+ * `window.addEventListener('storage', ...)` directly.
291
+ */
292
+ function onStorageEvent(listener) {
293
+ const handler = (event) => {
294
+ listener("detail" in event ? event.detail : event);
295
+ };
296
+ window.addEventListener("storage", handler);
297
+ return () => window.removeEventListener("storage", handler);
298
+ }
299
+ /**
276
300
  * A reactive wrapper around the Web Storage API (localStorage/sessionStorage)
277
301
  * that provides signal-based access to storage items and length.
278
302
  *
@@ -304,8 +328,7 @@ var ReactiveStorage = class {
304
328
  this._length = 0;
305
329
  } else throw error;
306
330
  }
307
- if (!this._memoryOnly) window.addEventListener("storage", (event) => {
308
- const data = "detail" in event ? event.detail : event;
331
+ if (!this._memoryOnly) onStorageEvent((data) => {
309
332
  if (data.storageArea === storage) {
310
333
  this._values[data.key] = data.newValue;
311
334
  this._signals.notify(data.key);
@@ -444,9 +467,6 @@ defineSignal(ReactiveStorage.prototype, "_signals", makeInitializer(() => new Si
444
467
  //#endregion
445
468
  //#region src/storage/-private/storage-infra.ts
446
469
  /**
447
- * Configuration options for fields that are also query parameters
448
- */
449
- /**
450
470
  * Metadata attached to persisted resource classes
451
471
  */
452
472
  /**
@@ -526,10 +546,29 @@ function keyFor(meta, key) {
526
546
  return `persisted:${meta.id}:${key}`;
527
547
  }
528
548
  function getStorage(type, namespace) {
529
- if (type === "local-resource") return getLocalStorage();
530
- else if (type === "session-resource") return getSessionStorage();
549
+ if (type === "local-resource" || type === "local-storage") return getLocalStorage();
550
+ else if (type === "session-resource" || type === "session-storage") return getSessionStorage();
531
551
  else return getCacheStorage(namespace);
532
552
  }
553
+ function peekField(meta, key, overrideType) {
554
+ const stored = getStorage(overrideType || meta.type, meta.namespace).peekItem(keyFor(meta, key));
555
+ if (stored) return JSON.parse(stored);
556
+ return null;
557
+ }
558
+ function initializeFields(instance, source) {
559
+ const meta = useMeta(getResourceMeta(instance), instance);
560
+ for (const [key] of meta.fields.entries()) if (key in source) {
561
+ const newValue = source[key];
562
+ const initializer = meta.initializers.get(key);
563
+ let defaultValue = null;
564
+ if (initializer) defaultValue = initializer.call(instance);
565
+ const overrideType = meta.typeOverrides?.get(key) ?? null;
566
+ const type = overrideType || meta.type;
567
+ const currentValue = peekField(meta, keyFor(meta, key), overrideType);
568
+ (type === "local-resource" ? localStorage : sessionStorage).setItem(keyFor(meta, key), JSON.stringify(newValue));
569
+ if (currentValue === defaultValue) setField(meta, keyFor(meta, key), newValue, overrideType);
570
+ }
571
+ }
533
572
  /**
534
573
  * Update storage field
535
574
  */
@@ -910,5 +949,97 @@ function effect(fn, type) {
910
949
  }
911
950
 
912
951
  //#endregion
913
- export { CacheResource, CacheStorage, DEFAULT_CACHE_ID, LocalResource, SessionResource, getParamCompanion as _getParamCompanion, initMeta as _initMeta, configureLocalStorage, configureSessionStorage, effect, field, getCacheStorage, getLocalStorage, getSessionStorage, input };
952
+ //#region src/storage/query-params.ts
953
+ /**
954
+ * Configuration options for fields that are also query parameters
955
+ */
956
+ /**
957
+ * Creates a {@link ParamConfig} for boolean fields that serialize to '1' or null.
958
+ *
959
+ * @returns ParamConfig for boolean fields
960
+ *
961
+ * @example
962
+ * ```ts
963
+ * @param(BooleanParam())
964
+ * @field
965
+ * myFlag: boolean = false;
966
+ * ```
967
+ */
968
+ function BooleanParam() {
969
+ return {
970
+ serialize: (value) => value ? "1" : null,
971
+ deserialize: (urlValue) => urlValue === "1"
972
+ };
973
+ }
974
+ /**
975
+ * Creates a {@link ParamConfig} for numeric fields with default value checking.
976
+ *
977
+ * @param precision - When given, the number of digits to serialize after the decimal point
978
+ * @param getDefault - Function to get the default value for comparison
979
+ * @returns ParamConfig for number fields
980
+ *
981
+ * @example
982
+ * ```ts
983
+ * @param(NumberParam(2, function (instance: MyClass) { return instance.defaultZoom; }))
984
+ * @field
985
+ * zoom: number = 12;
986
+ * ```
987
+ */
988
+ function NumberParam(precision, getDefault) {
989
+ const isPrecise = typeof precision === "number";
990
+ return {
991
+ serialize: function(value) {
992
+ if (typeof value !== "number") return null;
993
+ return isPrecise ? value.toFixed(precision) : value.toString();
994
+ },
995
+ deserialize: (urlValue) => {
996
+ const num = Number(urlValue);
997
+ return isNaN(num) ? null : num;
998
+ },
999
+ getDefault: (instance) => {
1000
+ return getDefault?.(instance);
1001
+ }
1002
+ };
1003
+ }
1004
+ /**
1005
+ * Decorator which marks a field as a query parameter.
1006
+ *
1007
+ * This decorator only stores metadata - it does not change the property behavior.
1008
+ * The field will operate as a normal `@field` until a router integration consumes it.
1009
+ *
1010
+ * The provided {@link ParamConfig} is used to:
1011
+ * - Serialize values for the URL
1012
+ * - Deserialize values from the URL
1013
+ * - Compare URL and local values
1014
+ * - Determine when to include/exclude params from the URL
1015
+ *
1016
+ * @param config - Configuration for URL serialization/deserialization
1017
+ *
1018
+ * @example
1019
+ * ```ts
1020
+ * @SessionResource('map-state')
1021
+ * class MapState {
1022
+ * @param({
1023
+ * serialize: (value: unknown) => (value ? '1' : null),
1024
+ * deserialize: (urlValue: string) => urlValue === '1',
1025
+ * })
1026
+ * @field
1027
+ * active: boolean = false;
1028
+ * }
1029
+ * ```
1030
+ */
1031
+ function param(config) {
1032
+ return function(target, key, desc) {
1033
+ macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) && ((test) => {
1034
+ if (!test) throw new Error("param decorator only supports string keys");
1035
+ })(typeof key === "string");
1036
+ const meta = initMeta(target);
1037
+ if (!meta.paramConfigs) meta.paramConfigs = /* @__PURE__ */ new Map();
1038
+ meta.paramConfigs.set(key, config);
1039
+ return desc;
1040
+ };
1041
+ }
1042
+
1043
+ //#endregion
1044
+ export { BooleanParam, CacheResource, CacheStorage, DEFAULT_CACHE_ID, LocalResource, NumberParam, SessionResource, getParamCompanion as _getParamCompanion, initMeta as _initMeta, initializeFields as _initializeFields, configureLocalStorage, configureSessionStorage, effect, field, getCacheStorage, getLocalStorage, getSessionStorage, input, onStorageEvent, param };
914
1045
  //# sourceMappingURL=storage.js.map