mindoodb 0.0.34 → 0.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +37 -3
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +158 -4
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.d.ts +54 -3
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.js +344 -17
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +39 -2
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +93 -11
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts +9 -1
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts.map +1 -1
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js +27 -0
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js.map +1 -1
- package/dist/browser/index.mjs +7 -0
- package/dist/core/BaseMindooDB.d.ts +112 -9
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +678 -153
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +31 -0
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +132 -3
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.js +4 -3
- package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantFactory.js +2 -1
- package/dist/core/BaseMindooTenantFactory.js.map +1 -1
- package/dist/core/DocumentDagAnalysis.d.ts +39 -0
- package/dist/core/DocumentDagAnalysis.d.ts.map +1 -1
- package/dist/core/DocumentDagAnalysis.js +147 -3
- package/dist/core/DocumentDagAnalysis.js.map +1 -1
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts +7 -1
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js +15 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js.map +1 -1
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts +55 -6
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/binaryEntryFraming.d.ts +58 -0
- package/dist/core/appendonlystores/network/binaryEntryFraming.d.ts.map +1 -0
- package/dist/core/appendonlystores/network/binaryEntryFraming.js +121 -0
- package/dist/core/appendonlystores/network/binaryEntryFraming.js.map +1 -0
- package/dist/core/appendonlystores/network/types.d.ts +68 -0
- package/dist/core/appendonlystores/network/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/types.js.map +1 -1
- package/dist/core/appendonlystores/types.d.ts +58 -1
- package/dist/core/appendonlystores/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/types.js.map +1 -1
- package/dist/core/crypto/RSAEncryption.d.ts +11 -0
- package/dist/core/crypto/RSAEncryption.d.ts.map +1 -1
- package/dist/core/crypto/RSAEncryption.js +25 -0
- package/dist/core/crypto/RSAEncryption.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +8 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/types.d.ts +157 -8
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +9 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/utils/idGeneration.d.ts +52 -0
- package/dist/core/utils/idGeneration.d.ts.map +1 -1
- package/dist/core/utils/idGeneration.js +78 -1
- package/dist/core/utils/idGeneration.js.map +1 -1
- package/dist/core/utils/index.d.ts +2 -1
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core/utils/index.js +8 -1
- package/dist/core/utils/index.js.map +1 -1
- package/dist/core/utils/timeSource.d.ts +34 -0
- package/dist/core/utils/timeSource.d.ts.map +1 -0
- package/dist/core/utils/timeSource.js +49 -0
- package/dist/core/utils/timeSource.js.map +1 -0
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts +17 -1
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +1 -1
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js +43 -0
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js.map +1 -1
- package/dist/node/server/MindooDBServer.d.ts +38 -0
- package/dist/node/server/MindooDBServer.d.ts.map +1 -1
- package/dist/node/server/MindooDBServer.js +262 -6
- package/dist/node/server/MindooDBServer.js.map +1 -1
- package/dist/node/server/SyncEventBus.d.ts +29 -0
- package/dist/node/server/SyncEventBus.d.ts.map +1 -0
- package/dist/node/server/SyncEventBus.js +41 -0
- package/dist/node/server/SyncEventBus.js.map +1 -0
- package/dist/node/server/compressionMiddleware.d.ts +25 -0
- package/dist/node/server/compressionMiddleware.d.ts.map +1 -0
- package/dist/node/server/compressionMiddleware.js +140 -0
- package/dist/node/server/compressionMiddleware.js.map +1 -0
- package/package.json +2 -3
|
@@ -9,9 +9,12 @@
|
|
|
9
9
|
* - Blockchain-like integrity for document entries
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.generateDocId = generateDocId;
|
|
13
|
+
exports.matchesDocIdPrefix = matchesDocIdPrefix;
|
|
12
14
|
exports.generateDocEntryId = generateDocEntryId;
|
|
13
15
|
exports.generateDepsFingerprint = generateDepsFingerprint;
|
|
14
16
|
exports.generateAttachmentChunkId = generateAttachmentChunkId;
|
|
17
|
+
exports.generateUniqueAttachmentChunkId = generateUniqueAttachmentChunkId;
|
|
15
18
|
exports.generateFileUuid7 = generateFileUuid7;
|
|
16
19
|
exports.generateChunkUuid7 = generateChunkUuid7;
|
|
17
20
|
exports.parseDocEntryId = parseDocEntryId;
|
|
@@ -21,7 +24,13 @@ exports.isAttachmentChunkId = isAttachmentChunkId;
|
|
|
21
24
|
exports.extractDocIdFromEntryId = extractDocIdFromEntryId;
|
|
22
25
|
exports.computeContentHash = computeContentHash;
|
|
23
26
|
const uuid_1 = require("uuid");
|
|
24
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Base62 alphabet in ASCII order (digits < uppercase < lowercase). The order
|
|
29
|
+
* matters: fixed-length, left-zero-padded encodings of numerically increasing
|
|
30
|
+
* values (e.g. UUID7 timestamps) then sort chronologically under plain
|
|
31
|
+
* lexicographic string comparison. Do NOT reorder.
|
|
32
|
+
*/
|
|
33
|
+
const BASE62_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
25
34
|
const UUID_NO_DASH_LENGTH = 32;
|
|
26
35
|
const BASE62_UUID_LENGTH = 22;
|
|
27
36
|
function trimLeft(target, length) {
|
|
@@ -57,6 +66,46 @@ function hexToBase62(uuid) {
|
|
|
57
66
|
}
|
|
58
67
|
return ensureLength(encoded, BASE62_UUID_LENGTH);
|
|
59
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Generate a fresh, globally unique document id: a UUID7 encoded as a
|
|
71
|
+
* fixed-length (22 char), left-zero-padded base62 string, optionally prefixed
|
|
72
|
+
* with `<prefix>_`.
|
|
73
|
+
*
|
|
74
|
+
* Because the UUID7 timestamp occupies the most significant bits and the
|
|
75
|
+
* base62 alphabet is in ASCII order, ids generated later sort lexicographically
|
|
76
|
+
* after ids generated earlier (within the same prefix) — same property as raw
|
|
77
|
+
* UUID7 strings, but 14 characters shorter.
|
|
78
|
+
*
|
|
79
|
+
* The prefix (if any) is NOT validated here; callers validate it against
|
|
80
|
+
* `DOC_ID_PREFIX_REGEX` before invoking this.
|
|
81
|
+
*
|
|
82
|
+
* @param prefix Optional short application prefix (e.g. "cls"); joined with "_".
|
|
83
|
+
* @returns e.g. "0BqXa9yTFn2M4kVzR1sWpq" or "cls_0BqXa9yTFn2M4kVzR1sWpq"
|
|
84
|
+
*/
|
|
85
|
+
function generateDocId(prefix) {
|
|
86
|
+
const encoded = hexToBase62((0, uuid_1.v7)());
|
|
87
|
+
return prefix ? `${prefix}_${encoded}` : encoded;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Boundary-aware document-id prefix match used by prefix-filtered listing and
|
|
91
|
+
* changefeed iteration.
|
|
92
|
+
*
|
|
93
|
+
* A `docId` matches `idPrefix` when it either equals the prefix exactly or
|
|
94
|
+
* begins with `<idPrefix>_`. Matching on the `_` boundary (rather than a raw
|
|
95
|
+
* `startsWith`) mirrors the `<prefix>_<base62>` id scheme, so filtering by
|
|
96
|
+
* `"cls"` returns `cls_…` documents without also catching an unrelated prefix
|
|
97
|
+
* like `classroom_…`.
|
|
98
|
+
*
|
|
99
|
+
* An empty `idPrefix` matches every id (i.e. "no filter").
|
|
100
|
+
*
|
|
101
|
+
* @param docId The document id to test.
|
|
102
|
+
* @param idPrefix The prefix to match (without the trailing `_`).
|
|
103
|
+
*/
|
|
104
|
+
function matchesDocIdPrefix(docId, idPrefix) {
|
|
105
|
+
if (idPrefix.length === 0)
|
|
106
|
+
return true;
|
|
107
|
+
return docId === idPrefix || docId.startsWith(`${idPrefix}_`);
|
|
108
|
+
}
|
|
60
109
|
/**
|
|
61
110
|
* Generate a document entry ID with blockchain-like chaining.
|
|
62
111
|
* Format: <docId>_d_<depsFingerprint>_<automergeHash>
|
|
@@ -109,6 +158,34 @@ function generateAttachmentChunkId(docId, fileUuid7, chunkUuid7) {
|
|
|
109
158
|
const base62Chunk = hexToBase62(chunkId);
|
|
110
159
|
return `${docId}_a_${fileUuid7}_${base62Chunk}`;
|
|
111
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate an attachment chunk id that is unique within one write operation
|
|
163
|
+
* even under case-insensitive comparison.
|
|
164
|
+
*
|
|
165
|
+
* Chunk entry ids become on-disk filenames (`entries/<id>.json`) and — unlike
|
|
166
|
+
* document entry ids — contain no lowercase-hex hash component, so two chunk
|
|
167
|
+
* ids differing only in the case of their base62 part would collide on
|
|
168
|
+
* case-insensitive filesystems (APFS/NTFS). The caller passes a set of
|
|
169
|
+
* case-folded ids already used in the current write; on the (astronomically
|
|
170
|
+
* unlikely) fold-collision the id is simply regenerated. The set is expected
|
|
171
|
+
* to be scoped to a single attachment write, so there is no persistent cost.
|
|
172
|
+
*
|
|
173
|
+
* @param docId The document ID this attachment belongs to
|
|
174
|
+
* @param fileUuid7 The UUID7 for the whole file (same for all chunks)
|
|
175
|
+
* @param usedCaseFoldedIds Case-folded ids already used in this write; the
|
|
176
|
+
* returned id's folded form is added to the set.
|
|
177
|
+
* @returns The generated chunk ID
|
|
178
|
+
*/
|
|
179
|
+
function generateUniqueAttachmentChunkId(docId, fileUuid7, usedCaseFoldedIds) {
|
|
180
|
+
for (;;) {
|
|
181
|
+
const id = generateAttachmentChunkId(docId, fileUuid7);
|
|
182
|
+
const folded = id.toLowerCase();
|
|
183
|
+
if (!usedCaseFoldedIds.has(folded)) {
|
|
184
|
+
usedCaseFoldedIds.add(folded);
|
|
185
|
+
return id;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
112
189
|
/**
|
|
113
190
|
* Generate a new file UUID7.
|
|
114
191
|
* This should be called once per file and reused for all chunks of that file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idGeneration.js","sourceRoot":"","sources":["../../../src/core/utils/idGeneration.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;
|
|
1
|
+
{"version":3,"file":"idGeneration.js","sourceRoot":"","sources":["../../../src/core/utils/idGeneration.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core utility functions for MindooDB.
|
|
3
3
|
*/
|
|
4
|
-
export { generateDocEntryId, generateDepsFingerprint, generateAttachmentChunkId, generateFileUuid7, generateChunkUuid7, parseDocEntryId, parseAttachmentChunkId, isDocEntryId, isAttachmentChunkId, extractDocIdFromEntryId, computeContentHash, } from './idGeneration';
|
|
4
|
+
export { generateDocId, matchesDocIdPrefix, generateDocEntryId, generateDepsFingerprint, generateAttachmentChunkId, generateUniqueAttachmentChunkId, generateFileUuid7, generateChunkUuid7, parseDocEntryId, parseAttachmentChunkId, isDocEntryId, isAttachmentChunkId, extractDocIdFromEntryId, computeContentHash, } from './idGeneration';
|
|
5
|
+
export { semanticNow, setSemanticTimeSourceForTesting, createQuantizedTimeSource, } from './timeSource';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,EACzB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,YAAY,EACZ,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,EACzB,+BAA+B,EAC/B,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,YAAY,EACZ,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,WAAW,EACX,+BAA+B,EAC/B,yBAAyB,GAC1B,MAAM,cAAc,CAAC"}
|
package/dist/core/utils/index.js
CHANGED
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
* Core utility functions for MindooDB.
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.computeContentHash = exports.extractDocIdFromEntryId = exports.isAttachmentChunkId = exports.isDocEntryId = exports.parseAttachmentChunkId = exports.parseDocEntryId = exports.generateChunkUuid7 = exports.generateFileUuid7 = exports.generateAttachmentChunkId = exports.generateDepsFingerprint = exports.generateDocEntryId = void 0;
|
|
6
|
+
exports.createQuantizedTimeSource = exports.setSemanticTimeSourceForTesting = exports.semanticNow = exports.computeContentHash = exports.extractDocIdFromEntryId = exports.isAttachmentChunkId = exports.isDocEntryId = exports.parseAttachmentChunkId = exports.parseDocEntryId = exports.generateChunkUuid7 = exports.generateFileUuid7 = exports.generateUniqueAttachmentChunkId = exports.generateAttachmentChunkId = exports.generateDepsFingerprint = exports.generateDocEntryId = exports.matchesDocIdPrefix = exports.generateDocId = void 0;
|
|
7
7
|
var idGeneration_1 = require("./idGeneration");
|
|
8
|
+
Object.defineProperty(exports, "generateDocId", { enumerable: true, get: function () { return idGeneration_1.generateDocId; } });
|
|
9
|
+
Object.defineProperty(exports, "matchesDocIdPrefix", { enumerable: true, get: function () { return idGeneration_1.matchesDocIdPrefix; } });
|
|
8
10
|
Object.defineProperty(exports, "generateDocEntryId", { enumerable: true, get: function () { return idGeneration_1.generateDocEntryId; } });
|
|
9
11
|
Object.defineProperty(exports, "generateDepsFingerprint", { enumerable: true, get: function () { return idGeneration_1.generateDepsFingerprint; } });
|
|
10
12
|
Object.defineProperty(exports, "generateAttachmentChunkId", { enumerable: true, get: function () { return idGeneration_1.generateAttachmentChunkId; } });
|
|
13
|
+
Object.defineProperty(exports, "generateUniqueAttachmentChunkId", { enumerable: true, get: function () { return idGeneration_1.generateUniqueAttachmentChunkId; } });
|
|
11
14
|
Object.defineProperty(exports, "generateFileUuid7", { enumerable: true, get: function () { return idGeneration_1.generateFileUuid7; } });
|
|
12
15
|
Object.defineProperty(exports, "generateChunkUuid7", { enumerable: true, get: function () { return idGeneration_1.generateChunkUuid7; } });
|
|
13
16
|
Object.defineProperty(exports, "parseDocEntryId", { enumerable: true, get: function () { return idGeneration_1.parseDocEntryId; } });
|
|
@@ -16,4 +19,8 @@ Object.defineProperty(exports, "isDocEntryId", { enumerable: true, get: function
|
|
|
16
19
|
Object.defineProperty(exports, "isAttachmentChunkId", { enumerable: true, get: function () { return idGeneration_1.isAttachmentChunkId; } });
|
|
17
20
|
Object.defineProperty(exports, "extractDocIdFromEntryId", { enumerable: true, get: function () { return idGeneration_1.extractDocIdFromEntryId; } });
|
|
18
21
|
Object.defineProperty(exports, "computeContentHash", { enumerable: true, get: function () { return idGeneration_1.computeContentHash; } });
|
|
22
|
+
var timeSource_1 = require("./timeSource");
|
|
23
|
+
Object.defineProperty(exports, "semanticNow", { enumerable: true, get: function () { return timeSource_1.semanticNow; } });
|
|
24
|
+
Object.defineProperty(exports, "setSemanticTimeSourceForTesting", { enumerable: true, get: function () { return timeSource_1.setSemanticTimeSourceForTesting; } });
|
|
25
|
+
Object.defineProperty(exports, "createQuantizedTimeSource", { enumerable: true, get: function () { return timeSource_1.createQuantizedTimeSource; } });
|
|
19
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/utils/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/utils/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,+CAewB;AAdtB,6GAAA,aAAa,OAAA;AACb,kHAAA,kBAAkB,OAAA;AAClB,kHAAA,kBAAkB,OAAA;AAClB,uHAAA,uBAAuB,OAAA;AACvB,yHAAA,yBAAyB,OAAA;AACzB,+HAAA,+BAA+B,OAAA;AAC/B,iHAAA,iBAAiB,OAAA;AACjB,kHAAA,kBAAkB,OAAA;AAClB,+GAAA,eAAe,OAAA;AACf,sHAAA,sBAAsB,OAAA;AACtB,4GAAA,YAAY,OAAA;AACZ,mHAAA,mBAAmB,OAAA;AACnB,uHAAA,uBAAuB,OAAA;AACvB,kHAAA,kBAAkB,OAAA;AAGpB,2CAIsB;AAHpB,yGAAA,WAAW,OAAA;AACX,6HAAA,+BAA+B,OAAA;AAC/B,uHAAA,yBAAyB,OAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic time source for MindooDB.
|
|
3
|
+
*
|
|
4
|
+
* Every timestamp that becomes part of persisted or user-visible state —
|
|
5
|
+
* store-entry `createdAt`, document `lastModified`/`_lastModified`, the
|
|
6
|
+
* provisional trusted-time "now" for un-witnessed entries, audit records —
|
|
7
|
+
* must come from {@link semanticNow} instead of calling `Date.now()`
|
|
8
|
+
* directly. Pure elapsed-time measurements (performance metrics, event-loop
|
|
9
|
+
* pacing, in-memory cache TTLs) intentionally keep using `Date.now()`.
|
|
10
|
+
*
|
|
11
|
+
* Why a single funnel:
|
|
12
|
+
* - Tests can pin or quantize the clock (see
|
|
13
|
+
* {@link createQuantizedTimeSource}) to make same-millisecond timestamp
|
|
14
|
+
* ties deterministic instead of rare — surfacing tie-handling bugs that
|
|
15
|
+
* otherwise appear as flaky failures.
|
|
16
|
+
* - It is the seam for upgrading the timestamp scheme later (e.g. a hybrid
|
|
17
|
+
* logical clock that can never tie or run backwards): only this module
|
|
18
|
+
* would change, not every call site.
|
|
19
|
+
*/
|
|
20
|
+
/** Current semantic time in ms since epoch (wall clock unless overridden). */
|
|
21
|
+
export declare function semanticNow(): number;
|
|
22
|
+
/**
|
|
23
|
+
* Install (or remove, with `null`) a test-only override for
|
|
24
|
+
* {@link semanticNow}. Not intended for production use.
|
|
25
|
+
*/
|
|
26
|
+
export declare function setSemanticTimeSourceForTesting(fn: (() => number) | null): void;
|
|
27
|
+
/**
|
|
28
|
+
* A time source that floors the wall clock to `quantumMs` buckets. Time
|
|
29
|
+
* still advances (timeouts/cooldowns keep working), but all semantic
|
|
30
|
+
* timestamps produced within one quantum collide — making timestamp-tie
|
|
31
|
+
* hazards deterministic for stress testing.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createQuantizedTimeSource(quantumMs: number): () => number;
|
|
34
|
+
//# sourceMappingURL=timeSource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeSource.d.ts","sourceRoot":"","sources":["../../../src/core/utils/timeSource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,8EAA8E;AAC9E,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,EAAE,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAE/E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,MAAM,CAKzE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Semantic time source for MindooDB.
|
|
4
|
+
*
|
|
5
|
+
* Every timestamp that becomes part of persisted or user-visible state —
|
|
6
|
+
* store-entry `createdAt`, document `lastModified`/`_lastModified`, the
|
|
7
|
+
* provisional trusted-time "now" for un-witnessed entries, audit records —
|
|
8
|
+
* must come from {@link semanticNow} instead of calling `Date.now()`
|
|
9
|
+
* directly. Pure elapsed-time measurements (performance metrics, event-loop
|
|
10
|
+
* pacing, in-memory cache TTLs) intentionally keep using `Date.now()`.
|
|
11
|
+
*
|
|
12
|
+
* Why a single funnel:
|
|
13
|
+
* - Tests can pin or quantize the clock (see
|
|
14
|
+
* {@link createQuantizedTimeSource}) to make same-millisecond timestamp
|
|
15
|
+
* ties deterministic instead of rare — surfacing tie-handling bugs that
|
|
16
|
+
* otherwise appear as flaky failures.
|
|
17
|
+
* - It is the seam for upgrading the timestamp scheme later (e.g. a hybrid
|
|
18
|
+
* logical clock that can never tie or run backwards): only this module
|
|
19
|
+
* would change, not every call site.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.semanticNow = semanticNow;
|
|
23
|
+
exports.setSemanticTimeSourceForTesting = setSemanticTimeSourceForTesting;
|
|
24
|
+
exports.createQuantizedTimeSource = createQuantizedTimeSource;
|
|
25
|
+
let overrideFn = null;
|
|
26
|
+
/** Current semantic time in ms since epoch (wall clock unless overridden). */
|
|
27
|
+
function semanticNow() {
|
|
28
|
+
return overrideFn ? overrideFn() : Date.now();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Install (or remove, with `null`) a test-only override for
|
|
32
|
+
* {@link semanticNow}. Not intended for production use.
|
|
33
|
+
*/
|
|
34
|
+
function setSemanticTimeSourceForTesting(fn) {
|
|
35
|
+
overrideFn = fn;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A time source that floors the wall clock to `quantumMs` buckets. Time
|
|
39
|
+
* still advances (timeouts/cooldowns keep working), but all semantic
|
|
40
|
+
* timestamps produced within one quantum collide — making timestamp-tie
|
|
41
|
+
* hazards deterministic for stress testing.
|
|
42
|
+
*/
|
|
43
|
+
function createQuantizedTimeSource(quantumMs) {
|
|
44
|
+
if (!Number.isFinite(quantumMs) || quantumMs < 1) {
|
|
45
|
+
throw new Error(`Invalid clock quantum: ${quantumMs}`);
|
|
46
|
+
}
|
|
47
|
+
return () => Math.floor(Date.now() / quantumMs) * quantumMs;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=timeSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeSource.js","sourceRoot":"","sources":["../../../src/core/utils/timeSource.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;AAKH,kCAEC;AAMD,0EAEC;AAQD,8DAKC;AA1BD,IAAI,UAAU,GAA0B,IAAI,CAAC;AAE7C,8EAA8E;AAC9E,SAAgB,WAAW;IACzB,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,SAAgB,+BAA+B,CAAC,EAAyB;IACvE,UAAU,GAAG,EAAE,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,yBAAyB,CAAC,SAAiB;IACzD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,0BAA0B,SAAS,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;AAC9D,CAAC"}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*
|
|
39
39
|
* @module BasicOnDiskContentAddressedStore
|
|
40
40
|
*/
|
|
41
|
-
import { AttachmentReadPlan, AttachmentReadPlanOptions, ContentAddressedStore, ContentAddressedStoreFactory, CreateStoreResult, DocumentMaterializationBatchPlan, DocumentMaterializationPlan, MaterializationPlanOptions, OpenStoreOptions, StoreIndexBuildStatus, StoreCompactionStatus, StoreKind, AwaitIndexReadyOptions, StoreScanCursor, StoreScanFilters, StoreScanResult, StoreIdBloomSummary } from "../../core/appendonlystores/types";
|
|
41
|
+
import { AttachmentReadPlan, AttachmentReadPlanOptions, ContentAddressedStore, ContentAddressedStoreFactory, CreateStoreResult, DocumentMaterializationBatchPlan, DocumentMaterializationPlan, MaterializationPlanOptions, OpenStoreOptions, StoreIndexBuildStatus, StoreCompactionStatus, StoreKind, AwaitIndexReadyOptions, StoreScanCursor, StoreScanFilters, StoreScanResult, StoreIdBloomSummary, StoreHead } from "../../core/appendonlystores/types";
|
|
42
42
|
import type { StoreEntry, StoreEntryMetadata, StoreEntryType } from "../../core/types";
|
|
43
43
|
import { Logger } from "../../core/logging";
|
|
44
44
|
/**
|
|
@@ -75,6 +75,8 @@ export declare class BasicOnDiskContentAddressedStore implements ContentAddresse
|
|
|
75
75
|
private readonly metadataIndexPath;
|
|
76
76
|
/** Directory containing append-only metadata segment files. */
|
|
77
77
|
private readonly metadataSegmentsDir;
|
|
78
|
+
/** Path to the persisted cursor-lineage epoch file (see {@link StoreHead}). */
|
|
79
|
+
private readonly storeEpochPath;
|
|
78
80
|
/** Whether in-memory indexing is active (default true). */
|
|
79
81
|
private readonly indexingEnabled;
|
|
80
82
|
/** Trigger compaction when this many segment files have accumulated. */
|
|
@@ -120,6 +122,12 @@ export declare class BasicOnDiskContentAddressedStore implements ContentAddresse
|
|
|
120
122
|
private orderedMetadata;
|
|
121
123
|
/** Next monotonic local receipt order assigned on insert. */
|
|
122
124
|
private nextReceiptOrder;
|
|
125
|
+
/**
|
|
126
|
+
* Cursor-lineage epoch (see {@link StoreHead}). Loaded from / persisted to
|
|
127
|
+
* `store-epoch.json`; regenerated on store reset and on legacy
|
|
128
|
+
* receipt-order migration so peers discard stale persisted scan cursors.
|
|
129
|
+
*/
|
|
130
|
+
private storeEpoch;
|
|
123
131
|
/** Current phase and progress of the index build (building / ready). */
|
|
124
132
|
private indexStatus;
|
|
125
133
|
/**
|
|
@@ -336,6 +344,13 @@ export declare class BasicOnDiskContentAddressedStore implements ContentAddresse
|
|
|
336
344
|
* store already had receipt-order metadata (or was empty).
|
|
337
345
|
*/
|
|
338
346
|
private ensurePersistedReceiptOrder;
|
|
347
|
+
/**
|
|
348
|
+
* Load the persisted cursor-lineage epoch, creating (and persisting) a new
|
|
349
|
+
* one when it is missing, unreadable, or `forceNew` is set (receipt-order
|
|
350
|
+
* migration). The epoch lives in its own small file so it survives index
|
|
351
|
+
* rebuilds and works with indexing disabled.
|
|
352
|
+
*/
|
|
353
|
+
private loadOrCreateStoreEpoch;
|
|
339
354
|
/** List all `.json` files in the `entries/` directory. */
|
|
340
355
|
private listEntryFiles;
|
|
341
356
|
/** Resolve the absolute path to the metadata file for a given entry id. */
|
|
@@ -502,6 +517,7 @@ export declare class BasicOnDiskContentAddressedStore implements ContentAddresse
|
|
|
502
517
|
* bitset, suitable for transmission over the network.
|
|
503
518
|
*/
|
|
504
519
|
getIdBloomSummary(): Promise<StoreIdBloomSummary>;
|
|
520
|
+
getStoreHead(): Promise<StoreHead>;
|
|
505
521
|
planDocumentMaterialization(docId: string, options?: MaterializationPlanOptions): Promise<DocumentMaterializationPlan>;
|
|
506
522
|
planDocumentMaterializationBatch(docIds: string[], options?: MaterializationPlanOptions): Promise<DocumentMaterializationBatchPlan>;
|
|
507
523
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BasicOnDiskContentAddressedStore.d.ts","sourceRoot":"","sources":["../../../src/node/appendonlystores/BasicOnDiskContentAddressedStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAKH,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,4BAA4B,EAC5B,iBAAiB,EACjB,gCAAgC,EAChC,2BAA2B,EAC3B,0BAA0B,EAC1B,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,SAAS,EACT,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,mBAAmB,
|
|
1
|
+
{"version":3,"file":"BasicOnDiskContentAddressedStore.d.ts","sourceRoot":"","sources":["../../../src/node/appendonlystores/BasicOnDiskContentAddressedStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAKH,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,qBAAqB,EACrB,4BAA4B,EAC5B,iBAAiB,EACjB,gCAAgC,EAChC,2BAA2B,EAC3B,0BAA0B,EAC1B,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,SAAS,EACT,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,SAAS,EACV,MAAM,mCAAmC,CAAC;AAM3C,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,MAAM,EAAoC,MAAM,oBAAoB,CAAC;AA2H9E;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gCAAiC,YAAW,qBAAqB;IAK5E,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAE9B,0EAA0E;IAC1E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,gEAAgE;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,wDAAwD;IACxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAE3C,+DAA+D;IAC/D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAE7C,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAE1C,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,iCAAiC,CAAS;IAE3D,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,iCAAiC,CAAS;IAE3D;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAqB;IAEjE,gFAAgF;IAChF,OAAO,CAAC,gBAAgB,CAAwB;IAMhD;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAgB;IAMnC;;;;OAIG;IACH,OAAO,CAAC,OAAO,CAAyC;IAExD;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAkC;IAElD;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAA6B;IAEpD;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAA4B;IAEnD,6DAA6D;IAC7D,OAAO,CAAC,gBAAgB,CAAK;IAE7B;;;;OAIG;IACH,OAAO,CAAC,UAAU,CAAoB;IAEtC,wEAAwE;IACxE,OAAO,CAAC,WAAW,CAAwB;IAM3C;;;;;;;;;;;OAWG;gBAED,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,SAA0B,EACrC,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gBAAgB;IAgD5B;;;;;;;;;;;;;OAaG;YACW,UAAU;IAwDxB,qFAAqF;YACvE,iBAAiB;IAI/B;;;;OAIG;YACW,yBAAyB;IAUvC;;;;;;;;;OASG;YACW,sBAAsB;IA4BpC;;;;;;;;;;OAUG;YACW,qBAAqB;IAmCnC;;;;;;;;;;;;;OAaG;YACW,8BAA8B;IAsB5C;;;;;;OAMG;YACW,oBAAoB;IAQlC;;;;;OAKG;YACW,qBAAqB;IAUnC;;;;;OAKG;YACW,wBAAwB;IAStC;;;;;;;;;;;;OAYG;YACW,sBAAsB;IAwBpC;;;;;;;;;;OAUG;YACW,qBAAqB;IAYnC;;;;;;;;;;;;;;;;OAgBG;YACW,4BAA4B;IAmD1C;;;;OAIG;YACW,6BAA6B;IAkB3C;;;OAGG;IACH,OAAO,CAAC,eAAe;IASvB;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAqB3B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAgB9B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAkB3B,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,wBAAwB;IAOhC;;;;;;;;;;;;;OAaG;YACW,2BAA2B;IA8CzC;;;;;OAKG;YACW,sBAAsB;IAqBpC,0DAA0D;YAC5C,cAAc;IAS5B,2EAA2E;IAC3E,OAAO,CAAC,iBAAiB;IAIzB,6EAA6E;IAC7E,OAAO,CAAC,kBAAkB;IAI1B,gEAAgE;YAClD,UAAU;IASxB;;;;;;;;;;;OAWG;YACW,eAAe;IAkB7B;;;;;;;;OAQG;YACW,mBAAmB;IAcjC;;;;;;;OAOG;YACW,gBAAgB;IAa9B;;;;OAIG;YACW,sBAAsB;IAYpC;;;;;;OAMG;YACW,eAAe;IAmB7B,yDAAyD;IACzD,KAAK,IAAI,MAAM;IAIf,YAAY,IAAI,SAAS;IAIzB,gBAAgB,IAAI,MAAM;IAI1B;;;;;;;;;;;;OAYG;IACG,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CtD;;;;;;;OAOG;IACG,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA2CzE;;;;;;OAMG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAsChD,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAKhE,mCAAmC,CACvC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,kBAAkB,CAAC;IAK9B;;;;;;;;OAQG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAkBlD;;;;;OAKG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAOvE;;;;;OAKG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAuB5F;;;;;;;OAOG;IACG,WAAW,CACf,IAAI,EAAE,cAAc,EACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAC/B,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAiBhC;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IASpC;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,gBAAgB,CACpB,MAAM,EAAE,eAAe,GAAG,IAAI,EAC9B,KAAK,GAAE,MAAgC,EACvC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,CAAC;IA2F3B;;;;;;;;;;;OAWG;IACG,iBAAiB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAMjD,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAQlC,2BAA2B,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,2BAA2B,CAAC;IAejC,gCAAgC,CACpC,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,gCAAgC,CAAC;IAM5C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,MAAM,EAAE,CAAC;IAiDpB;;;;;;;;;;;;OAYG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8CnD;;;;;;OAMG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBxC;;;;OAIG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAKxF,6DAA6D;IAC7D,mBAAmB,IAAI,qBAAqB;IAI5C,8EAA8E;IACxE,mBAAmB,IAAI,OAAO,CAAC,qBAAqB,CAAC;CAG5D;AAED;;;;;;;GAOG;AACH,qBAAa,uCAAwC,YAAW,4BAA4B;IAC1F;;;;;;OAMG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,iBAAiB;CAWzE"}
|
|
@@ -78,6 +78,7 @@ const promises_1 = require("fs/promises");
|
|
|
78
78
|
const fs_1 = require("fs");
|
|
79
79
|
const path = __importStar(require("path"));
|
|
80
80
|
const types_1 = require("../../core/appendonlystores/types");
|
|
81
|
+
const uuid_1 = require("uuid");
|
|
81
82
|
const AttachmentReadPlanner_1 = require("../../core/appendonlystores/AttachmentReadPlanner");
|
|
82
83
|
const bloom_1 = require("../../core/appendonlystores/bloom");
|
|
83
84
|
const MaterializationPlanner_1 = require("../../core/appendonlystores/MaterializationPlanner");
|
|
@@ -221,6 +222,12 @@ class BasicOnDiskContentAddressedStore {
|
|
|
221
222
|
this.orderedMetadata = [];
|
|
222
223
|
/** Next monotonic local receipt order assigned on insert. */
|
|
223
224
|
this.nextReceiptOrder = 1;
|
|
225
|
+
/**
|
|
226
|
+
* Cursor-lineage epoch (see {@link StoreHead}). Loaded from / persisted to
|
|
227
|
+
* `store-epoch.json`; regenerated on store reset and on legacy
|
|
228
|
+
* receipt-order migration so peers discard stale persisted scan cursors.
|
|
229
|
+
*/
|
|
230
|
+
this.storeEpoch = (0, uuid_1.v7)();
|
|
224
231
|
this.dbId = dbId;
|
|
225
232
|
this.storeKind = storeKind;
|
|
226
233
|
this.logger =
|
|
@@ -231,6 +238,7 @@ class BasicOnDiskContentAddressedStore {
|
|
|
231
238
|
this.contentDir = path.join(this.storeRoot, "content");
|
|
232
239
|
this.metadataIndexPath = path.join(this.storeRoot, "metadata-index.json");
|
|
233
240
|
this.metadataSegmentsDir = path.join(this.storeRoot, "metadata-segments");
|
|
241
|
+
this.storeEpochPath = path.join(this.storeRoot, "store-epoch.json");
|
|
234
242
|
this.indexingEnabled = options?.indexingEnabled !== false;
|
|
235
243
|
const compactionOption = options?.metadataSegmentCompactionMinFiles;
|
|
236
244
|
this.metadataSegmentCompactionMinFiles =
|
|
@@ -285,6 +293,9 @@ class BasicOnDiskContentAddressedStore {
|
|
|
285
293
|
await (0, promises_1.mkdir)(this.contentDir, { recursive: true });
|
|
286
294
|
await (0, promises_1.mkdir)(this.metadataSegmentsDir, { recursive: true });
|
|
287
295
|
const migratedReceiptOrder = await this.ensurePersistedReceiptOrder();
|
|
296
|
+
// A receipt-order migration reassigns receiptOrder values, so persisted
|
|
297
|
+
// scan cursors from before the migration are invalid: start a new epoch.
|
|
298
|
+
await this.loadOrCreateStoreEpoch({ forceNew: migratedReceiptOrder });
|
|
288
299
|
if (!this.indexingEnabled) {
|
|
289
300
|
this.indexStatus = {
|
|
290
301
|
phase: "ready",
|
|
@@ -845,6 +856,29 @@ class BasicOnDiskContentAddressedStore {
|
|
|
845
856
|
this.nextReceiptOrder = nextReceiptOrder;
|
|
846
857
|
return true;
|
|
847
858
|
}
|
|
859
|
+
/**
|
|
860
|
+
* Load the persisted cursor-lineage epoch, creating (and persisting) a new
|
|
861
|
+
* one when it is missing, unreadable, or `forceNew` is set (receipt-order
|
|
862
|
+
* migration). The epoch lives in its own small file so it survives index
|
|
863
|
+
* rebuilds and works with indexing disabled.
|
|
864
|
+
*/
|
|
865
|
+
async loadOrCreateStoreEpoch(options) {
|
|
866
|
+
if (!options?.forceNew && (await this.fileExists(this.storeEpochPath))) {
|
|
867
|
+
try {
|
|
868
|
+
const raw = await (0, promises_1.readFile)(this.storeEpochPath, "utf-8");
|
|
869
|
+
const parsed = JSON.parse(raw);
|
|
870
|
+
if (typeof parsed.epoch === "string" && parsed.epoch.length > 0) {
|
|
871
|
+
this.storeEpoch = parsed.epoch;
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
catch (err) {
|
|
876
|
+
this.logger.warn(`Failed to read store epoch, creating a new one: ${String(err)}`);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
this.storeEpoch = (0, uuid_1.v7)();
|
|
880
|
+
await this.writeFileAtomic(this.storeEpochPath, JSON.stringify({ epoch: this.storeEpoch }));
|
|
881
|
+
}
|
|
848
882
|
// ---------------------------------------------------------------------------
|
|
849
883
|
// Filesystem I/O helpers
|
|
850
884
|
// ---------------------------------------------------------------------------
|
|
@@ -1353,6 +1387,13 @@ class BasicOnDiskContentAddressedStore {
|
|
|
1353
1387
|
const ids = await this.getAllIds();
|
|
1354
1388
|
return (0, bloom_1.createIdBloomSummary)(ids);
|
|
1355
1389
|
}
|
|
1390
|
+
async getStoreHead() {
|
|
1391
|
+
await this.ensureInitialized();
|
|
1392
|
+
return {
|
|
1393
|
+
epoch: this.storeEpoch,
|
|
1394
|
+
maxReceiptOrder: this.nextReceiptOrder - 1,
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1356
1397
|
async planDocumentMaterialization(docId, options) {
|
|
1357
1398
|
await this.ensureInitialized();
|
|
1358
1399
|
let entries = [];
|
|
@@ -1503,6 +1544,8 @@ class BasicOnDiskContentAddressedStore {
|
|
|
1503
1544
|
await (0, promises_1.mkdir)(this.entriesDir, { recursive: true });
|
|
1504
1545
|
await (0, promises_1.mkdir)(this.contentDir, { recursive: true });
|
|
1505
1546
|
await (0, promises_1.mkdir)(this.metadataSegmentsDir, { recursive: true });
|
|
1547
|
+
// New cursor lineage after a full reset (see StoreHead.epoch).
|
|
1548
|
+
await this.loadOrCreateStoreEpoch({ forceNew: true });
|
|
1506
1549
|
if (this.indexingEnabled) {
|
|
1507
1550
|
this.indexStatus = { phase: "ready", indexingEnabled: true, progress01: 1 };
|
|
1508
1551
|
}
|