@contember/bindx 0.1.46 → 0.1.47
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/core/ActionDispatcher.d.ts +4 -1
- package/dist/core/ActionDispatcher.d.ts.map +1 -1
- package/dist/core/actions.d.ts +7 -1
- package/dist/core/actions.d.ts.map +1 -1
- package/dist/events/EventEmitter.d.ts +13 -1
- package/dist/events/EventEmitter.d.ts.map +1 -1
- package/dist/handles/BaseHandle.d.ts +14 -3
- package/dist/handles/BaseHandle.d.ts.map +1 -1
- package/dist/handles/EntityHandle.d.ts +14 -5
- package/dist/handles/EntityHandle.d.ts.map +1 -1
- package/dist/handles/FieldHandle.d.ts +11 -4
- package/dist/handles/FieldHandle.d.ts.map +1 -1
- package/dist/handles/HasManyListHandle.d.ts +36 -2
- package/dist/handles/HasManyListHandle.d.ts.map +1 -1
- package/dist/handles/HasOneHandle.d.ts +52 -9
- package/dist/handles/HasOneHandle.d.ts.map +1 -1
- package/dist/handles/PlaceholderHandle.d.ts +25 -13
- package/dist/handles/PlaceholderHandle.d.ts.map +1 -1
- package/dist/handles/index.d.ts +1 -1
- package/dist/handles/index.d.ts.map +1 -1
- package/dist/handles/proxyFactory.d.ts +7 -1
- package/dist/handles/proxyFactory.d.ts.map +1 -1
- package/dist/handles/types.d.ts +33 -0
- package/dist/handles/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/persistence/BatchPersister.d.ts +53 -37
- package/dist/persistence/BatchPersister.d.ts.map +1 -1
- package/dist/persistence/ChangeRegistry.d.ts +15 -0
- package/dist/persistence/ChangeRegistry.d.ts.map +1 -1
- package/dist/persistence/MutationCollector.d.ts +106 -3
- package/dist/persistence/MutationCollector.d.ts.map +1 -1
- package/dist/persistence/PersistExecution.d.ts +26 -0
- package/dist/persistence/PersistExecution.d.ts.map +1 -0
- package/dist/persistence/types.d.ts +8 -2
- package/dist/persistence/types.d.ts.map +1 -1
- package/dist/store/EntityMetaStore.d.ts +32 -10
- package/dist/store/EntityMetaStore.d.ts.map +1 -1
- package/dist/store/EntitySnapshotStore.d.ts +50 -3
- package/dist/store/EntitySnapshotStore.d.ts.map +1 -1
- package/dist/store/ErrorStore.d.ts +3 -2
- package/dist/store/ErrorStore.d.ts.map +1 -1
- package/dist/store/HasManyStore.d.ts +214 -0
- package/dist/store/HasManyStore.d.ts.map +1 -0
- package/dist/store/HasOneStore.d.ts +159 -0
- package/dist/store/HasOneStore.d.ts.map +1 -0
- package/dist/store/ReachabilityAnalyzer.d.ts +19 -0
- package/dist/store/ReachabilityAnalyzer.d.ts.map +1 -1
- package/dist/store/RekeyOrchestrator.d.ts +76 -0
- package/dist/store/RekeyOrchestrator.d.ts.map +1 -0
- package/dist/store/RelationEdgeIndex.d.ts +34 -0
- package/dist/store/RelationEdgeIndex.d.ts.map +1 -0
- package/dist/store/RelationStore.d.ts +74 -137
- package/dist/store/RelationStore.d.ts.map +1 -1
- package/dist/store/RootRegistry.d.ts +25 -4
- package/dist/store/RootRegistry.d.ts.map +1 -1
- package/dist/store/SnapshotStore.d.ts +137 -13
- package/dist/store/SnapshotStore.d.ts.map +1 -1
- package/dist/store/SubscriptionManager.d.ts +63 -14
- package/dist/store/SubscriptionManager.d.ts.map +1 -1
- package/dist/store/TouchedStore.d.ts +3 -2
- package/dist/store/TouchedStore.d.ts.map +1 -1
- package/dist/store/relationKey.d.ts +15 -0
- package/dist/store/relationKey.d.ts.map +1 -0
- package/dist/undo/UndoJournal.d.ts +133 -0
- package/dist/undo/UndoJournal.d.ts.map +1 -0
- package/dist/undo/UndoManager.d.ts +25 -82
- package/dist/undo/UndoManager.d.ts.map +1 -1
- package/dist/undo/UnrecordedWriteError.d.ts +16 -0
- package/dist/undo/UnrecordedWriteError.d.ts.map +1 -0
- package/dist/undo/index.d.ts +3 -1
- package/dist/undo/index.d.ts.map +1 -1
- package/dist/undo/rekeyJournalEntry.d.ts +20 -0
- package/dist/undo/rekeyJournalEntry.d.ts.map +1 -0
- package/dist/undo/types.d.ts +0 -48
- package/dist/undo/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/core/ActionDispatcher.ts +56 -36
- package/src/core/actions.ts +8 -1
- package/src/events/EventEmitter.ts +78 -24
- package/src/handles/BaseHandle.ts +19 -2
- package/src/handles/EntityHandle.ts +48 -17
- package/src/handles/FieldHandle.ts +36 -10
- package/src/handles/HasManyListHandle.ts +120 -16
- package/src/handles/HasOneHandle.ts +177 -44
- package/src/handles/PlaceholderHandle.ts +184 -36
- package/src/handles/index.ts +3 -0
- package/src/handles/proxyFactory.ts +27 -0
- package/src/handles/types.ts +39 -0
- package/src/index.ts +4 -4
- package/src/persistence/BatchPersister.ts +810 -446
- package/src/persistence/ChangeRegistry.ts +27 -3
- package/src/persistence/MutationCollector.ts +265 -31
- package/src/persistence/PersistExecution.ts +217 -0
- package/src/persistence/types.ts +8 -2
- package/src/store/EntityMetaStore.ts +89 -45
- package/src/store/EntitySnapshotStore.ts +102 -19
- package/src/store/ErrorStore.ts +6 -5
- package/src/store/HasManyStore.ts +810 -0
- package/src/store/HasOneStore.ts +454 -0
- package/src/store/ReachabilityAnalyzer.ts +37 -0
- package/src/store/RekeyOrchestrator.ts +123 -0
- package/src/store/RelationEdgeIndex.ts +79 -0
- package/src/store/RelationStore.ts +176 -725
- package/src/store/RootRegistry.ts +50 -8
- package/src/store/SnapshotStore.ts +572 -101
- package/src/store/SubscriptionManager.ts +122 -75
- package/src/store/TouchedStore.ts +5 -2
- package/src/store/relationKey.ts +20 -0
- package/src/undo/UndoJournal.ts +258 -0
- package/src/undo/UndoManager.ts +151 -281
- package/src/undo/UnrecordedWriteError.ts +23 -0
- package/src/undo/index.ts +8 -7
- package/src/undo/rekeyJournalEntry.ts +145 -0
- package/src/undo/types.ts +0 -58
- package/dist/core/actionClassification.d.ts +0 -48
- package/dist/core/actionClassification.d.ts.map +0 -1
- package/src/core/actionClassification.ts +0 -199
|
@@ -3,117 +3,60 @@ import type { SnapshotStore } from '../store/SnapshotStore.js';
|
|
|
3
3
|
import type { UndoManagerConfig, UndoState } from './types.js';
|
|
4
4
|
type Subscriber = () => void;
|
|
5
5
|
/**
|
|
6
|
-
* UndoManager
|
|
6
|
+
* UndoManager — the policy layer over the {@link UndoJournal}.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* The journal records each gesture (one dispatch / one handle transaction) as a
|
|
9
|
+
* {@link JournalEntry} of editable-layer pre-images. UndoManager owns the undo /
|
|
10
|
+
* redo stacks and the grouping policy (debounced auto-grouping + manual
|
|
11
|
+
* begin/endGroup), blocks during persist, and keeps the stacks aligned across a
|
|
12
|
+
* temp→persisted rekey. Restore goes straight through the store's write paths, so
|
|
13
|
+
* the edge index and reachability cache rebuild themselves; the event/interceptor
|
|
14
|
+
* pipeline is NOT replayed.
|
|
14
15
|
*/
|
|
15
16
|
export declare class UndoManager {
|
|
16
17
|
private readonly store;
|
|
18
|
+
private readonly journal;
|
|
17
19
|
private undoStack;
|
|
18
20
|
private redoStack;
|
|
19
|
-
|
|
21
|
+
/** Cells accumulated while a debounce window or manual group is open (first-writer-wins). */
|
|
22
|
+
private pending;
|
|
20
23
|
private debounceTimer;
|
|
21
|
-
private isBlocked;
|
|
22
24
|
private manualGroupId;
|
|
23
|
-
private
|
|
25
|
+
private blockDepth;
|
|
24
26
|
private subscribers;
|
|
25
27
|
private cachedState;
|
|
26
28
|
private readonly maxHistorySize;
|
|
27
29
|
private readonly debounceMs;
|
|
28
30
|
constructor(store: SnapshotStore, config?: UndoManagerConfig);
|
|
29
31
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
+
* Wires the journal into the store so its write paths record gestures. The
|
|
33
|
+
* returned middleware is a backward-compatible pass-through (recording is native
|
|
34
|
+
* to the store transaction, not the middleware).
|
|
32
35
|
*/
|
|
33
36
|
createMiddleware(): ActionMiddleware;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
/**
|
|
39
|
-
* Handles action in manual group mode.
|
|
40
|
-
*/
|
|
41
|
-
private handleManualGroupAction;
|
|
42
|
-
/**
|
|
43
|
-
* Handles action in debounced auto-group mode.
|
|
44
|
-
*/
|
|
45
|
-
private handleDebouncedAction;
|
|
46
|
-
/**
|
|
47
|
-
* Gets keys that are in source but not in target.
|
|
48
|
-
*/
|
|
49
|
-
private getNewKeys;
|
|
50
|
-
/**
|
|
51
|
-
* Checks if keys object is empty.
|
|
52
|
-
*/
|
|
53
|
-
private isEmptyKeys;
|
|
54
|
-
/**
|
|
55
|
-
* Merges additional snapshot into target.
|
|
56
|
-
*/
|
|
57
|
-
private mergeSnapshots;
|
|
58
|
-
/**
|
|
59
|
-
* Starts the debounce timer.
|
|
60
|
-
*/
|
|
61
|
-
private startDebounceTimer;
|
|
62
|
-
/**
|
|
63
|
-
* Resets the debounce timer.
|
|
64
|
-
*/
|
|
37
|
+
private onEntry;
|
|
38
|
+
private mergeIntoPending;
|
|
39
|
+
private flushPending;
|
|
40
|
+
private pushEntry;
|
|
65
41
|
private resetDebounceTimer;
|
|
66
42
|
/**
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
private flushPendingEntry;
|
|
70
|
-
/**
|
|
71
|
-
* Trims history to max size.
|
|
72
|
-
*/
|
|
73
|
-
private trimHistory;
|
|
74
|
-
/**
|
|
75
|
-
* Starts a manual group. All actions until endGroup are grouped as one undo entry.
|
|
76
|
-
* Returns group ID that must be passed to endGroup.
|
|
77
|
-
*/
|
|
78
|
-
beginGroup(label?: string): string;
|
|
79
|
-
/**
|
|
80
|
-
* Ends a manual group and pushes to undo stack.
|
|
43
|
+
* Starts a manual group: every gesture until {@link endGroup} folds into one
|
|
44
|
+
* undo entry. Returns a handle that must be passed back to endGroup.
|
|
81
45
|
*/
|
|
46
|
+
beginGroup(_label?: string): string;
|
|
82
47
|
endGroup(groupId: string): void;
|
|
83
|
-
/**
|
|
84
|
-
* Undoes the last entry.
|
|
85
|
-
*/
|
|
86
48
|
undo(): void;
|
|
87
|
-
/**
|
|
88
|
-
* Redoes the last undone entry.
|
|
89
|
-
*/
|
|
90
49
|
redo(): void;
|
|
91
|
-
/**
|
|
92
|
-
* Blocks undo/redo operations.
|
|
93
|
-
* Use during persist to prevent inconsistent state.
|
|
94
|
-
*/
|
|
95
50
|
block(): void;
|
|
96
|
-
/**
|
|
97
|
-
* Unblocks undo/redo operations.
|
|
98
|
-
*/
|
|
99
51
|
unblock(): void;
|
|
100
52
|
/**
|
|
101
|
-
*
|
|
53
|
+
* Rewrites every stacked entry when a temp id is replaced by its persisted id,
|
|
54
|
+
* so stored cells keep valid keys / id references (and sealed creates drop out).
|
|
102
55
|
*/
|
|
56
|
+
private rekeyStacks;
|
|
103
57
|
clear(): void;
|
|
104
|
-
/**
|
|
105
|
-
* Subscribes to state changes.
|
|
106
|
-
* Returns unsubscribe function.
|
|
107
|
-
*/
|
|
108
58
|
subscribe(callback: Subscriber): () => void;
|
|
109
|
-
/**
|
|
110
|
-
* Gets current state for React integration.
|
|
111
|
-
* Returns a cached object to satisfy useSyncExternalStore's referential equality requirement.
|
|
112
|
-
*/
|
|
113
59
|
getState(): UndoState;
|
|
114
|
-
/**
|
|
115
|
-
* Notifies all subscribers of state change.
|
|
116
|
-
*/
|
|
117
60
|
private notifySubscribers;
|
|
118
61
|
}
|
|
119
62
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UndoManager.d.ts","sourceRoot":"","sources":["../../src/undo/UndoManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"UndoManager.d.ts","sourceRoot":"","sources":["../../src/undo/UndoManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAI9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE9D,KAAK,UAAU,GAAG,MAAM,IAAI,CAAA;AAS5B;;;;;;;;;;GAUG;AACH,qBAAa,WAAW;IAkBtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAjBvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAqB;IAEtC,6FAA6F;IAC7F,OAAO,CAAC,OAAO,CAA6C;IAC5D,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,aAAa,CAAsB;IAE3C,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,WAAW,CAAyB;IAE5C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAGjB,KAAK,EAAE,aAAa,EACrC,MAAM,GAAE,iBAAsB;IAY/B;;;;OAIG;IACH,gBAAgB,IAAI,gBAAgB;IAWpC,OAAO,CAAC,OAAO;IAwBf,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,kBAAkB;IAS1B;;;OAGG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAOnC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAW/B,IAAI,IAAI,IAAI;IAcZ,IAAI,IAAI,IAAI;IAaZ,KAAK,IAAI,IAAI;IAUb,OAAO,IAAI,IAAI;IAUf;;;OAGG;IACH,OAAO,CAAC,WAAW;IAiCnB,KAAK,IAAI,IAAI;IAYb,SAAS,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,IAAI;IAO3C,QAAQ,IAAI,SAAS;IAcrB,OAAO,CAAC,iBAAiB;CAMzB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { JournalCellKind } from './UndoJournal.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a journal transaction closes after an editable-layer store write
|
|
4
|
+
* that was NOT preceded by a matching `journal.record*` call — i.e. a mutating
|
|
5
|
+
* SnapshotStore method wrote primary state a gesture can no longer undo.
|
|
6
|
+
*
|
|
7
|
+
* This turns the "every mutating method must record before writing" convention
|
|
8
|
+
* into a checked invariant: the sub-store editable-write counters advanced for a
|
|
9
|
+
* kind the transaction never recorded. The named kinds pinpoint which record call
|
|
10
|
+
* is missing (recordEntity / recordRelation / recordHasMany).
|
|
11
|
+
*/
|
|
12
|
+
export declare class UnrecordedWriteError extends Error {
|
|
13
|
+
readonly kinds: ReadonlyArray<JournalCellKind>;
|
|
14
|
+
constructor(kinds: ReadonlyArray<JournalCellKind>);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=UnrecordedWriteError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnrecordedWriteError.d.ts","sourceRoot":"","sources":["../../src/undo/UnrecordedWriteError.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD;;;;;;;;;GASG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aAClB,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC;gBAArC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC;CASjE"}
|
package/dist/undo/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { UndoManager } from './UndoManager.js';
|
|
2
|
-
export
|
|
2
|
+
export { UnrecordedWriteError } from './UnrecordedWriteError.js';
|
|
3
|
+
export type { UndoManagerConfig, UndoState } from './types.js';
|
|
4
|
+
export type { JournalEntry, JournalCellImage, EntityCellImage, RelationCellImage, HasManyCellImage, } from './UndoJournal.js';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/undo/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/undo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EACX,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/undo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC9D,YAAY,EACX,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RekeyContext } from '../store/RekeyOrchestrator.js';
|
|
2
|
+
import type { JournalEntry } from './UndoJournal.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rewrites a journal entry for a temp→persisted rekey so stored cells stay valid
|
|
5
|
+
* after persist:
|
|
6
|
+
* - owner keys move from the temp prefix to the persisted prefix;
|
|
7
|
+
* - embedded id references (snapshot ids, relation currentId/serverId, has-many
|
|
8
|
+
* members) are remapped oldId→newId;
|
|
9
|
+
* - the create is SEALED: an "absent" pre-image of the now-persisted entity (or
|
|
10
|
+
* its owned relations) is dropped, so undo can no longer delete the
|
|
11
|
+
* server-backed row — only later edits to it remain undoable.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Looks up the live server-member ids of a has-many list by its key. Lets the
|
|
15
|
+
* rekey rebase a pre-image when the just-persisted create has become a permanent
|
|
16
|
+
* member of that list.
|
|
17
|
+
*/
|
|
18
|
+
export type LiveServerIdsLookup = (relationKey: string) => Set<string>;
|
|
19
|
+
export declare function rekeyJournalEntry(entry: JournalEntry, ctx: RekeyContext, liveServerIds: LiveServerIdsLookup): JournalEntry;
|
|
20
|
+
//# sourceMappingURL=rekeyJournalEntry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rekeyJournalEntry.d.ts","sourceRoot":"","sources":["../../src/undo/rekeyJournalEntry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAIjE,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,kBAAkB,CAAA;AAEtE;;;;;;;;;GASG;AACH;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CAAA;AAEtE,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,YAAY,EACjB,aAAa,EAAE,mBAAmB,GAChC,YAAY,CAOd"}
|
package/dist/undo/types.d.ts
CHANGED
|
@@ -1,50 +1,3 @@
|
|
|
1
|
-
import type { StoreAffectedKeys } from '../core/actionClassification.js';
|
|
2
|
-
import type { EntitySnapshot } from '../store/snapshots.js';
|
|
3
|
-
import type { StoredRelationState, StoredHasManyState, EntityMeta } from '../store/SnapshotStore.js';
|
|
4
|
-
/**
|
|
5
|
-
* Partial snapshot of store state.
|
|
6
|
-
* Contains only the data affected by an action or group of actions.
|
|
7
|
-
*/
|
|
8
|
-
export interface PartialStoreSnapshot {
|
|
9
|
-
/** Entity snapshots (frozen, immutable) */
|
|
10
|
-
entitySnapshots: Map<string, EntitySnapshot>;
|
|
11
|
-
/** Has-one relation states */
|
|
12
|
-
relationStates: Map<string, StoredRelationState>;
|
|
13
|
-
/** Has-many list states */
|
|
14
|
-
hasManyStates: Map<string, StoredHasManyState>;
|
|
15
|
-
/** Entity metadata (existsOnServer, deletion flags) */
|
|
16
|
-
entityMetas: Map<string, EntityMeta>;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* A single undo/redo entry.
|
|
20
|
-
* Contains the snapshot of state BEFORE the action(s) were applied.
|
|
21
|
-
*/
|
|
22
|
-
export interface UndoEntry {
|
|
23
|
-
/** Unique identifier for this entry */
|
|
24
|
-
id: string;
|
|
25
|
-
/** Optional human-readable label */
|
|
26
|
-
label?: string;
|
|
27
|
-
/** Snapshot of state BEFORE the action(s) */
|
|
28
|
-
beforeSnapshot: PartialStoreSnapshot;
|
|
29
|
-
/** Keys that were affected (for redo snapshot capture) */
|
|
30
|
-
affectedKeys: StoreAffectedKeys;
|
|
31
|
-
/** When this entry was created */
|
|
32
|
-
timestamp: number;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Pending entry during debounce window.
|
|
36
|
-
* Accumulates affected keys while waiting for debounce to complete.
|
|
37
|
-
*/
|
|
38
|
-
export interface PendingUndoEntry {
|
|
39
|
-
/** Snapshot captured before the first action in the group */
|
|
40
|
-
beforeSnapshot: PartialStoreSnapshot;
|
|
41
|
-
/** Accumulated affected keys */
|
|
42
|
-
affectedKeys: StoreAffectedKeys;
|
|
43
|
-
/** When the first action occurred */
|
|
44
|
-
timestamp: number;
|
|
45
|
-
/** Optional label for manual grouping */
|
|
46
|
-
label?: string;
|
|
47
|
-
}
|
|
48
1
|
/**
|
|
49
2
|
* Configuration options for UndoManager.
|
|
50
3
|
*/
|
|
@@ -70,5 +23,4 @@ export interface UndoState {
|
|
|
70
23
|
/** Number of entries in redo stack */
|
|
71
24
|
redoCount: number;
|
|
72
25
|
}
|
|
73
|
-
export type { StoreAffectedKeys } from '../core/actionClassification.js';
|
|
74
26
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/undo/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/undo/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/undo/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAA;IAClB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAA;IACjB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAA;CACjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/bindx",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
4
4
|
"description": "Type-safe data binding framework (core)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@contember/bindx-client": "0.1.
|
|
20
|
+
"@contember/bindx-client": "0.1.47",
|
|
21
21
|
"@contember/graphql-client": "^2.1.0-beta.1"
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
@@ -27,6 +27,7 @@ export class ActionDispatcher {
|
|
|
27
27
|
eventEmitter?: EventEmitter,
|
|
28
28
|
) {
|
|
29
29
|
this.eventEmitter = eventEmitter ?? new EventEmitter()
|
|
30
|
+
this.store.attachRekeyParticipant(this.eventEmitter)
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -42,39 +43,46 @@ export class ActionDispatcher {
|
|
|
42
43
|
* Async interceptors are skipped with a warning — use dispatchAsync() for those.
|
|
43
44
|
*/
|
|
44
45
|
dispatch(action: Action): void {
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
// One dispatch = one undoable gesture. The store records every primary write
|
|
47
|
+
// made between begin/commit into a single journal entry (no-op without undo).
|
|
48
|
+
this.store.beginTransaction()
|
|
49
|
+
try {
|
|
50
|
+
// Run through middlewares first
|
|
51
|
+
for (const middleware of this.middlewares) {
|
|
52
|
+
const result = middleware(action, this.store)
|
|
53
|
+
if (result === false) {
|
|
54
|
+
// Middleware can cancel the action
|
|
55
|
+
return
|
|
56
|
+
}
|
|
51
57
|
}
|
|
52
|
-
}
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
// Create and run before event through interceptors (synchronously)
|
|
60
|
+
const beforeEvent = createBeforeEvent(action, this.store)
|
|
61
|
+
if (beforeEvent) {
|
|
62
|
+
const result = this.eventEmitter.runInterceptorsSync(beforeEvent)
|
|
63
|
+
if (result === null) {
|
|
64
|
+
// Interceptor cancelled the action
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
// If event was modified, update action accordingly
|
|
68
|
+
if (result !== beforeEvent) {
|
|
69
|
+
action = this.updateActionFromEvent(action, result)
|
|
70
|
+
}
|
|
65
71
|
}
|
|
66
|
-
}
|
|
67
72
|
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
// Capture state before execution (for after events)
|
|
74
|
+
const stateBefore = captureStateBeforeAction(action, this.store)
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
// Execute the action
|
|
77
|
+
this.execute(action)
|
|
73
78
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
// Emit after event
|
|
80
|
+
const afterEvent = createAfterEvent(action, stateBefore, this.store)
|
|
81
|
+
if (afterEvent) {
|
|
82
|
+
this.eventEmitter.emit(afterEvent)
|
|
83
|
+
}
|
|
84
|
+
} finally {
|
|
85
|
+
this.store.commitTransaction()
|
|
78
86
|
}
|
|
79
87
|
}
|
|
80
88
|
|
|
@@ -108,16 +116,21 @@ export class ActionDispatcher {
|
|
|
108
116
|
// Capture state before execution (for after events)
|
|
109
117
|
const stateBefore = captureStateBeforeAction(action, this.store)
|
|
110
118
|
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
this.store.beginTransaction()
|
|
120
|
+
try {
|
|
121
|
+
// Execute the action
|
|
122
|
+
this.execute(action)
|
|
113
123
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
124
|
+
// Emit after event
|
|
125
|
+
const afterEvent = createAfterEvent(action, stateBefore, this.store)
|
|
126
|
+
if (afterEvent) {
|
|
127
|
+
this.eventEmitter.emit(afterEvent)
|
|
128
|
+
}
|
|
119
129
|
|
|
120
|
-
|
|
130
|
+
return true
|
|
131
|
+
} finally {
|
|
132
|
+
this.store.commitTransaction()
|
|
133
|
+
}
|
|
121
134
|
}
|
|
122
135
|
|
|
123
136
|
/**
|
|
@@ -174,6 +187,9 @@ export class ActionDispatcher {
|
|
|
174
187
|
const index = this.middlewares.indexOf(middleware)
|
|
175
188
|
if (index !== -1) {
|
|
176
189
|
this.middlewares.splice(index, 1)
|
|
190
|
+
if (!this.middlewares.includes(middleware)) {
|
|
191
|
+
middleware.dispose?.()
|
|
192
|
+
}
|
|
177
193
|
}
|
|
178
194
|
}
|
|
179
195
|
|
|
@@ -373,6 +389,7 @@ export class ActionDispatcher {
|
|
|
373
389
|
action.entityType,
|
|
374
390
|
action.entityId,
|
|
375
391
|
action.isPersisting,
|
|
392
|
+
action.pessimistic ?? false,
|
|
376
393
|
)
|
|
377
394
|
break
|
|
378
395
|
|
|
@@ -455,7 +472,10 @@ export class ActionDispatcher {
|
|
|
455
472
|
* Can inspect/modify actions before execution.
|
|
456
473
|
* Return false to cancel the action.
|
|
457
474
|
*/
|
|
458
|
-
export
|
|
475
|
+
export interface ActionMiddleware {
|
|
476
|
+
(action: Action, store: SnapshotStore): boolean | void
|
|
477
|
+
dispose?: () => void
|
|
478
|
+
}
|
|
459
479
|
|
|
460
480
|
/**
|
|
461
481
|
* Creates a logging middleware for debugging.
|
package/src/core/actions.ts
CHANGED
|
@@ -202,6 +202,12 @@ export interface SetPersistingAction {
|
|
|
202
202
|
readonly entityType: string
|
|
203
203
|
readonly entityId: string
|
|
204
204
|
readonly isPersisting: boolean
|
|
205
|
+
/**
|
|
206
|
+
* Whether this persist is pessimistic. While a pessimistic persist is
|
|
207
|
+
* in-flight, handles present the server baseline instead of the (still dirty)
|
|
208
|
+
* local data. Ignored when isPersisting is false.
|
|
209
|
+
*/
|
|
210
|
+
readonly pessimistic?: boolean
|
|
205
211
|
}
|
|
206
212
|
|
|
207
213
|
// ==================== Error Actions ====================
|
|
@@ -428,8 +434,9 @@ export function setPersisting(
|
|
|
428
434
|
entityType: string,
|
|
429
435
|
entityId: string,
|
|
430
436
|
isPersisting: boolean,
|
|
437
|
+
pessimistic: boolean = false,
|
|
431
438
|
): SetPersistingAction {
|
|
432
|
-
return { type: 'SET_PERSISTING', entityType, entityId, isPersisting }
|
|
439
|
+
return { type: 'SET_PERSISTING', entityType, entityId, isPersisting, pessimistic }
|
|
433
440
|
}
|
|
434
441
|
|
|
435
442
|
/**
|