@shirudo/ddd-kit 3.0.0-rc.11 → 3.0.0-rc.12
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/chunks/read-stream-pages.js +268 -219
- package/dist/chunks/read-stream-pages.js.map +1 -1
- package/dist/chunks/snapshot-store.d.ts +55 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
|
@@ -49,7 +49,7 @@ const sharedArrayBufferByteLengthGet = typeof SharedArrayBuffer === "undefined"
|
|
|
49
49
|
const regExpSourceGet = intrinsicGetter(RegExp.prototype, "source");
|
|
50
50
|
const booleanValueOf = Boolean.prototype.valueOf;
|
|
51
51
|
const numberValueOf = Number.prototype.valueOf;
|
|
52
|
-
const stringValueOf = String.prototype.valueOf;
|
|
52
|
+
const stringValueOf$1 = String.prototype.valueOf;
|
|
53
53
|
const bigIntValueOf = BigInt.prototype.valueOf;
|
|
54
54
|
const functionToString = Function.prototype.toString;
|
|
55
55
|
const PROBE_KEY = {};
|
|
@@ -197,6 +197,10 @@ function builtInTagWithoutInvokingAccessors(value) {
|
|
|
197
197
|
if (BUILT_IN_TAGS.has(tag) && hasBrand(value, tag)) return tag;
|
|
198
198
|
return descriptor === void 0 ? void 0 : builtInTagFromBrand(value);
|
|
199
199
|
}
|
|
200
|
+
/** The type name in a tag: `"Map"` for `"[object Map]"`. */
|
|
201
|
+
function builtInTypeName(tag) {
|
|
202
|
+
return tag.slice(8, -1);
|
|
203
|
+
}
|
|
200
204
|
function builtInTagFromBrand(value) {
|
|
201
205
|
if (hasBrand(value, "[object Date]")) return "[object Date]";
|
|
202
206
|
if (hasBrand(value, "[object RegExp]")) return "[object RegExp]";
|
|
@@ -268,7 +272,7 @@ function hasBrand(obj, tag) {
|
|
|
268
272
|
numberValueOf.call(obj);
|
|
269
273
|
return true;
|
|
270
274
|
case "[object String]":
|
|
271
|
-
stringValueOf.call(obj);
|
|
275
|
+
stringValueOf$1.call(obj);
|
|
272
276
|
return true;
|
|
273
277
|
case "[object BigInt]":
|
|
274
278
|
bigIntValueOf.call(obj);
|
|
@@ -646,47 +650,106 @@ function deepEqualExcept(a, b, options) {
|
|
|
646
650
|
}
|
|
647
651
|
|
|
648
652
|
//#endregion
|
|
649
|
-
//#region src/
|
|
653
|
+
//#region src/internal/cooperative-brand.ts
|
|
654
|
+
/**
|
|
655
|
+
* A cooperative brand marks an object that a kit constructor produced, so
|
|
656
|
+
* a second loaded copy of the kit (duplicate npm dependency, dual CJS/ESM
|
|
657
|
+
* load, plugin bundle) recognizes it. A module-private WeakSet cannot do
|
|
658
|
+
* that: it is bound to one loaded copy. The brand is a `Symbol.for` key
|
|
659
|
+
* with the value `true`. The property is non-enumerable, so it never
|
|
660
|
+
* leaks into spreads, JSON, or equality, and non-writable and
|
|
661
|
+
* non-configurable, so nothing edits it after the stamp.
|
|
662
|
+
*
|
|
663
|
+
* The probe reads the brand as an OWN property with exactly these
|
|
664
|
+
* attributes and requires the carrier to be frozen. An object that
|
|
665
|
+
* inherits a branded object through its prototype can carry mutable own
|
|
666
|
+
* overrides; a branded object that is still open can change after the
|
|
667
|
+
* stamp. Neither is what the constructor produced. Every stamp site
|
|
668
|
+
* therefore freezes the carrier right after {@link stampCooperativeBrand}.
|
|
669
|
+
*
|
|
670
|
+
* The brand is forgeable BY DESIGN. It catches accidental hand-rolled
|
|
671
|
+
* literals; it is not a security boundary against code in the same
|
|
672
|
+
* process that fakes it on purpose.
|
|
673
|
+
*
|
|
674
|
+
* Internal utility (not exported from the package barrels).
|
|
675
|
+
*/
|
|
676
|
+
function stampCooperativeBrand(target, brand) {
|
|
677
|
+
Object.defineProperty(target, brand, {
|
|
678
|
+
value: true,
|
|
679
|
+
enumerable: false,
|
|
680
|
+
writable: false,
|
|
681
|
+
configurable: false
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Whether `value` carries `brand` as an own, non-enumerable, non-writable,
|
|
686
|
+
* non-configurable `true` and is frozen. A Proxy trap that throws reads
|
|
687
|
+
* as unbranded.
|
|
688
|
+
*/
|
|
689
|
+
function hasCooperativeBrand(value, brand) {
|
|
690
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return false;
|
|
691
|
+
try {
|
|
692
|
+
const marker = Reflect.getOwnPropertyDescriptor(value, brand);
|
|
693
|
+
return marker?.value === true && marker.enumerable === false && marker.writable === false && marker.configurable === false && Object.isFrozen(value);
|
|
694
|
+
} catch {
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
//#endregion
|
|
700
|
+
//#region src/internal/structural/shadowed-mutators.ts
|
|
650
701
|
/**
|
|
651
702
|
* `Object.freeze` does not protect internal slots: a frozen Date still
|
|
652
|
-
* accepts `setTime`, a frozen Map still accepts `set`.
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
* round-trip never sees them).
|
|
703
|
+
* accepts `setTime`, a frozen Map still accepts `set`. A deep freeze
|
|
704
|
+
* therefore shadows these mutators with own throwing functions. The
|
|
705
|
+
* shadows are non-enumerable, so they are invisible to `Object.keys` and
|
|
706
|
+
* spread, and `structuredClone` drops them. A walk that checks a copy
|
|
707
|
+
* accepts them as machinery, not data.
|
|
658
708
|
*/
|
|
659
|
-
const
|
|
660
|
-
"
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
709
|
+
const mutatorsByTag = /* @__PURE__ */ new Map([
|
|
710
|
+
["[object Date]", [
|
|
711
|
+
"setTime",
|
|
712
|
+
"setMilliseconds",
|
|
713
|
+
"setUTCMilliseconds",
|
|
714
|
+
"setSeconds",
|
|
715
|
+
"setUTCSeconds",
|
|
716
|
+
"setMinutes",
|
|
717
|
+
"setUTCMinutes",
|
|
718
|
+
"setHours",
|
|
719
|
+
"setUTCHours",
|
|
720
|
+
"setDate",
|
|
721
|
+
"setUTCDate",
|
|
722
|
+
"setMonth",
|
|
723
|
+
"setUTCMonth",
|
|
724
|
+
"setFullYear",
|
|
725
|
+
"setUTCFullYear",
|
|
726
|
+
"setYear"
|
|
727
|
+
]],
|
|
728
|
+
["[object Map]", [
|
|
729
|
+
"set",
|
|
730
|
+
"delete",
|
|
731
|
+
"clear"
|
|
732
|
+
]],
|
|
733
|
+
["[object Set]", [
|
|
734
|
+
"add",
|
|
735
|
+
"delete",
|
|
736
|
+
"clear"
|
|
737
|
+
]]
|
|
738
|
+
]);
|
|
739
|
+
const mutatorShadowBrand = Symbol.for("@shirudo/ddd-kit/mutator-shadow/v1");
|
|
740
|
+
const shadows = /* @__PURE__ */ new Map();
|
|
741
|
+
function shadowOf(typeName, method) {
|
|
681
742
|
const key = `${typeName}.${method}`;
|
|
682
|
-
let
|
|
683
|
-
if (
|
|
684
|
-
|
|
743
|
+
let shadow = shadows.get(key);
|
|
744
|
+
if (shadow === void 0) {
|
|
745
|
+
shadow = function throwFrozenMutation() {
|
|
685
746
|
throw new TypeError(`Cannot call ${method}() on a ${typeName} inside a deeply frozen value`);
|
|
686
747
|
};
|
|
687
|
-
|
|
748
|
+
stampCooperativeBrand(shadow, mutatorShadowBrand);
|
|
749
|
+
Object.freeze(shadow);
|
|
750
|
+
shadows.set(key, shadow);
|
|
688
751
|
}
|
|
689
|
-
return
|
|
752
|
+
return shadow;
|
|
690
753
|
}
|
|
691
754
|
const shadowDescriptor = {
|
|
692
755
|
value: void 0,
|
|
@@ -694,15 +757,36 @@ const shadowDescriptor = {
|
|
|
694
757
|
enumerable: false,
|
|
695
758
|
configurable: false
|
|
696
759
|
};
|
|
697
|
-
/**
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
760
|
+
/**
|
|
761
|
+
* Installs the mutator shadows on a Date, a Map, or a Set whose tag is
|
|
762
|
+
* `tag`. Returns whether it installed them: a built-in of another kind has
|
|
763
|
+
* no mutator shadows, and a non-extensible one cannot take them.
|
|
764
|
+
*/
|
|
765
|
+
function installMutatorShadows(object, tag) {
|
|
766
|
+
const mutators = mutatorsByTag.get(tag);
|
|
767
|
+
if (mutators === void 0 || !Object.isExtensible(object)) return false;
|
|
768
|
+
const typeName = builtInTypeName(tag);
|
|
769
|
+
for (const method of mutators) {
|
|
770
|
+
shadowDescriptor.value = shadowOf(typeName, method);
|
|
771
|
+
Object.defineProperty(object, method, shadowDescriptor);
|
|
703
772
|
}
|
|
704
773
|
return true;
|
|
705
774
|
}
|
|
775
|
+
/**
|
|
776
|
+
* Whether the own property `key` of a built-in whose tag is `tag` is a
|
|
777
|
+
* mutator shadow: a locked, non-enumerable function with the cooperative
|
|
778
|
+
* brand of a shadow, under a mutator key of that built-in. The brand
|
|
779
|
+
* catches accidents, not a forgery.
|
|
780
|
+
*/
|
|
781
|
+
function isMutatorShadow(tag, key, descriptor) {
|
|
782
|
+
const shadow = descriptor.value;
|
|
783
|
+
return (mutatorsByTag.get(tag)?.includes(key) ?? false) && typeof shadow === "function" && descriptor.enumerable === false && descriptor.writable === false && descriptor.configurable === false && hasCooperativeBrand(shadow, mutatorShadowBrand);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
//#endregion
|
|
787
|
+
//#region src/domain/value-object/value-object.ts
|
|
788
|
+
const mapEntries$1 = Map.prototype.entries;
|
|
789
|
+
const setValues$1 = Set.prototype.values;
|
|
706
790
|
const VALUE_OBJECT_CLASS = Symbol.for("@shirudo/ddd-kit/value-object-class/v1");
|
|
707
791
|
function recordValueObjectClass(instance, valueObjectClass) {
|
|
708
792
|
Object.defineProperty(instance, VALUE_OBJECT_CLASS, {
|
|
@@ -795,27 +879,14 @@ function freezeDeep(obj, walk) {
|
|
|
795
879
|
walk.inProgress.add(obj);
|
|
796
880
|
let sealed = true;
|
|
797
881
|
if (builtInTag === "[object Date]" || builtInTag === "[object Map]" || builtInTag === "[object Set]") {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (!freezeDeep(value, walk)) sealed = false;
|
|
804
|
-
}
|
|
805
|
-
shadowed = shadowMutators(obj, "Map", [
|
|
806
|
-
"set",
|
|
807
|
-
"delete",
|
|
808
|
-
"clear"
|
|
809
|
-
]) || shadowed;
|
|
810
|
-
} else if (builtInTag === "[object Set]") {
|
|
882
|
+
if (builtInTag === "[object Map]") for (const [key, value] of obj) {
|
|
883
|
+
if (!freezeDeep(key, walk)) sealed = false;
|
|
884
|
+
if (!freezeDeep(value, walk)) sealed = false;
|
|
885
|
+
}
|
|
886
|
+
else if (builtInTag === "[object Set]") {
|
|
811
887
|
for (const member of obj) if (!freezeDeep(member, walk)) sealed = false;
|
|
812
|
-
shadowed = shadowMutators(obj, "Set", [
|
|
813
|
-
"add",
|
|
814
|
-
"delete",
|
|
815
|
-
"clear"
|
|
816
|
-
]) || shadowed;
|
|
817
888
|
}
|
|
818
|
-
if (
|
|
889
|
+
if (installMutatorShadows(obj, builtInTag) || KIT_SHADOWED.has(obj)) KIT_SHADOWED.add(obj);
|
|
819
890
|
else sealed = false;
|
|
820
891
|
}
|
|
821
892
|
const keys = Reflect.ownKeys(obj);
|
|
@@ -1200,53 +1271,6 @@ var ValueObject = class {
|
|
|
1200
1271
|
}
|
|
1201
1272
|
};
|
|
1202
1273
|
|
|
1203
|
-
//#endregion
|
|
1204
|
-
//#region src/internal/cooperative-brand.ts
|
|
1205
|
-
/**
|
|
1206
|
-
* A cooperative brand marks an object that a kit constructor produced, so
|
|
1207
|
-
* a second loaded copy of the kit (duplicate npm dependency, dual CJS/ESM
|
|
1208
|
-
* load, plugin bundle) recognizes it. A module-private WeakSet cannot do
|
|
1209
|
-
* that: it is bound to one loaded copy. The brand is a `Symbol.for` key
|
|
1210
|
-
* with the value `true`. The property is non-enumerable, so it never
|
|
1211
|
-
* leaks into spreads, JSON, or equality, and non-writable and
|
|
1212
|
-
* non-configurable, so nothing edits it after the stamp.
|
|
1213
|
-
*
|
|
1214
|
-
* The probe reads the brand as an OWN property with exactly these
|
|
1215
|
-
* attributes and requires the carrier to be frozen. An object that
|
|
1216
|
-
* inherits a branded object through its prototype can carry mutable own
|
|
1217
|
-
* overrides; a branded object that is still open can change after the
|
|
1218
|
-
* stamp. Neither is what the constructor produced. Every stamp site
|
|
1219
|
-
* therefore freezes the carrier right after {@link stampCooperativeBrand}.
|
|
1220
|
-
*
|
|
1221
|
-
* The brand is forgeable BY DESIGN. It catches accidental hand-rolled
|
|
1222
|
-
* literals; it is not a security boundary against code in the same
|
|
1223
|
-
* process that fakes it on purpose.
|
|
1224
|
-
*
|
|
1225
|
-
* Internal utility (not exported from the package barrels).
|
|
1226
|
-
*/
|
|
1227
|
-
function stampCooperativeBrand(target, brand) {
|
|
1228
|
-
Object.defineProperty(target, brand, {
|
|
1229
|
-
value: true,
|
|
1230
|
-
enumerable: false,
|
|
1231
|
-
writable: false,
|
|
1232
|
-
configurable: false
|
|
1233
|
-
});
|
|
1234
|
-
}
|
|
1235
|
-
/**
|
|
1236
|
-
* Whether `value` carries `brand` as an own, non-enumerable, non-writable,
|
|
1237
|
-
* non-configurable `true` and is frozen. A Proxy trap that throws reads
|
|
1238
|
-
* as unbranded.
|
|
1239
|
-
*/
|
|
1240
|
-
function hasCooperativeBrand(value, brand) {
|
|
1241
|
-
if (value === null || typeof value !== "object" && typeof value !== "function") return false;
|
|
1242
|
-
try {
|
|
1243
|
-
const marker = Reflect.getOwnPropertyDescriptor(value, brand);
|
|
1244
|
-
return marker?.value === true && marker.enumerable === false && marker.writable === false && marker.configurable === false && Object.isFrozen(value);
|
|
1245
|
-
} catch {
|
|
1246
|
-
return false;
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
1274
|
//#endregion
|
|
1251
1275
|
//#region src/internal/structural/detach-state.ts
|
|
1252
1276
|
/**
|
|
@@ -1259,7 +1283,9 @@ function hasCooperativeBrand(value, brand) {
|
|
|
1259
1283
|
* `DataCloneError`. An Error, a Promise, a WeakMap, or a WeakSet cannot be
|
|
1260
1284
|
* detached at all. A SharedArrayBuffer and a view over one keep sharing
|
|
1261
1285
|
* their memory. A Proxy fails in the walk or in the clone; a failure in
|
|
1262
|
-
* the clone is rethrown as a `TypeError` with the cause.
|
|
1286
|
+
* the clone is rethrown as a `TypeError` with the cause. An error that a
|
|
1287
|
+
* Proxy trap throws in the walk passes unchanged, so a coded error of the
|
|
1288
|
+
* caller keeps its code.
|
|
1263
1289
|
*
|
|
1264
1290
|
* The walk reads the graph through property descriptors and walks a Map
|
|
1265
1291
|
* or a Set with the built-in iteration, so no accessor and no own iterator
|
|
@@ -1267,17 +1293,22 @@ function hasCooperativeBrand(value, brand) {
|
|
|
1267
1293
|
* change the graph, and an accessor that a trap adds runs during the
|
|
1268
1294
|
* clone. A second walk checks the clone, so a value that a trap swapped in
|
|
1269
1295
|
* and the content of a built-in whose prototype was replaced are rejected
|
|
1270
|
-
* too.
|
|
1271
|
-
* copy
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1296
|
+
* too. A trap that changes the graph after the first walk can still hide a
|
|
1297
|
+
* value that the copy drops: the walks catch accidents, not a hostile
|
|
1298
|
+
* Proxy. The second walk also follows the steps of the first walk: the kind
|
|
1299
|
+
* of each object and the key of each data property, in walk order. A copy
|
|
1300
|
+
* that differs throws, because a built-in whose prototype was replaced is
|
|
1301
|
+
* a built-in again in the copy and loses its own properties. `subject`
|
|
1302
|
+
* names the state in the messages.
|
|
1274
1303
|
*
|
|
1275
1304
|
* Plain objects (from any realm), arrays, Dates, Maps, Sets, bigints, and
|
|
1276
1305
|
* typed arrays pass. A RegExp passes: pattern and flags survive the clone,
|
|
1277
1306
|
* and `lastIndex` restores as 0. The scan state of a global or sticky
|
|
1278
|
-
* pattern is not domain data.
|
|
1279
|
-
*
|
|
1280
|
-
*
|
|
1307
|
+
* pattern is not domain data. On a built-in, the mutator shadows of a deep
|
|
1308
|
+
* freeze, the `lastIndex` of a RegExp, and the `length` of a boxed String
|
|
1309
|
+
* pass: they are machinery, not data. Every other non-enumerable property
|
|
1310
|
+
* throws. A non-enumerable symbol key passes anywhere: it is metadata by
|
|
1311
|
+
* convention.
|
|
1281
1312
|
*
|
|
1282
1313
|
* The concrete entity uses it for a detached read DTO of a plain-data
|
|
1283
1314
|
* state. The snapshot model uses it for the captured DTO and the restored
|
|
@@ -1296,41 +1327,18 @@ function detachState(state, subject = "detachState: state") {
|
|
|
1296
1327
|
function detachFreezableState(state, subject) {
|
|
1297
1328
|
return detach(state, subject, "freeze");
|
|
1298
1329
|
}
|
|
1299
|
-
/**
|
|
1300
|
-
* Throws the `TypeError` of {@link detachFreezableState} and copies
|
|
1301
|
-
* nothing. A caller that has a clone already checks it with this, so the
|
|
1302
|
-
* rule is the same. Kit modules only.
|
|
1303
|
-
*/
|
|
1304
|
-
function assertFreezableState(state, subject) {
|
|
1305
|
-
assertDetachable(state, "", {
|
|
1306
|
-
seen: /* @__PURE__ */ new WeakSet(),
|
|
1307
|
-
subject,
|
|
1308
|
-
rule: "freeze",
|
|
1309
|
-
dataProperties: 0
|
|
1310
|
-
});
|
|
1311
|
-
}
|
|
1312
1330
|
function detach(state, subject, rule) {
|
|
1313
|
-
const
|
|
1314
|
-
|
|
1315
|
-
subject,
|
|
1316
|
-
rule,
|
|
1317
|
-
dataProperties: 0
|
|
1318
|
-
};
|
|
1319
|
-
assertDetachable(state, "", original);
|
|
1331
|
+
const recording = new StepRecording();
|
|
1332
|
+
assertDetachable(state, "", newWalk(subject, rule, recording));
|
|
1320
1333
|
let copy;
|
|
1321
1334
|
try {
|
|
1322
1335
|
copy = structuredClone(state);
|
|
1323
1336
|
} catch (cause) {
|
|
1324
|
-
throw new TypeError(`${subject} holds a Proxy or a host object that cannot be cloned; map it to plain data`, { cause });
|
|
1337
|
+
throw new TypeError(`${subject} holds a Proxy or a host object that cannot be cloned, or a view over a detached or shrunk buffer; the cause names the value; map it to plain data`, { cause });
|
|
1325
1338
|
}
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
rule,
|
|
1330
|
-
dataProperties: 0
|
|
1331
|
-
};
|
|
1332
|
-
assertDetachable(copy, "", copied);
|
|
1333
|
-
if (copied.dataProperties !== original.dataProperties) throw new TypeError(`${subject} changed in the copy: the state has ${original.dataProperties} data properties and the copy has ${copied.dataProperties}; a built-in whose prototype was replaced loses its own properties in the copy, and a Proxy trap can change the graph; map it to plain data`);
|
|
1339
|
+
const comparison = new StepComparison(recording, subject);
|
|
1340
|
+
assertDetachable(copy, "", newWalk(subject, rule, comparison));
|
|
1341
|
+
comparison.assertComplete();
|
|
1334
1342
|
return copy;
|
|
1335
1343
|
}
|
|
1336
1344
|
const INDEX_KEY = /^(0|[1-9]\d*)$/;
|
|
@@ -1341,8 +1349,76 @@ const BINARY_DATA_TAGS = /* @__PURE__ */ new Set([
|
|
|
1341
1349
|
"[object SharedArrayBuffer]"
|
|
1342
1350
|
]);
|
|
1343
1351
|
const REGEXP_TAG = "[object RegExp]";
|
|
1352
|
+
const STRING_TAG = "[object String]";
|
|
1344
1353
|
const mapEntries = Map.prototype.entries;
|
|
1345
1354
|
const setValues = Set.prototype.values;
|
|
1355
|
+
const RECORD_STEP = Symbol("record");
|
|
1356
|
+
const ARRAY_STEP = Symbol("array");
|
|
1357
|
+
const builtInSteps = /* @__PURE__ */ new Map();
|
|
1358
|
+
function builtInStep(tag) {
|
|
1359
|
+
let kind = builtInSteps.get(tag);
|
|
1360
|
+
if (kind === void 0) {
|
|
1361
|
+
kind = Symbol(tag);
|
|
1362
|
+
builtInSteps.set(tag, kind);
|
|
1363
|
+
}
|
|
1364
|
+
return kind;
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* The steps of the walk over the original, in walk order.
|
|
1368
|
+
*/
|
|
1369
|
+
var StepRecording = class {
|
|
1370
|
+
steps = [];
|
|
1371
|
+
take(next) {
|
|
1372
|
+
this.steps.push(next);
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
/**
|
|
1376
|
+
* The walk over the copy compares each of its steps with the step of the
|
|
1377
|
+
* walk over the original at the same position. Structured clone keeps the
|
|
1378
|
+
* order of the keys, of Map entries, and of Set members, and it keeps
|
|
1379
|
+
* shared references, so the walk over an unchanged copy takes the same
|
|
1380
|
+
* steps. A step that differs, or a step that is missing, means that the
|
|
1381
|
+
* copy changed.
|
|
1382
|
+
*/
|
|
1383
|
+
var StepComparison = class {
|
|
1384
|
+
recording;
|
|
1385
|
+
subject;
|
|
1386
|
+
#position = 0;
|
|
1387
|
+
constructor(recording, subject) {
|
|
1388
|
+
this.recording = recording;
|
|
1389
|
+
this.subject = subject;
|
|
1390
|
+
}
|
|
1391
|
+
take(next, path) {
|
|
1392
|
+
const expected = this.recording.steps[this.#position];
|
|
1393
|
+
if (expected !== next) throwChangedInCopy(this.subject, path, expected, next);
|
|
1394
|
+
this.#position += 1;
|
|
1395
|
+
}
|
|
1396
|
+
assertComplete() {
|
|
1397
|
+
if (this.#position < this.recording.steps.length) throwChangedInCopy(this.subject, "", this.recording.steps[this.#position], void 0);
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
function newWalk(subject, rule, trace) {
|
|
1401
|
+
return {
|
|
1402
|
+
seen: /* @__PURE__ */ new WeakSet(),
|
|
1403
|
+
subject,
|
|
1404
|
+
rule,
|
|
1405
|
+
trace
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
function step(walk, next, path) {
|
|
1409
|
+
walk.trace.take(next, path);
|
|
1410
|
+
}
|
|
1411
|
+
function throwChangedInCopy(subject, path, expected, found) {
|
|
1412
|
+
throw new TypeError(`${subject}${path} changed in the copy: the state has ${describeStep(expected)} there, and the copy has ${describeStep(found)}; a built-in whose prototype was replaced is a built-in again in the copy and loses its own properties, and a Proxy trap can change the graph; map it to plain data`);
|
|
1413
|
+
}
|
|
1414
|
+
function describeStep(step) {
|
|
1415
|
+
if (step === void 0) return "nothing";
|
|
1416
|
+
if (typeof step === "string") return `the key "${step}"`;
|
|
1417
|
+
if (step === RECORD_STEP) return "a record";
|
|
1418
|
+
if (step === ARRAY_STEP) return "an array";
|
|
1419
|
+
const name = builtInTypeName(step.description);
|
|
1420
|
+
return /^[AEIOU]/.test(name) ? `an ${name}` : `a ${name}`;
|
|
1421
|
+
}
|
|
1346
1422
|
function assertDetachable(value, path, walk) {
|
|
1347
1423
|
if (typeof value === "function") throw new TypeError(`${walk.subject}${path} is a function; map it to plain data`);
|
|
1348
1424
|
if (typeof value === "symbol") throw new TypeError(`${walk.subject}${path} is a symbol; map it to plain data`);
|
|
@@ -1352,6 +1428,7 @@ function assertDetachable(value, path, walk) {
|
|
|
1352
1428
|
walk.seen.add(object);
|
|
1353
1429
|
if (Array.isArray(object)) {
|
|
1354
1430
|
if (!hasIntrinsicPrototypeChain(object, "Array")) throwClassInstance(object, path, walk.subject);
|
|
1431
|
+
step(walk, ARRAY_STEP, path);
|
|
1355
1432
|
assertOwnPropertiesDetachable(object, path, walk, "array");
|
|
1356
1433
|
return;
|
|
1357
1434
|
}
|
|
@@ -1359,6 +1436,7 @@ function assertDetachable(value, path, walk) {
|
|
|
1359
1436
|
if (tag !== void 0) {
|
|
1360
1437
|
if (walk.rule === "freeze") assertFreezable(tag, path, walk.subject);
|
|
1361
1438
|
if (!hasIntrinsicPrototypeChain(object)) throwClassInstance(object, path, walk.subject);
|
|
1439
|
+
step(walk, builtInStep(tag), path);
|
|
1362
1440
|
if (tag === "[object Map]") {
|
|
1363
1441
|
let index = 0;
|
|
1364
1442
|
for (const [key, entry] of mapEntries.call(object)) {
|
|
@@ -1372,25 +1450,30 @@ function assertDetachable(value, path, walk) {
|
|
|
1372
1450
|
assertDetachable(member, `${path}<set member #${index}>`, walk);
|
|
1373
1451
|
index++;
|
|
1374
1452
|
}
|
|
1375
|
-
} else if (tag === "[object Promise]" || tag === "[object WeakMap]" || tag === "[object WeakSet]") throw new TypeError(`${walk.subject}${path} is a ${tag
|
|
1453
|
+
} else if (tag === "[object Promise]" || tag === "[object WeakMap]" || tag === "[object WeakSet]") throw new TypeError(`${walk.subject}${path} is a ${builtInTypeName(tag)} and cannot be detached`);
|
|
1376
1454
|
else if (tag === "[object Error]") throw new TypeError(`${walk.subject}${path} is an Error; map it to plain data`);
|
|
1377
1455
|
else if (sharesMemory(object, tag)) throw new TypeError(`${walk.subject}${path} is backed by a SharedArrayBuffer and the copy would share its memory; map it to plain data`);
|
|
1378
|
-
assertOwnPropertiesDetachable(object, path, walk,
|
|
1456
|
+
assertOwnPropertiesDetachable(object, path, walk, tag);
|
|
1379
1457
|
return;
|
|
1380
1458
|
}
|
|
1381
1459
|
const prototype = Object.getPrototypeOf(object);
|
|
1382
1460
|
if (!(prototype === null || isIntrinsicConstructorPrototype(prototype, "Object") && Object.getPrototypeOf(prototype) === null)) throwClassInstance(object, path, walk.subject);
|
|
1461
|
+
step(walk, RECORD_STEP, path);
|
|
1383
1462
|
assertOwnPropertiesDetachable(object, path, walk, "record");
|
|
1384
1463
|
}
|
|
1385
1464
|
/**
|
|
1386
1465
|
* Audits the own properties the clone would copy or drop. The clone keeps
|
|
1387
1466
|
* the enumerable own keys of a record and of an array, expandos included,
|
|
1388
|
-
* and drops every own key of another built-in. `length` on an array
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1391
|
-
* its content and pass as such.
|
|
1467
|
+
* and drops every own key of another built-in. `length` on an array is
|
|
1468
|
+
* its own machinery, not data, and so are the keys that
|
|
1469
|
+
* {@link isBuiltInMachinery} names. The index keys of a built-in below its
|
|
1470
|
+
* content length are its content and pass as such. Another index key of a
|
|
1471
|
+
* built-in is an expando. `owner` is the kind of `object`: an array, a
|
|
1472
|
+
* record, or the tag of a built-in.
|
|
1392
1473
|
*/
|
|
1393
|
-
function assertOwnPropertiesDetachable(object, path, walk,
|
|
1474
|
+
function assertOwnPropertiesDetachable(object, path, walk, owner) {
|
|
1475
|
+
const tag = owner === "array" || owner === "record" ? void 0 : owner;
|
|
1476
|
+
const contentLength = tag === void 0 ? 0 : contentLengthOf(object, tag);
|
|
1394
1477
|
for (const key of Reflect.ownKeys(object)) {
|
|
1395
1478
|
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
1396
1479
|
if (descriptor === void 0) continue;
|
|
@@ -1398,20 +1481,41 @@ function assertOwnPropertiesDetachable(object, path, walk, kind) {
|
|
|
1398
1481
|
if (!descriptor.enumerable) continue;
|
|
1399
1482
|
throw new TypeError(`${walk.subject}${path} has a symbol-keyed property; map it to plain data`);
|
|
1400
1483
|
}
|
|
1401
|
-
if (
|
|
1484
|
+
if (owner === "array" && key === "length") continue;
|
|
1402
1485
|
const isIndex = INDEX_KEY.test(key);
|
|
1486
|
+
const memberPath = isIndex ? `${path}[${key}]` : `${path}.${key}`;
|
|
1403
1487
|
if (!descriptor.enumerable) {
|
|
1404
|
-
if (
|
|
1405
|
-
throw new TypeError(`${walk.subject}${
|
|
1488
|
+
if (tag !== void 0 && isBuiltInMachinery(tag, key, descriptor)) continue;
|
|
1489
|
+
throw new TypeError(`${walk.subject}${memberPath} is not enumerable and the clone would drop it; map it to plain data`);
|
|
1406
1490
|
}
|
|
1407
|
-
if (
|
|
1408
|
-
const memberPath = isIndex ? `${path}[${key}]` : `${path}.${key}`;
|
|
1491
|
+
if (tag !== void 0 && isIndex && Number(key) < contentLength) continue;
|
|
1409
1492
|
if (!("value" in descriptor)) throw new TypeError(`${walk.subject}${memberPath} is an accessor property; map it to plain data`);
|
|
1410
|
-
if (
|
|
1411
|
-
walk
|
|
1493
|
+
if (tag !== void 0) throw new TypeError(`${walk.subject}${memberPath} is an expando on a ${constructorName(Object.getPrototypeOf(object)) ?? "built-in"} and the clone would drop it; map it to plain data`);
|
|
1494
|
+
step(walk, key, memberPath);
|
|
1412
1495
|
assertDetachable(descriptor.value, memberPath, walk);
|
|
1413
1496
|
}
|
|
1414
1497
|
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Whether an own non-enumerable property of a built-in is machinery, not
|
|
1500
|
+
* data: a function that shadows a mutator of a frozen Date, Map, or Set,
|
|
1501
|
+
* the scan position of a RegExp, or the length of a boxed String. The
|
|
1502
|
+
* clone drops the shadow and rebuilds the other two from the internal
|
|
1503
|
+
* slots.
|
|
1504
|
+
*/
|
|
1505
|
+
function isBuiltInMachinery(tag, key, descriptor) {
|
|
1506
|
+
return isMutatorShadow(tag, key, descriptor) || tag === REGEXP_TAG && key === "lastIndex" || tag === STRING_TAG && key === "length";
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* The number of index keys that hold the content of a built-in: the
|
|
1510
|
+
* elements of a typed array and the characters of a boxed String.
|
|
1511
|
+
*/
|
|
1512
|
+
function contentLengthOf(object, tag) {
|
|
1513
|
+
if (tag === "[object TypedArray]") return typedArrayLength.call(object);
|
|
1514
|
+
if (tag === STRING_TAG) return stringValueOf.call(object).length;
|
|
1515
|
+
return 0;
|
|
1516
|
+
}
|
|
1517
|
+
const typedArrayLength = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), "length")?.get;
|
|
1518
|
+
const stringValueOf = String.prototype.valueOf;
|
|
1415
1519
|
const typedArrayBuffer = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), "buffer")?.get;
|
|
1416
1520
|
const dataViewBuffer = Object.getOwnPropertyDescriptor(DataView.prototype, "buffer")?.get;
|
|
1417
1521
|
function sharesMemory(object, tag) {
|
|
@@ -1544,48 +1648,6 @@ function buildDomainEventFactory(options, createOperation) {
|
|
|
1544
1648
|
* with {@link createDomainEventFactory} for custom policy.
|
|
1545
1649
|
*/
|
|
1546
1650
|
const defaultDomainEventFactory = buildDomainEventFactory({}, "createDomainEvent");
|
|
1547
|
-
/**
|
|
1548
|
-
* Creates a domain event with default values.
|
|
1549
|
-
* Sets occurredAt to current date and schemaVersion to 1 if not provided.
|
|
1550
|
-
*
|
|
1551
|
-
* **Input ownership.** The event is deeply frozen, and `payload` and
|
|
1552
|
-
* `metadata` are deep-cloned first, so the caller's own objects are never
|
|
1553
|
-
* frozen in place and later mutation of them does not bleed into the
|
|
1554
|
-
* event (same contract as `vo()`). The clone follows the plain-data event
|
|
1555
|
-
* contract via `structuredClone`: functions, Promise, and WeakMap/WeakSet
|
|
1556
|
-
* values throw a `TypeError`; symbol-keyed properties are not carried
|
|
1557
|
-
* over. The clone is then checked with the rule of the in-memory event
|
|
1558
|
-
* store: an `Error`, a host object such as a `File`, a binary buffer, and
|
|
1559
|
-
* shared memory throw a `TypeError`. A class instance or an accessor becomes
|
|
1560
|
-
* plain data in the clone.
|
|
1561
|
-
*
|
|
1562
|
-
* **For aggregate-internal events, prefer `this.createEvent(...)` on
|
|
1563
|
-
* `StateStoredAggregate` / `EventSourcedAggregate`.** That helper auto-injects
|
|
1564
|
-
* `aggregateId` (from `this.id`) and `aggregateType` (from the
|
|
1565
|
-
* aggregate's declared `aggregateType` property), which downstream
|
|
1566
|
-
* consumers (outbox dispatchers, projection handlers, audit logs)
|
|
1567
|
-
* route by. The commit boundary validates that both fields are present
|
|
1568
|
-
* and throws if they are missing, so a direct `createDomainEvent(...)`
|
|
1569
|
-
* call inside an aggregate that forgets the options is caught at
|
|
1570
|
-
* runtime. Record pending decisions in the application
|
|
1571
|
-
* shell before repository persistence or outbox harvest.
|
|
1572
|
-
*
|
|
1573
|
-
* Use `createDomainEvent(...)` directly for events that don't belong to
|
|
1574
|
-
* an aggregate: system events, integration events, configuration events,
|
|
1575
|
-
* test fixtures. For those, set `aggregateId` / `aggregateType` in
|
|
1576
|
-
* `options` if downstream consumers expect routing metadata.
|
|
1577
|
-
*
|
|
1578
|
-
* @param type - The event type
|
|
1579
|
-
* @param payload - The event payload
|
|
1580
|
-
* @param options - Optional event configuration (including `aggregateId`
|
|
1581
|
-
* and `aggregateType` for routing)
|
|
1582
|
-
* @returns A domain event
|
|
1583
|
-
*
|
|
1584
|
-
* @example
|
|
1585
|
-
* ```typescript
|
|
1586
|
-
* const event = createDomainEvent("OrderCreated", { orderId: "123" });
|
|
1587
|
-
* ```
|
|
1588
|
-
*/
|
|
1589
1651
|
const RECORDED_EVENTS = /* @__PURE__ */ new WeakSet();
|
|
1590
1652
|
const UNCOMMITTED_EVENTS = /* @__PURE__ */ new WeakSet();
|
|
1591
1653
|
const FACTORY_OWNED_EVENT_STAMPS = /* @__PURE__ */ new WeakSet();
|
|
@@ -1792,25 +1854,12 @@ function isPlainRecordCopy(copy) {
|
|
|
1792
1854
|
/**
|
|
1793
1855
|
* Deep-clones caller-supplied event data (payload, metadata) before the
|
|
1794
1856
|
* event is frozen, so a constructor never freezes or aliases the caller's
|
|
1795
|
-
* own object graph
|
|
1796
|
-
*
|
|
1797
|
-
* instance or an accessor becomes plain data in the clone.
|
|
1857
|
+
* own object graph. {@link detachFreezableState} checks the data and the
|
|
1858
|
+
* clone; its JSDoc states the rule and its limits.
|
|
1798
1859
|
*/
|
|
1799
1860
|
function cloneOwnedEventData(value, field, operation) {
|
|
1800
|
-
if (typeof value === "
|
|
1801
|
-
|
|
1802
|
-
assertFreezableState(value, `${operation}: ${field}`);
|
|
1803
|
-
return value;
|
|
1804
|
-
}
|
|
1805
|
-
let clone;
|
|
1806
|
-
try {
|
|
1807
|
-
clone = structuredClone(value);
|
|
1808
|
-
} catch (cause) {
|
|
1809
|
-
throw new TypeError(`${operation}: ${field} cannot be copied, because structuredClone failed (the cause names the value); domain events are plain data`, { cause });
|
|
1810
|
-
}
|
|
1811
|
-
assertNoHostileOwnProtoKey(clone, `Event ${field} of ${operation}`);
|
|
1812
|
-
assertFreezableState(clone, `${operation}: ${field}`);
|
|
1813
|
-
return clone;
|
|
1861
|
+
if (value !== null && typeof value === "object") assertNoHostileOwnProtoKey(value, `Event ${field} of ${operation}`);
|
|
1862
|
+
return detachFreezableState(value, `${operation}: ${field}`);
|
|
1814
1863
|
}
|
|
1815
1864
|
/**
|
|
1816
1865
|
* Copies metadata from a source event to a new event.
|
|
@@ -2250,5 +2299,5 @@ function throwIfAborted(signal) {
|
|
|
2250
2299
|
}
|
|
2251
2300
|
|
|
2252
2301
|
//#endregion
|
|
2253
|
-
export { SnapshotTimeValidationError as A,
|
|
2302
|
+
export { SnapshotTimeValidationError as A, stampCooperativeBrand as B, defaultDomainEventFactory as C, mintUncommittedDomainEvent as D, mergeMetadata as E, vo as F, isBuiltInObject as G, deepOmit as H, voEquals as I, isIntrinsicConstructorPrototype as K, voEqualsExcept as L, detachState as M, ValueObject as N, recordDomainEvent as O, deepFreeze as P, voWithValidation as R, createUncommittedDomainEvent as S, isUncommittedDomainEvent as T, deepEqual as U, deepEqualExcept as V, findPropertyDescriptor as W, adoptUncommittedDomainEvent as _, isDispatchTrackingOutbox as a, createDomainEventFactory as b, runBoundedExecution as c, assertPositiveInteger as d, assertPositiveSafeInteger as f, adoptRecordedDomainEvent as g, waitRejectingOnAbort as h, assertPageWithinWindow as i, detachFreezableState as j, DomainEventValidationError as k, MAX_TIMER_DELAY_MS as l, abortReason as m, readStreamPages as n, DEFAULT_EXECUTION_TIMEOUT_MS as o, assertTimerDelay as p, isWeakMap as q, assertPageNotEmpty as r, ownerSignalOf as s, pinTargetVersion as t, assertNonNegativeSafeInteger as u, copyMetadata as v, isRecordedDomainEvent as w, createDomainEventFromFacts as x, createDomainEvent as y, hasCooperativeBrand as z };
|
|
2254
2303
|
//# sourceMappingURL=read-stream-pages.js.map
|