@sovereignbase/convergent-replicated-struct 1.0.1 → 1.1.0

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/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } var _class;/*
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }/*
2
2
  * Copyright 2026 Sovereignbase
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,276 +15,399 @@
15
15
  */
16
16
 
17
17
 
18
- // src/OOStruct/class.ts
18
+ // src/.helpers/overwriteAndReturnSnapshotEntry/index.ts
19
19
  var _uuid = require('uuid');
20
+ function overwriteAndReturnSnapshotEntry(key, value, crStructReplica) {
21
+ const target = crStructReplica.entries[key];
22
+ const oldUuidv7 = target.uuidv7;
23
+ target.uuidv7 = _uuid.v7.call(void 0, );
24
+ target.value = value;
25
+ target.predecessor = oldUuidv7;
26
+ target.tombstones.add(oldUuidv7);
27
+ return parseStateEntryToSnapshotEntry(target);
28
+ }
20
29
 
21
- // src/.errors/class.ts
22
- var OOStructError = class extends Error {
23
- /**
24
- * The semantic error code for the failure.
25
- */
26
-
27
- /**
28
- * Creates a typed OO-Struct error.
29
- *
30
- * @param code - The semantic error code.
31
- * @param message - An optional human-readable detail message.
32
- */
33
- constructor(code, message) {
34
- const detail = _nullishCoalesce(message, () => ( code));
35
- super(`{@sovereignbase/observed-overwrite-struct} ${detail}`);
36
- this.code = code;
37
- this.name = "OOStructError";
38
- }
39
- };
40
-
41
- // src/OOStruct/parseSnapshotEntryToStateEntry/index.ts
30
+ // src/.helpers/parseSnapshotEntryToStateEntry/index.ts
42
31
  var _utils = require('@sovereignbase/utils');
43
32
  function parseSnapshotEntryToStateEntry(defaultValue, snapshotEntry) {
44
- if (_utils.prototype.call(void 0, snapshotEntry) !== "record" || !Object.hasOwn(snapshotEntry, "__value") || !_utils.isUuidV7.call(void 0, snapshotEntry.__uuidv7) || !_utils.isUuidV7.call(void 0, snapshotEntry.__after) || !Array.isArray(snapshotEntry.__overwrites))
33
+ if (_utils.prototype.call(void 0, snapshotEntry) !== "record" || !Object.hasOwn(snapshotEntry, "value") || !_utils.isUuidV7.call(void 0, snapshotEntry.uuidv7) || !_utils.isUuidV7.call(void 0, snapshotEntry.predecessor) || !Array.isArray(snapshotEntry.tombstones))
45
34
  return false;
46
- const [cloned, copiedValue] = _utils.safeStructuredClone.call(void 0, snapshotEntry.__value);
35
+ const [cloned, copiedValue] = _utils.safeStructuredClone.call(void 0, snapshotEntry.value);
47
36
  if (!cloned || _utils.prototype.call(void 0, copiedValue) !== _utils.prototype.call(void 0, defaultValue))
48
37
  return false;
49
- const overwrites = /* @__PURE__ */ new Set([]);
50
- for (const overwrite of snapshotEntry.__overwrites) {
51
- if (!_utils.isUuidV7.call(void 0, overwrite) || overwrite === snapshotEntry.__uuidv7)
38
+ const tombstones = /* @__PURE__ */ new Set([]);
39
+ for (const overwrite of snapshotEntry.tombstones) {
40
+ if (!_utils.isUuidV7.call(void 0, overwrite) || overwrite === snapshotEntry.uuidv7)
52
41
  continue;
53
- overwrites.add(overwrite);
42
+ tombstones.add(overwrite);
54
43
  }
55
- if (!overwrites.has(snapshotEntry.__after)) return false;
44
+ if (!tombstones.has(snapshotEntry.predecessor)) return false;
56
45
  return {
57
- __uuidv7: snapshotEntry.__uuidv7,
58
- __value: copiedValue,
59
- __after: snapshotEntry.__after,
60
- __overwrites: overwrites
46
+ uuidv7: snapshotEntry.uuidv7,
47
+ value: copiedValue,
48
+ predecessor: snapshotEntry.predecessor,
49
+ tombstones
61
50
  };
62
51
  }
63
52
 
64
- // src/OOStruct/parseStateEntryToSnapshotEntry/index.ts
53
+ // src/.helpers/parseStateEntryToSnapshotEntry/index.ts
65
54
  function parseStateEntryToSnapshotEntry(stateEntry) {
66
55
  return {
67
- __uuidv7: stateEntry.__uuidv7,
68
- __value: structuredClone(stateEntry.__value),
69
- __after: stateEntry.__after,
70
- __overwrites: Array.from(stateEntry.__overwrites)
56
+ uuidv7: stateEntry.uuidv7,
57
+ value: structuredClone(stateEntry.value),
58
+ predecessor: stateEntry.predecessor,
59
+ tombstones: Array.from(stateEntry.tombstones)
71
60
  };
72
61
  }
73
62
 
74
- // src/OOStruct/class.ts
75
-
76
- var OOStruct = (_class = class _OOStruct {
77
- __init() {this.__eventTarget = new EventTarget()}
78
-
79
-
80
-
81
- /**
82
- * Creates a replica from default values and an optional snapshot.
83
- *
84
- * @param defaults - The default field values that define the struct shape.
85
- * @param snapshot - An optional serialized snapshot used for hydration.
86
- * @throws {OOStructError} Thrown when the default values are not supported by `structuredClone`.
87
- */
88
- constructor(defaults, snapshot) {;_class.prototype.__init.call(this);
89
- const [cloned, copiedDefaults] = _utils.safeStructuredClone.call(void 0, defaults);
90
- if (!cloned)
91
- throw new OOStructError(
92
- "DEFAULTS_NOT_CLONEABLE",
93
- "Default values must be supported by structuredClone."
94
- );
95
- this.__defaults = copiedDefaults;
96
- this.__state = {};
97
- this.__live = {};
98
- const snapshotIsObject = snapshot && _utils.prototype.call(void 0, snapshot) === "record";
99
- for (const key of Object.keys(this.__defaults)) {
100
- const defaultValue = this.__defaults[key];
101
- if (snapshotIsObject && Object.hasOwn(snapshot, key)) {
102
- const valid = parseSnapshotEntryToStateEntry(
103
- defaultValue,
104
- snapshot[key]
63
+ // src/core/mags/merge/index.ts
64
+ function __merge(crStructDelta, crStructReplica) {
65
+ if (!crStructDelta || typeof crStructDelta !== "object" || Array.isArray(crStructDelta))
66
+ return false;
67
+ const delta = {};
68
+ const change = {};
69
+ let hasDelta = false;
70
+ let hasChange = false;
71
+ for (const [key, value] of Object.entries(crStructDelta)) {
72
+ if (!Object.hasOwn(crStructReplica.defaults, key)) continue;
73
+ const candidate = parseSnapshotEntryToStateEntry(
74
+ crStructReplica.defaults[key],
75
+ value
76
+ );
77
+ if (!candidate) continue;
78
+ const target = crStructReplica.entries[key];
79
+ const current = { ...target };
80
+ let frontier = "";
81
+ for (const overwrite of target.tombstones) {
82
+ if (frontier < overwrite) frontier = overwrite;
83
+ }
84
+ for (const overwrite of candidate.tombstones) {
85
+ if (overwrite <= frontier || target.tombstones.has(overwrite)) continue;
86
+ target.tombstones.add(overwrite);
87
+ }
88
+ if (target.tombstones.has(candidate.uuidv7)) continue;
89
+ if (current.uuidv7 === candidate.uuidv7) {
90
+ if (current.predecessor < candidate.predecessor) {
91
+ target.value = candidate.value;
92
+ target.predecessor = candidate.predecessor;
93
+ target.tombstones.add(candidate.predecessor);
94
+ change[key] = structuredClone(candidate.value);
95
+ hasChange = true;
96
+ } else {
97
+ delta[key] = overwriteAndReturnSnapshotEntry(
98
+ key,
99
+ current.value,
100
+ crStructReplica
105
101
  );
106
- if (valid) {
107
- this.__live[key] = valid.__value;
108
- this.__state[key] = valid;
109
- continue;
110
- }
102
+ hasDelta = true;
111
103
  }
112
- this.__live[key] = defaultValue;
113
- const root = _uuid.v7.call(void 0, );
114
- this.__state[key] = {
115
- __uuidv7: _uuid.v7.call(void 0, ),
116
- __after: root,
117
- __value: defaultValue,
118
- __overwrites: /* @__PURE__ */ new Set([root])
119
- };
104
+ continue;
105
+ }
106
+ if (current.uuidv7 === candidate.predecessor || target.tombstones.has(current.uuidv7) || candidate.uuidv7 > current.uuidv7) {
107
+ target.uuidv7 = candidate.uuidv7;
108
+ target.value = candidate.value;
109
+ target.predecessor = candidate.predecessor;
110
+ target.tombstones.add(candidate.predecessor);
111
+ target.tombstones.add(current.uuidv7);
112
+ change[key] = structuredClone(candidate.value);
113
+ hasChange = true;
114
+ continue;
120
115
  }
116
+ target.tombstones.add(candidate.uuidv7);
117
+ delta[key] = parseStateEntryToSnapshotEntry(target);
118
+ hasDelta = true;
121
119
  }
122
- /**CRUD*/
123
- /**
124
- * Creates a new replica.
125
- *
126
- * @param defaults - The default field values that define the struct shape.
127
- * @param snapshot - An optional serialized snapshot used for hydration.
128
- * @returns A new OO-Struct replica.
129
- */
130
- static create(defaults, snapshot) {
131
- return new _OOStruct(defaults, snapshot);
120
+ if (!hasDelta && !hasChange) return false;
121
+ return { change, delta };
122
+ }
123
+
124
+ // src/core/mags/acknowledge/index.ts
125
+ function __acknowledge(crStructReplica) {
126
+ const ack = {};
127
+ for (const [key, value] of Object.entries(crStructReplica.entries)) {
128
+ let max = "";
129
+ for (const tombstone of value.tombstones) {
130
+ if (max < tombstone) max = tombstone;
131
+ }
132
+ ack[key] = max;
132
133
  }
133
- /**
134
- * Reads the current value of a field.
135
- *
136
- * @param key - The field key to read.
137
- * @returns A cloned copy of the field's current value.
138
- */
139
- read(key) {
140
- return structuredClone(this.__live[key]);
134
+ return ack;
135
+ }
136
+
137
+ // src/core/mags/garbageCollect/index.ts
138
+
139
+ function __garbageCollect(frontiers, crStructReplica) {
140
+ if (!Array.isArray(frontiers) || frontiers.length < 1) return;
141
+ const smallestAcknowledgementsPerKey = {};
142
+ for (const frontier of frontiers) {
143
+ for (const [key, value] of Object.entries(frontier)) {
144
+ if (!Object.hasOwn(crStructReplica.entries, key) || !_utils.isUuidV7.call(void 0, value))
145
+ continue;
146
+ const current = smallestAcknowledgementsPerKey[key];
147
+ if (typeof current === "string" && current <= value) continue;
148
+ smallestAcknowledgementsPerKey[key] = value;
149
+ }
141
150
  }
142
- /**
143
- * Overwrites a field with a new value.
144
- *
145
- * @param key - The field key to overwrite.
146
- * @param value - The next value for the field.
147
- * @throws {OOStructError} Thrown when the value is not supported by `structuredClone`.
148
- * @throws {OOStructError} Thrown when the value runtime type does not match the default value runtime type.
149
- */
150
- update(key, value) {
151
- const [cloned, copiedValue] = _utils.safeStructuredClone.call(void 0, value);
152
- if (!cloned)
153
- throw new OOStructError(
154
- "VALUE_NOT_CLONEABLE",
155
- "Updated values must be supported by structuredClone."
156
- );
157
- if (_utils.prototype.call(void 0, copiedValue) !== _utils.prototype.call(void 0, this.__defaults[key]))
158
- throw new OOStructError(
159
- "VALUE_TYPE_MISMATCH",
160
- "Updated value must match the default value runtime type."
161
- );
162
- const delta = {};
163
- const change = {};
164
- delta[key] = this.overwriteAndReturnSnapshotEntry(key, copiedValue);
165
- change[key] = structuredClone(copiedValue);
166
- this.__eventTarget.dispatchEvent(
167
- new CustomEvent("delta", { detail: delta })
168
- );
169
- this.__eventTarget.dispatchEvent(
170
- new CustomEvent("change", { detail: change })
151
+ for (const [key, value] of Object.entries(smallestAcknowledgementsPerKey)) {
152
+ const target = crStructReplica.entries[key];
153
+ const smallest = value;
154
+ for (const uuidv73 of target.tombstones) {
155
+ if (uuidv73 === target.predecessor || uuidv73 > smallest) continue;
156
+ target.tombstones.delete(uuidv73);
157
+ }
158
+ }
159
+ }
160
+
161
+ // src/core/mags/snapshot/index.ts
162
+ function __snapshot(crStructReplica) {
163
+ const snapshot = {};
164
+ for (const [key, value] of Object.entries(crStructReplica.entries)) {
165
+ snapshot[key] = parseStateEntryToSnapshotEntry(
166
+ value
171
167
  );
172
168
  }
169
+ return snapshot;
170
+ }
171
+
172
+ // src/core/crud/create/index.ts
173
+
174
+
175
+ // src/.errors/class.ts
176
+ var CRStructError = class extends Error {
177
+ /**
178
+ * The semantic error code for the failure.
179
+ */
180
+
173
181
  /**
174
- * Resets one field or the entire struct back to default values.
182
+ * Creates a typed CR-Struct error.
175
183
  *
176
- * @param key - The optional field key to reset. When omitted, every field is reset.
184
+ * @param code - The semantic error code.
185
+ * @param message - An optional human-readable detail message.
177
186
  */
178
- delete(key) {
179
- const delta = {};
180
- const change = {};
181
- if (key !== void 0) {
182
- if (!Object.hasOwn(this.__defaults, key)) return;
183
- const value = this.__defaults[key];
184
- delta[key] = this.overwriteAndReturnSnapshotEntry(key, value);
185
- change[key] = structuredClone(value);
186
- } else {
187
- for (const [key2, value] of Object.entries(this.__defaults)) {
188
- delta[key2] = this.overwriteAndReturnSnapshotEntry(
189
- key2,
190
- value
191
- );
192
- change[key2] = structuredClone(value);
187
+ constructor(code, message) {
188
+ const detail = _nullishCoalesce(message, () => ( code));
189
+ super(`{@sovereignbase/convergent-replicated-struct} ${detail}`);
190
+ this.code = code;
191
+ this.name = "CRStructError";
192
+ }
193
+ };
194
+
195
+ // src/core/crud/create/index.ts
196
+
197
+ function __create(defaults, snapshot) {
198
+ const [cloned, copiedDefaults] = _utils.safeStructuredClone.call(void 0, defaults);
199
+ if (!cloned)
200
+ throw new CRStructError(
201
+ "DEFAULTS_NOT_CLONEABLE",
202
+ "Default values must be supported by structuredClone."
203
+ );
204
+ const state = {
205
+ entries: {},
206
+ defaults: copiedDefaults
207
+ };
208
+ const snapshotIsObject = snapshot && _utils.prototype.call(void 0, snapshot) === "record";
209
+ for (const key of Object.keys(defaults)) {
210
+ const defaultValue = copiedDefaults[key];
211
+ if (snapshotIsObject && Object.hasOwn(snapshot, key)) {
212
+ const valid = parseSnapshotEntryToStateEntry(
213
+ defaultValue,
214
+ snapshot[key]
215
+ );
216
+ if (valid) {
217
+ state.entries[key] = valid;
218
+ continue;
193
219
  }
194
220
  }
195
- this.__eventTarget.dispatchEvent(
196
- new CustomEvent("delta", { detail: delta })
221
+ const root = _uuid.v7.call(void 0, );
222
+ state.entries[key] = {
223
+ uuidv7: _uuid.v7.call(void 0, ),
224
+ predecessor: root,
225
+ value: defaultValue,
226
+ tombstones: /* @__PURE__ */ new Set([root])
227
+ };
228
+ }
229
+ return state;
230
+ }
231
+
232
+ // src/core/crud/read/index.ts
233
+ function __read(key, crStructReplica) {
234
+ return structuredClone(crStructReplica.entries[key].value);
235
+ }
236
+
237
+ // src/core/crud/update/index.ts
238
+
239
+ function __update(key, value, crStructReplica) {
240
+ const [cloned, copiedValue] = _utils.safeStructuredClone.call(void 0, value);
241
+ if (!cloned)
242
+ throw new CRStructError(
243
+ "VALUE_NOT_CLONEABLE",
244
+ "Updated values must be supported by structuredClone."
197
245
  );
198
- this.__eventTarget.dispatchEvent(
199
- new CustomEvent("change", { detail: change })
246
+ if (_utils.prototype.call(void 0, copiedValue) !== _utils.prototype.call(void 0, crStructReplica.defaults[key]))
247
+ throw new CRStructError(
248
+ "VALUE_TYPE_MISMATCH",
249
+ "Updated value must match the default value runtime type."
200
250
  );
251
+ const delta = {};
252
+ const change = {};
253
+ delta[key] = overwriteAndReturnSnapshotEntry(
254
+ key,
255
+ copiedValue,
256
+ crStructReplica
257
+ );
258
+ change[key] = structuredClone(copiedValue);
259
+ return { change, delta };
260
+ }
261
+
262
+ // src/core/crud/delete/index.ts
263
+ function __delete(crStructReplica, key) {
264
+ const delta = {};
265
+ const change = {};
266
+ if (key !== void 0) {
267
+ if (!Object.hasOwn(crStructReplica.defaults, key)) return false;
268
+ const value = crStructReplica.defaults[key];
269
+ delta[key] = overwriteAndReturnSnapshotEntry(key, value, crStructReplica);
270
+ change[key] = structuredClone(value);
271
+ } else {
272
+ for (const [key2, value] of Object.entries(crStructReplica.defaults)) {
273
+ delta[key2] = overwriteAndReturnSnapshotEntry(
274
+ key2,
275
+ value,
276
+ crStructReplica
277
+ );
278
+ change[key2] = structuredClone(value);
279
+ }
201
280
  }
202
- /**MAGS*/
281
+ return { change, delta };
282
+ }
283
+
284
+ // src/CRStruct/class.ts
285
+ var CRStructRaw = class {
203
286
  /**
204
- * Merges an incoming delta into the current replica.
287
+ * Creates a replica from default values and an optional snapshot.
288
+ *
289
+ * The struct shape is fixed by the provided default values. The returned
290
+ * proxy exposes those fields as direct properties on the instance.
205
291
  *
206
- * @param replica - The incoming partial snapshot projection to merge.
292
+ * @param defaults - The default field values that define the struct shape.
293
+ * @param snapshot - An optional serialized snapshot used to hydrate the replica.
294
+ * @throws {CRStructError} Thrown when the default values are not supported by `structuredClone`.
207
295
  */
208
- merge(replica) {
209
- if (!replica || typeof replica !== "object" || Array.isArray(replica))
210
- return;
211
- const delta = {};
212
- const change = {};
213
- let hasDelta = false;
214
- let hasChange = false;
215
- for (const [key, value] of Object.entries(replica)) {
216
- if (!Object.hasOwn(this.__state, key)) continue;
217
- const candidate = parseSnapshotEntryToStateEntry(
218
- this.__defaults[key],
219
- value
220
- );
221
- if (!candidate) continue;
222
- const target = this.__state[key];
223
- const current = { ...target };
224
- let frontier = "";
225
- for (const overwrite of target.__overwrites) {
226
- if (frontier < overwrite) frontier = overwrite;
227
- }
228
- for (const overwrite of candidate.__overwrites) {
229
- if (overwrite <= frontier || target.__overwrites.has(overwrite))
230
- continue;
231
- target.__overwrites.add(overwrite);
296
+ constructor(defaults, snapshot) {
297
+ Object.defineProperties(this, {
298
+ state: {
299
+ value: __create(defaults, snapshot),
300
+ enumerable: false,
301
+ configurable: false,
302
+ writable: false
303
+ },
304
+ eventTarget: {
305
+ value: new EventTarget(),
306
+ enumerable: false,
307
+ configurable: false,
308
+ writable: false
232
309
  }
233
- if (target.__overwrites.has(candidate.__uuidv7)) continue;
234
- if (current.__uuidv7 === candidate.__uuidv7) {
235
- if (current.__after < candidate.__after) {
236
- target.__value = candidate.__value;
237
- target.__after = candidate.__after;
238
- target.__overwrites.add(candidate.__after);
239
- this.__live[key] = candidate.__value;
240
- change[key] = structuredClone(candidate.__value);
241
- hasChange = true;
242
- } else {
243
- delta[key] = this.overwriteAndReturnSnapshotEntry(
244
- key,
245
- current.__value
246
- );
247
- hasDelta = true;
310
+ });
311
+ const keys = new Set(Object.keys(defaults));
312
+ return new Proxy(this, {
313
+ get(target, key, receiver) {
314
+ if (typeof key !== "string" || !keys.has(key))
315
+ return Reflect.get(target, key, receiver);
316
+ return __read(key, target.state);
317
+ },
318
+ has(target, key) {
319
+ if (typeof key !== "string" || !keys.has(key))
320
+ return Reflect.has(target, key);
321
+ return true;
322
+ },
323
+ set(target, key, value) {
324
+ if (typeof key !== "string" || !keys.has(key)) return false;
325
+ try {
326
+ const result = __update(key, value, target.state);
327
+ if (!result) return false;
328
+ const { delta, change } = result;
329
+ if (delta)
330
+ void target.eventTarget.dispatchEvent(
331
+ new CustomEvent("delta", { detail: delta })
332
+ );
333
+ if (change)
334
+ void target.eventTarget.dispatchEvent(
335
+ new CustomEvent("change", { detail: change })
336
+ );
337
+ return true;
338
+ } catch (e) {
339
+ return false;
248
340
  }
249
- continue;
250
- }
251
- if (current.__uuidv7 === candidate.__after || target.__overwrites.has(current.__uuidv7) || candidate.__uuidv7 > current.__uuidv7) {
252
- target.__uuidv7 = candidate.__uuidv7;
253
- target.__value = candidate.__value;
254
- target.__after = candidate.__after;
255
- target.__overwrites.add(candidate.__after);
256
- target.__overwrites.add(current.__uuidv7);
257
- this.__live[key] = candidate.__value;
258
- change[key] = structuredClone(candidate.__value);
259
- hasChange = true;
260
- continue;
341
+ },
342
+ deleteProperty(target, key) {
343
+ if (typeof key !== "string" || !keys.has(key)) return false;
344
+ try {
345
+ const result = __delete(target.state, key);
346
+ if (!result) return false;
347
+ const { delta, change } = result;
348
+ if (delta) {
349
+ void target.eventTarget.dispatchEvent(
350
+ new CustomEvent("delta", { detail: delta })
351
+ );
352
+ }
353
+ if (change) {
354
+ void target.eventTarget.dispatchEvent(
355
+ new CustomEvent("change", { detail: change })
356
+ );
357
+ }
358
+ return true;
359
+ } catch (e2) {
360
+ return false;
361
+ }
362
+ },
363
+ ownKeys(target) {
364
+ return [
365
+ ...Reflect.ownKeys(target),
366
+ ...Reflect.ownKeys(target.state.defaults)
367
+ ];
368
+ },
369
+ getOwnPropertyDescriptor(target, key) {
370
+ if (typeof key !== "string" || !keys.has(key))
371
+ return Reflect.getOwnPropertyDescriptor(target, key);
372
+ return {
373
+ value: __read(key, target.state),
374
+ writable: true,
375
+ enumerable: true,
376
+ configurable: true
377
+ };
261
378
  }
262
- target.__overwrites.add(candidate.__uuidv7);
263
- delta[key] = parseStateEntryToSnapshotEntry(target);
264
- hasDelta = true;
265
- }
266
- if (hasDelta)
267
- this.__eventTarget.dispatchEvent(
379
+ });
380
+ }
381
+ /**
382
+ * Applies a remote or local delta to the replica state.
383
+ *
384
+ * @param crStructDelta - The partial serialized field state to merge.
385
+ */
386
+ merge(crStructDelta) {
387
+ const result = __merge(crStructDelta, this.state);
388
+ if (!result) return;
389
+ const { delta, change } = result;
390
+ if (delta) {
391
+ void this.eventTarget.dispatchEvent(
268
392
  new CustomEvent("delta", { detail: delta })
269
393
  );
270
- if (hasChange)
271
- this.__eventTarget.dispatchEvent(
394
+ }
395
+ if (change) {
396
+ void this.eventTarget.dispatchEvent(
272
397
  new CustomEvent("change", { detail: change })
273
398
  );
399
+ }
274
400
  }
275
401
  /**
276
402
  * Emits the current acknowledgement frontier for each field.
277
403
  */
278
404
  acknowledge() {
279
- const ack = {};
280
- for (const [key, value] of Object.entries(this.__state)) {
281
- let max = "";
282
- for (const overwrite of value.__overwrites) {
283
- if (max < overwrite) max = overwrite;
284
- }
285
- ack[key] = max;
405
+ const ack = __acknowledge(this.state);
406
+ if (ack) {
407
+ void this.eventTarget.dispatchEvent(
408
+ new CustomEvent("ack", { detail: ack })
409
+ );
286
410
  }
287
- this.__eventTarget.dispatchEvent(new CustomEvent("ack", { detail: ack }));
288
411
  }
289
412
  /**
290
413
  * Removes overwritten identifiers that every provided frontier has acknowledged.
@@ -292,47 +415,57 @@ var OOStruct = (_class = class _OOStruct {
292
415
  * @param frontiers - A collection of acknowledgement frontiers to compact against.
293
416
  */
294
417
  garbageCollect(frontiers) {
295
- if (!Array.isArray(frontiers) || frontiers.length < 1) return;
296
- const smallestAcknowledgementsPerKey = {};
297
- for (const frontier of frontiers) {
298
- for (const [key, value] of Object.entries(frontier)) {
299
- if (!Object.hasOwn(this.__state, key) || !_utils.isUuidV7.call(void 0, value)) continue;
300
- const current = smallestAcknowledgementsPerKey[key];
301
- if (typeof current === "string" && current <= value) continue;
302
- smallestAcknowledgementsPerKey[key] = value;
303
- }
304
- }
305
- for (const [key, value] of Object.entries(smallestAcknowledgementsPerKey)) {
306
- const target = this.__state[key];
307
- const smallest = value;
308
- for (const uuidv72 of target.__overwrites) {
309
- if (uuidv72 === target.__after || uuidv72 > smallest) continue;
310
- target.__overwrites.delete(uuidv72);
311
- }
312
- }
418
+ void __garbageCollect(frontiers, this.state);
313
419
  }
314
420
  /**
315
421
  * Emits a serialized snapshot of the current replica state.
316
422
  */
317
423
  snapshot() {
318
- const snapshot = {};
319
- for (const [key, value] of Object.entries(this.__state)) {
320
- snapshot[key] = parseStateEntryToSnapshotEntry(
321
- value
424
+ const snapshot = __snapshot(this.state);
425
+ if (snapshot) {
426
+ void this.eventTarget.dispatchEvent(
427
+ new CustomEvent("snapshot", { detail: snapshot })
322
428
  );
323
429
  }
324
- this.__eventTarget.dispatchEvent(
325
- new CustomEvent("snapshot", { detail: snapshot })
326
- );
327
430
  }
328
- /**ADDITIONAL*/
329
431
  /**
330
432
  * Returns the struct field keys.
331
433
  *
332
434
  * @returns The field keys in the current replica.
333
435
  */
334
436
  keys() {
335
- return Object.keys(this.__live);
437
+ return Object.keys(this.state.entries);
438
+ }
439
+ /**
440
+ * Resets every field in the replica back to its default value.
441
+ */
442
+ clear() {
443
+ const result = __delete(this.state);
444
+ if (result) {
445
+ const { delta, change } = result;
446
+ if (delta) {
447
+ void this.eventTarget.dispatchEvent(
448
+ new CustomEvent("delta", { detail: delta })
449
+ );
450
+ }
451
+ if (change) {
452
+ void this.eventTarget.dispatchEvent(
453
+ new CustomEvent("change", { detail: change })
454
+ );
455
+ }
456
+ }
457
+ }
458
+ /**
459
+ * Returns a cloned plain object view of the current replica fields.
460
+ *
461
+ * @returns The current field values keyed by field name.
462
+ */
463
+ clone() {
464
+ const out = {};
465
+ for (const [key, entry] of Object.entries(this.state.entries)) {
466
+ out[key] = structuredClone(entry.value);
467
+ }
468
+ return out;
336
469
  }
337
470
  /**
338
471
  * Returns cloned copies of the current field values.
@@ -340,8 +473,8 @@ var OOStruct = (_class = class _OOStruct {
340
473
  * @returns The current field values.
341
474
  */
342
475
  values() {
343
- return Object.values(this.__live).map(
344
- (value) => structuredClone(value)
476
+ return Object.values(this.state.entries).map(
477
+ (entry) => structuredClone(entry.value)
345
478
  );
346
479
  }
347
480
  /**
@@ -350,12 +483,45 @@ var OOStruct = (_class = class _OOStruct {
350
483
  * @returns The current field entries.
351
484
  */
352
485
  entries() {
353
- return Object.entries(this.__live).map(([key, value]) => [
486
+ return Object.entries(this.state.entries).map(([key, entry]) => [
354
487
  key,
355
- structuredClone(value)
488
+ structuredClone(entry.value)
356
489
  ]);
357
490
  }
358
- /**EVENTS*/
491
+ /**
492
+ * Returns a serializable snapshot representation of this replica.
493
+ *
494
+ * Called automatically by `JSON.stringify`.
495
+ */
496
+ toJSON() {
497
+ return __snapshot(this.state);
498
+ }
499
+ /**
500
+ * Returns this replica as a JSON string.
501
+ */
502
+ toString() {
503
+ return JSON.stringify(this);
504
+ }
505
+ /**
506
+ * Returns the Node.js console inspection representation.
507
+ */
508
+ [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
509
+ return this.toJSON();
510
+ }
511
+ /**
512
+ * Returns the Deno console inspection representation.
513
+ */
514
+ [/* @__PURE__ */ Symbol.for("Deno.customInspect")]() {
515
+ return this.toJSON();
516
+ }
517
+ /**
518
+ * Iterates over the current live field entries.
519
+ */
520
+ *[Symbol.iterator]() {
521
+ for (const [key, entry] of Object.entries(this.state.entries)) {
522
+ yield [key, structuredClone(entry.value)];
523
+ }
524
+ }
359
525
  /**
360
526
  * Registers an event listener.
361
527
  *
@@ -364,7 +530,7 @@ var OOStruct = (_class = class _OOStruct {
364
530
  * @param options - Listener registration options.
365
531
  */
366
532
  addEventListener(type, listener, options) {
367
- this.__eventTarget.addEventListener(
533
+ this.eventTarget.addEventListener(
368
534
  type,
369
535
  listener,
370
536
  options
@@ -378,32 +544,23 @@ var OOStruct = (_class = class _OOStruct {
378
544
  * @param options - Listener removal options.
379
545
  */
380
546
  removeEventListener(type, listener, options) {
381
- this.__eventTarget.removeEventListener(
547
+ this.eventTarget.removeEventListener(
382
548
  type,
383
549
  listener,
384
550
  options
385
551
  );
386
552
  }
387
- /**HELPERS*/
388
- /**
389
- * Overwrites a field and returns the serialized delta entry for that overwrite.
390
- *
391
- * @param key - The field key to overwrite.
392
- * @param value - The next value for the field.
393
- * @returns The serialized snapshot entry for the new winning value.
394
- */
395
- overwriteAndReturnSnapshotEntry(key, value) {
396
- const target = this.__state[key];
397
- const old = { ...target };
398
- target.__uuidv7 = _uuid.v7.call(void 0, );
399
- target.__value = value;
400
- target.__after = old.__uuidv7;
401
- target.__overwrites.add(old.__uuidv7);
402
- this.__live[key] = value;
403
- return parseStateEntryToSnapshotEntry(target);
404
- }
405
- }, _class);
553
+ };
554
+ var CRStruct = CRStructRaw;
555
+
556
+
557
+
558
+
559
+
560
+
561
+
562
+
406
563
 
407
564
 
408
- exports.OOStruct = OOStruct;
565
+ exports.CRStruct = CRStruct; exports.__acknowledge = __acknowledge; exports.__create = __create; exports.__delete = __delete; exports.__garbageCollect = __garbageCollect; exports.__merge = __merge; exports.__read = __read; exports.__snapshot = __snapshot; exports.__update = __update;
409
566
  //# sourceMappingURL=index.cjs.map