mindoodb 0.0.45 → 0.0.47

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 (92) hide show
  1. package/README.md +9 -0
  2. package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
  3. package/dist/appendonlystores/network/HttpTransport.js +4 -0
  4. package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
  5. package/dist/browser/index.mjs +31 -0
  6. package/dist/core/BaseMindooDB.d.ts +75 -0
  7. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  8. package/dist/core/BaseMindooDB.js +204 -0
  9. package/dist/core/BaseMindooDB.js.map +1 -1
  10. package/dist/core/BaseMindooTenant.d.ts +22 -0
  11. package/dist/core/BaseMindooTenant.d.ts.map +1 -1
  12. package/dist/core/BaseMindooTenant.js +38 -0
  13. package/dist/core/BaseMindooTenant.js.map +1 -1
  14. package/dist/core/DocumentDagAnalysis.d.ts +32 -0
  15. package/dist/core/DocumentDagAnalysis.d.ts.map +1 -1
  16. package/dist/core/DocumentDagAnalysis.js +46 -6
  17. package/dist/core/DocumentDagAnalysis.js.map +1 -1
  18. package/dist/core/copy/attachments.d.ts +53 -0
  19. package/dist/core/copy/attachments.d.ts.map +1 -0
  20. package/dist/core/copy/attachments.js +186 -0
  21. package/dist/core/copy/attachments.js.map +1 -0
  22. package/dist/core/copy/copyDocument.d.ts +86 -0
  23. package/dist/core/copy/copyDocument.d.ts.map +1 -0
  24. package/dist/core/copy/copyDocument.js +369 -0
  25. package/dist/core/copy/copyDocument.js.map +1 -0
  26. package/dist/core/copy/copyDocuments.d.ts +57 -0
  27. package/dist/core/copy/copyDocuments.d.ts.map +1 -0
  28. package/dist/core/copy/copyDocuments.js +167 -0
  29. package/dist/core/copy/copyDocuments.js.map +1 -0
  30. package/dist/core/copy/entryRewrite.d.ts +49 -0
  31. package/dist/core/copy/entryRewrite.d.ts.map +1 -0
  32. package/dist/core/copy/entryRewrite.js +74 -0
  33. package/dist/core/copy/entryRewrite.js.map +1 -0
  34. package/dist/core/copy/feasibility.d.ts +73 -0
  35. package/dist/core/copy/feasibility.d.ts.map +1 -0
  36. package/dist/core/copy/feasibility.js +169 -0
  37. package/dist/core/copy/feasibility.js.map +1 -0
  38. package/dist/core/copy/flatten.d.ts +55 -0
  39. package/dist/core/copy/flatten.d.ts.map +1 -0
  40. package/dist/core/copy/flatten.js +155 -0
  41. package/dist/core/copy/flatten.js.map +1 -0
  42. package/dist/core/copy/host.d.ts +92 -0
  43. package/dist/core/copy/host.d.ts.map +1 -0
  44. package/dist/core/copy/host.js +16 -0
  45. package/dist/core/copy/host.js.map +1 -0
  46. package/dist/core/copy/preflight.d.ts +62 -0
  47. package/dist/core/copy/preflight.d.ts.map +1 -0
  48. package/dist/core/copy/preflight.js +98 -0
  49. package/dist/core/copy/preflight.js.map +1 -0
  50. package/dist/core/copy/provenance.d.ts +74 -0
  51. package/dist/core/copy/provenance.d.ts.map +1 -0
  52. package/dist/core/copy/provenance.js +91 -0
  53. package/dist/core/copy/provenance.js.map +1 -0
  54. package/dist/core/copy/types.d.ts +418 -0
  55. package/dist/core/copy/types.d.ts.map +1 -0
  56. package/dist/core/copy/types.js +21 -0
  57. package/dist/core/copy/types.js.map +1 -0
  58. package/dist/core/crypto/DomainStatement.d.ts +44 -0
  59. package/dist/core/crypto/DomainStatement.d.ts.map +1 -0
  60. package/dist/core/crypto/DomainStatement.js +71 -0
  61. package/dist/core/crypto/DomainStatement.js.map +1 -0
  62. package/dist/core/crypto/EntrySignature.d.ts +109 -15
  63. package/dist/core/crypto/EntrySignature.d.ts.map +1 -1
  64. package/dist/core/crypto/EntrySignature.js +83 -22
  65. package/dist/core/crypto/EntrySignature.js.map +1 -1
  66. package/dist/core/index.d.ts +21 -0
  67. package/dist/core/index.d.ts.map +1 -1
  68. package/dist/core/index.js +54 -3
  69. package/dist/core/index.js.map +1 -1
  70. package/dist/core/timestamps/timestampClient.d.ts +88 -0
  71. package/dist/core/timestamps/timestampClient.d.ts.map +1 -0
  72. package/dist/core/timestamps/timestampClient.js +157 -0
  73. package/dist/core/timestamps/timestampClient.js.map +1 -0
  74. package/dist/core/types.d.ts +118 -1
  75. package/dist/core/types.d.ts.map +1 -1
  76. package/dist/core/types.js.map +1 -1
  77. package/dist/node/server/MindooDBServer.d.ts +37 -0
  78. package/dist/node/server/MindooDBServer.d.ts.map +1 -1
  79. package/dist/node/server/MindooDBServer.js +157 -0
  80. package/dist/node/server/MindooDBServer.js.map +1 -1
  81. package/dist/node/server/config.d.ts.map +1 -1
  82. package/dist/node/server/config.js +16 -0
  83. package/dist/node/server/config.js.map +1 -1
  84. package/dist/node/server/timestampProxy.d.ts +129 -0
  85. package/dist/node/server/timestampProxy.d.ts.map +1 -0
  86. package/dist/node/server/timestampProxy.js +361 -0
  87. package/dist/node/server/timestampProxy.js.map +1 -0
  88. package/dist/node/server/types.d.ts +20 -0
  89. package/dist/node/server/types.d.ts.map +1 -1
  90. package/dist/node/server/types.js +12 -0
  91. package/dist/node/server/types.js.map +1 -1
  92. package/package.json +1 -1
@@ -0,0 +1,418 @@
1
+ /**
2
+ * Public types for copying documents between MindooDB databases.
3
+ *
4
+ * See `docs/document-copy.md` for the full picture (strategy matrix, sharding
5
+ * playbook, caveats). The short version:
6
+ *
7
+ * - **flatten** collapses a document's whole history into a single new change
8
+ * in the target. Cheap, always available, loses history and authorship.
9
+ * - **graft** copies the original store entries byte-for-byte. The ONLY way to
10
+ * keep the original signers, and only legal within one tenant, under the same
11
+ * document id and the same encryption key, into a different database.
12
+ * - **replay** re-writes every historical change under a new identity: the
13
+ * Automerge history survives intact, the store-level author becomes the
14
+ * copying user, and the original authorship is recorded as a verifiable
15
+ * {@link EntryProvenance} record instead.
16
+ *
17
+ * @module
18
+ */
19
+ import type { SigningKeyPair } from "../types";
20
+ /**
21
+ * How much of the source document's history the copy carries over.
22
+ *
23
+ * - `"flatten"` — read the document's state (at head, or at
24
+ * {@link CopyDocumentOptions.atTimestamp}) and write it as one fresh change.
25
+ * - `"history"` — carry every historical change, so the copy has the same
26
+ * Automerge revision graph as the source and supports time travel.
27
+ *
28
+ * @defaultValue `"flatten"`
29
+ */
30
+ export type CopyDocumentMode = "flatten" | "history";
31
+ /**
32
+ * Whether the copied entries keep the original authors' signatures.
33
+ *
34
+ * - `"reauthor"` — the copying user signs every produced entry. Always
35
+ * possible.
36
+ * - `"preserve"` — the original entries are copied byte-for-byte so the
37
+ * original authors' signatures stay valid. Only possible in one exact
38
+ * configuration (see {@link CopyDocumentOptions.authorship}); requesting it
39
+ * anywhere else throws rather than silently downgrading.
40
+ *
41
+ * @defaultValue `"reauthor"`
42
+ */
43
+ export type CopyDocumentAuthorship = "preserve" | "reauthor";
44
+ /**
45
+ * The concrete execution strategy chosen for a copy, resolved from
46
+ * {@link CopyDocumentOptions.mode} and {@link CopyDocumentOptions.authorship}
47
+ * plus the source/target context. Reported on {@link CopyFeasibility} and
48
+ * {@link CopyDocumentResult} so callers can see what actually ran.
49
+ */
50
+ export type CopyStrategy = "flatten" | "graft" | "replay";
51
+ /**
52
+ * Why a requested copy cannot run, or cannot preserve authorship. Codes are
53
+ * stable and safe to branch on; `message` is for humans and may change.
54
+ */
55
+ export type CopyFeasibilityReasonCode =
56
+ /** Source and target belong to different tenants, so the payload must be
57
+ * re-encrypted under the target tenant key and the source authors are not
58
+ * in the target tenant's directory. */
59
+ "different_tenant"
60
+ /** The copy lands under a new document id, which changes the entry ids and
61
+ * therefore invalidates the original authors' metadata signatures. */
62
+ | "different_doc_id"
63
+ /** The target uses a different `decryptionKeyId`, forcing re-encryption,
64
+ * which changes `contentHash` and invalidates the original signatures. */
65
+ | "different_key"
66
+ /** Flatten mode produces a single new change, so there is no original entry
67
+ * whose authorship could be preserved. */
68
+ | "flatten_mode"
69
+ /** Source and target resolve to the same store under the same document id:
70
+ * there is nothing to copy. */
71
+ | "same_database_same_doc_id"
72
+ /** The tenant directory database is never a valid copy source or target. */
73
+ | "directory_database";
74
+ /** One structured explanation attached to a {@link CopyFeasibility}. */
75
+ export interface CopyFeasibilityReason {
76
+ /** Stable, branchable identifier for the condition. */
77
+ code: CopyFeasibilityReasonCode;
78
+ /** Human-readable explanation, suitable for surfacing in a UI or an error. */
79
+ message: string;
80
+ }
81
+ /**
82
+ * The outcome of the pure strategy resolver: what a copy *would* do, computed
83
+ * without writing anything. Returned by `canCopyDocumentTo()` so a caller can
84
+ * explain the plan (or the refusal) before committing to it.
85
+ */
86
+ export interface CopyFeasibility {
87
+ /** Whether the copy can run at all with the requested options. */
88
+ allowed: boolean;
89
+ /**
90
+ * The strategy that would execute. Meaningful only when {@link allowed} is
91
+ * true.
92
+ */
93
+ strategy: CopyStrategy;
94
+ /**
95
+ * Whether the original authors' signatures would survive. True only for the
96
+ * `graft` strategy.
97
+ */
98
+ authorshipPreserved: boolean;
99
+ /**
100
+ * True when the target database already holds the destination document id.
101
+ * The copy then *merges* into that document (CRDT union of both histories)
102
+ * rather than creating a separate one.
103
+ */
104
+ willMergeIntoExisting: boolean;
105
+ /** True when source and target document entries live in the same store. */
106
+ sameStore: boolean;
107
+ /**
108
+ * True when payloads must be decrypted and re-encrypted, because the tenant
109
+ * or the `decryptionKeyId` differs. Implies the copy needs read access to the
110
+ * source key and write access to the target key.
111
+ */
112
+ requiresReEncryption: boolean;
113
+ /**
114
+ * Why the copy is disallowed, or why authorship cannot be preserved. Empty
115
+ * when the copy runs exactly as requested. Populated even when
116
+ * {@link allowed} is true, to explain a `reauthor` outcome.
117
+ */
118
+ reasons: CopyFeasibilityReason[];
119
+ }
120
+ /**
121
+ * Lifecycle stage of a running copy. Mirrors `SyncProgress.phase` so a UI can
122
+ * reuse the same progress rendering for syncs and copies.
123
+ */
124
+ export type CopyProgressPhase = "preparing" | "planning" | "transferring" | "processing" | "complete";
125
+ /**
126
+ * Progress event emitted during a copy. Shaped to match `SyncProgress` so the
127
+ * two are interchangeable in a progress UI.
128
+ */
129
+ export interface CopyProgress {
130
+ /** Current lifecycle stage. */
131
+ phase: CopyProgressPhase;
132
+ /** Human-readable status description suitable for display. */
133
+ message: string;
134
+ /** Cumulative entries written to the target so far. */
135
+ copiedEntries: number;
136
+ /**
137
+ * Cumulative encrypted payload size (bytes) written to the target, summed
138
+ * from each entry's `encryptedSize`. Note this is real duplicated storage for
139
+ * a cross-database copy: content deduplication is per-store.
140
+ */
141
+ copiedBytes: number;
142
+ /** Cumulative source entries whose metadata has been examined. */
143
+ scannedEntries: number;
144
+ /**
145
+ * Total entries on the source that are in scope, when known. Fixed for the
146
+ * run, so `scannedEntries / totalSourceEntries` is a stable completion ratio.
147
+ */
148
+ totalSourceEntries?: number;
149
+ /** The document currently being copied, during a bulk copy. */
150
+ currentDocId?: string;
151
+ /** Documents finished so far, during a bulk copy. */
152
+ documentsCompleted?: number;
153
+ /** Total documents selected, during a bulk copy. */
154
+ totalDocuments?: number;
155
+ }
156
+ /**
157
+ * Options for copying a single document into another database.
158
+ *
159
+ * Defaults are chosen so the zero-config call — `sourceDb.copyDocumentTo(id,
160
+ * targetDb)` — does the safe, obvious thing: a flattened copy under a fresh
161
+ * document id, authored by the current user.
162
+ */
163
+ export interface CopyDocumentOptions {
164
+ /**
165
+ * How much history to carry over.
166
+ *
167
+ * @defaultValue `"flatten"`
168
+ */
169
+ mode?: CopyDocumentMode;
170
+ /**
171
+ * The document id to write in the target database.
172
+ *
173
+ * - `"new"` — allocate a fresh id (with {@link idPrefix} when given).
174
+ * - `"same"` — reuse the source document id. Required for authorship
175
+ * preservation. If the target database already holds that id the copy
176
+ * **merges** into the existing document instead of creating a new one;
177
+ * {@link CopyDocumentResult.mergedIntoExisting} reports when that happened.
178
+ * - an explicit string — use exactly this id. Must satisfy the same
179
+ * constraints as `CreateOptions.id`.
180
+ *
181
+ * @defaultValue `"new"`
182
+ */
183
+ targetDocId?: "same" | "new" | string;
184
+ /**
185
+ * Prefix for the generated id when {@link targetDocId} is `"new"`. Same rules
186
+ * as `CreateOptions.idPrefix` (1-10 alphanumerics, starting with a letter).
187
+ * Ignored for any other {@link targetDocId} value.
188
+ */
189
+ idPrefix?: string;
190
+ /**
191
+ * Caller assertion that the document ids being written are random enough that
192
+ * no other replica can create the same id concurrently — the copy equivalent
193
+ * of `CreateOptions.assumeUniqueId`.
194
+ *
195
+ * **Flatten only, and only when the copy keeps a caller-provided id**
196
+ * ({@link targetDocId} `"same"` or an explicit string). It has no meaning for
197
+ * `mode: "history"`, which copies the source's own `doc_create` entry rather
198
+ * than synthesizing one, and none for {@link targetDocId} `"new"`, whose ids
199
+ * MindooDB generates and already knows to be unique.
200
+ *
201
+ * Without it, a flatten under a caller-provided id costs **two** store
202
+ * entries: the id is seeded from a hard-coded Automerge change so that two
203
+ * replicas creating it independently converge on the same hash, and content
204
+ * cannot be baked into that change without diverging it. With it, the create
205
+ * takes the generated-id path and the payload folds into a single entry —
206
+ * halving the storage and the write cost of a large flatten migration.
207
+ *
208
+ * Safe when the ids were minted by MindooDB (`<prefix>_<22-char-base62>` from
209
+ * `createDocument`, ~128 bits of uuidv7 entropy) or by an equivalent random
210
+ * scheme.
211
+ *
212
+ * WARNING: do NOT set this for semantic or well-known ids (`"settings"`,
213
+ * `"config"`, a natural key imported from another system). If two replicas
214
+ * create the same id with this flag, their `doc_create` entries share no
215
+ * Automerge ancestry and the document **forks** instead of converging. The
216
+ * risk is concurrent creation on replicas that have not synced — a single
217
+ * operator running one migration into a fresh target is not exposed to it,
218
+ * and re-running a copy is still idempotent either way.
219
+ *
220
+ * @defaultValue `false`
221
+ */
222
+ assumeUniqueTargetDocId?: boolean;
223
+ /**
224
+ * Whether to keep the original authors' signatures on the copied entries.
225
+ *
226
+ * `"preserve"` is only legal when ALL of the following hold, and **throws**
227
+ * otherwise rather than silently downgrading:
228
+ *
229
+ * - {@link mode} is `"history"`,
230
+ * - source and target are in the same tenant,
231
+ * - {@link targetDocId} resolves to the source document id,
232
+ * - {@link decryptionKeyId} is unchanged,
233
+ * - source and target are different databases.
234
+ *
235
+ * The constraint is cryptographic, not a policy choice: an entry's
236
+ * `metadataSignature` binds its id, `docId`, `decryptionKeyId` and
237
+ * `contentHash`, so changing any of them requires a signature only the
238
+ * original author could produce. Use `canCopyDocumentTo()` to test first.
239
+ *
240
+ * @defaultValue `"reauthor"`
241
+ */
242
+ authorship?: CopyDocumentAuthorship;
243
+ /**
244
+ * Symmetric key id to encrypt the copy under, in the target tenant.
245
+ * Defaults to the source document's key id when the tenant is unchanged,
246
+ * otherwise to `"default"` (the target tenant key).
247
+ *
248
+ * Changing it forces decrypt + re-encrypt, which changes `contentHash` and
249
+ * therefore rules out {@link authorship} `"preserve"`.
250
+ */
251
+ decryptionKeyId?: string;
252
+ /**
253
+ * Record a verifiable {@link EntryProvenance} on each copied entry (history
254
+ * modes), or a document-level `_provenance` object in the payload (flatten
255
+ * mode), capturing where the copy came from and who originally authored it.
256
+ *
257
+ * Provenance is *self-verifying*: it carries the original entry's signed
258
+ * field projection plus the original author's signature, so a reader can
259
+ * confirm the original author really signed this payload. Has no effect on
260
+ * `graft`, where the original signature is still present on the entry itself.
261
+ *
262
+ * @defaultValue `true`
263
+ */
264
+ provenance?: boolean;
265
+ /**
266
+ * Copy the document's state as of this timestamp (epoch millis) rather than
267
+ * its current head.
268
+ *
269
+ * Flatten mode only — ignored by `history` mode, which always carries the
270
+ * whole revision graph.
271
+ */
272
+ atTimestamp?: number;
273
+ /**
274
+ * Copy the document's attachments as well as its content.
275
+ *
276
+ * @defaultValue `true`
277
+ */
278
+ includeAttachments?: boolean;
279
+ /**
280
+ * Sign the produced entries with this key pair instead of the current user's
281
+ * key. Useful for attributing a bulk import or migration to a dedicated
282
+ * service identity. Must be supplied together with
283
+ * {@link signingKeyPassword}.
284
+ *
285
+ * Ignored by `graft`, which does not re-sign anything.
286
+ */
287
+ signingKeyPair?: SigningKeyPair;
288
+ /** Password decrypting {@link signingKeyPair}'s private key. Required with it. */
289
+ signingKeyPassword?: string;
290
+ /** Called as the copy progresses. See {@link CopyProgress}. */
291
+ onProgress?: (progress: CopyProgress) => void;
292
+ /**
293
+ * Cancels the copy. Because every produced entry id is deterministic, a
294
+ * cancelled copy is safe to re-run: already-written entries are skipped.
295
+ * {@link CopyDocumentResult.targetDocId} is returned even when cancelled, so
296
+ * the caller can resume against the same target id.
297
+ */
298
+ signal?: AbortSignal;
299
+ /**
300
+ * Entries written to the target store per `putEntries` call.
301
+ *
302
+ * @defaultValue `200`
303
+ */
304
+ batchSize?: number;
305
+ /**
306
+ * Skip the client-side access-control write precheck on the target. For
307
+ * trusted bulk paths only; the server witness and quarantine-on-
308
+ * materialization still enforce the rules.
309
+ *
310
+ * @defaultValue `false`
311
+ */
312
+ bypassAccessControlPrecheck?: boolean;
313
+ }
314
+ /** Outcome of copying one document. */
315
+ export interface CopyDocumentResult {
316
+ /** The document id that was read from the source. */
317
+ sourceDocId: string;
318
+ /**
319
+ * The document id written in the target. Returned even when
320
+ * {@link cancelled} is true, so a resumed run can target the same id and
321
+ * benefit from deterministic-id deduplication.
322
+ */
323
+ targetDocId: string;
324
+ /** The strategy that actually executed. */
325
+ strategy: CopyStrategy;
326
+ /** True when the original authors' signatures were kept (graft only). */
327
+ authorshipPreserved: boolean;
328
+ /**
329
+ * True when the target already held {@link targetDocId}, so the copy merged
330
+ * into that existing document rather than creating a new one.
331
+ */
332
+ mergedIntoExisting: boolean;
333
+ /** Store entries written to the target (excluding ones already present). */
334
+ copiedEntries: number;
335
+ /**
336
+ * Encrypted payload bytes written to the target. For a cross-database copy
337
+ * this is genuinely duplicated storage — content dedup is per-store.
338
+ */
339
+ copiedBytes: number;
340
+ /** Attachments carried over. */
341
+ copiedAttachments: number;
342
+ /** True when the copy stopped early because {@link CopyDocumentOptions.signal} aborted. */
343
+ cancelled: boolean;
344
+ }
345
+ /**
346
+ * Selects which documents a bulk copy operates on. At least one of
347
+ * {@link docIds} or {@link idPrefix} must be given; when both are present a
348
+ * document matching either is selected.
349
+ */
350
+ export interface CopyDocumentSelector {
351
+ /** Explicit document ids to copy. */
352
+ docIds?: string[];
353
+ /**
354
+ * Select every document whose id matches one of these prefixes, using the
355
+ * boundary-aware `matchesDocIdPrefix` rule: an id matches when it equals the
356
+ * prefix exactly or begins with `<prefix>_`.
357
+ *
358
+ * A list is accepted because prefixes do not nest. Document id prefixes are
359
+ * 1-10 alphanumerics with no underscore, so a monthly scheme like
360
+ * `inv202506` cannot be selected a year at a time via `inv2025` — pass the
361
+ * twelve monthly prefixes instead.
362
+ *
363
+ * Selecting by prefix reads only store metadata, which is what keeps the
364
+ * sharding fast path keyless. Partitioning on an encrypted payload field
365
+ * would instead require decrypting every document just to place it.
366
+ */
367
+ idPrefix?: string | string[];
368
+ }
369
+ /**
370
+ * Options for a bulk copy. Identical to {@link CopyDocumentOptions} except that
371
+ * {@link CopyDocumentOptions.targetDocId} cannot be an explicit id string —
372
+ * with many documents in flight only the `"same"` / `"new"` policies are
373
+ * meaningful.
374
+ */
375
+ export interface CopyDocumentsOptions extends Omit<CopyDocumentOptions, "targetDocId"> {
376
+ /**
377
+ * Document id policy for every copied document.
378
+ *
379
+ * `"same"` is what sharding uses: it keeps document ids stable across the
380
+ * split and is a precondition for {@link CopyDocumentOptions.authorship}
381
+ * `"preserve"`.
382
+ *
383
+ * @defaultValue `"new"`
384
+ */
385
+ targetDocId?: "same" | "new";
386
+ }
387
+ /** One document that could not be copied during a bulk run. */
388
+ export interface CopyDocumentFailure {
389
+ /** The source document id that failed. */
390
+ docId: string;
391
+ /** The failure message. */
392
+ error: string;
393
+ }
394
+ /** Outcome of a bulk copy. */
395
+ export interface CopyDocumentsResult {
396
+ /** Per-document results, in the order the documents were processed. */
397
+ documents: CopyDocumentResult[];
398
+ /**
399
+ * Source document ids that copied successfully. Shaped for direct use as
400
+ * `DocHistoryPurgeRequest.docIds` when reclaiming the source after a shard —
401
+ * see `buildDocHistoryPurgeRequest()`.
402
+ */
403
+ copiedDocIds: string[];
404
+ /**
405
+ * Documents that failed. A bulk copy continues past per-document errors and
406
+ * reports them here, mirroring how `pushChangesTo` reports `rejectedEntries`.
407
+ */
408
+ failed: CopyDocumentFailure[];
409
+ /** Total store entries written to the target across all documents. */
410
+ copiedEntries: number;
411
+ /** Total encrypted payload bytes written to the target. */
412
+ copiedBytes: number;
413
+ /** Total attachments carried over. */
414
+ copiedAttachments: number;
415
+ /** True when the run stopped early because the abort signal fired. */
416
+ cancelled: boolean;
417
+ }
418
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/copy/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,UAAU,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE1D;;;GAGG;AACH,MAAM,MAAM,yBAAyB;AACnC;;wCAEwC;AACtC,kBAAkB;AACpB;uEACuE;GACrE,kBAAkB;AACpB;2EAC2E;GACzE,eAAe;AACjB;2CAC2C;GACzC,cAAc;AAChB;gCACgC;GAC9B,2BAA2B;AAC7B,4EAA4E;GAC1E,oBAAoB,CAAC;AAEzB,wEAAwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,IAAI,EAAE,yBAAyB,CAAC;IAChC,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB;;;OAGG;IACH,mBAAmB,EAAE,OAAO,CAAC;IAC7B;;;;OAIG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B,2EAA2E;IAC3E,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,oBAAoB,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GACzB,WAAW,GACX,UAAU,GACV,cAAc,GACd,YAAY,GACZ,UAAU,CAAC;AAEf;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,KAAK,EAAE,iBAAiB,CAAC;IACzB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC;IAExB;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IAEtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CAAC,EAAE,sBAAsB,CAAC;IAEpC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IAE9C;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;OAMG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,QAAQ,EAAE,YAAY,CAAC;IACvB,yEAAyE;IACzE,mBAAmB,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAC5B,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,2FAA2F;IAC3F,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBACf,SAAQ,IAAI,CAAC,mBAAmB,EAAE,aAAa,CAAC;IAChD;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED,+DAA+D;AAC/D,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,8BAA8B;AAC9B,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC;;;;OAIG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,sEAAsE;IACtE,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,SAAS,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Public types for copying documents between MindooDB databases.
4
+ *
5
+ * See `docs/document-copy.md` for the full picture (strategy matrix, sharding
6
+ * playbook, caveats). The short version:
7
+ *
8
+ * - **flatten** collapses a document's whole history into a single new change
9
+ * in the target. Cheap, always available, loses history and authorship.
10
+ * - **graft** copies the original store entries byte-for-byte. The ONLY way to
11
+ * keep the original signers, and only legal within one tenant, under the same
12
+ * document id and the same encryption key, into a different database.
13
+ * - **replay** re-writes every historical change under a new identity: the
14
+ * Automerge history survives intact, the store-level author becomes the
15
+ * copying user, and the original authorship is recorded as a verifiable
16
+ * {@link EntryProvenance} record instead.
17
+ *
18
+ * @module
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/copy/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Domain-separated statement signing.
3
+ *
4
+ * A user's Ed25519 identity key already signs two things with fixed layouts:
5
+ * store-entry metadata (`crypto/EntrySignature.ts`) and authentication
6
+ * challenges. Letting an application hand arbitrary bytes to that same key
7
+ * would make the signer a confused deputy — an app could ask for a "statement"
8
+ * that happens to be a valid entry-signing payload and obtain a signature the
9
+ * user never meant to give.
10
+ *
11
+ * The fix is a mandatory prefix: what gets signed is
12
+ *
13
+ * utf8(domain) || 0x00 || statementBytes
14
+ *
15
+ * and `domain` must come from {@link SIGNING_DOMAINS}. Because every allowed
16
+ * domain starts with an ASCII letter while the entry layout starts with its
17
+ * version byte `0x01`, and challenges are random tokens that never begin with
18
+ * `"mindoodb-"`, the three input spaces cannot overlap. The `0x00` separator
19
+ * stops one domain from being a prefix of another.
20
+ */
21
+ /**
22
+ * Every purpose an app may request a signature for. Deliberately a closed list:
23
+ * adding a domain is a security decision, not a caller's choice.
24
+ */
25
+ export declare const SIGNING_DOMAINS: Readonly<{
26
+ /** Approval / counter-signature seal statement (TeamSketchbook and friends). */
27
+ readonly SEAL_V1: "mindoodb-seal/v1";
28
+ }>;
29
+ export type SigningDomain = (typeof SIGNING_DOMAINS)[keyof typeof SIGNING_DOMAINS];
30
+ /** Statements are user-reviewable documents, not bulk data. */
31
+ export declare const MAX_DOMAIN_STATEMENT_BYTES: number;
32
+ export declare class InvalidSigningDomainError extends Error {
33
+ constructor(domain: string);
34
+ }
35
+ export declare function isAllowedSigningDomain(domain: string): domain is SigningDomain;
36
+ export declare function assertAllowedSigningDomain(domain: string): asserts domain is SigningDomain;
37
+ /**
38
+ * Build the bytes actually covered by a domain-separated signature.
39
+ *
40
+ * Verifiers must reconstruct these from the domain and the statement rather
41
+ * than trusting a transmitted blob, otherwise the separation buys nothing.
42
+ */
43
+ export declare function buildDomainStatementBytes(domain: string, statement: Uint8Array): Uint8Array;
44
+ //# sourceMappingURL=DomainStatement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DomainStatement.d.ts","sourceRoot":"","sources":["../../../src/core/crypto/DomainStatement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;IAC1B,gFAAgF;;EAEvE,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAInF,+DAA+D;AAC/D,eAAO,MAAM,0BAA0B,QAAa,CAAC;AAErD,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,MAAM,EAAE,MAAM;CAM3B;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,aAAa,CAE9E;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAI1F;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAa3F"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Domain-separated statement signing.
4
+ *
5
+ * A user's Ed25519 identity key already signs two things with fixed layouts:
6
+ * store-entry metadata (`crypto/EntrySignature.ts`) and authentication
7
+ * challenges. Letting an application hand arbitrary bytes to that same key
8
+ * would make the signer a confused deputy — an app could ask for a "statement"
9
+ * that happens to be a valid entry-signing payload and obtain a signature the
10
+ * user never meant to give.
11
+ *
12
+ * The fix is a mandatory prefix: what gets signed is
13
+ *
14
+ * utf8(domain) || 0x00 || statementBytes
15
+ *
16
+ * and `domain` must come from {@link SIGNING_DOMAINS}. Because every allowed
17
+ * domain starts with an ASCII letter while the entry layout starts with its
18
+ * version byte `0x01`, and challenges are random tokens that never begin with
19
+ * `"mindoodb-"`, the three input spaces cannot overlap. The `0x00` separator
20
+ * stops one domain from being a prefix of another.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.InvalidSigningDomainError = exports.MAX_DOMAIN_STATEMENT_BYTES = exports.SIGNING_DOMAINS = void 0;
24
+ exports.isAllowedSigningDomain = isAllowedSigningDomain;
25
+ exports.assertAllowedSigningDomain = assertAllowedSigningDomain;
26
+ exports.buildDomainStatementBytes = buildDomainStatementBytes;
27
+ /**
28
+ * Every purpose an app may request a signature for. Deliberately a closed list:
29
+ * adding a domain is a security decision, not a caller's choice.
30
+ */
31
+ exports.SIGNING_DOMAINS = Object.freeze({
32
+ /** Approval / counter-signature seal statement (TeamSketchbook and friends). */
33
+ SEAL_V1: "mindoodb-seal/v1",
34
+ });
35
+ const ALLOWED_DOMAINS = new Set(Object.values(exports.SIGNING_DOMAINS));
36
+ /** Statements are user-reviewable documents, not bulk data. */
37
+ exports.MAX_DOMAIN_STATEMENT_BYTES = 256 * 1024;
38
+ class InvalidSigningDomainError extends Error {
39
+ constructor(domain) {
40
+ super(`"${domain}" is not an allowed signing domain (expected one of: ${Array.from(ALLOWED_DOMAINS).join(", ")})`);
41
+ this.name = "InvalidSigningDomainError";
42
+ }
43
+ }
44
+ exports.InvalidSigningDomainError = InvalidSigningDomainError;
45
+ function isAllowedSigningDomain(domain) {
46
+ return ALLOWED_DOMAINS.has(domain);
47
+ }
48
+ function assertAllowedSigningDomain(domain) {
49
+ if (!isAllowedSigningDomain(domain)) {
50
+ throw new InvalidSigningDomainError(domain);
51
+ }
52
+ }
53
+ /**
54
+ * Build the bytes actually covered by a domain-separated signature.
55
+ *
56
+ * Verifiers must reconstruct these from the domain and the statement rather
57
+ * than trusting a transmitted blob, otherwise the separation buys nothing.
58
+ */
59
+ function buildDomainStatementBytes(domain, statement) {
60
+ assertAllowedSigningDomain(domain);
61
+ if (statement.byteLength > exports.MAX_DOMAIN_STATEMENT_BYTES) {
62
+ throw new Error(`Statement too large (${statement.byteLength} bytes, max ${exports.MAX_DOMAIN_STATEMENT_BYTES})`);
63
+ }
64
+ const prefix = new TextEncoder().encode(domain);
65
+ const out = new Uint8Array(prefix.byteLength + 1 + statement.byteLength);
66
+ out.set(prefix, 0);
67
+ out[prefix.byteLength] = 0x00;
68
+ out.set(statement, prefix.byteLength + 1);
69
+ return out;
70
+ }
71
+ //# sourceMappingURL=DomainStatement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DomainStatement.js","sourceRoot":"","sources":["../../../src/core/crypto/DomainStatement.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AA2BH,wDAEC;AAED,gEAIC;AAQD,8DAaC;AAtDD;;;GAGG;AACU,QAAA,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,gFAAgF;IAChF,OAAO,EAAE,kBAAkB;CACnB,CAAC,CAAC;AAIZ,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,uBAAe,CAAC,CAAC,CAAC;AAErF,+DAA+D;AAClD,QAAA,0BAA0B,GAAG,GAAG,GAAG,IAAI,CAAC;AAErD,MAAa,yBAA0B,SAAQ,KAAK;IAClD,YAAY,MAAc;QACxB,KAAK,CACH,IAAI,MAAM,wDAAwD,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5G,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAPD,8DAOC;AAED,SAAgB,sBAAsB,CAAC,MAAc;IACnD,OAAO,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,SAAgB,0BAA0B,CAAC,MAAc;IACvD,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,yBAAyB,CAAC,MAAc,EAAE,SAAqB;IAC7E,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,SAAS,CAAC,UAAU,GAAG,kCAA0B,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,wBAAwB,SAAS,CAAC,UAAU,eAAe,kCAA0B,GAAG,CACzF,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IACzE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACnB,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC9B,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IAC1C,OAAO,GAAG,CAAC;AACb,CAAC"}