@hamak/ui-store 0.6.0 → 0.7.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.
- package/dist/api/api/index.d.ts +3 -3
- package/dist/api/api/index.js +3 -3
- package/dist/api/api/middleware-registry.d.ts +1 -1
- package/dist/api/api/reducer-registry.d.ts +1 -1
- package/dist/api/api/store-manager.d.ts +3 -3
- package/dist/api/autosave/autosave-action-factory.d.ts +2 -2
- package/dist/api/autosave/autosave-action-factory.js +1 -1
- package/dist/api/autosave/autosave-action-types.d.ts +1 -1
- package/dist/api/autosave/index.d.ts +3 -3
- package/dist/api/autosave/index.js +3 -3
- package/dist/api/fs/index.d.ts +2 -2
- package/dist/api/fs/index.js +2 -2
- package/dist/api/index.d.ts +5 -5
- package/dist/api/index.js +5 -5
- package/dist/api/tokens/index.d.ts +1 -1
- package/dist/api/tokens/index.js +1 -1
- package/dist/api/tokens/service-tokens.d.ts +8 -0
- package/dist/api/tokens/service-tokens.d.ts.map +1 -1
- package/dist/api/tokens/service-tokens.js +11 -0
- package/dist/api/types/extension-types.d.ts +1 -1
- package/dist/api/types/index.d.ts +4 -4
- package/dist/api/types/index.js +4 -4
- package/dist/api/types/store-types.d.ts +20 -12
- package/dist/api/types/store-types.d.ts.map +1 -1
- package/dist/impl/autosave/autosave-config-resolver.d.ts +1 -1
- package/dist/impl/autosave/autosave-config-resolver.js +1 -1
- package/dist/impl/autosave/autosave-middleware.d.ts +2 -2
- package/dist/impl/autosave/autosave-middleware.js +2 -2
- package/dist/impl/autosave/autosave-registry.d.ts +1 -1
- package/dist/impl/autosave/autosave-sync-middleware.d.ts +1 -1
- package/dist/impl/autosave/autosave-sync-middleware.js +1 -1
- package/dist/impl/autosave/index.d.ts +4 -4
- package/dist/impl/autosave/index.js +4 -4
- package/dist/impl/core/index.d.ts +3 -3
- package/dist/impl/core/index.js +3 -3
- package/dist/impl/core/middleware-registry.d.ts +1 -1
- package/dist/impl/core/reducer-registry.d.ts +1 -1
- package/dist/impl/core/store-manager.d.ts +16 -4
- package/dist/impl/core/store-manager.d.ts.map +1 -1
- package/dist/impl/core/store-manager.js +19 -2
- package/dist/impl/extensions/store-extensions.d.ts +1 -1
- package/dist/impl/fs/commands/fs-commands.d.ts +3 -3
- package/dist/impl/fs/commands/fs-commands.d.ts.map +1 -1
- package/dist/impl/fs/commands/fs-commands.js +35 -9
- package/dist/impl/fs/commands/structure-commands.d.ts +25 -0
- package/dist/impl/fs/commands/structure-commands.d.ts.map +1 -1
- package/dist/impl/fs/core/fs-adapter.d.ts +3 -3
- package/dist/impl/fs/core/fs-adapter.js +2 -2
- package/dist/impl/fs/core/fs-facade.d.ts +2 -2
- package/dist/impl/fs/index.d.ts +6 -6
- package/dist/impl/fs/index.js +6 -6
- package/dist/impl/fs/utils/data-updater.d.ts +1 -1
- package/dist/impl/index.d.ts +8 -7
- package/dist/impl/index.d.ts.map +1 -1
- package/dist/impl/index.js +8 -7
- package/dist/impl/middleware/index.d.ts +2 -2
- package/dist/impl/middleware/index.js +2 -2
- package/dist/impl/persistence/index.d.ts +9 -0
- package/dist/impl/persistence/index.d.ts.map +1 -0
- package/dist/impl/persistence/index.js +8 -0
- package/dist/impl/persistence/persistence-filter.d.ts +11 -0
- package/dist/impl/persistence/persistence-filter.d.ts.map +1 -0
- package/dist/impl/persistence/persistence-filter.js +24 -0
- package/dist/impl/persistence/persistence-resolver.d.ts +9 -0
- package/dist/impl/persistence/persistence-resolver.d.ts.map +1 -0
- package/dist/impl/persistence/persistence-resolver.js +22 -0
- package/dist/impl/persistence/persistence-wiring.d.ts +29 -0
- package/dist/impl/persistence/persistence-wiring.d.ts.map +1 -0
- package/dist/impl/persistence/persistence-wiring.js +69 -0
- package/dist/impl/persistence/web-storage-persistence-provider.d.ts +46 -0
- package/dist/impl/persistence/web-storage-persistence-provider.d.ts.map +1 -0
- package/dist/impl/persistence/web-storage-persistence-provider.js +155 -0
- package/dist/impl/plugin/index.d.ts +1 -1
- package/dist/impl/plugin/index.js +1 -1
- package/dist/impl/plugin/store-plugin-factory.d.ts +13 -1
- package/dist/impl/plugin/store-plugin-factory.d.ts.map +1 -1
- package/dist/impl/plugin/store-plugin-factory.js +60 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/spi/autosave/i-autosave-registry.d.ts +1 -1
- package/dist/spi/autosave/index.d.ts +2 -2
- package/dist/spi/autosave/index.js +2 -2
- package/dist/spi/index.d.ts +4 -4
- package/dist/spi/index.js +4 -4
- package/dist/spi/middleware/index.d.ts +1 -1
- package/dist/spi/middleware/index.js +1 -1
- package/dist/spi/middleware/middleware-provider.d.ts +1 -1
- package/dist/spi/persistence/index.d.ts +1 -1
- package/dist/spi/persistence/index.js +1 -1
- package/package.json +8 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { fileSystemNodeInitialState } from '../../../api';
|
|
1
|
+
import { fileSystemNodeInitialState } from '../../../api/index.js';
|
|
2
2
|
import { pathSteps } from '@hamak/shared-utils';
|
|
3
|
-
import { DataUpdater } from '../utils/data-updater';
|
|
3
|
+
import { DataUpdater } from '../utils/data-updater.js';
|
|
4
4
|
import { produce, current, isDraft, original } from 'immer';
|
|
5
|
-
import { deepEqual } from '../utils/deep-equal';
|
|
5
|
+
import { deepEqual } from '../utils/deep-equal.js';
|
|
6
6
|
// Re-export path utilities from shared-utils for internal use
|
|
7
7
|
export { pathSteps, parentPathSteps } from '@hamak/shared-utils';
|
|
8
8
|
/**
|
|
@@ -258,6 +258,20 @@ export class FileSystemCommandHandler {
|
|
|
258
258
|
return isDraft(o) ? original(o) : o;
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Build an empty-object prototype stack mirroring `itinerary` depth-for-depth,
|
|
263
|
+
* with `{}` at every level. Passed to `DataUpdater` so that missing object
|
|
264
|
+
* intermediates along the path are materialized instead of silently no-op'ing.
|
|
265
|
+
*
|
|
266
|
+
* Object-only: it cannot synthesize array intermediates — callers needing those
|
|
267
|
+
* must supply an explicit `prototypes` stack (see `ensurePath` JSDoc).
|
|
268
|
+
*/
|
|
269
|
+
function buildEmptyObjectProtos(itinerary) {
|
|
270
|
+
if (itinerary === undefined) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
return { value: {}, parent: buildEmptyObjectProtos(itinerary.parent) };
|
|
274
|
+
}
|
|
261
275
|
/**
|
|
262
276
|
* File content command handler - handles structure commands on file content
|
|
263
277
|
*/
|
|
@@ -308,25 +322,37 @@ export class FileContentCommandHandler {
|
|
|
308
322
|
this.updater.executeDelete(content, itinerary);
|
|
309
323
|
}
|
|
310
324
|
executeSet(file, command) {
|
|
311
|
-
const { itinerary, value } = command;
|
|
325
|
+
const { itinerary, value, prototypes } = command;
|
|
312
326
|
if (itinerary === undefined) {
|
|
313
327
|
file.content = value;
|
|
314
328
|
}
|
|
315
329
|
const { content } = file;
|
|
316
|
-
|
|
330
|
+
// executeSet navigates the itinerary's parent, so the prototype stack must
|
|
331
|
+
// mirror `itinerary.parent`.
|
|
332
|
+
const effectivePrototypes = prototypes
|
|
333
|
+
?? (command.ensurePath ? buildEmptyObjectProtos(itinerary?.parent) : undefined);
|
|
334
|
+
this.updater.executeSet(content, itinerary, value, effectivePrototypes);
|
|
317
335
|
}
|
|
318
336
|
executeAdd(file, command) {
|
|
319
|
-
const { itinerary, value } = command;
|
|
337
|
+
const { itinerary, value, prototypes } = command;
|
|
320
338
|
const { content } = file;
|
|
321
|
-
|
|
339
|
+
// executeAdd navigates the full itinerary (the target container), so the
|
|
340
|
+
// prototype stack mirrors `itinerary`.
|
|
341
|
+
const effectivePrototypes = prototypes
|
|
342
|
+
?? (command.ensurePath ? buildEmptyObjectProtos(itinerary) : undefined);
|
|
343
|
+
this.updater.executeAdd(content, itinerary, value, effectivePrototypes);
|
|
322
344
|
}
|
|
323
345
|
executeInsert(file, command) {
|
|
324
|
-
const { itinerary, value } = command;
|
|
346
|
+
const { itinerary, value, prototypes } = command;
|
|
325
347
|
if (itinerary === undefined) {
|
|
326
348
|
return;
|
|
327
349
|
}
|
|
328
350
|
const { content } = file;
|
|
329
|
-
|
|
351
|
+
// executeInsert navigates the itinerary's parent, so the prototype stack
|
|
352
|
+
// mirrors `itinerary.parent`.
|
|
353
|
+
const effectivePrototypes = prototypes
|
|
354
|
+
?? (command.ensurePath ? buildEmptyObjectProtos(itinerary.parent) : undefined);
|
|
355
|
+
this.updater.executeInsert(content, itinerary, value, effectivePrototypes);
|
|
330
356
|
}
|
|
331
357
|
/**
|
|
332
358
|
* Executes a batch of commands, rebasing each on previous mutations.
|
|
@@ -17,7 +17,32 @@ export interface UnitaryStructureNodeCommandBase extends StructureNodeCommandBas
|
|
|
17
17
|
*/
|
|
18
18
|
export interface StructureNodeUpsertCommandBase extends UnitaryStructureNodeCommandBase {
|
|
19
19
|
name: "add-at" | "set-at" | 'insert-at';
|
|
20
|
+
/**
|
|
21
|
+
* Explicit prototype stack used to materialize missing intermediates along
|
|
22
|
+
* the itinerary's parent. Each {@link StackElement} level mirrors one
|
|
23
|
+
* itinerary step (deepest first) and its `value` is the node inserted when
|
|
24
|
+
* that step is absent. Use this when the missing intermediates include
|
|
25
|
+
* arrays, or when they need non-empty seed values.
|
|
26
|
+
*
|
|
27
|
+
* Takes precedence over {@link ensurePath} when both are supplied.
|
|
28
|
+
*/
|
|
20
29
|
prototypes?: StackElement<any>;
|
|
30
|
+
/**
|
|
31
|
+
* Convenience flag for the common "create missing object intermediates"
|
|
32
|
+
* case: when true (and `prototypes` is absent), the handler synthesizes an
|
|
33
|
+
* empty-object (`{}`) prototype stack of matching depth, so deep writes into
|
|
34
|
+
* nested-object documents materialize their parent path instead of silently
|
|
35
|
+
* no-op'ing when the parent is absent.
|
|
36
|
+
*
|
|
37
|
+
* Object-only: each synthesized intermediate is `{}`. For **absent-array**
|
|
38
|
+
* intermediates this is insufficient — supply `prototypes` explicitly with
|
|
39
|
+
* an array (`[]`) at the relevant level.
|
|
40
|
+
*
|
|
41
|
+
* When false/absent, today's silent-no-op semantics are preserved (no
|
|
42
|
+
* intermediates are created and a deep write into an absent parent does
|
|
43
|
+
* nothing).
|
|
44
|
+
*/
|
|
45
|
+
ensurePath?: boolean;
|
|
21
46
|
}
|
|
22
47
|
/**
|
|
23
48
|
* Add a value at the specified itinerary
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structure-commands.d.ts","sourceRoot":"","sources":["../../../../src/impl/fs/commands/structure-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,CAAA;CACvE;AAED;;GAEG;AACH,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAC/E,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAA;IACrD,SAAS,EAAE,SAAS,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,8BAA+B,SAAQ,+BAA+B;IACrF,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAA;IACvC,UAAU,CAAC,EAAG,YAAY,CAAC,GAAG,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"structure-commands.d.ts","sourceRoot":"","sources":["../../../../src/impl/fs/commands/structure-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,CAAA;CACvE;AAED;;GAEG;AACH,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAC/E,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAA;IACrD,SAAS,EAAE,SAAS,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,8BAA+B,SAAQ,+BAA+B;IACrF,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAA;IACvC;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAC/B;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,EAAG,OAAO,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,8BAA8B;IAC7E,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,GAAG,CAAA;CACX;AAED;;GAEG;AACH,MAAM,WAAW,0BAA2B,SAAQ,8BAA8B;IAChF,IAAI,EAAE,WAAW,CAAA;IACjB,KAAK,EAAE,GAAG,CAAA;CACX;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,8BAA8B;IAC7E,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,GAAG,CAAA;CACX;AAED;;GAEG;AACH,MAAM,WAAW,0BAA2B,SAAQ,+BAA+B;IACjF,IAAI,EAAE,WAAW,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAC/E,IAAI,EAAE,cAAc,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,2BAA2B,EAAE,CAAA;CACxC;AAED;;GAEG;AACH,MAAM,MAAM,2BAA2B,GACnC,uBAAuB,GACvB,0BAA0B,GAC1B,uBAAuB,GACvB,0BAA0B,CAAA;AAE9B;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,2BAA2B,GAAG,+BAA+B,CAAA;AAEhG;;GAEG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,SAAS,EAAG,SAAS,EAAE,KAAK,EAAG,GAAG,EAAE,UAAU,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,GAAI,uBAAuB;IAIrG,UAAU,CAAC,SAAS,EAAG,SAAS,EAAE,KAAK,EAAG,GAAG,EAAE,UAAU,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,GAAI,0BAA0B;IAI3G,OAAO,CAAC,SAAS,EAAG,SAAS,EAAE,KAAK,EAAG,GAAG,EAAE,UAAU,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,GAAI,uBAAuB;IAIrG,UAAU,CAAC,SAAS,EAAG,SAAS,GAAI,0BAA0B;IAI9D,WAAW,CAAC,QAAQ,EAAG,2BAA2B,EAAE,EAAE,UAAU,UAAQ,GAAI,+BAA+B;CAG5G;AAED,eAAO,MAAM,OAAO,4BAAmC,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Action } from '@reduxjs/toolkit';
|
|
2
|
-
import { FileSystemCommandHandler } from '../commands/fs-commands';
|
|
3
|
-
import { FileSystemNode, FileSystemState, FileContentSchema, FileSystemNodeActionParams, FileSystemNodeAction, Selector } from '../../../api';
|
|
4
|
-
import { StructureNodeCommand } from '../commands/structure-commands';
|
|
2
|
+
import { FileSystemCommandHandler } from '../commands/fs-commands.js';
|
|
3
|
+
import { FileSystemNode, FileSystemState, FileContentSchema, FileSystemNodeActionParams, FileSystemNodeAction, Selector } from '../../../api/index.js';
|
|
4
|
+
import { StructureNodeCommand } from '../commands/structure-commands.js';
|
|
5
5
|
/**
|
|
6
6
|
* Factory function to create a FileSystemAdapter
|
|
7
7
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
|
-
import { FileSystemCommandHandler, pathSteps } from '../commands/fs-commands';
|
|
3
|
-
import { fileSystemNodeInitialState } from '../../../api';
|
|
2
|
+
import { FileSystemCommandHandler, pathSteps } from '../commands/fs-commands.js';
|
|
3
|
+
import { fileSystemNodeInitialState } from '../../../api/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* Factory function to create a FileSystemAdapter
|
|
6
6
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FileNode, FileSystemNode, FileSystemState, Selector } from '../../../api';
|
|
2
|
-
import { FileSystemAdapter, FileSystemNodeActions } from './fs-adapter';
|
|
1
|
+
import { FileNode, FileSystemNode, FileSystemState, Selector } from '../../../api/index.js';
|
|
2
|
+
import { FileSystemAdapter, FileSystemNodeActions } from './fs-adapter.js';
|
|
3
3
|
import { Path, Pathway, PathwayResolver, RelativePathwayResolver } from '@hamak/shared-utils';
|
|
4
4
|
/**
|
|
5
5
|
* Selector that returns a FileSystemNode generally the root of the Filesystem Overlay
|
package/dist/impl/fs/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from './core/fs-adapter';
|
|
2
|
-
export * from './core/fs-facade';
|
|
3
|
-
export * from './commands/fs-commands';
|
|
4
|
-
export * from './commands/structure-commands';
|
|
1
|
+
export * from './core/fs-adapter.js';
|
|
2
|
+
export * from './core/fs-facade.js';
|
|
3
|
+
export * from './commands/fs-commands.js';
|
|
4
|
+
export * from './commands/structure-commands.js';
|
|
5
5
|
export { pathSteps, parentPathSteps } from '@hamak/shared-utils';
|
|
6
|
-
export * from './utils/data-updater';
|
|
7
|
-
export * from './utils/deep-equal';
|
|
6
|
+
export * from './utils/data-updater.js';
|
|
7
|
+
export * from './utils/deep-equal.js';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/impl/fs/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Core filesystem functionality
|
|
2
|
-
export * from './core/fs-adapter';
|
|
3
|
-
export * from './core/fs-facade';
|
|
2
|
+
export * from './core/fs-adapter.js';
|
|
3
|
+
export * from './core/fs-facade.js';
|
|
4
4
|
// Commands
|
|
5
|
-
export * from './commands/fs-commands';
|
|
6
|
-
export * from './commands/structure-commands';
|
|
5
|
+
export * from './commands/fs-commands.js';
|
|
6
|
+
export * from './commands/structure-commands.js';
|
|
7
7
|
// Re-export path utilities from shared-utils for backward compatibility
|
|
8
8
|
export { pathSteps, parentPathSteps } from '@hamak/shared-utils';
|
|
9
9
|
// Utilities
|
|
10
|
-
export * from './utils/data-updater';
|
|
11
|
-
export * from './utils/deep-equal';
|
|
10
|
+
export * from './utils/data-updater.js';
|
|
11
|
+
export * from './utils/deep-equal.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Itinerary, StackElement } from '@hamak/shared-utils';
|
|
2
|
-
import { UnitaryStructureNodeCommand, BatchUpdateStructureNodeCommand } from '../commands/structure-commands';
|
|
2
|
+
import { UnitaryStructureNodeCommand, BatchUpdateStructureNodeCommand } from '../commands/structure-commands.js';
|
|
3
3
|
/**
|
|
4
4
|
* DataUpdater class handles operations on data structures using itineraries
|
|
5
5
|
*/
|
package/dist/impl/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* UI Store Implementation
|
|
3
3
|
* Concrete implementations of Redux store management
|
|
4
4
|
*/
|
|
5
|
-
export * from '../api';
|
|
6
|
-
export * from '../spi';
|
|
7
|
-
export * from './core';
|
|
8
|
-
export * from './middleware';
|
|
9
|
-
export * from './plugin';
|
|
10
|
-
export * from './fs';
|
|
11
|
-
export * from './autosave';
|
|
5
|
+
export * from '../api/index.js';
|
|
6
|
+
export * from '../spi/index.js';
|
|
7
|
+
export * from './core/index.js';
|
|
8
|
+
export * from './middleware/index.js';
|
|
9
|
+
export * from './plugin/index.js';
|
|
10
|
+
export * from './fs/index.js';
|
|
11
|
+
export * from './autosave/index.js';
|
|
12
|
+
export * from './persistence/index.js';
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/impl/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/impl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,MAAM,CAAC;AACrB,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/impl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,MAAM,CAAC;AACrB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
|
package/dist/impl/index.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* Concrete implementations of Redux store management
|
|
4
4
|
*/
|
|
5
5
|
// Re-export API and SPI for convenience
|
|
6
|
-
export * from '../api';
|
|
7
|
-
export * from '../spi';
|
|
8
|
-
export * from './core';
|
|
9
|
-
export * from './middleware';
|
|
10
|
-
export * from './plugin';
|
|
11
|
-
export * from './fs';
|
|
12
|
-
export * from './autosave';
|
|
6
|
+
export * from '../api/index.js';
|
|
7
|
+
export * from '../spi/index.js';
|
|
8
|
+
export * from './core/index.js';
|
|
9
|
+
export * from './middleware/index.js';
|
|
10
|
+
export * from './plugin/index.js';
|
|
11
|
+
export * from './fs/index.js';
|
|
12
|
+
export * from './autosave/index.js';
|
|
13
|
+
export * from './persistence/index.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State persistence implementations and wiring.
|
|
3
|
+
* See amah/app-framework#30.
|
|
4
|
+
*/
|
|
5
|
+
export * from './web-storage-persistence-provider.js';
|
|
6
|
+
export * from './persistence-filter.js';
|
|
7
|
+
export * from './persistence-resolver.js';
|
|
8
|
+
export * from './persistence-wiring.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/impl/persistence/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,oCAAoC,CAAC;AACnD,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State persistence implementations and wiring.
|
|
3
|
+
* See amah/app-framework#30.
|
|
4
|
+
*/
|
|
5
|
+
export * from './web-storage-persistence-provider.js';
|
|
6
|
+
export * from './persistence-filter.js';
|
|
7
|
+
export * from './persistence-resolver.js';
|
|
8
|
+
export * from './persistence-wiring.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice-level whitelist/blacklist filtering for persisted state.
|
|
3
|
+
*
|
|
4
|
+
* Persistence operates at the top-level reducer key ("slice") granularity:
|
|
5
|
+
* a whitelist keeps only the named slices; a blacklist drops named slices.
|
|
6
|
+
* The whitelist is applied first, then the blacklist. See amah/app-framework#30.
|
|
7
|
+
*/
|
|
8
|
+
import type { StorePersistenceConfig } from '../../api/index.js';
|
|
9
|
+
export type SliceSelection = Pick<StorePersistenceConfig, 'whitelist' | 'blacklist'>;
|
|
10
|
+
export declare function pickPersistableState(state: Record<string, unknown> | null | undefined, selection: SliceSelection): Record<string, unknown>;
|
|
11
|
+
//# sourceMappingURL=persistence-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence-filter.d.ts","sourceRoot":"","sources":["../../../src/impl/persistence/persistence-filter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,IAAI,CAC/B,sBAAsB,EACtB,WAAW,GAAG,WAAW,CAC1B,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EACjD,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBzB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice-level whitelist/blacklist filtering for persisted state.
|
|
3
|
+
*
|
|
4
|
+
* Persistence operates at the top-level reducer key ("slice") granularity:
|
|
5
|
+
* a whitelist keeps only the named slices; a blacklist drops named slices.
|
|
6
|
+
* The whitelist is applied first, then the blacklist. See amah/app-framework#30.
|
|
7
|
+
*/
|
|
8
|
+
export function pickPersistableState(state, selection) {
|
|
9
|
+
if (!state || typeof state !== 'object')
|
|
10
|
+
return {};
|
|
11
|
+
const { whitelist, blacklist } = selection;
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const key of Object.keys(state)) {
|
|
14
|
+
// A set whitelist constrains to its members (an empty whitelist persists
|
|
15
|
+
// nothing); an unset whitelist imposes no constraint. The blacklist is
|
|
16
|
+
// then applied on top.
|
|
17
|
+
if (whitelist && !whitelist.includes(key))
|
|
18
|
+
continue;
|
|
19
|
+
if (blacklist && blacklist.includes(key))
|
|
20
|
+
continue;
|
|
21
|
+
result[key] = state[key];
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a concrete `IPersistenceProvider` from a `StorePersistenceConfig`.
|
|
3
|
+
* Used to build the default provider when a consumer enables persistence but
|
|
4
|
+
* does not mount a custom one. See amah/app-framework#30.
|
|
5
|
+
*/
|
|
6
|
+
import type { StorePersistenceConfig } from '../../api/index.js';
|
|
7
|
+
import type { IPersistenceProvider } from '../../spi/index.js';
|
|
8
|
+
export declare function resolvePersistenceProvider(persistence: StorePersistenceConfig): IPersistenceProvider;
|
|
9
|
+
//# sourceMappingURL=persistence-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence-resolver.d.ts","sourceRoot":"","sources":["../../../src/impl/persistence/persistence-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAMtD,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,sBAAsB,GAClC,oBAAoB,CAiBtB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a concrete `IPersistenceProvider` from a `StorePersistenceConfig`.
|
|
3
|
+
* Used to build the default provider when a consumer enables persistence but
|
|
4
|
+
* does not mount a custom one. See amah/app-framework#30.
|
|
5
|
+
*/
|
|
6
|
+
import { createLocalStoragePersistenceProvider, createSessionStoragePersistenceProvider, } from './web-storage-persistence-provider.js';
|
|
7
|
+
export function resolvePersistenceProvider(persistence) {
|
|
8
|
+
const storage = persistence.storage ?? 'localStorage';
|
|
9
|
+
switch (storage) {
|
|
10
|
+
case 'sessionStorage':
|
|
11
|
+
return createSessionStoragePersistenceProvider();
|
|
12
|
+
case 'indexedDB':
|
|
13
|
+
// Not yet implemented — fall back to localStorage so enabling it is not a
|
|
14
|
+
// silent no-op. Tracked as a follow-up in #30.
|
|
15
|
+
console.warn("[persistence] storage 'indexedDB' is not implemented yet; " +
|
|
16
|
+
'falling back to localStorage.');
|
|
17
|
+
return createLocalStoragePersistenceProvider();
|
|
18
|
+
case 'localStorage':
|
|
19
|
+
default:
|
|
20
|
+
return createLocalStoragePersistenceProvider();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load/save wiring that connects a Redux store to an `IPersistenceProvider`.
|
|
3
|
+
*
|
|
4
|
+
* - `loadPersistedState` rehydrates the whitelisted slice on boot (async,
|
|
5
|
+
* called before store creation so the result can seed `preloadedState`).
|
|
6
|
+
* - `attachPersistenceSave` subscribes to the store and writes the whitelisted
|
|
7
|
+
* slice back, debounced, on every change. See amah/app-framework#30.
|
|
8
|
+
*/
|
|
9
|
+
import type { Store } from 'redux';
|
|
10
|
+
import type { StorePersistenceConfig } from '../../api/index.js';
|
|
11
|
+
import type { IPersistenceProvider } from '../../spi/index.js';
|
|
12
|
+
/** Default storage key when `persistence.key` is not set. */
|
|
13
|
+
export declare const DEFAULT_PERSISTENCE_KEY = "state";
|
|
14
|
+
/** Default debounce window for save-on-change. */
|
|
15
|
+
export declare const DEFAULT_PERSISTENCE_DEBOUNCE_MS = 250;
|
|
16
|
+
export declare function persistenceKey(persistence: StorePersistenceConfig): string;
|
|
17
|
+
/**
|
|
18
|
+
* Load the persisted slice and re-apply the whitelist/blacklist defensively
|
|
19
|
+
* (in case the config tightened since the data was written). Returns
|
|
20
|
+
* `undefined` when nothing is persisted, so callers can spread it into
|
|
21
|
+
* `preloadedState` without overwriting reducer defaults.
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadPersistedState(provider: IPersistenceProvider, persistence: StorePersistenceConfig): Promise<Record<string, unknown> | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* Subscribe to the store and persist the whitelisted slice on change,
|
|
26
|
+
* debounced. Returns an unsubscribe function that also cancels a pending save.
|
|
27
|
+
*/
|
|
28
|
+
export declare function attachPersistenceSave(store: Pick<Store, 'getState' | 'subscribe'>, provider: IPersistenceProvider, persistence: StorePersistenceConfig): () => void;
|
|
29
|
+
//# sourceMappingURL=persistence-wiring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence-wiring.d.ts","sourceRoot":"","sources":["../../../src/impl/persistence/persistence-wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGtD,6DAA6D;AAC7D,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAE/C,kDAAkD;AAClD,eAAO,MAAM,+BAA+B,MAAM,CAAC;AAEnD,wBAAgB,cAAc,CAAC,WAAW,EAAE,sBAAsB,GAAG,MAAM,CAE1E;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,sBAAsB,GAClC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAQ9C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAAC,EAC5C,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,sBAAsB,GAClC,MAAM,IAAI,CAyCZ"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load/save wiring that connects a Redux store to an `IPersistenceProvider`.
|
|
3
|
+
*
|
|
4
|
+
* - `loadPersistedState` rehydrates the whitelisted slice on boot (async,
|
|
5
|
+
* called before store creation so the result can seed `preloadedState`).
|
|
6
|
+
* - `attachPersistenceSave` subscribes to the store and writes the whitelisted
|
|
7
|
+
* slice back, debounced, on every change. See amah/app-framework#30.
|
|
8
|
+
*/
|
|
9
|
+
import { pickPersistableState } from './persistence-filter.js';
|
|
10
|
+
/** Default storage key when `persistence.key` is not set. */
|
|
11
|
+
export const DEFAULT_PERSISTENCE_KEY = 'state';
|
|
12
|
+
/** Default debounce window for save-on-change. */
|
|
13
|
+
export const DEFAULT_PERSISTENCE_DEBOUNCE_MS = 250;
|
|
14
|
+
export function persistenceKey(persistence) {
|
|
15
|
+
return persistence.key ?? DEFAULT_PERSISTENCE_KEY;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Load the persisted slice and re-apply the whitelist/blacklist defensively
|
|
19
|
+
* (in case the config tightened since the data was written). Returns
|
|
20
|
+
* `undefined` when nothing is persisted, so callers can spread it into
|
|
21
|
+
* `preloadedState` without overwriting reducer defaults.
|
|
22
|
+
*/
|
|
23
|
+
export async function loadPersistedState(provider, persistence) {
|
|
24
|
+
const loaded = await provider.load(persistenceKey(persistence));
|
|
25
|
+
if (loaded == null || typeof loaded !== 'object')
|
|
26
|
+
return undefined;
|
|
27
|
+
const filtered = pickPersistableState(loaded, persistence);
|
|
28
|
+
return Object.keys(filtered).length > 0 ? filtered : undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Subscribe to the store and persist the whitelisted slice on change,
|
|
32
|
+
* debounced. Returns an unsubscribe function that also cancels a pending save.
|
|
33
|
+
*/
|
|
34
|
+
export function attachPersistenceSave(store, provider, persistence) {
|
|
35
|
+
const key = persistenceKey(persistence);
|
|
36
|
+
const debounceMs = persistence.debounceMs ?? DEFAULT_PERSISTENCE_DEBOUNCE_MS;
|
|
37
|
+
let timer = null;
|
|
38
|
+
// Seed the baseline with the current slice so a change that leaves the
|
|
39
|
+
// persisted slice untouched (e.g. a non-whitelisted slice updated) never
|
|
40
|
+
// triggers a redundant write — including right after rehydration.
|
|
41
|
+
let lastSerialized = JSON.stringify(pickPersistableState(store.getState(), persistence));
|
|
42
|
+
const flush = () => {
|
|
43
|
+
timer = null;
|
|
44
|
+
const slice = pickPersistableState(store.getState(), persistence);
|
|
45
|
+
const serialized = JSON.stringify(slice);
|
|
46
|
+
// Skip redundant writes when the persisted slice did not actually change.
|
|
47
|
+
if (serialized === lastSerialized)
|
|
48
|
+
return;
|
|
49
|
+
lastSerialized = serialized;
|
|
50
|
+
void provider.save(key, slice);
|
|
51
|
+
};
|
|
52
|
+
const unsubscribe = store.subscribe(() => {
|
|
53
|
+
if (timer !== null)
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
if (debounceMs <= 0) {
|
|
56
|
+
flush();
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
timer = setTimeout(flush, debounceMs);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return () => {
|
|
63
|
+
if (timer !== null) {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
timer = null;
|
|
66
|
+
}
|
|
67
|
+
unsubscribe();
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Storage Persistence Provider
|
|
3
|
+
*
|
|
4
|
+
* Concrete `IPersistenceProvider` backed by a Web Storage area
|
|
5
|
+
* (`localStorage` / `sessionStorage`). When the backing storage is
|
|
6
|
+
* unavailable — SSR, private-mode quota errors, disabled storage — it
|
|
7
|
+
* degrades gracefully to an in-memory map so callers never throw. This mirrors
|
|
8
|
+
* the `createLocalStorageActiveProjectStorage` fallback pattern used
|
|
9
|
+
* downstream. See amah/app-framework#30.
|
|
10
|
+
*/
|
|
11
|
+
import type { IPersistenceProvider } from '../../spi/index.js';
|
|
12
|
+
/** Minimal structural subset of the Web Storage API we depend on. */
|
|
13
|
+
export interface WebStorageLike {
|
|
14
|
+
getItem(key: string): string | null;
|
|
15
|
+
setItem(key: string, value: string): void;
|
|
16
|
+
removeItem(key: string): void;
|
|
17
|
+
key(index: number): string | null;
|
|
18
|
+
readonly length: number;
|
|
19
|
+
}
|
|
20
|
+
/** Default namespace every persisted key is prefixed with. */
|
|
21
|
+
export declare const DEFAULT_PERSISTENCE_NAMESPACE = "@hamak/ui-store";
|
|
22
|
+
export declare class WebStoragePersistenceProvider implements IPersistenceProvider {
|
|
23
|
+
private readonly storage;
|
|
24
|
+
private readonly namespace;
|
|
25
|
+
private readonly memory;
|
|
26
|
+
private readonly available;
|
|
27
|
+
/**
|
|
28
|
+
* @param storage Backing web storage, or `null` to run in-memory only.
|
|
29
|
+
* @param namespace Key prefix; `clear()` only removes keys under this prefix
|
|
30
|
+
* so it never wipes unrelated app state.
|
|
31
|
+
*/
|
|
32
|
+
constructor(storage: WebStorageLike | null, namespace?: string);
|
|
33
|
+
isAvailable(): boolean;
|
|
34
|
+
save(key: string, state: unknown): Promise<void>;
|
|
35
|
+
load(key: string): Promise<any | null>;
|
|
36
|
+
remove(key: string): Promise<void>;
|
|
37
|
+
clear(): Promise<void>;
|
|
38
|
+
private fullKey;
|
|
39
|
+
/** Verify the storage area is usable with a write/remove round-trip. */
|
|
40
|
+
private static probe;
|
|
41
|
+
}
|
|
42
|
+
/** Provider backed by `window.localStorage` (in-memory fallback when absent). */
|
|
43
|
+
export declare function createLocalStoragePersistenceProvider(namespace?: string): WebStoragePersistenceProvider;
|
|
44
|
+
/** Provider backed by `window.sessionStorage` (in-memory fallback when absent). */
|
|
45
|
+
export declare function createSessionStoragePersistenceProvider(namespace?: string): WebStoragePersistenceProvider;
|
|
46
|
+
//# sourceMappingURL=web-storage-persistence-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-storage-persistence-provider.d.ts","sourceRoot":"","sources":["../../../src/impl/persistence/web-storage-persistence-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEtD,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,8DAA8D;AAC9D,eAAO,MAAM,6BAA6B,oBAAoB,CAAC;AAI/D,qBAAa,6BAA8B,YAAW,oBAAoB;IAUtE,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAV5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IAEpC;;;;OAIG;gBAEgB,OAAO,EAAE,cAAc,GAAG,IAAI,EAC9B,SAAS,GAAE,MAAsC;IAKpE,WAAW,IAAI,OAAO;IAIhB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAchD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAsBtC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B,OAAO,CAAC,OAAO;IAIf,wEAAwE;IACxE,OAAO,CAAC,MAAM,CAAC,KAAK;CAUrB;AAcD,iFAAiF;AACjF,wBAAgB,qCAAqC,CACnD,SAAS,CAAC,EAAE,MAAM,GACjB,6BAA6B,CAK/B;AAED,mFAAmF;AACnF,wBAAgB,uCAAuC,CACrD,SAAS,CAAC,EAAE,MAAM,GACjB,6BAA6B,CAK/B"}
|