@telperion/ng-pack 1.3.2 → 1.4.2

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,13 +1,514 @@
1
1
  import { WritableSignal, Provider } from '@angular/core';
2
+ import { ReactiveCookieStorageOptions } from '@telperion/reactive-storage';
2
3
 
4
+ /**
5
+ * A specialized writable signal interface for browser storage that extends Angular's WritableSignal
6
+ * with storage-specific operations.
7
+ *
8
+ * @template T - The type of value stored in the storage signal
9
+ *
10
+ * @remarks
11
+ * StorageSignal combines Angular's signal reactivity with browser storage persistence.
12
+ * It supports standard signal operations (get, set, update) plus a delete operation to remove
13
+ * the stored value.
14
+ *
15
+ * The signal value is always `T | null | undefined` because:
16
+ * - `null` indicates the key exists but has no value
17
+ * - `undefined` indicates the key doesn't exist in storage
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // Type-safe signal for user preferences
22
+ * const theme: StorageSignal<string> = localStorageSignal('settings', 'theme');
23
+ *
24
+ * // Read value (returns string | null | undefined)
25
+ * const currentTheme = theme();
26
+ *
27
+ * // Set new value
28
+ * theme.set('dark');
29
+ *
30
+ * // Update based on current value
31
+ * theme.update(current => current === 'dark' ? 'light' : 'dark');
32
+ *
33
+ * // Delete from storage
34
+ * theme.delete();
35
+ * ```
36
+ *
37
+ * @see {@link WritableSignal}
38
+ * @public
39
+ */
3
40
  interface StorageSignal<T> extends WritableSignal<T | null | undefined> {
41
+ /**
42
+ * Deletes the value from storage and updates the signal to undefined.
43
+ *
44
+ * @remarks
45
+ * This method removes the key-value pair from the underlying storage
46
+ * (localStorage, sessionStorage, or cookies) and updates the signal
47
+ * to reflect the deletion by setting its value to `undefined`.
48
+ *
49
+ * All components or effects subscribed to this signal will be notified
50
+ * of the change.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const userToken = localStorageSignal<string>('auth', 'token');
55
+ * userToken.set('abc123');
56
+ *
57
+ * // Later, on logout
58
+ * userToken.delete(); // Removes from storage, signal() returns undefined
59
+ * ```
60
+ */
4
61
  delete(): void;
5
62
  }
6
63
 
64
+ /**
65
+ * Provides a ReactiveWebLocalStorage instance for dependency injection.
66
+ *
67
+ * @param appName - Optional application name for namespacing localStorage keys
68
+ * @returns An Angular provider configuration
69
+ *
70
+ * @remarks
71
+ * This provider creates a singleton ReactiveWebLocalStorage instance that can be injected
72
+ * throughout your application. All `localStorageSignal` calls will use this shared instance,
73
+ * ensuring consistent storage access and change detection.
74
+ *
75
+ * **Namespacing:**
76
+ * The `appName` parameter prefixes all localStorage keys to prevent conflicts:
77
+ * - With appName: `my-app:store:key`
78
+ * - Without appName: `store:key`
79
+ *
80
+ * **Singleton Pattern:**
81
+ * Only one instance is created per application, ensuring:
82
+ * - Consistent storage access across components
83
+ * - Efficient memory usage
84
+ * - Reliable cross-component synchronization
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * // app.config.ts
89
+ * import { ApplicationConfig } from '@angular/core';
90
+ * import { provideLocalStorage } from '@telperion/ng-pack/storage-signals';
91
+ *
92
+ * export const appConfig: ApplicationConfig = {
93
+ * providers: [
94
+ * provideLocalStorage('my-app'),
95
+ * // ... other providers
96
+ * ]
97
+ * };
98
+ * ```
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * // Without namespace (keys are not prefixed)
103
+ * export const appConfig: ApplicationConfig = {
104
+ * providers: [
105
+ * provideLocalStorage(),
106
+ * ]
107
+ * };
108
+ * ```
109
+ *
110
+ * @public
111
+ */
7
112
  declare function provideLocalStorage(appName?: string): Provider;
113
+ /**
114
+ * Creates a reactive signal connected to browser's localStorage.
115
+ *
116
+ * @template T - The type of value stored
117
+ * @param store - The storage namespace/store name
118
+ * @param key - The key within the store
119
+ * @returns A StorageSignal that reactively tracks the localStorage value
120
+ *
121
+ * @remarks
122
+ * This function creates an Angular signal that automatically syncs with localStorage.
123
+ * Any changes to the value (via `set`, `update`, or `delete`) are immediately persisted
124
+ * to localStorage and propagate to all components using the same signal.
125
+ *
126
+ * **Requirements:**
127
+ * Must call {@link provideLocalStorage} in application config before using this function.
128
+ *
129
+ * **Storage Key:**
130
+ * The actual localStorage key is formed as:
131
+ * - With app name: `appName:store:key`
132
+ * - Without app name: `store:key`
133
+ *
134
+ * **Type Safety:**
135
+ * Values are automatically serialized/deserialized as JSON:
136
+ * - Objects and arrays are preserved
137
+ * - Primitives (string, number, boolean) work correctly
138
+ * - Functions and undefined values are not supported
139
+ *
140
+ * **Cross-Component Sync:**
141
+ * All components using the same `store` and `key` share the same signal state.
142
+ * Changes in one component immediately reflect in others.
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * import { Component } from '@angular/core';
147
+ * import { localStorageSignal } from '@telperion/ng-pack/storage-signals';
148
+ *
149
+ * @Component({
150
+ * selector: 'app-settings',
151
+ * template: `
152
+ * <div>
153
+ * <p>Theme: {{ theme() }}</p>
154
+ * <button (click)="theme.set('dark')">Dark</button>
155
+ * <button (click)="theme.set('light')">Light</button>
156
+ * <button (click)="theme.delete()">Reset</button>
157
+ * </div>
158
+ * `
159
+ * })
160
+ * export class SettingsComponent {
161
+ * theme = localStorageSignal<string>('settings', 'theme');
162
+ * }
163
+ * ```
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // Complex types
168
+ * interface UserPreferences {
169
+ * theme: 'light' | 'dark';
170
+ * fontSize: number;
171
+ * notifications: boolean;
172
+ * }
173
+ *
174
+ * const prefs = localStorageSignal<UserPreferences>('user', 'preferences');
175
+ *
176
+ * // Set entire object
177
+ * prefs.set({ theme: 'dark', fontSize: 14, notifications: true });
178
+ *
179
+ * // Update specific property
180
+ * prefs.update(current => ({
181
+ * ...current,
182
+ * theme: current?.theme === 'dark' ? 'light' : 'dark'
183
+ * }));
184
+ * ```
185
+ *
186
+ * @throws Error if {@link provideLocalStorage} was not called in application config
187
+ *
188
+ * @public
189
+ */
8
190
  declare function localStorageSignal<T>(store: string, key: string): StorageSignal<T>;
9
191
 
192
+ /**
193
+ * Provides a ReactiveWebSessionStorage instance for dependency injection.
194
+ *
195
+ * @param appName - Optional application name for namespacing sessionStorage keys
196
+ * @returns An Angular provider configuration
197
+ *
198
+ * @remarks
199
+ * This provider creates a singleton ReactiveWebSessionStorage instance that can be injected
200
+ * throughout your application. All `sessionStorageSignal` calls will use this shared instance,
201
+ * ensuring consistent storage access and change detection.
202
+ *
203
+ * **SessionStorage vs LocalStorage:**
204
+ * - **sessionStorage**: Data persists only for the browser tab/window session (cleared on close)
205
+ * - **localStorage**: Data persists indefinitely until explicitly cleared
206
+ *
207
+ * **Use Cases for sessionStorage:**
208
+ * - Multi-step form wizards
209
+ * - Temporary authentication tokens
210
+ * - Per-session user preferences
211
+ * - Shopping cart for current session
212
+ * - Tab-specific state isolation
213
+ *
214
+ * **Namespacing:**
215
+ * The `appName` parameter prefixes all sessionStorage keys to prevent conflicts:
216
+ * - With appName: `my-app:store:key`
217
+ * - Without appName: `store:key`
218
+ *
219
+ * **Singleton Pattern:**
220
+ * Only one instance is created per application, ensuring:
221
+ * - Consistent storage access across components
222
+ * - Efficient memory usage
223
+ * - Reliable cross-component synchronization
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * // app.config.ts
228
+ * import { ApplicationConfig } from '@angular/core';
229
+ * import { provideSessionStorage } from '@telperion/ng-pack/storage-signals';
230
+ *
231
+ * export const appConfig: ApplicationConfig = {
232
+ * providers: [
233
+ * provideSessionStorage('my-app'),
234
+ * // ... other providers
235
+ * ]
236
+ * };
237
+ * ```
238
+ *
239
+ * @example
240
+ * ```typescript
241
+ * // Without namespace
242
+ * export const appConfig: ApplicationConfig = {
243
+ * providers: [
244
+ * provideSessionStorage(),
245
+ * ]
246
+ * };
247
+ * ```
248
+ *
249
+ * @public
250
+ */
10
251
  declare function provideSessionStorage(appName?: string): Provider;
252
+ /**
253
+ * Creates a reactive signal connected to browser's sessionStorage.
254
+ *
255
+ * @template T - The type of value stored
256
+ * @param store - The storage namespace/store name
257
+ * @param key - The key within the store
258
+ * @returns A StorageSignal that reactively tracks the sessionStorage value
259
+ *
260
+ * @remarks
261
+ * This function creates an Angular signal that automatically syncs with sessionStorage.
262
+ * Any changes to the value (via `set`, `update`, or `delete`) are immediately persisted
263
+ * to sessionStorage and propagate to all components using the same signal.
264
+ *
265
+ * **Session Lifecycle:**
266
+ * - Data is cleared when the browser tab/window is closed
267
+ * - Each tab has its own independent sessionStorage
268
+ * - Opening a page in a new tab creates fresh sessionStorage (even for same URL)
269
+ * - Refreshing the page preserves sessionStorage data
270
+ *
271
+ * **Requirements:**
272
+ * Must call {@link provideSessionStorage} in application config before using this function.
273
+ *
274
+ * **Storage Key:**
275
+ * The actual sessionStorage key is formed as:
276
+ * - With app name: `appName:store:key`
277
+ * - Without app name: `store:key`
278
+ *
279
+ * **Type Safety:**
280
+ * Values are automatically serialized/deserialized as JSON:
281
+ * - Objects and arrays are preserved
282
+ * - Primitives (string, number, boolean) work correctly
283
+ * - Functions and undefined values are not supported
284
+ *
285
+ * **Cross-Component Sync:**
286
+ * All components in the same tab using the same `store` and `key` share the same signal state.
287
+ * Changes in one component immediately reflect in others within the same tab.
288
+ * Different tabs do NOT share sessionStorage.
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * import { Component } from '@angular/core';
293
+ * import { sessionStorageSignal } from '@telperion/ng-pack/storage-signals';
294
+ *
295
+ * @Component({
296
+ * selector: 'app-wizard',
297
+ * template: `
298
+ * <div>
299
+ * <p>Current Step: {{ currentStep() }}</p>
300
+ * <button (click)="nextStep()">Next</button>
301
+ * <button (click)="currentStep.delete()">Reset</button>
302
+ * </div>
303
+ * `
304
+ * })
305
+ * export class WizardComponent {
306
+ * currentStep = sessionStorageSignal<number>('wizard', 'step');
307
+ *
308
+ * nextStep() {
309
+ * this.currentStep.update(step => (step ?? 0) + 1);
310
+ * }
311
+ * }
312
+ * ```
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * // Form data that shouldn't persist across sessions
317
+ * interface FormData {
318
+ * email: string;
319
+ * message: string;
320
+ * }
321
+ *
322
+ * const formData = sessionStorageSignal<FormData>('contact', 'draft');
323
+ *
324
+ * // Auto-save form data (cleared when tab closes)
325
+ * formData.set({ email: 'user@example.com', message: 'Hello!' });
326
+ *
327
+ * // Update specific field
328
+ * formData.update(current => ({
329
+ * ...current,
330
+ * message: 'Updated message'
331
+ * }));
332
+ * ```
333
+ *
334
+ * @throws Error if {@link provideSessionStorage} was not called in application config
335
+ *
336
+ * @public
337
+ */
11
338
  declare function sessionStorageSignal<T>(store: string, key: string): StorageSignal<T>;
12
339
 
13
- export { localStorageSignal, provideLocalStorage, provideSessionStorage, sessionStorageSignal };
340
+ /**
341
+ * Provides a CookieStorageProvider instance for dependency injection.
342
+ *
343
+ * @param appName - Optional application name for namespacing cookie keys
344
+ * @param options - Default cookie options applied to all cookie storage signals
345
+ * @returns An Angular provider configuration
346
+ *
347
+ * @remarks
348
+ * This provider creates a singleton CookieStorageProvider that manages all cookie storage
349
+ * instances in your application. All `cookieStorageSignal` calls will use this shared provider.
350
+ *
351
+ * **Cookie Namespacing:**
352
+ * The `appName` parameter prefixes all cookie names to prevent conflicts:
353
+ * - With appName: `my-app:store:key`
354
+ * - Without appName: `store:key`
355
+ *
356
+ * **Base Options:**
357
+ * The `options` parameter provides default cookie configuration for all signals.
358
+ * Individual signals can override these options when created.
359
+ *
360
+ * **Common Options:**
361
+ * - `path` - Cookie path (default: current path)
362
+ * - `domain` - Cookie domain (default: current domain)
363
+ * - `secure` - Require HTTPS (recommended for production)
364
+ * - `sameSite` - CSRF protection ('strict' | 'lax' | 'none')
365
+ * - `maxAge` - Expiry time in seconds
366
+ * - `expires` - Expiry as Date object
367
+ *
368
+ * **Instance Management:**
369
+ * The provider automatically deduplicates storage instances:
370
+ * - Signals with identical options share the same storage instance
371
+ * - All instances are linked for cross-instance synchronization
372
+ * - Memory-efficient for applications with many cookie signals
373
+ *
374
+ * @example
375
+ * ```typescript
376
+ * // app.config.ts
377
+ * import { ApplicationConfig } from '@angular/core';
378
+ * import { provideCookieStorage } from '@telperion/ng-pack/storage-signals';
379
+ *
380
+ * export const appConfig: ApplicationConfig = {
381
+ * providers: [
382
+ * provideCookieStorage('my-app', {
383
+ * path: '/',
384
+ * secure: true,
385
+ * sameSite: 'strict',
386
+ * maxAge: 86400 // 24 hours
387
+ * }),
388
+ * ]
389
+ * };
390
+ * ```
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * // Minimal configuration
395
+ * export const appConfig: ApplicationConfig = {
396
+ * providers: [
397
+ * provideCookieStorage('my-app'),
398
+ * ]
399
+ * };
400
+ * ```
401
+ *
402
+ * @public
403
+ */
404
+ declare function provideCookieStorage(appName?: string, options?: ReactiveCookieStorageOptions): Provider;
405
+ /**
406
+ * Creates a reactive signal connected to browser cookies.
407
+ *
408
+ * @template T - The type of value stored
409
+ * @param store - The cookie namespace/store name
410
+ * @param key - The cookie key within the store
411
+ * @param options - Optional cookie-specific options that override provider defaults
412
+ * @returns A StorageSignal that reactively tracks the cookie value
413
+ *
414
+ * @remarks
415
+ * This function creates an Angular signal that automatically syncs with browser cookies.
416
+ * Any changes to the value (via `set`, `update`, or `delete`) are immediately written
417
+ * to cookies and propagate to all components using the same signal.
418
+ *
419
+ * **Requirements:**
420
+ * Must call {@link provideCookieStorage} in application config before using this function.
421
+ *
422
+ * **Cookie Name:**
423
+ * The actual cookie name is formed as:
424
+ * - With app name: `appName:store:key`
425
+ * - Without app name: `store:key`
426
+ *
427
+ * **Size Limitations:**
428
+ * Cookies have a ~4KB size limit. The underlying ReactiveCookieStorage enforces a 4000 byte
429
+ * limit and throws an error if exceeded. Use localStorage for larger data.
430
+ *
431
+ * **Options Merging:**
432
+ * Cookie options are merged in this order (later overrides earlier):
433
+ * 1. Provider base options (from `provideCookieStorage`)
434
+ * 2. Signal-specific options (from this function's `options` parameter)
435
+ *
436
+ * **Instance Deduplication:**
437
+ * Signals with identical merged options share the same underlying storage instance:
438
+ * ```typescript
439
+ * // These share the same storage instance
440
+ * const token1 = cookieStorageSignal('auth', 'token', { secure: true });
441
+ * const token2 = cookieStorageSignal('auth', 'token', { secure: true });
442
+ *
443
+ * // These use different instances (different options)
444
+ * const temp = cookieStorageSignal('auth', 'token', { maxAge: 300 });
445
+ * ```
446
+ *
447
+ * **Type Safety:**
448
+ * Values are automatically serialized/deserialized as JSON:
449
+ * - Objects and arrays are preserved
450
+ * - Primitives (string, number, boolean) work correctly
451
+ * - Functions and undefined values are not supported
452
+ *
453
+ * **Security Best Practices:**
454
+ * - Use `secure: true` in production (HTTPS only)
455
+ * - Use `sameSite: 'strict'` for CSRF protection
456
+ * - Set appropriate `maxAge` or `expires` for sensitive data
457
+ * - Never store sensitive data in cookies without encryption
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * import { Component } from '@angular/core';
462
+ * import { cookieStorageSignal } from '@telperion/ng-pack/storage-signals';
463
+ *
464
+ * @Component({
465
+ * selector: 'app-auth',
466
+ * template: `
467
+ * <div>
468
+ * <p>Token: {{ authToken() }}</p>
469
+ * <button (click)="login()">Login</button>
470
+ * <button (click)="logout()">Logout</button>
471
+ * </div>
472
+ * `
473
+ * })
474
+ * export class AuthComponent {
475
+ * // Secure cookie with 1 hour expiry
476
+ * authToken = cookieStorageSignal<string>('auth', 'token', {
477
+ * secure: true,
478
+ * sameSite: 'strict',
479
+ * maxAge: 3600
480
+ * });
481
+ *
482
+ * login() {
483
+ * this.authToken.set('abc123');
484
+ * }
485
+ *
486
+ * logout() {
487
+ * this.authToken.delete();
488
+ * }
489
+ * }
490
+ * ```
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * // User preferences with different cookie lifetimes
495
+ * const theme = cookieStorageSignal<string>('prefs', 'theme', {
496
+ * maxAge: 31536000 // 1 year
497
+ * });
498
+ *
499
+ * const tempSetting = cookieStorageSignal<boolean>('prefs', 'banner-dismissed', {
500
+ * maxAge: 86400 // 1 day
501
+ * });
502
+ *
503
+ * theme.set('dark');
504
+ * tempSetting.set(true);
505
+ * ```
506
+ *
507
+ * @throws Error if {@link provideCookieStorage} was not called in application config
508
+ * @throws Error if the serialized value exceeds 4000 bytes
509
+ *
510
+ * @public
511
+ */
512
+ declare function cookieStorageSignal<T>(store: string, key: string, options?: ReactiveCookieStorageOptions): StorageSignal<T>;
513
+
514
+ export { cookieStorageSignal, localStorageSignal, provideCookieStorage, provideLocalStorage, provideSessionStorage, sessionStorageSignal };