@peerbit/document 13.1.19 → 13.1.20

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.
@@ -1,2 +1,15 @@
1
+ import { type CustomField, type SimpleField } from "@dao-xyz/borsh";
2
+ /**
3
+ * Register a Borsh field backed by an accessor and explicitly preserve that
4
+ * accessor when Documents wraps an indexed value with its local context.
5
+ *
6
+ * The accessor must not inherit from another Borsh-decorated class, must be
7
+ * defined directly on `clazz.prototype`, have both a getter and setter, and be
8
+ * safe when invoked with the generated wrapper as `this`. In particular, it
9
+ * cannot depend on private fields, constructor-only state, or state stored in a
10
+ * WeakMap keyed by instances of `clazz`. The setter is invoked while Borsh
11
+ * deserializes persisted index rows.
12
+ */
13
+ export declare const registerIndexFieldAccessor: (clazz: Function, key: string, properties: SimpleField | CustomField<any>) => void;
1
14
  export declare const copySerialization: (sourceClazz: any, targetClazz: any) => void;
2
15
  //# sourceMappingURL=borsh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"borsh.d.ts","sourceRoot":"","sources":["../../src/borsh.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,GAAI,aAAa,GAAG,EAAE,aAAa,GAAG,SAgBnE,CAAC"}
1
+ {"version":3,"file":"borsh.d.ts","sourceRoot":"","sources":["../../src/borsh.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,WAAW,EAGhB,MAAM,gBAAgB,CAAC;AAQxB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,0BAA0B,GACtC,OAAO,QAAQ,EACf,KAAK,MAAM,EACX,YAAY,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,KACxC,IAqCF,CAAC;AA8CF,eAAO,MAAM,iBAAiB,GAAI,aAAa,GAAG,EAAE,aAAa,GAAG,SAsCnE,CAAC"}
package/dist/src/borsh.js CHANGED
@@ -1,16 +1,93 @@
1
- import { getSchema } from "@dao-xyz/borsh";
1
+ import { field, getSchema, } from "@dao-xyz/borsh";
2
+ const serializedFieldAccessors = new WeakMap();
3
+ const copiedSerializations = new WeakMap();
4
+ /**
5
+ * Register a Borsh field backed by an accessor and explicitly preserve that
6
+ * accessor when Documents wraps an indexed value with its local context.
7
+ *
8
+ * The accessor must not inherit from another Borsh-decorated class, must be
9
+ * defined directly on `clazz.prototype`, have both a getter and setter, and be
10
+ * safe when invoked with the generated wrapper as `this`. In particular, it
11
+ * cannot depend on private fields, constructor-only state, or state stored in a
12
+ * WeakMap keyed by instances of `clazz`. The setter is invoked while Borsh
13
+ * deserializes persisted index rows.
14
+ */
15
+ export const registerIndexFieldAccessor = (clazz, key, properties) => {
16
+ if (typeof key !== "string") {
17
+ throw new Error("Index field accessor keys must be strings");
18
+ }
19
+ const prototype = clazz.prototype;
20
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
21
+ if (!descriptor?.get || !descriptor.set) {
22
+ throw new Error(`Index field accessor '${key}' must define both a getter and setter`);
23
+ }
24
+ const registered = serializedFieldAccessors.get(prototype);
25
+ if (registered?.has(key)) {
26
+ return;
27
+ }
28
+ let parent = Object.getPrototypeOf(clazz);
29
+ while (parent && parent !== Function.prototype) {
30
+ if (getSchema(parent)) {
31
+ throw new Error("Index field accessors cannot inherit from a Borsh-decorated class");
32
+ }
33
+ parent = Object.getPrototypeOf(parent);
34
+ }
35
+ if (getSchema(clazz)?.fields.some((existing) => existing.key === key)) {
36
+ throw new Error(`Index field accessor '${key}' is already registered as a Borsh field`);
37
+ }
38
+ field(properties)(prototype, key);
39
+ serializedFieldAccessors.set(prototype, new Map([...(registered ?? []), [key, descriptor]]));
40
+ };
41
+ const getSerializedFieldAccessor = (sourceClazz, targetClazz, targetSchema, key) => {
42
+ const sourcePrototype = sourceClazz.prototype;
43
+ const registeredDescriptor = serializedFieldAccessors
44
+ .get(sourcePrototype)
45
+ ?.get(key);
46
+ if (!registeredDescriptor) {
47
+ return undefined;
48
+ }
49
+ if (targetSchema.fields.some((field) => field.key === key)) {
50
+ throw new Error(`Cannot preserve index field accessor '${key}': the wrapper schema already contains that field`);
51
+ }
52
+ if (Object.getOwnPropertyDescriptor(targetClazz.prototype, key)) {
53
+ throw new Error(`Cannot preserve index field accessor '${key}': the wrapper prototype already defines it`);
54
+ }
55
+ const descriptor = Object.getOwnPropertyDescriptor(sourcePrototype, key);
56
+ if (!descriptor?.get || !descriptor.set) {
57
+ throw new Error(`Registered index field accessor '${key}' must define both a getter and setter`);
58
+ }
59
+ if (descriptor.get !== registeredDescriptor.get ||
60
+ descriptor.set !== registeredDescriptor.set ||
61
+ descriptor.enumerable !== registeredDescriptor.enumerable ||
62
+ descriptor.configurable !== registeredDescriptor.configurable) {
63
+ throw new Error(`Registered index field accessor '${key}' changed after registration`);
64
+ }
65
+ return descriptor;
66
+ };
2
67
  export const copySerialization = (sourceClazz, targetClazz) => {
3
- const copiedFromAlready = targetClazz["__copiedFrom"] || [];
4
- if (copiedFromAlready?.includes(sourceClazz)) {
68
+ const copiedFromAlready = copiedSerializations.get(targetClazz);
69
+ if (copiedFromAlready?.has(sourceClazz)) {
5
70
  return;
6
71
  }
7
- copiedFromAlready.push(sourceClazz);
8
- targetClazz["__copiedFrom"] = copiedFromAlready;
9
72
  const targetSchema = getSchema(targetClazz);
10
73
  const sourceSchema = getSchema(sourceClazz);
74
+ const accessors = [];
75
+ for (const sourceField of sourceSchema.fields) {
76
+ const descriptor = getSerializedFieldAccessor(sourceClazz, targetClazz, targetSchema, sourceField.key);
77
+ if (descriptor) {
78
+ accessors.push([sourceField.key, descriptor]);
79
+ }
80
+ }
81
+ if (accessors.length > 0 && !Object.isExtensible(targetClazz.prototype)) {
82
+ throw new Error("Cannot preserve index field accessors: the wrapper prototype is not extensible");
83
+ }
84
+ for (const [key, descriptor] of accessors) {
85
+ Object.defineProperty(targetClazz.prototype, key, descriptor);
86
+ }
11
87
  targetSchema.fields = [...sourceSchema.fields, ...targetSchema.fields];
12
88
  targetSchema.variant = sourceSchema.variant;
13
89
  targetSchema.getDependencies =
14
90
  sourceSchema.getDependencies.bind(sourceSchema);
91
+ copiedSerializations.set(targetClazz, new Set([...(copiedFromAlready ?? []), sourceClazz]));
15
92
  };
16
93
  //# sourceMappingURL=borsh.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"borsh.js","sourceRoot":"","sources":["../../src/borsh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAgB,EAAE,WAAgB,EAAE,EAAE;IACvE,MAAM,iBAAiB,GAAU,WAAW,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IACnE,IAAI,iBAAiB,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9C,OAAO;IACR,CAAC;IAED,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACpC,WAAW,CAAC,cAAc,CAAC,GAAG,iBAAiB,CAAC;IAEhD,MAAM,YAAY,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IAE5C,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACvE,YAAY,CAAC,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;IAC5C,YAAY,CAAC,eAAe;QAC3B,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAClD,CAAC,CAAC"}
1
+ {"version":3,"file":"borsh.js","sourceRoot":"","sources":["../../src/borsh.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ export { coerceWithContext, coerceWithIndexed } from "./search.js";
6
6
  export * from "./operation.js";
7
7
  export { policy } from "./policy.js";
8
8
  export { transform } from "./transform.js";
9
+ export { registerIndexFieldAccessor } from "./borsh.js";
9
10
  export { MAX_BATCH_SIZE as MAX_DOCUMENT_SIZE } from "./constants.js";
10
11
  export { ClosedError } from "@peerbit/program";
11
12
  export { type CustomDocumentDomain, createDocumentDomain, createDocumentDomainFromProperty, } from "./domain.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,cAAc,CAAC;AAC7B,YAAY,EACX,OAAO,EACP,SAAS,EACT,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,oBAAoB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACN,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,gCAAgC,GAChC,MAAM,aAAa,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,YAAY,EACX,aAAa,EACb,yBAAyB,EACzB,kBAAkB,EAClB,kBAAkB,EAClB,2BAA2B,GAC3B,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,cAAc,CAAC;AAC7B,YAAY,EACX,OAAO,EACP,SAAS,EACT,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,oBAAoB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACN,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,gCAAgC,GAChC,MAAM,aAAa,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,YAAY,EACX,aAAa,EACb,yBAAyB,EACzB,kBAAkB,EAClB,kBAAkB,EAClB,2BAA2B,GAC3B,MAAM,WAAW,CAAC"}
package/dist/src/index.js CHANGED
@@ -5,6 +5,7 @@ export { coerceWithContext, coerceWithIndexed } from "./search.js";
5
5
  export * from "./operation.js";
6
6
  export { policy } from "./policy.js";
7
7
  export { transform } from "./transform.js";
8
+ export { registerIndexFieldAccessor } from "./borsh.js";
8
9
  export { MAX_BATCH_SIZE as MAX_DOCUMENT_SIZE } from "./constants.js";
9
10
  export { ClosedError } from "@peerbit/program";
10
11
  export { createDocumentDomain, createDocumentDomainFromProperty, } from "./domain.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,cAAc,CAAC;AA+B7B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAEN,oBAAoB,EACpB,gCAAgC,GAChC,MAAM,aAAa,CAAC;AACrB,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,cAAc,CAAC;AA+B7B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAEN,oBAAoB,EACpB,gCAAgC,GAChC,MAAM,aAAa,CAAC;AACrB,cAAc,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/document",
3
- "version": "13.1.19",
3
+ "version": "13.1.20",
4
4
  "description": "Document store implementation",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -59,21 +59,21 @@
59
59
  "@multiformats/multiaddr": "^13.0.1",
60
60
  "p-defer": "^4.0.0",
61
61
  "uint8arrays": "^5.1.0",
62
- "@peerbit/crypto": "3.1.4",
63
- "@peerbit/document-interface": "3.2.54",
64
62
  "@peerbit/cache": "3.1.1",
65
- "@peerbit/indexer-interface": "3.0.8",
63
+ "@peerbit/crypto": "3.1.4",
66
64
  "@peerbit/indexer-cache": "0.2.11",
65
+ "@peerbit/indexer-interface": "3.0.8",
66
+ "@peerbit/document-interface": "3.2.54",
67
67
  "@peerbit/indexer-simple": "1.2.12",
68
68
  "@peerbit/indexer-sqlite3": "3.0.11",
69
69
  "@peerbit/log": "6.2.11",
70
70
  "@peerbit/logger": "2.0.1",
71
- "@peerbit/program": "6.0.42",
72
71
  "@peerbit/pubsub": "5.3.7",
73
72
  "@peerbit/rpc": "6.1.10",
73
+ "@peerbit/program": "6.0.42",
74
74
  "@peerbit/shared-log": "13.2.18",
75
- "@peerbit/stream-interface": "6.0.14",
76
- "@peerbit/time": "3.0.1"
75
+ "@peerbit/time": "3.0.1",
76
+ "@peerbit/stream-interface": "6.0.14"
77
77
  },
78
78
  "optionalDependencies": {
79
79
  "@peerbit/document-rust": "0.1.1"
@@ -86,8 +86,8 @@
86
86
  "uuid": "^11.1.1",
87
87
  "@peerbit/log-rust": "1.1.2",
88
88
  "@peerbit/native-backbone": "0.2.4",
89
- "@peerbit/test-utils": "3.1.14",
90
- "peerbit": "5.3.14"
89
+ "peerbit": "5.3.14",
90
+ "@peerbit/test-utils": "3.1.14"
91
91
  },
92
92
  "repository": {
93
93
  "type": "git",
package/src/borsh.ts CHANGED
@@ -1,19 +1,150 @@
1
- import { getSchema } from "@dao-xyz/borsh";
1
+ import {
2
+ type CustomField,
3
+ type SimpleField,
4
+ field,
5
+ getSchema,
6
+ } from "@dao-xyz/borsh";
2
7
 
3
- export const copySerialization = (sourceClazz: any, targetClazz: any) => {
4
- const copiedFromAlready: any[] = targetClazz["__copiedFrom"] || [];
5
- if (copiedFromAlready?.includes(sourceClazz)) {
8
+ const serializedFieldAccessors = new WeakMap<
9
+ object,
10
+ ReadonlyMap<string, PropertyDescriptor>
11
+ >();
12
+ const copiedSerializations = new WeakMap<Function, ReadonlySet<Function>>();
13
+
14
+ /**
15
+ * Register a Borsh field backed by an accessor and explicitly preserve that
16
+ * accessor when Documents wraps an indexed value with its local context.
17
+ *
18
+ * The accessor must not inherit from another Borsh-decorated class, must be
19
+ * defined directly on `clazz.prototype`, have both a getter and setter, and be
20
+ * safe when invoked with the generated wrapper as `this`. In particular, it
21
+ * cannot depend on private fields, constructor-only state, or state stored in a
22
+ * WeakMap keyed by instances of `clazz`. The setter is invoked while Borsh
23
+ * deserializes persisted index rows.
24
+ */
25
+ export const registerIndexFieldAccessor = (
26
+ clazz: Function,
27
+ key: string,
28
+ properties: SimpleField | CustomField<any>,
29
+ ): void => {
30
+ if (typeof key !== "string") {
31
+ throw new Error("Index field accessor keys must be strings");
32
+ }
33
+
34
+ const prototype = clazz.prototype;
35
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
36
+ if (!descriptor?.get || !descriptor.set) {
37
+ throw new Error(
38
+ `Index field accessor '${key}' must define both a getter and setter`,
39
+ );
40
+ }
41
+
42
+ const registered = serializedFieldAccessors.get(prototype);
43
+ if (registered?.has(key)) {
6
44
  return;
7
45
  }
46
+ let parent = Object.getPrototypeOf(clazz);
47
+ while (parent && parent !== Function.prototype) {
48
+ if (getSchema(parent)) {
49
+ throw new Error(
50
+ "Index field accessors cannot inherit from a Borsh-decorated class",
51
+ );
52
+ }
53
+ parent = Object.getPrototypeOf(parent);
54
+ }
55
+ if (getSchema(clazz)?.fields.some((existing) => existing.key === key)) {
56
+ throw new Error(
57
+ `Index field accessor '${key}' is already registered as a Borsh field`,
58
+ );
59
+ }
60
+
61
+ (field(properties) as unknown as PropertyDecorator)(prototype, key);
62
+ serializedFieldAccessors.set(
63
+ prototype,
64
+ new Map([...(registered ?? []), [key, descriptor]]),
65
+ );
66
+ };
67
+
68
+ const getSerializedFieldAccessor = (
69
+ sourceClazz: any,
70
+ targetClazz: any,
71
+ targetSchema: ReturnType<typeof getSchema>,
72
+ key: string,
73
+ ): PropertyDescriptor | undefined => {
74
+ const sourcePrototype = sourceClazz.prototype;
75
+ const registeredDescriptor = serializedFieldAccessors
76
+ .get(sourcePrototype)
77
+ ?.get(key);
78
+ if (!registeredDescriptor) {
79
+ return undefined;
80
+ }
81
+
82
+ if (targetSchema.fields.some((field) => field.key === key)) {
83
+ throw new Error(
84
+ `Cannot preserve index field accessor '${key}': the wrapper schema already contains that field`,
85
+ );
86
+ }
87
+ if (Object.getOwnPropertyDescriptor(targetClazz.prototype, key)) {
88
+ throw new Error(
89
+ `Cannot preserve index field accessor '${key}': the wrapper prototype already defines it`,
90
+ );
91
+ }
8
92
 
9
- copiedFromAlready.push(sourceClazz);
10
- targetClazz["__copiedFrom"] = copiedFromAlready;
93
+ const descriptor = Object.getOwnPropertyDescriptor(sourcePrototype, key);
94
+ if (!descriptor?.get || !descriptor.set) {
95
+ throw new Error(
96
+ `Registered index field accessor '${key}' must define both a getter and setter`,
97
+ );
98
+ }
99
+ if (
100
+ descriptor.get !== registeredDescriptor.get ||
101
+ descriptor.set !== registeredDescriptor.set ||
102
+ descriptor.enumerable !== registeredDescriptor.enumerable ||
103
+ descriptor.configurable !== registeredDescriptor.configurable
104
+ ) {
105
+ throw new Error(
106
+ `Registered index field accessor '${key}' changed after registration`,
107
+ );
108
+ }
109
+ return descriptor;
110
+ };
111
+
112
+ export const copySerialization = (sourceClazz: any, targetClazz: any) => {
113
+ const copiedFromAlready = copiedSerializations.get(targetClazz);
114
+ if (copiedFromAlready?.has(sourceClazz)) {
115
+ return;
116
+ }
11
117
 
12
118
  const targetSchema = getSchema(targetClazz);
13
119
  const sourceSchema = getSchema(sourceClazz);
120
+ const accessors: Array<[string, PropertyDescriptor]> = [];
121
+ for (const sourceField of sourceSchema.fields) {
122
+ const descriptor = getSerializedFieldAccessor(
123
+ sourceClazz,
124
+ targetClazz,
125
+ targetSchema,
126
+ sourceField.key,
127
+ );
128
+ if (descriptor) {
129
+ accessors.push([sourceField.key, descriptor]);
130
+ }
131
+ }
132
+ if (accessors.length > 0 && !Object.isExtensible(targetClazz.prototype)) {
133
+ throw new Error(
134
+ "Cannot preserve index field accessors: the wrapper prototype is not extensible",
135
+ );
136
+ }
137
+
138
+ for (const [key, descriptor] of accessors) {
139
+ Object.defineProperty(targetClazz.prototype, key, descriptor);
140
+ }
14
141
 
15
142
  targetSchema.fields = [...sourceSchema.fields, ...targetSchema.fields];
16
143
  targetSchema.variant = sourceSchema.variant;
17
144
  targetSchema.getDependencies =
18
145
  sourceSchema.getDependencies.bind(sourceSchema);
146
+ copiedSerializations.set(
147
+ targetClazz,
148
+ new Set([...(copiedFromAlready ?? []), sourceClazz]),
149
+ );
19
150
  };
package/src/index.ts CHANGED
@@ -35,6 +35,7 @@ export { coerceWithContext, coerceWithIndexed } from "./search.js";
35
35
  export * from "./operation.js";
36
36
  export { policy } from "./policy.js";
37
37
  export { transform } from "./transform.js";
38
+ export { registerIndexFieldAccessor } from "./borsh.js";
38
39
  export { MAX_BATCH_SIZE as MAX_DOCUMENT_SIZE } from "./constants.js";
39
40
  export { ClosedError } from "@peerbit/program";
40
41
  export {