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,88 @@
1
+ /**
2
+ * Client transport for RFC 3161 timestamps.
3
+ *
4
+ * Two paths, because no single one works everywhere:
5
+ *
6
+ * - **Direct.** `https://rfc3161.ai.moda` is the only public TSA measured to
7
+ * send CORS headers, so a browser can reach it unaided. This keeps sealing
8
+ * working on a Haven with no MindooDB server at all.
9
+ * - **Proxy.** Everything else is http-only or CORS-less — including every
10
+ * eIDAS-qualified authority — so those go through the tenant's server at
11
+ * `POST /:tenantId/timestamps/rfc3161`.
12
+ *
13
+ * Both carry opaque DER. **Neither is trusted.** The caller must verify that
14
+ * the returned token's `messageImprint` equals the digest it sent and that the
15
+ * token chains to a trusted root (see `verifyTimestampResponse` in
16
+ * `mindoodb-seal`). With those two checks a hostile transport can withhold a
17
+ * timestamp but cannot forge one, which is why calling a third-party proxy from
18
+ * the browser is acceptable at all.
19
+ */
20
+ export declare const TIMESTAMP_QUERY_CONTENT_TYPE = "application/timestamp-query";
21
+ export declare const TIMESTAMP_REPLY_CONTENT_TYPE = "application/timestamp-reply";
22
+ /** Bound on an accepted TimeStampResp; real tokens are a few KB. */
23
+ export declare const MAX_TIMESTAMP_RESPONSE_BYTES: number;
24
+ export declare const DEFAULT_TIMESTAMP_TIMEOUT_MS = 15000;
25
+ /**
26
+ * The one public TSA a browser can call directly (verified by CORS preflight:
27
+ * reflected origin, `POST, OPTIONS`, `Content-Type`). It is a failover proxy in
28
+ * front of DigiCert, Sectigo, Azure and others, so its tokens chain to roots
29
+ * already in public trust stores.
30
+ */
31
+ export declare const BROWSER_REACHABLE_TSA: Readonly<{
32
+ id: "aimoda";
33
+ name: "ai.moda RFC 3161 proxy";
34
+ url: "https://rfc3161.ai.moda";
35
+ }>;
36
+ export type TimestampSource = "direct" | "proxy";
37
+ export interface TimestampTokenResult {
38
+ /** Raw DER TimeStampResp, unverified. */
39
+ response: Uint8Array;
40
+ providerId: string;
41
+ source: TimestampSource;
42
+ }
43
+ export declare class TimestampRequestError extends Error {
44
+ readonly source: TimestampSource;
45
+ readonly httpStatus?: number | undefined;
46
+ constructor(message: string, source: TimestampSource, httpStatus?: number | undefined);
47
+ }
48
+ interface PostTimestampOptions {
49
+ request: Uint8Array;
50
+ timeoutMs?: number;
51
+ fetchImpl?: typeof fetch;
52
+ maxResponseBytes?: number;
53
+ }
54
+ /** Call a CORS-enabled TSA straight from the client. */
55
+ export declare function requestTimestampDirect(options: PostTimestampOptions & {
56
+ url?: string;
57
+ providerId?: string;
58
+ }): Promise<TimestampTokenResult>;
59
+ export interface ProxyTimestampOptions extends PostTimestampOptions {
60
+ /** Base URL of the MindooDB server, e.g. `https://sync.example.com`. */
61
+ serverUrl: string;
62
+ tenantId: string;
63
+ /** Bearer token from the tenant's existing authenticated session. */
64
+ authToken: string;
65
+ /** Provider id from the server's advertised list. Never a URL — the server allowlists. */
66
+ providerId?: string;
67
+ }
68
+ /** Route through the tenant's MindooDB server, for http-only or CORS-less authorities. */
69
+ export declare function requestTimestampViaProxy(options: ProxyTimestampOptions): Promise<TimestampTokenResult>;
70
+ export interface TimestampWithFallbackOptions extends PostTimestampOptions {
71
+ /** Proxy details, when the client has an authenticated server connection. */
72
+ proxy?: Omit<ProxyTimestampOptions, keyof PostTimestampOptions>;
73
+ /** Try the proxy first — the right order when the tenant has a qualified provider configured. */
74
+ preferProxy?: boolean;
75
+ /** Skip the direct call (air-gapped deployments, or policy against third-party endpoints). */
76
+ allowDirect?: boolean;
77
+ }
78
+ /**
79
+ * Try both transports, returning the first token obtained.
80
+ *
81
+ * A seal is worth little without a timestamp, so failing over is worth the
82
+ * extra round trip. The order is caller-chosen because it is a policy question,
83
+ * not a technical one: a tenant with a qualified provider configured wants the
84
+ * proxy first, while a laptop with no server reachable wants the direct path.
85
+ */
86
+ export declare function requestTimestampWithFallback(options: TimestampWithFallbackOptions): Promise<TimestampTokenResult>;
87
+ export {};
88
+ //# sourceMappingURL=timestampClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timestampClient.d.ts","sourceRoot":"","sources":["../../../src/core/timestamps/timestampClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,4BAA4B,gCAAgC,CAAC;AAC1E,eAAO,MAAM,4BAA4B,gCAAgC,CAAC;AAE1E,oEAAoE;AACpE,eAAO,MAAM,4BAA4B,QAAa,CAAC;AACvD,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;EAIhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,yCAAyC;IACzC,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG5C,QAAQ,CAAC,MAAM,EAAE,eAAe;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM;gBAF5B,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,eAAe,EACvB,UAAU,CAAC,EAAE,MAAM,YAAA;CAK/B;AAED,UAAU,oBAAoB;IAC5B,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkED,wDAAwD;AACxD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,oBAAoB,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE,OAAO,CAAC,oBAAoB,CAAC,CAQ/B;AAED,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0FAA0F;AAC1F,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAe/B;AAED,MAAM,WAAW,4BAA6B,SAAQ,oBAAoB;IACxE,6EAA6E;IAC7E,KAAK,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,oBAAoB,CAAC,CAAC;IAChE,iGAAiG;IACjG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,oBAAoB,CAAC,CA+B/B"}
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ /**
3
+ * Client transport for RFC 3161 timestamps.
4
+ *
5
+ * Two paths, because no single one works everywhere:
6
+ *
7
+ * - **Direct.** `https://rfc3161.ai.moda` is the only public TSA measured to
8
+ * send CORS headers, so a browser can reach it unaided. This keeps sealing
9
+ * working on a Haven with no MindooDB server at all.
10
+ * - **Proxy.** Everything else is http-only or CORS-less — including every
11
+ * eIDAS-qualified authority — so those go through the tenant's server at
12
+ * `POST /:tenantId/timestamps/rfc3161`.
13
+ *
14
+ * Both carry opaque DER. **Neither is trusted.** The caller must verify that
15
+ * the returned token's `messageImprint` equals the digest it sent and that the
16
+ * token chains to a trusted root (see `verifyTimestampResponse` in
17
+ * `mindoodb-seal`). With those two checks a hostile transport can withhold a
18
+ * timestamp but cannot forge one, which is why calling a third-party proxy from
19
+ * the browser is acceptable at all.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.TimestampRequestError = exports.BROWSER_REACHABLE_TSA = exports.DEFAULT_TIMESTAMP_TIMEOUT_MS = exports.MAX_TIMESTAMP_RESPONSE_BYTES = exports.TIMESTAMP_REPLY_CONTENT_TYPE = exports.TIMESTAMP_QUERY_CONTENT_TYPE = void 0;
23
+ exports.requestTimestampDirect = requestTimestampDirect;
24
+ exports.requestTimestampViaProxy = requestTimestampViaProxy;
25
+ exports.requestTimestampWithFallback = requestTimestampWithFallback;
26
+ exports.TIMESTAMP_QUERY_CONTENT_TYPE = "application/timestamp-query";
27
+ exports.TIMESTAMP_REPLY_CONTENT_TYPE = "application/timestamp-reply";
28
+ /** Bound on an accepted TimeStampResp; real tokens are a few KB. */
29
+ exports.MAX_TIMESTAMP_RESPONSE_BYTES = 128 * 1024;
30
+ exports.DEFAULT_TIMESTAMP_TIMEOUT_MS = 15000;
31
+ /**
32
+ * The one public TSA a browser can call directly (verified by CORS preflight:
33
+ * reflected origin, `POST, OPTIONS`, `Content-Type`). It is a failover proxy in
34
+ * front of DigiCert, Sectigo, Azure and others, so its tokens chain to roots
35
+ * already in public trust stores.
36
+ */
37
+ exports.BROWSER_REACHABLE_TSA = Object.freeze({
38
+ id: "aimoda",
39
+ name: "ai.moda RFC 3161 proxy",
40
+ url: "https://rfc3161.ai.moda",
41
+ });
42
+ class TimestampRequestError extends Error {
43
+ constructor(message, source, httpStatus) {
44
+ super(message);
45
+ this.source = source;
46
+ this.httpStatus = httpStatus;
47
+ this.name = "TimestampRequestError";
48
+ }
49
+ }
50
+ exports.TimestampRequestError = TimestampRequestError;
51
+ async function postTimestampQuery(url, source, options) {
52
+ const { request, timeoutMs = exports.DEFAULT_TIMESTAMP_TIMEOUT_MS, fetchImpl = fetch, maxResponseBytes = exports.MAX_TIMESTAMP_RESPONSE_BYTES, headers = {}, } = options;
53
+ const controller = new AbortController();
54
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
55
+ try {
56
+ const response = await fetchImpl(url, {
57
+ method: "POST",
58
+ headers: {
59
+ "content-type": exports.TIMESTAMP_QUERY_CONTENT_TYPE,
60
+ accept: exports.TIMESTAMP_REPLY_CONTENT_TYPE,
61
+ ...headers,
62
+ },
63
+ body: request.slice().buffer,
64
+ signal: controller.signal,
65
+ });
66
+ if (!response.ok) {
67
+ throw new TimestampRequestError(`Timestamp request failed with HTTP ${response.status}`, source, response.status);
68
+ }
69
+ const buffer = new Uint8Array(await response.arrayBuffer());
70
+ if (buffer.byteLength === 0) {
71
+ throw new TimestampRequestError("Timestamp authority returned an empty response", source);
72
+ }
73
+ if (buffer.byteLength > maxResponseBytes) {
74
+ throw new TimestampRequestError(`Timestamp response too large (${buffer.byteLength} bytes)`, source);
75
+ }
76
+ // Cheap sanity check; the real validation is CMS verification by the caller.
77
+ if (buffer[0] !== 0x30) {
78
+ throw new TimestampRequestError("Timestamp response is not DER-encoded", source);
79
+ }
80
+ return buffer;
81
+ }
82
+ catch (error) {
83
+ if (error instanceof TimestampRequestError)
84
+ throw error;
85
+ if (error instanceof Error && error.name === "AbortError") {
86
+ throw new TimestampRequestError(`Timestamp request timed out after ${timeoutMs}ms`, source);
87
+ }
88
+ throw new TimestampRequestError(`Timestamp request failed: ${error instanceof Error ? error.message : String(error)}`, source);
89
+ }
90
+ finally {
91
+ clearTimeout(timer);
92
+ }
93
+ }
94
+ /** Call a CORS-enabled TSA straight from the client. */
95
+ async function requestTimestampDirect(options) {
96
+ const url = options.url ?? exports.BROWSER_REACHABLE_TSA.url;
97
+ const response = await postTimestampQuery(url, "direct", options);
98
+ return {
99
+ response,
100
+ providerId: options.providerId ?? exports.BROWSER_REACHABLE_TSA.id,
101
+ source: "direct",
102
+ };
103
+ }
104
+ /** Route through the tenant's MindooDB server, for http-only or CORS-less authorities. */
105
+ async function requestTimestampViaProxy(options) {
106
+ const base = options.serverUrl.replace(/\/+$/, "");
107
+ const query = options.providerId ? `?provider=${encodeURIComponent(options.providerId)}` : "";
108
+ const url = `${base}/${encodeURIComponent(options.tenantId)}/timestamps/rfc3161${query}`;
109
+ const response = await postTimestampQuery(url, "proxy", {
110
+ ...options,
111
+ headers: { authorization: `Bearer ${options.authToken}` },
112
+ });
113
+ return {
114
+ response,
115
+ providerId: options.providerId ?? "server",
116
+ source: "proxy",
117
+ };
118
+ }
119
+ /**
120
+ * Try both transports, returning the first token obtained.
121
+ *
122
+ * A seal is worth little without a timestamp, so failing over is worth the
123
+ * extra round trip. The order is caller-chosen because it is a policy question,
124
+ * not a technical one: a tenant with a qualified provider configured wants the
125
+ * proxy first, while a laptop with no server reachable wants the direct path.
126
+ */
127
+ async function requestTimestampWithFallback(options) {
128
+ const { proxy, preferProxy = false, allowDirect = true, ...post } = options;
129
+ const attempts = [];
130
+ const direct = () => requestTimestampDirect(post);
131
+ const viaProxy = proxy ? () => requestTimestampViaProxy({ ...proxy, ...post }) : undefined;
132
+ if (preferProxy && viaProxy) {
133
+ attempts.push(viaProxy);
134
+ if (allowDirect)
135
+ attempts.push(direct);
136
+ }
137
+ else {
138
+ if (allowDirect)
139
+ attempts.push(direct);
140
+ if (viaProxy)
141
+ attempts.push(viaProxy);
142
+ }
143
+ if (attempts.length === 0) {
144
+ throw new TimestampRequestError("No timestamp transport is available", "direct");
145
+ }
146
+ const errors = [];
147
+ for (const attempt of attempts) {
148
+ try {
149
+ return await attempt();
150
+ }
151
+ catch (error) {
152
+ errors.push(error instanceof Error ? error.message : String(error));
153
+ }
154
+ }
155
+ throw new TimestampRequestError(`No timestamp authority could be reached (${errors.join("; ")})`, "direct");
156
+ }
157
+ //# sourceMappingURL=timestampClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timestampClient.js","sourceRoot":"","sources":["../../../src/core/timestamps/timestampClient.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,8 @@ import type { PublicUserId, PrivateUserId } from "./userid";
4
4
  import { StoreKind } from "./appendonlystores/types";
5
5
  import type { ContentAddressedStore, OpenStoreOptions, RejectedPutEntry } from "./appendonlystores/types";
6
6
  import type { CryptoAdapter } from "./crypto/CryptoAdapter";
7
+ import type { EntryProvenance } from "./crypto/EntrySignature";
8
+ import type { CopyDocumentOptions, CopyDocumentResult, CopyDocumentSelector, CopyDocumentsOptions, CopyDocumentsResult, CopyFeasibility } from "./copy/types";
7
9
  import { MindooDocSigner } from "./crypto/MindooDocSigner";
8
10
  import type { DefaultAccessPolicyDoc, KeyDistributionPushRecipient, KeyDistributionRequest, KeyDistributionView, KeyVersionRef, AppDistributionRequest, AppDistributionView, AppDistributionReconcilePlan, SyncSetupPolicyRequest, SyncSetupPolicyView, SyncSetupPolicyReconcilePlan, DocHistoryPurgeRequest, DocHistoryPurgeView, RuleTargets, RuleType, WithFieldClause, AclRuleDoc, AccessDecision } from "./accesscontrol/types";
9
11
  import type { DirectoryStateNode } from "./accesscontrol/DirectoryStateNode";
@@ -633,6 +635,28 @@ export interface MindooTenant {
633
635
  * @return The signature (Ed25519 signature as Uint8Array)
634
636
  */
635
637
  signPayloadWithKey(payload: Uint8Array, signingKeyPair: SigningKeyPair, password: string): Promise<Uint8Array>;
638
+ /**
639
+ * Sign application-supplied bytes under an allowlisted domain, signing
640
+ * `utf8(domain) || 0x00 || statement`.
641
+ *
642
+ * The only sanctioned way to have the identity key sign content an
643
+ * application chose. The domain prefix keeps such bytes disjoint from the
644
+ * store-entry and auth-challenge layouts, so a signature obtained here cannot
645
+ * be replayed as either (see `crypto/DomainStatement.ts`).
646
+ *
647
+ * @param domain One of `SIGNING_DOMAINS`; anything else is rejected.
648
+ * @param statement Canonical statement bytes.
649
+ * @return The Ed25519 signature over the domain-prefixed bytes.
650
+ */
651
+ signDomainStatement(domain: string, statement: Uint8Array): Promise<Uint8Array>;
652
+ /**
653
+ * Verify a domain-separated statement signature against a named public key.
654
+ *
655
+ * Does not consult the directory: whether that key is *currently trusted* is
656
+ * a separate question from whether it made this signature, and an evidence
657
+ * verifier legitimately asks only the second one.
658
+ */
659
+ verifyDomainStatement(domain: string, statement: Uint8Array, signature: Uint8Array, publicKeyPem: string): Promise<boolean>;
636
660
  /**
637
661
  * Verify a signature for a payload with a public key.
638
662
  *
@@ -962,6 +986,21 @@ export interface StoreEntryMetadata {
962
986
  * fall back to {@link signature} when it is missing (backward compatible).
963
987
  */
964
988
  metadataSignature?: Uint8Array;
989
+ /**
990
+ * Set on entries produced by copying a document into another database with
991
+ * `mode: "history"` and re-authored signatures (see `copyDocumentTo`). Records
992
+ * where the entry came from and who originally authored it, in a form a reader
993
+ * can verify rather than merely trust.
994
+ *
995
+ * Bound into {@link metadataSignature} as a tagged trailing block (see
996
+ * `crypto/EntrySignature.ts`), so a relay can neither attach, strip nor rewrite
997
+ * it. Absent on every entry that is not the product of such a copy, in which
998
+ * case the signing input is byte-identical to the original layout.
999
+ *
1000
+ * Plain JSON by design (the signature inside is base64) so it survives the
1001
+ * on-disk, IndexedDB and network serializers without per-field binary handling.
1002
+ */
1003
+ provenance?: EntryProvenance;
965
1004
  /**
966
1005
  * Original size of the plaintext data before encryption (in bytes).
967
1006
  * For doc_* entries: size of the Automerge binary change/snapshot
@@ -3012,6 +3051,16 @@ export interface DocumentHistoryResult {
3012
3051
  * The public signing key of the user who created this change (Ed25519, PEM format).
3013
3052
  */
3014
3053
  changeCreatedByPublicKey: string;
3054
+ /**
3055
+ * Parent DAG entry ids of this change — the edges of the signed change graph,
3056
+ * and the heads to pass to {@link MindooDB.materializeDocumentAtHeads} to get
3057
+ * the state this change was written against.
3058
+ *
3059
+ * More than one id means the change merged concurrent branches. Ids may point
3060
+ * at entries this generator never yields, because a change whose payload left
3061
+ * the Automerge heads untouched produces no new state to report.
3062
+ */
3063
+ changeDependencyIds: string[];
3015
3064
  }
3016
3065
  /**
3017
3066
  * Resumable position in a revision-grain changefeed
@@ -3179,7 +3228,7 @@ export interface PerformanceCallback {
3179
3228
  * Called for bounded history/time-travel workflows.
3180
3229
  */
3181
3230
  onHistoryOperation?: (metrics: {
3182
- operation: 'getDocumentAtTimestamp' | 'getDocumentHistoryPage' | 'analyzeDocumentDagAtTimestamp' | 'materializeDocumentBranchAtEntry' | 'materializeDocumentBranchAtTimestamp' | 'describeDocumentDagEntry' | 'analyzeDocumentConflicts' | 'getDocumentConflictReport' | 'getDocumentConflictBaseValues';
3231
+ operation: 'getDocumentAtTimestamp' | 'getDocumentHistoryPage' | 'analyzeDocumentDagAtTimestamp' | 'materializeDocumentBranchAtEntry' | 'materializeDocumentBranchAtTimestamp' | 'materializeDocumentAtHeads' | 'describeDocumentDagEntry' | 'analyzeDocumentConflicts' | 'getDocumentConflictReport' | 'getDocumentConflictBaseValues';
3183
3232
  docId: string;
3184
3233
  time: number;
3185
3234
  scannedEntries: number;
@@ -3493,6 +3542,12 @@ export interface DocumentDagBranchMaterializationResult {
3493
3542
  entryIdsApplied: string[];
3494
3543
  branchEntryIds: string[];
3495
3544
  doc: MindooDoc;
3545
+ /**
3546
+ * All heads this state was replayed from, set by
3547
+ * {@link MindooDB.materializeDocumentAtHeads}. Single-head materialization
3548
+ * leaves it undefined; `headEntryId` is then the only head.
3549
+ */
3550
+ headEntryIds?: string[];
3496
3551
  }
3497
3552
  /**
3498
3553
  * Progress information emitted during pull/push sync operations.
@@ -3841,6 +3896,17 @@ export interface MindooDB {
3841
3896
  * time-bounded DAG slice.
3842
3897
  */
3843
3898
  materializeDocumentBranchAtTimestamp(docId: string, timestamp: DocumentDagAnalysisTimestamp, headEntryId: string): Promise<DocumentDagBranchMaterializationResult | null>;
3899
+ /**
3900
+ * Reconstruct the document state at a set of concurrent heads: the Automerge
3901
+ * multi-head document formed by replaying the union of those heads' ancestor
3902
+ * closures, with no descendant applied.
3903
+ *
3904
+ * Passing an entry's `dependencyIds` therefore yields the state the writer saw
3905
+ * right before that entry — one "before" image even when the entry merges
3906
+ * several parents. Unknown heads are ignored; when no head resolves (or the
3907
+ * list is empty) the result is `null`, meaning the document did not exist yet.
3908
+ */
3909
+ materializeDocumentAtHeads(docId: string, headEntryIds: string[]): Promise<DocumentDagBranchMaterializationResult | null>;
3844
3910
  /**
3845
3911
  * Decode and summarize one DAG entry for hover/tooling use cases.
3846
3912
  */
@@ -4378,6 +4444,57 @@ export interface MindooDB {
4378
4444
  * call.
4379
4445
  */
4380
4446
  getBackgroundWarmerProgress?(): BackgroundWarmerProgress | null;
4447
+ /**
4448
+ * Copy one document into another database, either flattened to a single
4449
+ * revision or with its full revision history.
4450
+ *
4451
+ * Unlike {@link pullChangesFrom} / {@link pushChangesTo}, which replicate one
4452
+ * database between peers, this moves content ACROSS databases — and, with
4453
+ * `signingKeyPair` unset and the right options, across tenants too.
4454
+ *
4455
+ * The default is a flattened copy under a freshly generated document id,
4456
+ * authored by the current user. `mode: "history"` carries the whole revision
4457
+ * graph instead; adding `targetDocId: "same"` and `authorship: "preserve"`
4458
+ * (only legal within one tenant, under the same encryption key, into a
4459
+ * different database) keeps the original signers' signatures valid, which is
4460
+ * what makes {@link copyDocumentsTo} usable as a sharding tool.
4461
+ *
4462
+ * See `docs/document-copy.md` for the full strategy matrix and caveats.
4463
+ *
4464
+ * @param docId The document to copy.
4465
+ * @param target The database to copy into.
4466
+ * @param options See {@link CopyDocumentOptions}.
4467
+ * @return What was copied, including the resulting target document id.
4468
+ */
4469
+ copyDocumentTo(docId: string, target: MindooDB, options?: CopyDocumentOptions): Promise<CopyDocumentResult>;
4470
+ /**
4471
+ * Report what {@link copyDocumentTo} would do with these options, without
4472
+ * writing anything: the strategy it would use, whether the original authors'
4473
+ * signatures would survive, whether it would merge into an existing document,
4474
+ * and — via `reasons` — why not, when the answer is no.
4475
+ *
4476
+ * @param docId The document that would be copied.
4477
+ * @param target The database it would be copied into.
4478
+ * @param options The same options that would be passed to {@link copyDocumentTo}.
4479
+ */
4480
+ canCopyDocumentTo(docId: string, target: MindooDB, options?: CopyDocumentOptions): Promise<CopyFeasibility>;
4481
+ /**
4482
+ * Copy many documents into another database in one pass.
4483
+ *
4484
+ * With `mode: "history"`, `targetDocId: "same"` and `authorship: "preserve"`
4485
+ * this splits a database into shards with document ids, full history and
4486
+ * original signers intact, without decrypting or re-signing anything.
4487
+ * Repeated runs transfer only the delta, so a shard can proceed while users
4488
+ * keep working; see the migration playbook in `docs/document-copy.md`.
4489
+ *
4490
+ * A failure on one document does not abort the run — failures are collected
4491
+ * in {@link CopyDocumentsResult.failed}.
4492
+ *
4493
+ * @param selector Which documents to copy: explicit ids, id prefixes, or both.
4494
+ * @param target The database to copy into.
4495
+ * @param options See {@link CopyDocumentsOptions}.
4496
+ */
4497
+ copyDocumentsTo(selector: CopyDocumentSelector, target: MindooDB, options?: CopyDocumentsOptions): Promise<CopyDocumentsResult>;
4381
4498
  /**
4382
4499
  * Pull changes from a remote content-addressed store or another MindooDB instance.
4383
4500
  *