@arcmantle/chronicle 0.0.4

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.
Files changed (113) hide show
  1. package/README.md +563 -0
  2. package/dist/api-methods.d.ts +28 -0
  3. package/dist/api-methods.d.ts.map +1 -0
  4. package/dist/api-methods.js +206 -0
  5. package/dist/api-methods.js.map +1 -0
  6. package/dist/api.d.ts +12 -0
  7. package/dist/api.d.ts.map +1 -0
  8. package/dist/api.js +30 -0
  9. package/dist/api.js.map +1 -0
  10. package/dist/array-mutations.d.ts +31 -0
  11. package/dist/array-mutations.d.ts.map +1 -0
  12. package/dist/array-mutations.js +50 -0
  13. package/dist/array-mutations.js.map +1 -0
  14. package/dist/batch-transaction.d.ts +25 -0
  15. package/dist/batch-transaction.d.ts.map +1 -0
  16. package/dist/batch-transaction.js +138 -0
  17. package/dist/batch-transaction.js.map +1 -0
  18. package/dist/chronicle.d.ts +41 -0
  19. package/dist/chronicle.d.ts.map +1 -0
  20. package/dist/chronicle.js +40 -0
  21. package/dist/chronicle.js.map +1 -0
  22. package/dist/collection-adapters.d.ts +29 -0
  23. package/dist/collection-adapters.d.ts.map +1 -0
  24. package/dist/collection-adapters.js +184 -0
  25. package/dist/collection-adapters.js.map +1 -0
  26. package/dist/config.d.ts +7 -0
  27. package/dist/config.d.ts.map +1 -0
  28. package/dist/config.js +11 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/grouping.d.ts +17 -0
  31. package/dist/grouping.d.ts.map +1 -0
  32. package/dist/grouping.js +35 -0
  33. package/dist/grouping.js.map +1 -0
  34. package/dist/history-recorder.d.ts +39 -0
  35. package/dist/history-recorder.d.ts.map +1 -0
  36. package/dist/history-recorder.js +112 -0
  37. package/dist/history-recorder.js.map +1 -0
  38. package/dist/history.d.ts +29 -0
  39. package/dist/history.d.ts.map +1 -0
  40. package/dist/history.js +47 -0
  41. package/dist/history.js.map +1 -0
  42. package/dist/listener-affinity.d.ts +16 -0
  43. package/dist/listener-affinity.d.ts.map +1 -0
  44. package/dist/listener-affinity.js +58 -0
  45. package/dist/listener-affinity.js.map +1 -0
  46. package/dist/listener-trie.d.ts +10 -0
  47. package/dist/listener-trie.d.ts.map +1 -0
  48. package/dist/listener-trie.js +83 -0
  49. package/dist/listener-trie.js.map +1 -0
  50. package/dist/nameof.d.ts +12 -0
  51. package/dist/nameof.d.ts.map +1 -0
  52. package/dist/nameof.js +30 -0
  53. package/dist/nameof.js.map +1 -0
  54. package/dist/path-key.d.ts +11 -0
  55. package/dist/path-key.d.ts.map +1 -0
  56. package/dist/path-key.js +11 -0
  57. package/dist/path-key.js.map +1 -0
  58. package/dist/path.d.ts +7 -0
  59. package/dist/path.d.ts.map +1 -0
  60. package/dist/path.js +53 -0
  61. package/dist/path.js.map +1 -0
  62. package/dist/proxy-cache.d.ts +32 -0
  63. package/dist/proxy-cache.d.ts.map +1 -0
  64. package/dist/proxy-cache.js +72 -0
  65. package/dist/proxy-cache.js.map +1 -0
  66. package/dist/proxy-factory.d.ts +17 -0
  67. package/dist/proxy-factory.d.ts.map +1 -0
  68. package/dist/proxy-factory.js +124 -0
  69. package/dist/proxy-factory.js.map +1 -0
  70. package/dist/schedule-queue.d.ts +10 -0
  71. package/dist/schedule-queue.d.ts.map +1 -0
  72. package/dist/schedule-queue.js +112 -0
  73. package/dist/schedule-queue.js.map +1 -0
  74. package/dist/snapshot-diff.d.ts +6 -0
  75. package/dist/snapshot-diff.d.ts.map +1 -0
  76. package/dist/snapshot-diff.js +67 -0
  77. package/dist/snapshot-diff.js.map +1 -0
  78. package/dist/symbol-id.d.ts +3 -0
  79. package/dist/symbol-id.d.ts.map +1 -0
  80. package/dist/symbol-id.js +16 -0
  81. package/dist/symbol-id.js.map +1 -0
  82. package/dist/types.d.ts +48 -0
  83. package/dist/types.d.ts.map +1 -0
  84. package/dist/types.js +3 -0
  85. package/dist/types.js.map +1 -0
  86. package/dist/undo-redo.d.ts +12 -0
  87. package/dist/undo-redo.d.ts.map +1 -0
  88. package/dist/undo-redo.js +216 -0
  89. package/dist/undo-redo.js.map +1 -0
  90. package/package.json +45 -0
  91. package/src/api-methods.ts +292 -0
  92. package/src/api.ts +53 -0
  93. package/src/array-mutations.ts +64 -0
  94. package/src/batch-transaction.ts +183 -0
  95. package/src/chronicle.ts +100 -0
  96. package/src/collection-adapters.ts +224 -0
  97. package/src/config.ts +16 -0
  98. package/src/grouping.ts +47 -0
  99. package/src/history-recorder.ts +145 -0
  100. package/src/history.ts +75 -0
  101. package/src/listener-affinity.ts +69 -0
  102. package/src/listener-trie.ts +103 -0
  103. package/src/nameof.ts +42 -0
  104. package/src/path-key.ts +10 -0
  105. package/src/path.ts +69 -0
  106. package/src/proxy-cache.ts +86 -0
  107. package/src/proxy-factory.ts +168 -0
  108. package/src/schedule-queue.ts +144 -0
  109. package/src/snapshot-diff.ts +90 -0
  110. package/src/symbol-id.ts +20 -0
  111. package/src/tsconfig.json +3 -0
  112. package/src/types.ts +59 -0
  113. package/src/undo-redo.ts +249 -0
@@ -0,0 +1,29 @@
1
+ export interface CollectionAdapterDeps {
2
+ getBatchFrames: (root: object) => {
3
+ marker: number;
4
+ id: string;
5
+ }[] | undefined;
6
+ }
7
+ /**
8
+ * Wrap Map mutating methods to record changes and notify listeners.
9
+ *
10
+ * @param target - The Map instance
11
+ * @param currentPath - The path to the Map
12
+ * @param rootObject - The root object
13
+ * @param deps - Dependencies (getBatchFrames)
14
+ * @param method - The method name being accessed
15
+ * @returns Wrapped method or undefined if not a mutating method
16
+ */
17
+ export declare const adaptMapMethod: (target: Map<any, any>, currentPath: string[], rootObject: object, deps: CollectionAdapterDeps, method: string) => ((...args: any[]) => any) | undefined;
18
+ /**
19
+ * Wrap Set mutating methods to record changes and notify listeners.
20
+ *
21
+ * @param target - The Set instance
22
+ * @param currentPath - The path to the Set
23
+ * @param rootObject - The root object
24
+ * @param deps - Dependencies (getBatchFrames)
25
+ * @param method - The method name being accessed
26
+ * @returns Wrapped method or undefined if not a mutating method
27
+ */
28
+ export declare const adaptSetMethod: (target: Set<any>, currentPath: string[], rootObject: object, deps: CollectionAdapterDeps, method: string) => ((...args: any[]) => any) | undefined;
29
+ //# sourceMappingURL=collection-adapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-adapters.d.ts","sourceRoot":"","sources":["../src/collection-adapters.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,qBAAqB;IACrC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;KAAE,EAAE,GAAG,SAAS,CAAC;CAChF;AA+BD;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAC1B,QAAQ,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,EACrB,aAAa,MAAM,EAAE,EACrB,YAAY,MAAM,EAClB,MAAM,qBAAqB,EAC3B,QAAQ,MAAM,KACZ,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,SA0E9B,CAAC;AAGF;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAC1B,QAAQ,GAAG,CAAC,GAAG,CAAC,EAChB,aAAa,MAAM,EAAE,EACrB,YAAY,MAAM,EAClB,MAAM,qBAAqB,EAC3B,QAAQ,MAAM,KACZ,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,SAyE9B,CAAC"}
@@ -0,0 +1,184 @@
1
+ import { computeActiveGroupId } from "./grouping.js";
2
+ import { ensureHistory, getOptions, trimHistoryByGroups } from "./history.js";
3
+ import { computeAffectedListeners } from "./listener-affinity.js";
4
+ import { notifyListeners } from "./schedule-queue.js";
5
+ import { clearRedoCache, isSuspended } from "./undo-redo.js";
6
+ /**
7
+ * Create a history-and-notify callback for Map/Set mutations.
8
+ * This shared helper records the change and notifies listeners.
9
+ */
10
+ const createRecordAndNotify = (rootObject, currentPath) => (rec, newValForListener, oldValForListener) => {
11
+ // Record in history (Map/Set records have collection/key metadata, so push directly)
12
+ if (!isSuspended(rootObject)) {
13
+ const history = ensureHistory(rootObject);
14
+ clearRedoCache(rootObject);
15
+ const cfg = getOptions(rootObject);
16
+ if (!cfg?.filter || cfg.filter(rec))
17
+ history.push(rec);
18
+ if (cfg && typeof cfg.maxHistory === 'number')
19
+ trimHistoryByGroups(history, cfg.maxHistory);
20
+ }
21
+ // Notify listeners
22
+ const affected = computeAffectedListeners(rootObject, currentPath);
23
+ if (affected.size > 0) {
24
+ const meta = { type: rec.type, existedBefore: rec.existedBefore, groupId: rec.groupId };
25
+ notifyListeners(rootObject, affected, [currentPath, newValForListener, oldValForListener, meta]);
26
+ }
27
+ };
28
+ /**
29
+ * Wrap Map mutating methods to record changes and notify listeners.
30
+ *
31
+ * @param target - The Map instance
32
+ * @param currentPath - The path to the Map
33
+ * @param rootObject - The root object
34
+ * @param deps - Dependencies (getBatchFrames)
35
+ * @param method - The method name being accessed
36
+ * @returns Wrapped method or undefined if not a mutating method
37
+ */
38
+ export const adaptMapMethod = (target, currentPath, rootObject, deps, method) => {
39
+ const recordHistoryAndNotify = createRecordAndNotify(rootObject, currentPath);
40
+ if (method === 'set') {
41
+ return function (key, value) {
42
+ const m = target;
43
+ const had = m.has(key);
44
+ const oldV = had ? m.get(key) : undefined;
45
+ m.set(key, value);
46
+ const rec = {
47
+ path: currentPath.slice(),
48
+ type: 'set',
49
+ oldValue: oldV,
50
+ newValue: value,
51
+ timestamp: Date.now(),
52
+ existedBefore: had,
53
+ groupId: computeActiveGroupId(rootObject, deps.getBatchFrames),
54
+ collection: 'map',
55
+ key,
56
+ };
57
+ recordHistoryAndNotify(rec, value, oldV);
58
+ return this;
59
+ };
60
+ }
61
+ if (method === 'delete') {
62
+ return function (key) {
63
+ const m = target;
64
+ const had = m.has(key);
65
+ const oldV = had ? m.get(key) : undefined;
66
+ const res = m.delete(key);
67
+ if (had) {
68
+ const rec = {
69
+ path: currentPath.slice(),
70
+ type: 'delete',
71
+ oldValue: oldV,
72
+ newValue: undefined,
73
+ timestamp: Date.now(),
74
+ groupId: computeActiveGroupId(rootObject, deps.getBatchFrames),
75
+ collection: 'map',
76
+ key,
77
+ };
78
+ recordHistoryAndNotify(rec, undefined, oldV);
79
+ }
80
+ return res;
81
+ };
82
+ }
83
+ if (method === 'clear') {
84
+ return function () {
85
+ const m = target;
86
+ const entries = Array.from(m.entries());
87
+ const gid = computeActiveGroupId(rootObject, deps.getBatchFrames);
88
+ m.clear();
89
+ for (const [k, v] of entries) {
90
+ const rec = {
91
+ path: currentPath.slice(),
92
+ type: 'delete',
93
+ oldValue: v,
94
+ newValue: undefined,
95
+ timestamp: Date.now(),
96
+ groupId: gid,
97
+ collection: 'map',
98
+ key: k,
99
+ };
100
+ recordHistoryAndNotify(rec, undefined, v);
101
+ }
102
+ };
103
+ }
104
+ return undefined;
105
+ };
106
+ /**
107
+ * Wrap Set mutating methods to record changes and notify listeners.
108
+ *
109
+ * @param target - The Set instance
110
+ * @param currentPath - The path to the Set
111
+ * @param rootObject - The root object
112
+ * @param deps - Dependencies (getBatchFrames)
113
+ * @param method - The method name being accessed
114
+ * @returns Wrapped method or undefined if not a mutating method
115
+ */
116
+ export const adaptSetMethod = (target, currentPath, rootObject, deps, method) => {
117
+ const recordHistoryAndNotify = createRecordAndNotify(rootObject, currentPath);
118
+ if (method === 'add') {
119
+ return function (value) {
120
+ const s = target;
121
+ const had = s.has(value);
122
+ s.add(value);
123
+ if (!had) {
124
+ const rec = {
125
+ path: currentPath.slice(),
126
+ type: 'set',
127
+ oldValue: undefined,
128
+ newValue: value,
129
+ timestamp: Date.now(),
130
+ existedBefore: false,
131
+ groupId: computeActiveGroupId(rootObject, deps.getBatchFrames),
132
+ collection: 'set',
133
+ key: value,
134
+ };
135
+ recordHistoryAndNotify(rec, value, undefined);
136
+ }
137
+ return this; // chaining
138
+ };
139
+ }
140
+ if (method === 'delete') {
141
+ return function (value) {
142
+ const s = target;
143
+ const had = s.has(value);
144
+ const res = s.delete(value);
145
+ if (had) {
146
+ const rec = {
147
+ path: currentPath.slice(),
148
+ type: 'delete',
149
+ oldValue: value,
150
+ newValue: undefined,
151
+ timestamp: Date.now(),
152
+ groupId: computeActiveGroupId(rootObject, deps.getBatchFrames),
153
+ collection: 'set',
154
+ key: value,
155
+ };
156
+ recordHistoryAndNotify(rec, undefined, value);
157
+ }
158
+ return res; // boolean
159
+ };
160
+ }
161
+ if (method === 'clear') {
162
+ return function () {
163
+ const s = target;
164
+ const values = Array.from(s.values());
165
+ const gid = computeActiveGroupId(rootObject, deps.getBatchFrames);
166
+ s.clear();
167
+ for (const v of values) {
168
+ const rec = {
169
+ path: currentPath.slice(),
170
+ type: 'delete',
171
+ oldValue: v,
172
+ newValue: undefined,
173
+ timestamp: Date.now(),
174
+ groupId: gid,
175
+ collection: 'set',
176
+ key: v,
177
+ };
178
+ recordHistoryAndNotify(rec, undefined, v);
179
+ }
180
+ };
181
+ }
182
+ return undefined;
183
+ };
184
+ //# sourceMappingURL=collection-adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-adapters.js","sourceRoot":"","sources":["../src/collection-adapters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ChronicleOptions } from './history.ts';
2
+ export type ConfigureOptions = ChronicleOptions;
3
+ /**
4
+ * Configure per-root observe behavior by merging options and managing mergeUngrouped window reset.
5
+ */
6
+ export declare const configureRoot: (root: object, options: ConfigureOptions) => void;
7
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIrD,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAGhD;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,SAAS,gBAAgB,KAAG,IAKvE,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,11 @@
1
+ import { clearLastUngrouped, getOptions, setOptions } from "./history.js";
2
+ /**
3
+ * Configure per-root observe behavior by merging options and managing mergeUngrouped window reset.
4
+ */
5
+ export const configureRoot = (root, options) => {
6
+ const prev = getOptions(root) ?? {};
7
+ setOptions(root, { ...prev, ...options });
8
+ if (!options.mergeUngrouped)
9
+ clearLastUngrouped(root);
10
+ };
11
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1E;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,OAAyB,EAAQ,EAAE;IAC9E,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACpC,UAAU,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,CAAC,cAAc;QAC1B,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Compute the active group ID for a change.
3
+ *
4
+ * If inside a batch, uses the current batch frame's ID.
5
+ * Otherwise, if mergeUngrouped is enabled and within the merge window,
6
+ * reuses the last ungrouped ID. Otherwise generates a new group ID.
7
+ *
8
+ * @param root - The root object
9
+ * @param getBatchFrames - Function to get batch frames for the root
10
+ * @param nowProvider - Function to get current timestamp (defaults to Date.now)
11
+ * @returns The group ID to use for the current change
12
+ */
13
+ export declare const computeActiveGroupId: (root: object, getBatchFrames: (root: object) => {
14
+ marker: number;
15
+ id: string;
16
+ }[] | undefined, nowProvider?: () => number) => string;
17
+ //# sourceMappingURL=grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping.d.ts","sourceRoot":"","sources":["../src/grouping.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,MAAM,EACZ,gBAAgB,CAAC,IAAI,EAAE,MAAM,KAAK;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;CAAE,EAAE,GAAG,SAAS,EAC/E,cAAa,MAAM,MAAiB,KAClC,MA2BF,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { clearLastUngrouped, getLastUngrouped, getOptions, nextGroupId, setLastUngrouped } from "./history.js";
2
+ /**
3
+ * Compute the active group ID for a change.
4
+ *
5
+ * If inside a batch, uses the current batch frame's ID.
6
+ * Otherwise, if mergeUngrouped is enabled and within the merge window,
7
+ * reuses the last ungrouped ID. Otherwise generates a new group ID.
8
+ *
9
+ * @param root - The root object
10
+ * @param getBatchFrames - Function to get batch frames for the root
11
+ * @param nowProvider - Function to get current timestamp (defaults to Date.now)
12
+ * @returns The group ID to use for the current change
13
+ */
14
+ export const computeActiveGroupId = (root, getBatchFrames, nowProvider = Date.now) => {
15
+ const batchFrames = getBatchFrames(root);
16
+ if (batchFrames && batchFrames.length > 0)
17
+ return batchFrames[batchFrames.length - 1].id;
18
+ const opts = getOptions(root);
19
+ if (opts && opts.mergeUngrouped) {
20
+ const now = nowProvider();
21
+ const prev = getLastUngrouped(root);
22
+ const within = opts.mergeWindowMs == null
23
+ || (prev ? (now - prev.at) <= opts.mergeWindowMs : false);
24
+ if (prev && within) {
25
+ setLastUngrouped(root, { id: prev.id, at: now });
26
+ return prev.id;
27
+ }
28
+ const gid = nextGroupId(root);
29
+ setLastUngrouped(root, { id: gid, at: now });
30
+ return gid;
31
+ }
32
+ clearLastUngrouped(root);
33
+ return nextGroupId(root);
34
+ };
35
+ //# sourceMappingURL=grouping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping.js","sourceRoot":"","sources":["../src/grouping.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAG/G;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CACnC,IAAY,EACZ,cAA+E,EAC/E,cAA4B,IAAI,CAAC,GAAG,EAC3B,EAAE;IACX,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QACxC,OAAO,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,EAAE,CAAC;IAEhD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI;eACrC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAE3D,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YACpB,gBAAgB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YAEjD,OAAO,IAAI,CAAC,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAC9B,gBAAgB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAE7C,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAEzB,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Record a 'set' operation in history with filtering, compaction, and trimming.
3
+ *
4
+ * Handles optional compaction of consecutive sets on the same path within the same group,
5
+ * avoiding compaction of array indices and length properties.
6
+ *
7
+ * @param root - The root object
8
+ * @param path - The path where the set occurred
9
+ * @param oldValue - The previous value
10
+ * @param newValue - The new value
11
+ * @param existedBefore - Whether the property existed before
12
+ * @param groupId - The group ID for this change
13
+ */
14
+ export declare const recordSet: (root: object, path: string[], oldValue: any, newValue: any, existedBefore: boolean, groupId: string) => void;
15
+ /**
16
+ * Record a 'delete' operation in history with filtering and trimming.
17
+ *
18
+ * @param root - The root object
19
+ * @param path - The path where the delete occurred
20
+ * @param oldValue - The value that was deleted
21
+ * @param groupId - The group ID for this change
22
+ */
23
+ export declare const recordDelete: (root: object, path: string[], oldValue: any, groupId: string) => void;
24
+ /**
25
+ * Record delete operations for array elements removed by length shrinkage.
26
+ *
27
+ * Used when array.length is decreased, synthesizing delete records for removed indices.
28
+ * Does not apply compaction or other optimizations - just records the deletes.
29
+ *
30
+ * @param root - The root object
31
+ * @param basePath - The path to the array (not including indices)
32
+ * @param removed - Array of {index, value} pairs that were removed
33
+ * @param groupId - The group ID for these changes
34
+ */
35
+ export declare const recordArrayShrinkDeletes: (root: object, basePath: string[], removed: {
36
+ index: number;
37
+ value: any;
38
+ }[], groupId: string) => void;
39
+ //# sourceMappingURL=history-recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-recorder.d.ts","sourceRoot":"","sources":["../src/history-recorder.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,GACrB,MAAM,MAAM,EACZ,MAAM,MAAM,EAAE,EACd,UAAU,GAAG,EACb,UAAU,GAAG,EACb,eAAe,OAAO,EACtB,SAAS,MAAM,KACb,IA2CF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GACxB,MAAM,MAAM,EACZ,MAAM,MAAM,EAAE,EACd,UAAU,GAAG,EACb,SAAS,MAAM,KACb,IAuBF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,MAAM,EACZ,UAAU,MAAM,EAAE,EAClB,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC;CAAE,EAAE,EACzC,SAAS,MAAM,KACb,IAoBF,CAAC"}
@@ -0,0 +1,112 @@
1
+ import { ensureHistory, getOptions, trimHistoryByGroups } from "./history.js";
2
+ import { clearRedoCache, isSuspended } from "./undo-redo.js";
3
+ /**
4
+ * Record a 'set' operation in history with filtering, compaction, and trimming.
5
+ *
6
+ * Handles optional compaction of consecutive sets on the same path within the same group,
7
+ * avoiding compaction of array indices and length properties.
8
+ *
9
+ * @param root - The root object
10
+ * @param path - The path where the set occurred
11
+ * @param oldValue - The previous value
12
+ * @param newValue - The new value
13
+ * @param existedBefore - Whether the property existed before
14
+ * @param groupId - The group ID for this change
15
+ */
16
+ export const recordSet = (root, path, oldValue, newValue, existedBefore, groupId) => {
17
+ if (isSuspended(root))
18
+ return;
19
+ const history = ensureHistory(root);
20
+ clearRedoCache(root);
21
+ const cfg = getOptions(root);
22
+ const rec = {
23
+ path: path.slice(),
24
+ type: 'set',
25
+ oldValue,
26
+ newValue,
27
+ timestamp: Date.now(),
28
+ existedBefore,
29
+ groupId,
30
+ };
31
+ if (!cfg?.filter || cfg.filter(rec))
32
+ history.push(rec);
33
+ // Optional compaction: merge consecutive sets on the same path within the same group
34
+ if (cfg && cfg.compactConsecutiveSamePath && history.length >= 2) {
35
+ const a = history[history.length - 2];
36
+ const b = history[history.length - 1];
37
+ const sameGroup = (a.groupId ?? `__g#${history.length - 2}`) === (b.groupId ?? `__g#${history.length - 1}`);
38
+ const samePath = a.path.length === b.path.length && a.path.every((seg, i) => seg === b.path[i]);
39
+ const isSetSet = a.type === 'set' && b.type === 'set';
40
+ // Avoid compacting array index updates and length changes
41
+ const lastSeg = b.path[b.path.length - 1];
42
+ const isArrayIndex = /^(?:0|[1-9]\d*)$/.test(lastSeg);
43
+ const isLengthProp = lastSeg === 'length';
44
+ if (sameGroup && samePath && isSetSet && !isArrayIndex && !isLengthProp) {
45
+ // Merge: keep 'a' with oldValue from original and update newValue/timestamp from 'b'; drop 'b'
46
+ a.newValue = b.newValue;
47
+ a.timestamp = b.timestamp;
48
+ history.pop();
49
+ }
50
+ }
51
+ // Enforce maxHistory by trimming whole groups from the front
52
+ if (cfg && typeof cfg.maxHistory === 'number')
53
+ trimHistoryByGroups(history, cfg.maxHistory);
54
+ };
55
+ /**
56
+ * Record a 'delete' operation in history with filtering and trimming.
57
+ *
58
+ * @param root - The root object
59
+ * @param path - The path where the delete occurred
60
+ * @param oldValue - The value that was deleted
61
+ * @param groupId - The group ID for this change
62
+ */
63
+ export const recordDelete = (root, path, oldValue, groupId) => {
64
+ if (isSuspended(root))
65
+ return;
66
+ const history = ensureHistory(root);
67
+ clearRedoCache(root);
68
+ const cfg = getOptions(root);
69
+ const rec = {
70
+ path: path.slice(),
71
+ type: 'delete',
72
+ oldValue,
73
+ newValue: undefined,
74
+ timestamp: Date.now(),
75
+ groupId,
76
+ };
77
+ if (!cfg?.filter || cfg.filter(rec))
78
+ history.push(rec);
79
+ // Enforce maxHistory by trimming whole groups from the front
80
+ if (cfg && typeof cfg.maxHistory === 'number')
81
+ trimHistoryByGroups(history, cfg.maxHistory);
82
+ };
83
+ /**
84
+ * Record delete operations for array elements removed by length shrinkage.
85
+ *
86
+ * Used when array.length is decreased, synthesizing delete records for removed indices.
87
+ * Does not apply compaction or other optimizations - just records the deletes.
88
+ *
89
+ * @param root - The root object
90
+ * @param basePath - The path to the array (not including indices)
91
+ * @param removed - Array of {index, value} pairs that were removed
92
+ * @param groupId - The group ID for these changes
93
+ */
94
+ export const recordArrayShrinkDeletes = (root, basePath, removed, groupId) => {
95
+ if (isSuspended(root) || removed.length === 0)
96
+ return;
97
+ const history = ensureHistory(root);
98
+ const cfg = getOptions(root);
99
+ for (const { index, value: oldVal } of removed) {
100
+ const rec = {
101
+ path: [...basePath, String(index)],
102
+ type: 'delete',
103
+ oldValue: oldVal,
104
+ newValue: undefined,
105
+ timestamp: Date.now(),
106
+ groupId,
107
+ };
108
+ if (!cfg?.filter || cfg.filter(rec))
109
+ history.push(rec);
110
+ }
111
+ };
112
+ //# sourceMappingURL=history-recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-recorder.js","sourceRoot":"","sources":["../src/history-recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { ChangeRecord } from './types.ts';
2
+ export interface ChronicleOptions {
3
+ mergeUngrouped?: boolean;
4
+ mergeWindowMs?: number;
5
+ compactConsecutiveSamePath?: boolean;
6
+ maxHistory?: number;
7
+ filter?: (record: ChangeRecord) => boolean;
8
+ clone?: (value: any) => any;
9
+ compare?: (a: any, b: any, path: string[]) => boolean;
10
+ diffFilter?: (path: string[]) => boolean | 'shallow';
11
+ cacheProxies?: boolean;
12
+ }
13
+ export declare const ensureHistory: (root: object) => ChangeRecord[];
14
+ export declare const historyGet: (root: object) => ChangeRecord[] | undefined;
15
+ export declare const historyDelete: (root: object) => void;
16
+ export declare const trimHistoryByGroups: (history: ChangeRecord[], max: number) => void;
17
+ export declare const nextGroupId: (root: object) => string;
18
+ export declare const getOptions: (root: object) => ChronicleOptions;
19
+ export declare const setOptions: (root: object, options: ChronicleOptions) => void;
20
+ export declare const getLastUngrouped: (root: object) => {
21
+ id: string;
22
+ at: number;
23
+ } | undefined;
24
+ export declare const setLastUngrouped: (root: object, v: {
25
+ id: string;
26
+ at: number;
27
+ }) => void;
28
+ export declare const clearLastUngrouped: (root: object) => void;
29
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAU/C,MAAM,WAAW,gBAAgB;IAChC,cAAc,CAAC,EAAc,OAAO,CAAC;IACrC,aAAa,CAAC,EAAe,MAAM,CAAC;IACpC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,UAAU,CAAC,EAAkB,MAAM,CAAC;IACpC,MAAM,CAAC,EAAsB,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC;IAC/D,KAAK,CAAC,EAAuB,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC;IACjD,OAAO,CAAC,EAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;IACzE,UAAU,CAAC,EAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,GAAG,SAAS,CAAC;IACrE,YAAY,CAAC,EAAgB,OAAO,CAAC;CACrC;AAID,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,YAAY,EAQxD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,YAAY,EAAE,GAAG,SAAmC,CAAC;AAC/F,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,IAAsC,CAAC;AAIpF,eAAO,MAAM,mBAAmB,GAAI,SAAS,YAAY,EAAE,EAAE,KAAK,MAAM,KAAG,IAqB1E,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,MAK1C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,gBAAgD,CAAC;AAC3F,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,SAAS,gBAAgB,KAAG,IAA4C,CAAC;AAElH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;CAAE,GAAG,SAAoC,CAAC;AACnH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;CAAE,KAAG,IAAuC,CAAC;AACxH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,IAAuC,CAAC"}
@@ -0,0 +1,47 @@
1
+ // History records per root
2
+ const historyCache = new WeakMap();
3
+ // Group/merge state per root
4
+ const groupCounter = new WeakMap();
5
+ const lastUngrouped = new WeakMap();
6
+ const optionsCache = new WeakMap();
7
+ export const ensureHistory = (root) => {
8
+ let h = historyCache.get(root);
9
+ if (!h) {
10
+ h = [];
11
+ historyCache.set(root, h);
12
+ }
13
+ return h;
14
+ };
15
+ export const historyGet = (root) => historyCache.get(root);
16
+ export const historyDelete = (root) => { historyCache.delete(root); };
17
+ // Trim history by removing whole groups from the front until length <= max.
18
+ // This keeps undoGroups coherent and avoids splitting groups.
19
+ export const trimHistoryByGroups = (history, max) => {
20
+ if (!(typeof max === 'number') || max < 0)
21
+ return;
22
+ if (history.length <= max)
23
+ return;
24
+ let removeCount = 0;
25
+ let i = 0;
26
+ while (history.length - removeCount > max && i < history.length) {
27
+ const gid = history[i].groupId ?? `__g#${i}`;
28
+ let j = i;
29
+ while (j < history.length && (history[j].groupId ?? `__g#${j}`) === gid)
30
+ j++;
31
+ removeCount += (j - i);
32
+ i = j;
33
+ }
34
+ if (removeCount > 0)
35
+ history.splice(0, removeCount);
36
+ };
37
+ export const nextGroupId = (root) => {
38
+ const n = (groupCounter.get(root) ?? 0) + 1;
39
+ groupCounter.set(root, n);
40
+ return `g${n}`;
41
+ };
42
+ export const getOptions = (root) => optionsCache.get(root) ?? {};
43
+ export const setOptions = (root, options) => { optionsCache.set(root, options); };
44
+ export const getLastUngrouped = (root) => lastUngrouped.get(root);
45
+ export const setLastUngrouped = (root, v) => { lastUngrouped.set(root, v); };
46
+ export const clearLastUngrouped = (root) => { lastUngrouped.delete(root); };
47
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ChangeListener } from './types.ts';
2
+ /**
3
+ * Compute the set of listeners affected by a change at the given path.
4
+ *
5
+ * Collects listeners in this order:
6
+ * - Global listeners (onAny)
7
+ * - Down listeners on the path and all ancestors (listen for descendants)
8
+ * - Exact listeners at the exact path
9
+ * - Up listeners on all descendants (listen for ancestors)
10
+ *
11
+ * @param root - The root object
12
+ * @param path - The path where the change occurred
13
+ * @returns Set of all affected listeners
14
+ */
15
+ export declare const computeAffectedListeners: (root: object, path: string[]) => Set<ChangeListener>;
16
+ //# sourceMappingURL=listener-affinity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener-affinity.d.ts","sourceRoot":"","sources":["../src/listener-affinity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,YAAY,CAAC;AAG/D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,EAAE,KAAG,GAAG,CAAC,cAAc,CAmDzF,CAAC"}