@comapeo/core 1.0.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.
Files changed (186) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +31 -0
  3. package/dist/blob-api.d.ts +92 -0
  4. package/dist/blob-api.d.ts.map +1 -0
  5. package/dist/blob-store/index.d.ts +163 -0
  6. package/dist/blob-store/index.d.ts.map +1 -0
  7. package/dist/blob-store/live-download.d.ts +107 -0
  8. package/dist/blob-store/live-download.d.ts.map +1 -0
  9. package/dist/config-import.d.ts +74 -0
  10. package/dist/config-import.d.ts.map +1 -0
  11. package/dist/constants.d.ts +14 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/core-manager/bitfield-rle.d.ts +25 -0
  14. package/dist/core-manager/bitfield-rle.d.ts.map +1 -0
  15. package/dist/core-manager/core-index.d.ts +56 -0
  16. package/dist/core-manager/core-index.d.ts.map +1 -0
  17. package/dist/core-manager/index.d.ts +125 -0
  18. package/dist/core-manager/index.d.ts.map +1 -0
  19. package/dist/core-manager/random-access-file-pool.d.ts +17 -0
  20. package/dist/core-manager/random-access-file-pool.d.ts.map +1 -0
  21. package/dist/core-manager/remote-bitfield.d.ts +146 -0
  22. package/dist/core-manager/remote-bitfield.d.ts.map +1 -0
  23. package/dist/core-ownership.d.ts +112 -0
  24. package/dist/core-ownership.d.ts.map +1 -0
  25. package/dist/datastore/index.d.ts +91 -0
  26. package/dist/datastore/index.d.ts.map +1 -0
  27. package/dist/datatype/index.d.ts +108 -0
  28. package/dist/discovery/local-discovery.d.ts +64 -0
  29. package/dist/discovery/local-discovery.d.ts.map +1 -0
  30. package/dist/errors.d.ts +4 -0
  31. package/dist/errors.d.ts.map +1 -0
  32. package/dist/fastify-controller.d.ts +27 -0
  33. package/dist/fastify-controller.d.ts.map +1 -0
  34. package/dist/fastify-plugins/blobs.d.ts +6 -0
  35. package/dist/fastify-plugins/blobs.d.ts.map +1 -0
  36. package/dist/fastify-plugins/constants.d.ts +3 -0
  37. package/dist/fastify-plugins/constants.d.ts.map +1 -0
  38. package/dist/fastify-plugins/icons.d.ts +6 -0
  39. package/dist/fastify-plugins/icons.d.ts.map +1 -0
  40. package/dist/fastify-plugins/maps/index.d.ts +11 -0
  41. package/dist/fastify-plugins/maps/index.d.ts.map +1 -0
  42. package/dist/fastify-plugins/maps/offline-fallback-map.d.ts +12 -0
  43. package/dist/fastify-plugins/maps/offline-fallback-map.d.ts.map +1 -0
  44. package/dist/fastify-plugins/maps/static-maps.d.ts +11 -0
  45. package/dist/fastify-plugins/maps/static-maps.d.ts.map +1 -0
  46. package/dist/fastify-plugins/utils.d.ts +23 -0
  47. package/dist/fastify-plugins/utils.d.ts.map +1 -0
  48. package/dist/generated/extensions.d.ts +44 -0
  49. package/dist/generated/extensions.d.ts.map +1 -0
  50. package/dist/generated/keys.d.ts +36 -0
  51. package/dist/generated/keys.d.ts.map +1 -0
  52. package/dist/generated/rpc.d.ts +87 -0
  53. package/dist/generated/rpc.d.ts.map +1 -0
  54. package/dist/icon-api.d.ts +109 -0
  55. package/dist/icon-api.d.ts.map +1 -0
  56. package/dist/index-writer/index.d.ts +51 -0
  57. package/dist/index-writer/index.d.ts.map +1 -0
  58. package/dist/index.d.ts +14 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/invite-api.d.ts +70 -0
  61. package/dist/invite-api.d.ts.map +1 -0
  62. package/dist/lib/hashmap.d.ts +62 -0
  63. package/dist/lib/hashmap.d.ts.map +1 -0
  64. package/dist/lib/hypercore-helpers.d.ts +6 -0
  65. package/dist/lib/hypercore-helpers.d.ts.map +1 -0
  66. package/dist/lib/noise-secret-stream-helpers.d.ts +45 -0
  67. package/dist/lib/noise-secret-stream-helpers.d.ts.map +1 -0
  68. package/dist/lib/ponyfills.d.ts +10 -0
  69. package/dist/lib/ponyfills.d.ts.map +1 -0
  70. package/dist/lib/string.d.ts +2 -0
  71. package/dist/lib/string.d.ts.map +1 -0
  72. package/dist/lib/timing-safe-equal.d.ts +15 -0
  73. package/dist/lib/timing-safe-equal.d.ts.map +1 -0
  74. package/dist/local-peers.d.ts +151 -0
  75. package/dist/local-peers.d.ts.map +1 -0
  76. package/dist/logger.d.ts +32 -0
  77. package/dist/logger.d.ts.map +1 -0
  78. package/dist/mapeo-manager.d.ts +178 -0
  79. package/dist/mapeo-manager.d.ts.map +1 -0
  80. package/dist/mapeo-project.d.ts +3233 -0
  81. package/dist/mapeo-project.d.ts.map +1 -0
  82. package/dist/member-api.d.ts +114 -0
  83. package/dist/member-api.d.ts.map +1 -0
  84. package/dist/roles.d.ts +157 -0
  85. package/dist/roles.d.ts.map +1 -0
  86. package/dist/schema/client.d.ts +284 -0
  87. package/dist/schema/client.d.ts.map +1 -0
  88. package/dist/schema/project.d.ts +1812 -0
  89. package/dist/schema/project.d.ts.map +1 -0
  90. package/dist/schema/schema-to-drizzle.d.ts +20 -0
  91. package/dist/schema/schema-to-drizzle.d.ts.map +1 -0
  92. package/dist/schema/types.d.ts +98 -0
  93. package/dist/schema/types.d.ts.map +1 -0
  94. package/dist/schema/utils.d.ts +55 -0
  95. package/dist/schema/utils.d.ts.map +1 -0
  96. package/dist/sync/core-sync-state.d.ts +252 -0
  97. package/dist/sync/core-sync-state.d.ts.map +1 -0
  98. package/dist/sync/namespace-sync-state.d.ts +47 -0
  99. package/dist/sync/namespace-sync-state.d.ts.map +1 -0
  100. package/dist/sync/peer-sync-controller.d.ts +44 -0
  101. package/dist/sync/peer-sync-controller.d.ts.map +1 -0
  102. package/dist/sync/sync-api.d.ts +158 -0
  103. package/dist/sync/sync-api.d.ts.map +1 -0
  104. package/dist/sync/sync-state.d.ts +40 -0
  105. package/dist/sync/sync-state.d.ts.map +1 -0
  106. package/dist/translation-api.d.ts +288 -0
  107. package/dist/translation-api.d.ts.map +1 -0
  108. package/dist/types.d.ts +115 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/utils.d.ts +115 -0
  111. package/dist/utils.d.ts.map +1 -0
  112. package/dist/utils_types.d.ts +14 -0
  113. package/drizzle/client/0000_bumpy_carnage.sql +33 -0
  114. package/drizzle/client/meta/0000_snapshot.json +199 -0
  115. package/drizzle/client/meta/_journal.json +13 -0
  116. package/drizzle/project/0000_spooky_lady_ursula.sql +192 -0
  117. package/drizzle/project/meta/0000_snapshot.json +1137 -0
  118. package/drizzle/project/meta/_journal.json +13 -0
  119. package/package.json +202 -0
  120. package/src/blob-api.js +139 -0
  121. package/src/blob-store/index.js +325 -0
  122. package/src/blob-store/live-download.js +373 -0
  123. package/src/config-import.js +604 -0
  124. package/src/constants.js +34 -0
  125. package/src/core-manager/bitfield-rle.js +235 -0
  126. package/src/core-manager/core-index.js +87 -0
  127. package/src/core-manager/index.js +504 -0
  128. package/src/core-manager/random-access-file-pool.js +30 -0
  129. package/src/core-manager/remote-bitfield.js +416 -0
  130. package/src/core-ownership.js +235 -0
  131. package/src/datastore/README.md +46 -0
  132. package/src/datastore/index.js +234 -0
  133. package/src/datatype/README.md +33 -0
  134. package/src/datatype/index.d.ts +108 -0
  135. package/src/datatype/index.js +358 -0
  136. package/src/discovery/local-discovery.js +303 -0
  137. package/src/errors.js +5 -0
  138. package/src/fastify-controller.js +84 -0
  139. package/src/fastify-plugins/blobs.js +139 -0
  140. package/src/fastify-plugins/constants.js +5 -0
  141. package/src/fastify-plugins/icons.js +158 -0
  142. package/src/fastify-plugins/maps/index.js +173 -0
  143. package/src/fastify-plugins/maps/offline-fallback-map.js +114 -0
  144. package/src/fastify-plugins/maps/static-maps.js +271 -0
  145. package/src/fastify-plugins/utils.js +52 -0
  146. package/src/generated/README.md +3 -0
  147. package/src/generated/extensions.d.ts +44 -0
  148. package/src/generated/extensions.js +196 -0
  149. package/src/generated/extensions.ts +237 -0
  150. package/src/generated/keys.d.ts +36 -0
  151. package/src/generated/keys.js +148 -0
  152. package/src/generated/keys.ts +185 -0
  153. package/src/generated/rpc.d.ts +87 -0
  154. package/src/generated/rpc.js +389 -0
  155. package/src/generated/rpc.ts +463 -0
  156. package/src/icon-api.js +282 -0
  157. package/src/index-writer/README.md +38 -0
  158. package/src/index-writer/index.js +124 -0
  159. package/src/index.js +16 -0
  160. package/src/invite-api.js +450 -0
  161. package/src/lib/hashmap.js +91 -0
  162. package/src/lib/hypercore-helpers.js +18 -0
  163. package/src/lib/noise-secret-stream-helpers.js +37 -0
  164. package/src/lib/ponyfills.js +25 -0
  165. package/src/lib/string.js +7 -0
  166. package/src/lib/timing-safe-equal.js +34 -0
  167. package/src/local-peers.js +737 -0
  168. package/src/logger.js +99 -0
  169. package/src/mapeo-manager.js +914 -0
  170. package/src/mapeo-project.js +980 -0
  171. package/src/member-api.js +319 -0
  172. package/src/roles.js +412 -0
  173. package/src/schema/client.js +55 -0
  174. package/src/schema/project.js +44 -0
  175. package/src/schema/schema-to-drizzle.js +118 -0
  176. package/src/schema/types.ts +153 -0
  177. package/src/schema/utils.js +51 -0
  178. package/src/sync/core-sync-state.js +440 -0
  179. package/src/sync/namespace-sync-state.js +193 -0
  180. package/src/sync/peer-sync-controller.js +332 -0
  181. package/src/sync/sync-api.js +588 -0
  182. package/src/sync/sync-state.js +63 -0
  183. package/src/translation-api.js +141 -0
  184. package/src/types.ts +149 -0
  185. package/src/utils.js +210 -0
  186. package/src/utils_types.d.ts +14 -0
@@ -0,0 +1,125 @@
1
+ export const kCoreManagerReplicate: unique symbol;
2
+ /** @typedef {Hypercore<'binary', Buffer>} Core */
3
+ /** @typedef {{ core: Core, key: Buffer, namespace: Namespace }} CoreRecord */
4
+ /**
5
+ * @typedef {Object} Events
6
+ * @property {(coreRecord: CoreRecord) => void} add-core
7
+ * @property {(namespace: Namespace, msg: { coreDiscoveryId: string, peerId: string, start: number, bitfield: Uint32Array }) => void} peer-have
8
+ */
9
+ /**
10
+ * @extends {TypedEmitter<Events>}
11
+ */
12
+ export class CoreManager extends TypedEmitter<Events> {
13
+ static get namespaces(): readonly ["auth", "config", "data", "blobIndex", "blob"];
14
+ /**
15
+ * @param {Object} options
16
+ * @param {import('drizzle-orm/better-sqlite3').BetterSQLite3Database} options.db Drizzle better-sqlite3 database instance
17
+ * @param {import('@mapeo/crypto').KeyManager} options.keyManager mapeo/crypto KeyManager instance
18
+ * @param {Buffer} options.projectKey 32-byte public key of the project creator core
19
+ * @param {Buffer} [options.projectSecretKey] 32-byte secret key of the project creator core
20
+ * @param {Partial<Record<Namespace, Buffer>>} [options.encryptionKeys] Encryption keys for each namespace
21
+ * @param {import('hypercore').HypercoreStorage} options.storage Folder to store all hypercore data
22
+ * @param {boolean} [options.autoDownload=true] Immediately start downloading cores - should only be set to false for tests
23
+ * @param {Logger} [options.logger]
24
+ */
25
+ constructor({ db, keyManager, projectKey, projectSecretKey, encryptionKeys, storage, autoDownload, logger, }: {
26
+ db: import("drizzle-orm/better-sqlite3").BetterSQLite3Database;
27
+ keyManager: import("@mapeo/crypto/dist/key-manager.js");
28
+ projectKey: Buffer;
29
+ projectSecretKey?: Buffer | undefined;
30
+ encryptionKeys?: Partial<Record<"blob" | "auth" | "config" | "data" | "blobIndex", Buffer>> | undefined;
31
+ storage: import("hypercore").HypercoreStorage;
32
+ autoDownload?: boolean | undefined;
33
+ logger?: Logger | undefined;
34
+ });
35
+ get deviceId(): string;
36
+ get creatorCore(): Core;
37
+ /**
38
+ * Resolves when all cores have finished loading
39
+ *
40
+ * @returns {Promise<void>}
41
+ */
42
+ ready(): Promise<void>;
43
+ /**
44
+ * Get the writer core for the given namespace
45
+ *
46
+ * @param {Namespace} namespace
47
+ */
48
+ getWriterCore(namespace: Namespace): CoreRecord;
49
+ /**
50
+ * Get an array of all cores in the given namespace
51
+ *
52
+ * @param {Namespace} namespace
53
+ */
54
+ getCores(namespace: Namespace): CoreRecord[];
55
+ /**
56
+ * Get a core by its public key
57
+ *
58
+ * @param {Buffer} key
59
+ * @returns {Core | undefined}
60
+ */
61
+ getCoreByKey(key: Buffer): Core | undefined;
62
+ /**
63
+ * Get a core by its discovery key
64
+ *
65
+ * @param {Buffer} discoveryKey
66
+ * @returns {CoreRecord | undefined}
67
+ */
68
+ getCoreByDiscoveryKey(discoveryKey: Buffer): CoreRecord | undefined;
69
+ /**
70
+ * Close all open cores and end any replication streams
71
+ * TODO: gracefully close replication streams
72
+ */
73
+ close(): Promise<void>;
74
+ /**
75
+ * Add a core to the manager (will be persisted across restarts)
76
+ *
77
+ * @param {Buffer} key 32-byte public key of core to add
78
+ * @param {Namespace} namespace
79
+ * @returns {CoreRecord}
80
+ */
81
+ addCore(key: Buffer, namespace: Namespace): CoreRecord;
82
+ /**
83
+ * @param {Exclude<Namespace, 'auth'>} namespace
84
+ * @returns {Promise<void>}
85
+ */
86
+ deleteOthersData(namespace: Exclude<Namespace, "auth">): Promise<void>;
87
+ /**
88
+ * ONLY FOR TESTING
89
+ * Replicate all cores in core manager
90
+ *
91
+ * NB: Remote peers need to be manually added when unit testing core manager
92
+ * without the Sync API
93
+ *
94
+ * @param {Parameters<Corestore['replicate']>[0]} stream
95
+ */
96
+ [kCoreManagerReplicate](stream: Parameters<Corestore["replicate"]>[0]): ReplicationStream;
97
+ #private;
98
+ }
99
+ export type Core = Hypercore<"binary", Buffer>;
100
+ export type CoreRecord = {
101
+ core: Core;
102
+ key: Buffer;
103
+ namespace: Namespace;
104
+ };
105
+ export type Events = {
106
+ "add-core": (coreRecord: CoreRecord) => void;
107
+ "peer-have": (namespace: Namespace, msg: {
108
+ coreDiscoveryId: string;
109
+ peerId: string;
110
+ start: number;
111
+ bitfield: Uint32Array;
112
+ }) => void;
113
+ };
114
+ export type HaveMsg = {
115
+ discoveryKey: Buffer;
116
+ start: number;
117
+ bitfield: Uint32Array;
118
+ namespace: Namespace;
119
+ };
120
+ import { TypedEmitter } from 'tiny-typed-emitter';
121
+ import type { Namespace } from '../types.js';
122
+ import Corestore from 'corestore';
123
+ import { Logger } from '../logger.js';
124
+ import type Hypercore from 'hypercore';
125
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core-manager/index.js"],"names":[],"mappings":"AAmBA,kDAAqE;AAErE,kDAAkD;AAClD,8EAA8E;AAC9E;;;;GAIG;AAEH;;GAEG;AACH;IAiBE,kFAEC;IAED;;;;;;;;;;OAUG;IACH,8GATG;QAA4E,EAAE,EAAtE,OAAO,4BAA4B,EAAE,qBAAqB;QACd,UAAU,EAAtD,2CAAkC;QAClB,UAAU,EAA1B,MAAM;QACW,gBAAgB;QACY,cAAc;QACb,OAAO,EAArD,OAAO,WAAW,EAAE,gBAAgB;QAClB,YAAY;QACb,MAAM;KAAC,EAgHlC;IAED,uBAEC;IAED,wBAEC;IAED;;;;OAIG;IACH,SAFa,OAAO,CAAC,IAAI,CAAC,CAIzB;IAED;;;;OAIG;IACH,yBAFW,SAAS,cAInB;IAED;;;;OAIG;IACH,oBAFW,SAAS,gBAInB;IAED;;;;;OAKG;IACH,kBAHW,MAAM,GACJ,IAAI,GAAG,SAAS,CAK5B;IAED;;;;;OAKG;IACH,oCAHW,MAAM,GACJ,UAAU,GAAG,SAAS,CAOlC;IAED;;;OAGG;IACH,uBAQC;IAED;;;;;;OAMG;IACH,aAJW,MAAM,aACN,SAAS,GACP,UAAU,CAKtB;IAqLD;;;OAGG;IACH,4BAHW,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,GACxB,OAAO,CAAC,IAAI,CAAC,CAgBzB;IAhCD;;;;;;;;OAQG;IACH,gCAFW,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,qBAK/C;;CAqBF;mBAtba,UAAU,QAAQ,EAAE,MAAM,CAAC;yBAC3B;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE;;gBAGjD,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI;iBAChC,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI;;;kBAqbtH,MAAM;WACN,MAAM;cACN,WAAW;eACX,SAAS;;6BAldM,oBAAoB;+BAeH,aAAa;sBAdrC,WAAW;uBAMV,cAAc;2BAOV,WAAW"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * File descriptor pool for random-access-storage to limit the number of file
3
+ * descriptors used. Important particularly for Android where the hard limit for
4
+ * the app is 1024.
5
+ */
6
+ export class RandomAccessFilePool {
7
+ /** @param {number} maxSize max number of file descriptors to use */
8
+ constructor(maxSize: number);
9
+ maxSize: number;
10
+ /** @type {Set<import('random-access-file')>} */
11
+ active: Set<import("random-access-file")>;
12
+ /** @param {import('random-access-file')} file */
13
+ _onactive(file: import("random-access-file")): void;
14
+ /** @param {import('random-access-file')} file */
15
+ _oninactive(file: import("random-access-file")): void;
16
+ }
17
+ //# sourceMappingURL=random-access-file-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"random-access-file-pool.d.ts","sourceRoot":"","sources":["../../src/core-manager/random-access-file-pool.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;IACE,oEAAoE;IACpE,qBADY,MAAM,EAKjB;IAHC,gBAAsB;IACtB,gDAAgD;IAChD,QADW,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,CACrB;IAGzB,iDAAiD;IACjD,gBADY,OAAO,oBAAoB,CAAC,QAUvC;IAED,iDAAiD;IACjD,kBADY,OAAO,oBAAoB,CAAC,QAGvC;CACF"}
@@ -0,0 +1,146 @@
1
+ export const BITS_PER_PAGE: 32768;
2
+ export default class RemoteBitfield {
3
+ /** @type {BigSparseArray<RemoteBitfieldPage>} */
4
+ _pages: BigSparseArray<RemoteBitfieldPage>;
5
+ /** @type {BigSparseArray<RemoteBitfieldSegment>} */
6
+ _segments: BigSparseArray<RemoteBitfieldSegment>;
7
+ _maxSegments: number;
8
+ /**
9
+ * @param {number} index
10
+ */
11
+ get(index: number): boolean;
12
+ /**
13
+ * @param {number} index
14
+ */
15
+ getBitfield(index: number): RemoteBitfieldPage | null;
16
+ /**
17
+ * @param {number} index
18
+ * @param {boolean} val
19
+ */
20
+ set(index: number, val: boolean): void;
21
+ /**
22
+ * @param {number} start
23
+ * @param {number} length
24
+ * @param {boolean} val
25
+ */
26
+ setRange(start: number, length: number, val: boolean): void;
27
+ /**
28
+ * @param {boolean} val
29
+ * @param {number} position
30
+ */
31
+ findFirst(val: boolean, position: number): number;
32
+ /**
33
+ * @param {number} position
34
+ */
35
+ firstSet(position: number): number;
36
+ /**
37
+ * @param {number} position
38
+ */
39
+ firstUnset(position: number): number;
40
+ /**
41
+ * @param {boolean} val
42
+ * @param {number} position
43
+ */
44
+ findLast(val: boolean, position: number): number;
45
+ /**
46
+ * @param {number} position
47
+ */
48
+ lastSet(position: number): number;
49
+ /**
50
+ * @param {number} position
51
+ */
52
+ lastUnset(position: number): number;
53
+ /**
54
+ * @param {number} start
55
+ * @param {Uint32Array} bitfield
56
+ * @returns {boolean}
57
+ */
58
+ insert(start: number, bitfield: Uint32Array): boolean;
59
+ }
60
+ import BigSparseArray from 'big-sparse-array';
61
+ declare class RemoteBitfieldPage {
62
+ /**
63
+ *
64
+ * @param {number} index
65
+ * @param {Uint32Array} bitfield
66
+ * @param {RemoteBitfieldSegment} segment
67
+ */
68
+ constructor(index: number, bitfield: Uint32Array, segment: RemoteBitfieldSegment);
69
+ /** @type {typeof index} */
70
+ index: number;
71
+ /** @type {number} */
72
+ offset: number;
73
+ /** @type {typeof bitfield} */
74
+ bitfield: Uint32Array;
75
+ /** @type {typeof segment} */
76
+ segment: RemoteBitfieldSegment;
77
+ get tree(): quickbit.SparseIndex;
78
+ /**
79
+ *
80
+ * @param {number} index
81
+ * @returns {boolean}
82
+ */
83
+ get(index: number): boolean;
84
+ /**
85
+ *
86
+ * @param {number} index
87
+ * @param {boolean} val
88
+ */
89
+ set(index: number, val: boolean): void;
90
+ /**
91
+ *
92
+ * @param {number} start
93
+ * @param {number} length
94
+ * @param {boolean} val
95
+ */
96
+ setRange(start: number, length: number, val: boolean): void;
97
+ /**
98
+ *
99
+ * @param {boolean} val
100
+ * @param {number} position
101
+ */
102
+ findFirst(val: boolean, position: number): number;
103
+ /**
104
+ * @param {boolean} val
105
+ * @param {number} position
106
+ */
107
+ findLast(val: boolean, position: number): number;
108
+ /**
109
+ *
110
+ * @param {number} start
111
+ * @param {Uint32Array} bitfield
112
+ */
113
+ insert(start: number, bitfield: Uint32Array): void;
114
+ }
115
+ declare class RemoteBitfieldSegment {
116
+ /**
117
+ *
118
+ * @param {number} index
119
+ */
120
+ constructor(index: number);
121
+ index: number;
122
+ offset: number;
123
+ tree: quickbit.SparseIndex;
124
+ pages: any[];
125
+ pagesLength: number;
126
+ get chunks(): quickbit.Chunk[];
127
+ refresh(): void;
128
+ /**
129
+ * @param {RemoteBitfieldPage} page
130
+ */
131
+ add(page: RemoteBitfieldPage): void;
132
+ /**
133
+ *
134
+ * @param {boolean} val
135
+ * @param {number} position
136
+ */
137
+ findFirst(val: boolean, position: number): number;
138
+ /**
139
+ * @param {boolean} val
140
+ * @param {number} position
141
+ */
142
+ findLast(val: boolean, position: number): number;
143
+ }
144
+ import quickbit from 'quickbit-universal';
145
+ export {};
146
+ //# sourceMappingURL=remote-bitfield.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-bitfield.d.ts","sourceRoot":"","sources":["../../src/core-manager/remote-bitfield.js"],"names":[],"mappings":"AAOA,kCAAkC;AAsMlC;IAEI,iDAAiD;IACjD,QADW,cAAc,CAAC,kBAAkB,CAAC,CACX;IAClC,oDAAoD;IACpD,WADW,cAAc,CAAC,qBAAqB,CAAC,CACX;IACrC,qBAAqB;IAGvB;;OAEG;IACH,WAFW,MAAM,WAShB;IAED;;OAEG;IACH,mBAFW,MAAM,6BAQhB;IAED;;;OAGG;IACH,WAHW,MAAM,OACN,OAAO,QAsBjB;IAED;;;;OAIG;IACH,gBAJW,MAAM,UACN,MAAM,OACN,OAAO,QA+BjB;IAED;;;OAGG;IACH,eAHW,OAAO,YACP,MAAM,UAqBhB;IACD;;OAEG;IACH,mBAFW,MAAM,UAIhB;IACD;;OAEG;IACH,qBAFW,MAAM,UAIhB;IACD;;;OAGG;IACH,cAHW,OAAO,YACP,MAAM,UAqBhB;IAED;;OAEG;IACH,kBAFW,MAAM,UAIhB;IACD;;OAEG;IACH,oBAFW,MAAM,UAIhB;IACD;;;;OAIG;IACH,cAJW,MAAM,YACN,WAAW,GACT,OAAO,CAuCnB;CACF;2BA3Z0B,kBAAkB;AAU7C;IACE;;;;;OAKG;IACH,mBAJW,MAAM,YACN,WAAW,WACX,qBAAqB,EAa/B;IAVC,2BAA2B;IAC3B,cAAkB;IAClB,qBAAqB;IACrB,QADW,MAAM,CACoC;IACrD,8BAA8B;IAC9B,sBAAwB;IACxB,6BAA6B;IAC7B,+BAAsB;IAKxB,iCAEC;IAED;;;;OAIG;IACH,WAHW,MAAM,GACJ,OAAO,CAInB;IAED;;;;OAIG;IACH,WAHW,MAAM,OACN,OAAO,QAMjB;IAED;;;;;OAKG;IACH,gBAJW,MAAM,UACN,MAAM,OACN,OAAO,QASjB;IACD;;;;OAIG;IACH,eAHW,OAAO,YACP,MAAM,UAIhB;IACD;;;OAGG;IACH,cAHW,OAAO,YACP,MAAM,UAIhB;IAED;;;;OAIG;IACH,cAHW,MAAM,YACN,WAAW,QAKrB;CACF;AAED;IACE;;;OAGG;IACH,mBAFW,MAAM,EAUhB;IAPC,cAAkB;IAClB,eAAuC;IACvC,2BAEC;IACD,aAAyC;IACzC,oBAAoB;IAGtB,+BAEC;IAED,gBAIC;IAED;;OAEG;IACH,UAFW,kBAAkB,QAkB5B;IAED;;;;OAIG;IACH,eAHW,OAAO,YACP,MAAM,UAyBhB;IAED;;;OAGG;IACH,cAHW,OAAO,YACP,MAAM,UAyBhB;CACF;qBAtMoB,oBAAoB"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * - Validate that the doc is written to the core identified by doc.authCoreId
3
+ * - Verify the signatures
4
+ * - Remove the signatures (we don't add them to the indexer)
5
+ * - Set doc.links to an empty array - this forces the indexer to treat every
6
+ * document as a fork, so getWinner is called for every doc, which resolves to
7
+ * the doc with the lowest index (e.g. the first)
8
+ *
9
+ * @param {CoreOwnershipWithSignatures} doc
10
+ * @param {import('@comapeo/schema').VersionIdObject} version
11
+ * @returns {import('@comapeo/schema').CoreOwnership}
12
+ */
13
+ export function mapAndValidateCoreOwnership(doc: CoreOwnershipWithSignatures, { coreDiscoveryKey }: import("@comapeo/schema").VersionIdObject): import("@comapeo/schema").CoreOwnership;
14
+ export function getWinner<T extends import("@mapeo/sqlite-indexer").IndexableDocument, U extends import("@mapeo/sqlite-indexer").IndexableDocument>(docA: T, docB: U): T | U;
15
+ /**
16
+ * @import {
17
+ * CoreOwnershipWithSignatures,
18
+ * CoreOwnershipWithSignaturesValue,
19
+ * KeyPair,
20
+ * Namespace
21
+ * } from './types.js'
22
+ */
23
+ /**
24
+ * @typedef {object} CoreOwnershipEvents
25
+ * @property {(docIds: Set<string>) => void} update Emitted when new coreOwnership records are indexed
26
+ */
27
+ /**
28
+ * @extends {TypedEmitter<CoreOwnershipEvents>}
29
+ */
30
+ export class CoreOwnership extends TypedEmitter<CoreOwnershipEvents> {
31
+ /**
32
+ *
33
+ * @param {object} opts
34
+ * @param {import('./datatype/index.js').DataType<
35
+ * import('./datastore/index.js').DataStore<'auth'>,
36
+ * typeof import('./schema/project.js').coreOwnershipTable,
37
+ * 'coreOwnership',
38
+ * import('@comapeo/schema').CoreOwnership,
39
+ * import('@comapeo/schema').CoreOwnershipValue
40
+ * >} opts.dataType
41
+ * @param {Record<Namespace, KeyPair>} opts.coreKeypairs
42
+ * @param {KeyPair} opts.identityKeypair
43
+ */
44
+ constructor({ dataType, coreKeypairs, identityKeypair }: {
45
+ dataType: import("./datatype/index.js").DataType<import("./datastore/index.js").DataStore<"auth">, typeof import("./schema/project.js").coreOwnershipTable, "coreOwnership", import("@comapeo/schema").CoreOwnership, import("@comapeo/schema").CoreOwnershipValue>;
46
+ coreKeypairs: Record<Namespace, KeyPair>;
47
+ identityKeypair: KeyPair;
48
+ });
49
+ /**
50
+ * @param {string} coreId
51
+ * @returns {Promise<string>} deviceId of device that owns the core
52
+ */
53
+ getOwner(coreId: string): Promise<string>;
54
+ /**
55
+ *
56
+ * @param {string} deviceId
57
+ * @param {Namespace} namespace
58
+ * @returns {Promise<string>} coreId of core belonging to `deviceId` for `namespace`
59
+ */
60
+ getCoreId(deviceId: string, namespace: Namespace): Promise<string>;
61
+ /**
62
+ * Get capabilities for a given deviceId
63
+ *
64
+ * @param {string} deviceId
65
+ */
66
+ get(deviceId: string): Promise<{
67
+ schemaName: "coreOwnership";
68
+ authCoreId: string;
69
+ configCoreId: string;
70
+ dataCoreId: string;
71
+ blobCoreId: string;
72
+ blobIndexCoreId: string;
73
+ docId: string;
74
+ versionId: string;
75
+ originalVersionId: string;
76
+ createdAt: string;
77
+ updatedAt: string;
78
+ links: string[];
79
+ deleted: boolean;
80
+ } & {
81
+ forks: string[];
82
+ }>;
83
+ getAll(): Promise<({
84
+ schemaName: "coreOwnership";
85
+ authCoreId: string;
86
+ configCoreId: string;
87
+ dataCoreId: string;
88
+ blobCoreId: string;
89
+ blobIndexCoreId: string;
90
+ docId: string;
91
+ versionId: string;
92
+ originalVersionId: string;
93
+ createdAt: string;
94
+ updatedAt: string;
95
+ links: string[];
96
+ deleted: boolean;
97
+ } & {
98
+ forks: string[];
99
+ })[]>;
100
+ #private;
101
+ }
102
+ export type CoreOwnershipEvents = {
103
+ /**
104
+ * Emitted when new coreOwnership records are indexed
105
+ */
106
+ update: (docIds: Set<string>) => void;
107
+ };
108
+ import type { CoreOwnershipWithSignatures } from './types.js';
109
+ import { TypedEmitter } from 'tiny-typed-emitter';
110
+ import type { Namespace } from './types.js';
111
+ import type { KeyPair } from './types.js';
112
+ //# sourceMappingURL=core-ownership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-ownership.d.ts","sourceRoot":"","sources":["../src/core-ownership.js"],"names":[],"mappings":"AAoJA;;;;;;;;;;;GAWG;AACH,iDAJW,2BAA2B,wBAC3B,OAAO,iBAAiB,EAAE,eAAe,GACvC,OAAO,iBAAiB,EAAE,aAAa,CAenD;;AA5JD;;;;;;;GAOG;AAEH;;;GAGG;AAEH;;GAEG;AACH;IAGE;;;;;;;;;;;;OAYG;IACH,yDAVG;QAMQ,QAAQ,EANR,OAAO,qBAAqB,EAAE,QAAQ,CAChD,OAAW,sBAAsB,EAAE,SAAS,CAAC,MAAM,CAAC,EACpD,cAAkB,qBAAqB,EAAE,kBAAkB,EAC3D,eAAmB,EACnB,OAAW,iBAAiB,EAAE,aAAa,EAC3C,OAAW,iBAAiB,EAAE,kBAAkB,CAC7C;QACwC,YAAY,EAA7C,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;QACZ,eAAe,EAA7B,OAAO;KACjB,EAyBA;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAiB3B;IAED;;;;;OAKG;IACH,oBAJW,MAAM,aACN,SAAS,GACP,OAAO,CAAC,MAAM,CAAC,CAK3B;IAED;;;;OAIG;IACH,cAFW,MAAM;;;;;;;;;;;;;;;;OAKhB;IAED;;;;;;;;;;;;;;;;UAGC;;CAyBF;;;;;YAtHa,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;;iDALjC,YAAY;6BAPO,oBAAoB;+BAOvC,YAAY;6BAAZ,YAAY"}
@@ -0,0 +1,91 @@
1
+ /** @import { MapeoDoc } from '@comapeo/schema' */
2
+ /**
3
+ * For each schemaName in this dataStore, emits an array of docIds that have
4
+ * been indexed whenever indexing finishes (becomes idle). `projectSettings`
5
+ * currently not supported.
6
+ *
7
+ * @template {MapeoDoc['schemaName']} TSchemaName
8
+ * @typedef {{
9
+ * [S in Exclude<TSchemaName, 'projectSettings'>]: (docIds: Set<string>) => void
10
+ * }} DataStoreEvents
11
+ */
12
+ /**
13
+ * @template T
14
+ * @template {keyof any} K
15
+ * @typedef {T extends any ? Omit<T, K> : never} OmitUnion
16
+ */
17
+ /**
18
+ * @typedef {typeof NAMESPACE_SCHEMAS} NamespaceSchemas
19
+ */
20
+ /**
21
+ * @template {keyof NamespaceSchemas} [TNamespace=keyof NamespaceSchemas]
22
+ * @template {NamespaceSchemas[TNamespace][number]} [TSchemaName=NamespaceSchemas[TNamespace][number]]
23
+ * @extends {TypedEmitter<DataStoreEvents<TSchemaName>>}
24
+ */
25
+ export class DataStore<TNamespace extends keyof NamespaceSchemas = "auth" | "config" | "data", TSchemaName extends NamespaceSchemas[TNamespace][number] = {
26
+ readonly data: readonly ["observation", "track"];
27
+ readonly config: readonly ["translation", "preset", "field", "projectSettings", "deviceInfo", "icon"];
28
+ readonly auth: readonly ["coreOwnership", "role"];
29
+ }[TNamespace][number]> extends TypedEmitter<DataStoreEvents<TSchemaName>> {
30
+ /**
31
+ * @param {object} opts
32
+ * @param {import('../core-manager/index.js').CoreManager} opts.coreManager
33
+ * @param {TNamespace} opts.namespace
34
+ * @param {(entries: MultiCoreIndexer.Entry<'binary'>[]) => Promise<import('../index-writer/index.js').IndexedDocIds>} opts.batch
35
+ * @param {MultiCoreIndexer.StorageParam} opts.storage
36
+ */
37
+ constructor({ coreManager, namespace, batch, storage }: {
38
+ coreManager: import("../core-manager/index.js").CoreManager;
39
+ namespace: TNamespace;
40
+ batch: (entries: MultiCoreIndexer.Entry<"binary">[]) => Promise<import("../index-writer/index.js").IndexedDocIds>;
41
+ storage: MultiCoreIndexer.StorageParam;
42
+ });
43
+ get indexer(): MultiCoreIndexer<"binary">;
44
+ get namespace(): TNamespace;
45
+ get schemas(): ("observation" | "track")[] | ("translation" | "preset" | "field" | "projectSettings" | "deviceInfo" | "icon")[] | ("coreOwnership" | "role")[];
46
+ get writerCore(): import("../core-manager/index.js").Core;
47
+ getIndexState(): import("multi-core-indexer/types/lib/types.js").IndexState;
48
+ /**
49
+ * UNSAFE: Does not check links: [] refer to a valid doc - should only be used
50
+ * internally.
51
+ *
52
+ * Write a doc, must be one of the schema types supported by the namespace of
53
+ * this DataStore.
54
+ * @template {Extract<Parameters<encode>[0], { schemaName: TSchemaName }>} TDoc
55
+ * @param {TDoc} doc
56
+ * @returns {Promise<Extract<MapeoDoc, TDoc>>}
57
+ */
58
+ write<TDoc extends Extract<Parameters<typeof encode>[0], {
59
+ schemaName: TSchemaName;
60
+ }>>(doc: TDoc): Promise<Extract<MapeoDoc, TDoc>>;
61
+ /**
62
+ *
63
+ * @param {string} versionId
64
+ * @returns {Promise<MapeoDoc>}
65
+ */
66
+ read(versionId: string): Promise<MapeoDoc>;
67
+ /** @param {Buffer} buf */
68
+ writeRaw(buf: Buffer): Promise<string>;
69
+ /** @param {string} versionId */
70
+ readRaw(versionId: string): Promise<Buffer>;
71
+ close(): Promise<void>;
72
+ /**
73
+ * Unlink all index files. This should only be called after `close()` has resolved.
74
+ */
75
+ unlink(): Promise<void>;
76
+ #private;
77
+ }
78
+ /**
79
+ * For each schemaName in this dataStore, emits an array of docIds that have
80
+ * been indexed whenever indexing finishes (becomes idle). `projectSettings`
81
+ * currently not supported.
82
+ */
83
+ export type DataStoreEvents<TSchemaName extends MapeoDoc["schemaName"]> = { [S in Exclude<TSchemaName, "projectSettings">]: (docIds: Set<string>) => void; };
84
+ export type OmitUnion<T, K extends keyof any> = T extends any ? Omit<T, K> : never;
85
+ export type NamespaceSchemas = typeof NAMESPACE_SCHEMAS;
86
+ import { TypedEmitter } from 'tiny-typed-emitter';
87
+ import MultiCoreIndexer from 'multi-core-indexer';
88
+ import { encode } from '@comapeo/schema';
89
+ import type { MapeoDoc } from '@comapeo/schema';
90
+ import { NAMESPACE_SCHEMAS } from '../constants.js';
91
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/datastore/index.js"],"names":[],"mappings":"AAOA,kDAAkD;AAElD;;;;;;;;;GASG;AACH;;;;GAIG;AAEH;;GAEG;AAEH;;;;GAIG;AACH,uBAJuC,UAAU,SAApC,MAAO,gBAAiB,+BACgB,WAAW,SAAlD,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAE;;;;;IAgBjD;;;;;;OAMG;IACH,wDALG;QAA6D,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC7B,SAAS,EAA1B,UAAU;QACuG,KAAK,EAAtH,CAAC,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,0BAA0B,EAAE,aAAa,CAAC;QACtE,OAAO,EAA3C,gBAAgB,CAAC,YAAY;KACvC,EAqBA;IAED,0CAEC;IAED,4BAEC;IAED,+JAGC;IAED,0DAEC;IAED,4EAEC;IAkCD;;;;;;;;;OASG;IACH,MAJ2E,IAAI,SAAjE,OAAO,CAAC,UAAU,eAAQ,CAAC,CAAC,CAAC,EAAE;QAAE,UAAU,EAAE,WAAW,CAAA;KAAE,CAAE,OAC/D,IAAI,GACF,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAoC5C;IAED;;;;OAIG;IACH,gBAHW,MAAM,GACJ,OAAO,CAAC,QAAQ,CAAC,CAS7B;IAED,0BAA0B;IAC1B,cADY,MAAM,mBAUjB;IAED,gCAAgC;IAChC,mBADY,MAAM,mBAQjB;IAED,uBAEC;IAED;;OAEG;IACH,wBAEC;;CAaF;;;;;;4BA3NqC,WAAW,SAAnC,QAAQ,CAAC,YAAY,CAAE,IACxB,GACP,CAA4C,IAAvC,OAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,GAC9E;sBAGS,CAAC,EACW,CAAC,SAAb,MAAO,GAAI,IACX,CAAC,SAAS,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;+BAIlC,OAAO,iBAAiB;6BA1BR,oBAAoB;6BAEpB,oBAAoB;uBADY,iBAAiB;8BAMhD,iBAAiB;kCAFb,iBAAiB"}
@@ -0,0 +1,108 @@
1
+ // Typescript was incorrectly compiling declaration files for this, so the
2
+ // declaration for DataType is written manually below, and copied into the
3
+ // `dist` folder at build-time. The types are checked in `test-types/data-types.ts`
4
+
5
+ import { type MapeoDoc, type MapeoValue } from '@comapeo/schema'
6
+ import {
7
+ type MapeoDocMap,
8
+ type MapeoValueMap,
9
+ type CoreOwnershipWithSignaturesValue,
10
+ } from '../types.js'
11
+ import { type BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'
12
+ import { SQLiteSelectBase } from 'drizzle-orm/sqlite-core'
13
+ import { RunResult } from 'better-sqlite3'
14
+ import type Hypercore from 'hypercore'
15
+ import { TypedEmitter } from 'tiny-typed-emitter'
16
+ import TranslationApi from '../translation-api.js'
17
+
18
+ type MapeoDocTableName = `${MapeoDoc['schemaName']}Table`
19
+ type GetMapeoDocTables<T> = T[keyof T & MapeoDocTableName]
20
+ /** Union of Drizzle schema tables that correspond to MapeoDoc types (e.g. excluding backlink tables and other utility tables) */
21
+ type MapeoDocTables =
22
+ | GetMapeoDocTables<typeof import('../schema/project.js')>
23
+ | GetMapeoDocTables<typeof import('../schema/client.js')>
24
+ type MapeoDocTablesMap = {
25
+ [K in MapeoDocTables['_']['name']]: Extract<
26
+ MapeoDocTables,
27
+ { _: { name: K } }
28
+ >
29
+ }
30
+ export interface DataTypeEvents<TDoc extends MapeoDoc> {
31
+ 'updated-docs': (docs: TDoc[]) => void
32
+ }
33
+
34
+ export const kCreateWithDocId: unique symbol
35
+ export const kSelect: unique symbol
36
+ export const kTable: unique symbol
37
+ export const kDataStore: unique symbol
38
+
39
+ type OmitUnion<T, K extends keyof any> = T extends any ? Omit<T, K> : never
40
+ type ExcludeSchema<
41
+ T extends MapeoValue,
42
+ S extends MapeoValue['schemaName']
43
+ > = Exclude<T, { schemaName: S }>
44
+
45
+ export class DataType<
46
+ TDataStore extends import('../datastore/index.js').DataStore,
47
+ TTable extends MapeoDocTables,
48
+ TSchemaName extends TTable['_']['name'],
49
+ TDoc extends MapeoDocMap[TSchemaName],
50
+ TValue extends MapeoValueMap[TSchemaName]
51
+ > extends TypedEmitter<DataTypeEvents<TDoc>> {
52
+ constructor({
53
+ dataStore,
54
+ table,
55
+ db,
56
+ getTranslations,
57
+ }: {
58
+ table: TTable
59
+ dataStore: TDataStore
60
+ db: import('drizzle-orm/better-sqlite3').BetterSQLite3Database
61
+ getTranslations: TranslationApi['get']
62
+ })
63
+
64
+ get [kTable](): TTable
65
+
66
+ get [kDataStore](): TDataStore
67
+
68
+ get schemaName(): TSchemaName
69
+
70
+ get namespace(): TDataStore.namespace
71
+
72
+ [kCreateWithDocId](
73
+ docId: string,
74
+ value:
75
+ | ExcludeSchema<TValue, 'coreOwnership'>
76
+ | CoreOwnershipWithSignaturesValue
77
+ ): Promise<TDoc & { forks: string[] }>
78
+
79
+ [kSelect](): Promise<SQLiteSelectBase<TTable, 'sync', RunResult>>
80
+
81
+ create<
82
+ T extends import('type-fest').Exact<
83
+ ExcludeSchema<TValue, 'coreOwnership'>,
84
+ T
85
+ >
86
+ >(value: T): Promise<TDoc & { forks: string[] }>
87
+
88
+ getByDocId(
89
+ docId: string,
90
+ opts?: { lang?: string }
91
+ ): Promise<TDoc & { forks: string[] }>
92
+
93
+ getByVersionId(versionId: string, opts?: { lang?: string }): Promise<TDoc>
94
+
95
+ getMany(opts?: {
96
+ includeDeleted?: boolean
97
+ lang?: string
98
+ }): Promise<Array<TDoc & { forks: string[] }>>
99
+
100
+ update<
101
+ T extends import('type-fest').Exact<
102
+ ExcludeSchema<TValue, 'coreOwnership'>,
103
+ T
104
+ >
105
+ >(versionId: string | string[], value: T): Promise<TDoc & { forks: string[] }>
106
+
107
+ delete(docId: string): Promise<TDoc & { forks: string[] }>
108
+ }