mindoodb 0.0.73 → 0.0.75
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/dist/browser/index.mjs +9 -0
- package/dist/core/BackgroundTaskTracker.d.ts +18 -0
- package/dist/core/BackgroundTaskTracker.d.ts.map +1 -0
- package/dist/core/BackgroundTaskTracker.js +37 -0
- package/dist/core/BackgroundTaskTracker.js.map +1 -0
- package/dist/core/BaseMindooDB.d.ts +43 -7
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +271 -79
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +30 -12
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +90 -65
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.d.ts +57 -14
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.js +319 -164
- package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
- package/dist/core/appendonlystores/migration/StoreMigration.d.ts +34 -0
- package/dist/core/appendonlystores/migration/StoreMigration.d.ts.map +1 -0
- package/dist/core/appendonlystores/migration/StoreMigration.js +70 -0
- package/dist/core/appendonlystores/migration/StoreMigration.js.map +1 -0
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.d.ts +97 -0
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.d.ts.map +1 -0
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.js +128 -0
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.js.map +1 -0
- package/dist/core/appendonlystores/rpc/StoreRpcServer.d.ts +24 -0
- package/dist/core/appendonlystores/rpc/StoreRpcServer.d.ts.map +1 -0
- package/dist/core/appendonlystores/rpc/StoreRpcServer.js +102 -0
- package/dist/core/appendonlystores/rpc/StoreRpcServer.js.map +1 -0
- package/dist/core/appendonlystores/rpc/storeRpcCodec.d.ts +15 -0
- package/dist/core/appendonlystores/rpc/storeRpcCodec.d.ts.map +1 -0
- package/dist/core/appendonlystores/rpc/storeRpcCodec.js +100 -0
- package/dist/core/appendonlystores/rpc/storeRpcCodec.js.map +1 -0
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.d.ts +3 -0
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js +18 -11
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts +13 -0
- package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.js +74 -0
- package/dist/core/appendonlystores/sqlite/SqliteDriver.js.map +1 -1
- package/dist/core/cache/CacheManager.d.ts +4 -1
- package/dist/core/cache/CacheManager.d.ts.map +1 -1
- package/dist/core/cache/CacheManager.js +47 -19
- package/dist/core/cache/CacheManager.js.map +1 -1
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +13 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.d.ts +16 -1
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.d.ts.map +1 -1
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.js +86 -14
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.js.map +1 -1
- package/dist/core/indexing/summary/DocumentSummaryStore.d.ts +2 -0
- package/dist/core/indexing/summary/DocumentSummaryStore.d.ts.map +1 -1
- package/dist/core/indexing/summary/DocumentSummaryStore.js +19 -5
- package/dist/core/indexing/summary/DocumentSummaryStore.js.map +1 -1
- package/dist/core/types.d.ts +29 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +22 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/utils/singleFlight.d.ts +21 -0
- package/dist/core/utils/singleFlight.d.ts.map +1 -0
- package/dist/core/utils/singleFlight.js +47 -0
- package/dist/core/utils/singleFlight.js.map +1 -0
- package/dist/core/utils/timeSource.d.ts +3 -1
- package/dist/core/utils/timeSource.d.ts.map +1 -1
- package/dist/core/utils/timeSource.js +4 -0
- package/dist/core/utils/timeSource.js.map +1 -1
- package/dist/sqlite/index.d.ts +2 -0
- package/dist/sqlite/index.d.ts.map +1 -1
- package/dist/sqlite/index.js +8 -1
- package/dist/sqlite/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,9 +8,10 @@ const automerge_adapter_1 = require("./automerge-adapter");
|
|
|
8
8
|
const values_1 = require("./values");
|
|
9
9
|
const storeEntryTime_1 = require("./storeEntryTime");
|
|
10
10
|
const types_1 = require("./types");
|
|
11
|
-
const types_2 = require("./
|
|
11
|
+
const types_2 = require("./types");
|
|
12
|
+
const types_3 = require("./appendonlystores/types");
|
|
12
13
|
const syncStores_1 = require("./appendonlystores/syncStores");
|
|
13
|
-
const
|
|
14
|
+
const types_4 = require("./appendonlystores/network/types");
|
|
14
15
|
const MaterializationPlanner_1 = require("./appendonlystores/MaterializationPlanner");
|
|
15
16
|
const DocumentDagAnalysis_1 = require("./DocumentDagAnalysis");
|
|
16
17
|
const DocumentConflictAnalysis_1 = require("./DocumentConflictAnalysis");
|
|
@@ -33,13 +34,14 @@ const builtinDbInvariants_1 = require("./builtinDbInvariants");
|
|
|
33
34
|
const recipients_1 = require("./userkeys/recipients");
|
|
34
35
|
const sealedTypes_1 = require("./userkeys/sealedTypes");
|
|
35
36
|
const DocumentSummaryStore_1 = require("./indexing/summary/DocumentSummaryStore");
|
|
36
|
-
const
|
|
37
|
+
const types_5 = require("./indexing/summary/types");
|
|
37
38
|
const DocumentFullTextIndex_1 = require("./indexing/fulltext/DocumentFullTextIndex");
|
|
38
|
-
const
|
|
39
|
-
const
|
|
39
|
+
const types_6 = require("./indexing/fulltext/types");
|
|
40
|
+
const types_7 = require("./extraction/types");
|
|
40
41
|
const executeQuery_1 = require("./query/executeQuery");
|
|
41
42
|
const queryView_1 = require("./query/queryView");
|
|
42
43
|
const queryLive_1 = require("./query/queryLive");
|
|
44
|
+
const BackgroundTaskTracker_1 = require("./BackgroundTaskTracker");
|
|
43
45
|
/**
|
|
44
46
|
* Default chunk size for attachments: 256KB
|
|
45
47
|
*/
|
|
@@ -116,7 +118,7 @@ function networkErrorType(error) {
|
|
|
116
118
|
* server's `Retry-After` when it asks for a longer wait than our backoff.
|
|
117
119
|
*/
|
|
118
120
|
function rateLimitRetryDelayMs(error, attempt) {
|
|
119
|
-
if (networkErrorType(error) !==
|
|
121
|
+
if (networkErrorType(error) !== types_4.NetworkErrorType.RATE_LIMITED ||
|
|
120
122
|
attempt >= PREFETCH_RATE_LIMIT_DELAYS_MS.length) {
|
|
121
123
|
return null;
|
|
122
124
|
}
|
|
@@ -249,10 +251,12 @@ class BaseMindooDB {
|
|
|
249
251
|
*/
|
|
250
252
|
this.quarantineLog = new Map();
|
|
251
253
|
/**
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
+
* Last known "is access control active for this tenant?" verdict. Only used
|
|
255
|
+
* as the fail-closed fallback when the directory cannot be consulted; the
|
|
256
|
+
* live check itself is cheap because the directory skips its rebuild while
|
|
257
|
+
* its changefeed `changeSeq` is unchanged.
|
|
254
258
|
*/
|
|
255
|
-
this.
|
|
259
|
+
this.aclActiveLastKnown = null;
|
|
256
260
|
/**
|
|
257
261
|
* Per-document cache of the original creator's signing public key and the
|
|
258
262
|
* trusted time of the `doc_create` entry. Used by the client write prechecks
|
|
@@ -452,6 +456,8 @@ class BaseMindooDB {
|
|
|
452
456
|
this.changeNotifyTimer = null;
|
|
453
457
|
/** While > 0, timer-based emission is suppressed (e.g. during a sync batch). */
|
|
454
458
|
this.changeNotificationHolds = 0;
|
|
459
|
+
/** Fire-and-forget work of this database; see {@link whenBackgroundIdle}. */
|
|
460
|
+
this.backgroundTasks = new BackgroundTaskTracker_1.BackgroundTaskTracker();
|
|
455
461
|
// ---------------------------------------------------------------------------
|
|
456
462
|
// Summary auto-follow (see setSummaryAutoUpdateEnabled): keeps the summary
|
|
457
463
|
// buffer current as changes arrive (local writes and sync batches), so the
|
|
@@ -567,11 +573,11 @@ class BaseMindooDB {
|
|
|
567
573
|
if (store.getId() !== attachmentStore.getId()) {
|
|
568
574
|
throw new Error(`[BaseMindooDB] Expected document and attachment stores to share dbId but received ${store.getId()} and ${attachmentStore.getId()}`);
|
|
569
575
|
}
|
|
570
|
-
if (store.getStoreKind() !==
|
|
571
|
-
throw new Error(`[BaseMindooDB] Expected primary store kind ${
|
|
576
|
+
if (store.getStoreKind() !== types_3.StoreKind.docs) {
|
|
577
|
+
throw new Error(`[BaseMindooDB] Expected primary store kind ${types_3.StoreKind.docs} but received ${store.getStoreKind()}`);
|
|
572
578
|
}
|
|
573
|
-
if (attachmentStore.getStoreKind() !==
|
|
574
|
-
throw new Error(`[BaseMindooDB] Expected attachment store kind ${
|
|
579
|
+
if (attachmentStore.getStoreKind() !== types_3.StoreKind.attachments) {
|
|
580
|
+
throw new Error(`[BaseMindooDB] Expected attachment store kind ${types_3.StoreKind.attachments} but received ${attachmentStore.getStoreKind()}`);
|
|
575
581
|
}
|
|
576
582
|
this.tenant = tenant;
|
|
577
583
|
this.store = store;
|
|
@@ -898,7 +904,7 @@ class BaseMindooDB {
|
|
|
898
904
|
this.dirtyDocIds.clear();
|
|
899
905
|
this.cacheMetaDirty = false;
|
|
900
906
|
this.summaryStore?.discardDirtyState();
|
|
901
|
-
this.fulltextIndex?.
|
|
907
|
+
this.fulltextIndex?.discardDirtyState();
|
|
902
908
|
void cacheManager.deregister(this);
|
|
903
909
|
if (this.summaryStore) {
|
|
904
910
|
void cacheManager.deregister(this.summaryStore);
|
|
@@ -939,8 +945,8 @@ class BaseMindooDB {
|
|
|
939
945
|
*/
|
|
940
946
|
async getSummarySetup() {
|
|
941
947
|
try {
|
|
942
|
-
const doc = await this.getDocument(
|
|
943
|
-
return (0,
|
|
948
|
+
const doc = await this.getDocument(types_5.DB_SETUP_DOC_ID);
|
|
949
|
+
return (0, types_5.sanitizeSummaryConfig)(doc.getData()[types_5.SUMMARY_SETUP_FIELD]) ?? null;
|
|
944
950
|
}
|
|
945
951
|
catch (error) {
|
|
946
952
|
if (error instanceof errors_1.DocumentNotFoundError ||
|
|
@@ -962,14 +968,14 @@ class BaseMindooDB {
|
|
|
962
968
|
* backfill — locally and, after sync, on every other replica.
|
|
963
969
|
*/
|
|
964
970
|
async setSummarySetup(config) {
|
|
965
|
-
const doc = await this.createDocument({ id:
|
|
971
|
+
const doc = await this.createDocument({ id: types_5.DB_SETUP_DOC_ID });
|
|
966
972
|
await this.changeDoc(doc, (d) => {
|
|
967
973
|
const data = d.getData();
|
|
968
974
|
if (config === null) {
|
|
969
|
-
delete data[
|
|
975
|
+
delete data[types_5.SUMMARY_SETUP_FIELD];
|
|
970
976
|
}
|
|
971
977
|
else {
|
|
972
|
-
data[
|
|
978
|
+
data[types_5.SUMMARY_SETUP_FIELD] = (0, types_5.sanitizeSummaryConfig)(config) ?? {};
|
|
973
979
|
}
|
|
974
980
|
});
|
|
975
981
|
}
|
|
@@ -1013,12 +1019,12 @@ class BaseMindooDB {
|
|
|
1013
1019
|
this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
|
|
1014
1020
|
return;
|
|
1015
1021
|
}
|
|
1016
|
-
const hasSetupChange = changes.some((change) => change.docId ===
|
|
1022
|
+
const hasSetupChange = changes.some((change) => change.docId === types_5.DB_SETUP_DOC_ID);
|
|
1017
1023
|
if (!hasSetupChange && this.summarySetupProbed) {
|
|
1018
1024
|
return;
|
|
1019
1025
|
}
|
|
1020
1026
|
this.summarySetupProbed = true;
|
|
1021
|
-
|
|
1027
|
+
this.backgroundTasks.run(this.activateSummaryFromSetupDoc());
|
|
1022
1028
|
}
|
|
1023
1029
|
/** Create the summary store when the setup document configures one. */
|
|
1024
1030
|
async activateSummaryFromSetupDoc() {
|
|
@@ -1049,7 +1055,7 @@ class BaseMindooDB {
|
|
|
1049
1055
|
return;
|
|
1050
1056
|
}
|
|
1051
1057
|
this.summaryAutoUpdateRunning = true;
|
|
1052
|
-
|
|
1058
|
+
this.backgroundTasks.run((async () => {
|
|
1053
1059
|
try {
|
|
1054
1060
|
do {
|
|
1055
1061
|
this.summaryAutoUpdatePending = false;
|
|
@@ -1063,7 +1069,7 @@ class BaseMindooDB {
|
|
|
1063
1069
|
finally {
|
|
1064
1070
|
this.summaryAutoUpdateRunning = false;
|
|
1065
1071
|
}
|
|
1066
|
-
})();
|
|
1072
|
+
})());
|
|
1067
1073
|
}
|
|
1068
1074
|
// ---------------------------------------------------------------------------
|
|
1069
1075
|
// Full-text index (see docs/fulltext-search.md)
|
|
@@ -1103,8 +1109,8 @@ class BaseMindooDB {
|
|
|
1103
1109
|
*/
|
|
1104
1110
|
async getFulltextSetup() {
|
|
1105
1111
|
try {
|
|
1106
|
-
const doc = await this.getDocument(
|
|
1107
|
-
return ((0,
|
|
1112
|
+
const doc = await this.getDocument(types_5.DB_SETUP_DOC_ID);
|
|
1113
|
+
return ((0, types_6.sanitizeFulltextConfig)(doc.getData()[types_6.FULLTEXT_SETUP_FIELD]) ?? null);
|
|
1108
1114
|
}
|
|
1109
1115
|
catch (error) {
|
|
1110
1116
|
if (error instanceof errors_1.DocumentNotFoundError ||
|
|
@@ -1128,19 +1134,19 @@ class BaseMindooDB {
|
|
|
1128
1134
|
* resumable backfill — locally and, after sync, on every other replica.
|
|
1129
1135
|
*/
|
|
1130
1136
|
async setFulltextSetup(config) {
|
|
1131
|
-
const sanitized = config === null ? null : ((0,
|
|
1137
|
+
const sanitized = config === null ? null : ((0, types_6.sanitizeFulltextConfig)(config) ?? {});
|
|
1132
1138
|
const current = await this.getFulltextSetup();
|
|
1133
1139
|
if (JSON.stringify(current) === JSON.stringify(sanitized)) {
|
|
1134
1140
|
return;
|
|
1135
1141
|
}
|
|
1136
|
-
const doc = await this.createDocument({ id:
|
|
1142
|
+
const doc = await this.createDocument({ id: types_5.DB_SETUP_DOC_ID });
|
|
1137
1143
|
await this.changeDoc(doc, (d) => {
|
|
1138
1144
|
const data = d.getData();
|
|
1139
1145
|
if (sanitized === null) {
|
|
1140
|
-
delete data[
|
|
1146
|
+
delete data[types_6.FULLTEXT_SETUP_FIELD];
|
|
1141
1147
|
}
|
|
1142
1148
|
else {
|
|
1143
|
-
data[
|
|
1149
|
+
data[types_6.FULLTEXT_SETUP_FIELD] = sanitized;
|
|
1144
1150
|
}
|
|
1145
1151
|
});
|
|
1146
1152
|
}
|
|
@@ -1154,8 +1160,8 @@ class BaseMindooDB {
|
|
|
1154
1160
|
*/
|
|
1155
1161
|
async getExtractionSetup() {
|
|
1156
1162
|
try {
|
|
1157
|
-
const doc = await this.getDocument(
|
|
1158
|
-
return ((0,
|
|
1163
|
+
const doc = await this.getDocument(types_5.DB_SETUP_DOC_ID);
|
|
1164
|
+
return ((0, types_7.sanitizeExtractionConfig)(doc.getData()[types_7.EXTRACTION_SETUP_FIELD]) ?? null);
|
|
1159
1165
|
}
|
|
1160
1166
|
catch (error) {
|
|
1161
1167
|
if (error instanceof errors_1.DocumentNotFoundError ||
|
|
@@ -1175,19 +1181,19 @@ class BaseMindooDB {
|
|
|
1175
1181
|
* without producing changefeed/sync churn.
|
|
1176
1182
|
*/
|
|
1177
1183
|
async setExtractionSetup(config) {
|
|
1178
|
-
const sanitized = config === null ? null : ((0,
|
|
1184
|
+
const sanitized = config === null ? null : ((0, types_7.sanitizeExtractionConfig)(config) ?? {});
|
|
1179
1185
|
const current = await this.getExtractionSetup();
|
|
1180
1186
|
if (JSON.stringify(current) === JSON.stringify(sanitized)) {
|
|
1181
1187
|
return;
|
|
1182
1188
|
}
|
|
1183
|
-
const doc = await this.createDocument({ id:
|
|
1189
|
+
const doc = await this.createDocument({ id: types_5.DB_SETUP_DOC_ID });
|
|
1184
1190
|
await this.changeDoc(doc, (d) => {
|
|
1185
1191
|
const data = d.getData();
|
|
1186
1192
|
if (sanitized === null) {
|
|
1187
|
-
delete data[
|
|
1193
|
+
delete data[types_7.EXTRACTION_SETUP_FIELD];
|
|
1188
1194
|
}
|
|
1189
1195
|
else {
|
|
1190
|
-
data[
|
|
1196
|
+
data[types_7.EXTRACTION_SETUP_FIELD] = sanitized;
|
|
1191
1197
|
}
|
|
1192
1198
|
});
|
|
1193
1199
|
}
|
|
@@ -1255,12 +1261,12 @@ class BaseMindooDB {
|
|
|
1255
1261
|
this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
|
|
1256
1262
|
return;
|
|
1257
1263
|
}
|
|
1258
|
-
const hasSetupChange = changes.some((change) => change.docId ===
|
|
1264
|
+
const hasSetupChange = changes.some((change) => change.docId === types_5.DB_SETUP_DOC_ID);
|
|
1259
1265
|
if (!hasSetupChange && this.fulltextSetupProbed) {
|
|
1260
1266
|
return;
|
|
1261
1267
|
}
|
|
1262
1268
|
this.fulltextSetupProbed = true;
|
|
1263
|
-
|
|
1269
|
+
this.backgroundTasks.run(this.activateFulltextFromSetupDoc());
|
|
1264
1270
|
}
|
|
1265
1271
|
/** Create the full-text index when the setup document enables one. */
|
|
1266
1272
|
async activateFulltextFromSetupDoc() {
|
|
@@ -1290,7 +1296,7 @@ class BaseMindooDB {
|
|
|
1290
1296
|
return;
|
|
1291
1297
|
}
|
|
1292
1298
|
this.fulltextAutoUpdateRunning = true;
|
|
1293
|
-
|
|
1299
|
+
this.backgroundTasks.run((async () => {
|
|
1294
1300
|
try {
|
|
1295
1301
|
do {
|
|
1296
1302
|
this.fulltextAutoUpdatePending = false;
|
|
@@ -1304,7 +1310,7 @@ class BaseMindooDB {
|
|
|
1304
1310
|
finally {
|
|
1305
1311
|
this.fulltextAutoUpdateRunning = false;
|
|
1306
1312
|
}
|
|
1307
|
-
})();
|
|
1313
|
+
})());
|
|
1308
1314
|
}
|
|
1309
1315
|
// ---------------------------------------------------------------------------
|
|
1310
1316
|
// Change notifications (reactive support)
|
|
@@ -1325,6 +1331,29 @@ class BaseMindooDB {
|
|
|
1325
1331
|
this.changeListeners.delete(listener);
|
|
1326
1332
|
};
|
|
1327
1333
|
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Resolve once this database has no background work left: no coalesced
|
|
1336
|
+
* change event waiting for its timer and no auto-follow catch-up or setup
|
|
1337
|
+
* probe in flight (including work those start). Returns whether there was
|
|
1338
|
+
* anything to wait for.
|
|
1339
|
+
*
|
|
1340
|
+
* @internal Shutdown and test hook; not part of the {@link MindooDB}
|
|
1341
|
+
* interface.
|
|
1342
|
+
*/
|
|
1343
|
+
async whenBackgroundIdle() {
|
|
1344
|
+
let waited = false;
|
|
1345
|
+
for (;;) {
|
|
1346
|
+
if (this.changeNotifyTimer !== null) {
|
|
1347
|
+
waited = true;
|
|
1348
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1349
|
+
continue;
|
|
1350
|
+
}
|
|
1351
|
+
if (!(await this.backgroundTasks.settle())) {
|
|
1352
|
+
return waited;
|
|
1353
|
+
}
|
|
1354
|
+
waited = true;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1328
1357
|
/** Record a document transition for the coalesced change event. */
|
|
1329
1358
|
noteChangeForListeners(docId, lastModified, isDeleted) {
|
|
1330
1359
|
if (this.changeListeners.size === 0) {
|
|
@@ -2539,7 +2568,7 @@ class BaseMindooDB {
|
|
|
2539
2568
|
return;
|
|
2540
2569
|
}
|
|
2541
2570
|
this.summarySetupProbed = true;
|
|
2542
|
-
|
|
2571
|
+
this.backgroundTasks.run((async () => {
|
|
2543
2572
|
try {
|
|
2544
2573
|
const config = await this.getSummarySetup();
|
|
2545
2574
|
if (config === null || this.summaryStore) {
|
|
@@ -2554,7 +2583,7 @@ class BaseMindooDB {
|
|
|
2554
2583
|
catch (error) {
|
|
2555
2584
|
this.logger.warn(`Time-travel summary activation failed: ${error}`);
|
|
2556
2585
|
}
|
|
2557
|
-
})();
|
|
2586
|
+
})());
|
|
2558
2587
|
}
|
|
2559
2588
|
/**
|
|
2560
2589
|
* Open-time probe for full-text auto-activation. Without it, a
|
|
@@ -2580,7 +2609,7 @@ class BaseMindooDB {
|
|
|
2580
2609
|
return;
|
|
2581
2610
|
}
|
|
2582
2611
|
this.fulltextSetupProbed = true;
|
|
2583
|
-
|
|
2612
|
+
this.backgroundTasks.run(this.activateFulltextFromSetupDoc());
|
|
2584
2613
|
}
|
|
2585
2614
|
/**
|
|
2586
2615
|
* Compute the current tenant KeyBag fingerprint, or `null` when the
|
|
@@ -7478,8 +7507,7 @@ class BaseMindooDB {
|
|
|
7478
7507
|
try {
|
|
7479
7508
|
newDoc = this.runChangeWithOutdatedDocRecovery(internalDoc, (doc) => {
|
|
7480
7509
|
if (patch.baseHeads && patch.baseHeads.length > 0) {
|
|
7481
|
-
|
|
7482
|
-
return result.newDoc;
|
|
7510
|
+
return this.changeOnForkAt(doc, patch.baseHeads, applySpans);
|
|
7483
7511
|
}
|
|
7484
7512
|
return automerge_adapter_1.Automerge.change(doc, applySpans);
|
|
7485
7513
|
});
|
|
@@ -7505,6 +7533,120 @@ class BaseMindooDB {
|
|
|
7505
7533
|
data: wrapped.getData(),
|
|
7506
7534
|
};
|
|
7507
7535
|
}
|
|
7536
|
+
async applyDocumentUpdate(doc, update) {
|
|
7537
|
+
this.assertWritable("applyDocumentUpdate");
|
|
7538
|
+
const docId = doc.getId();
|
|
7539
|
+
let internalDoc = this.getCachedDocument(docId);
|
|
7540
|
+
if (!internalDoc) {
|
|
7541
|
+
const loadedDoc = await this.loadDocumentInternal(docId);
|
|
7542
|
+
if (!loadedDoc) {
|
|
7543
|
+
throw new errors_1.DocumentNotFoundError(docId);
|
|
7544
|
+
}
|
|
7545
|
+
internalDoc = loadedDoc;
|
|
7546
|
+
}
|
|
7547
|
+
if (internalDoc.isDeleted) {
|
|
7548
|
+
throw new errors_1.DocumentDeletedError(docId);
|
|
7549
|
+
}
|
|
7550
|
+
const baseHeads = (0, types_2.commonUpdateBaseHeads)(update);
|
|
7551
|
+
if (baseHeads === null) {
|
|
7552
|
+
throw new Error("applyDocumentUpdate: the parts of one update must share their baseHeads");
|
|
7553
|
+
}
|
|
7554
|
+
const hasFields = Object.keys(update.set ?? {}).length > 0 || (update.unset?.length ?? 0) > 0;
|
|
7555
|
+
if (update.json)
|
|
7556
|
+
this.validateJsonPatch(update.json);
|
|
7557
|
+
for (const patch of update.text ?? [])
|
|
7558
|
+
this.validateTextPatch(patch);
|
|
7559
|
+
for (const patch of update.richText ?? [])
|
|
7560
|
+
this.validateRichTextPatch(patch);
|
|
7561
|
+
for (const patch of update.richTextSteps ?? [])
|
|
7562
|
+
this.validateRichTextStepPatch(patch);
|
|
7563
|
+
// top-level fields go through changeDoc elsewhere, which checks sealed access
|
|
7564
|
+
if (hasFields)
|
|
7565
|
+
await this.assertCurrentSealedAccess(internalDoc);
|
|
7566
|
+
const now = (0, timeSource_1.semanticNow)();
|
|
7567
|
+
const headsBeforeChange = automerge_adapter_1.Automerge.getHeads(internalDoc.doc);
|
|
7568
|
+
const applyAll = (automergeDoc) => {
|
|
7569
|
+
for (const [key, value] of Object.entries(update.set ?? {})) {
|
|
7570
|
+
if (value !== undefined) {
|
|
7571
|
+
automergeDoc[key] = this.hydrateTypedValues(value);
|
|
7572
|
+
}
|
|
7573
|
+
}
|
|
7574
|
+
for (const key of update.unset ?? []) {
|
|
7575
|
+
delete automergeDoc[key];
|
|
7576
|
+
}
|
|
7577
|
+
if (update.json)
|
|
7578
|
+
this.applyJsonPatchOperations(automergeDoc, update.json);
|
|
7579
|
+
for (const patch of update.text ?? [])
|
|
7580
|
+
this.applyTextEditsInChange(automergeDoc, patch);
|
|
7581
|
+
for (const patch of update.richText ?? [])
|
|
7582
|
+
this.applyRichTextSpansInChange(automergeDoc, patch, docId);
|
|
7583
|
+
for (const patch of update.richTextSteps ?? [])
|
|
7584
|
+
this.applyRichTextStepsInChange(automergeDoc, patch);
|
|
7585
|
+
automergeDoc._lastModified = now;
|
|
7586
|
+
};
|
|
7587
|
+
let newDoc;
|
|
7588
|
+
try {
|
|
7589
|
+
newDoc = this.runChangeWithOutdatedDocRecovery(internalDoc, (current) => baseHeads
|
|
7590
|
+
? this.changeOnForkAt(current, baseHeads, applyAll)
|
|
7591
|
+
: automerge_adapter_1.Automerge.change(current, applyAll));
|
|
7592
|
+
}
|
|
7593
|
+
catch (error) {
|
|
7594
|
+
this.logger.error(`Error applying document update for document ${docId}:`, error);
|
|
7595
|
+
throw error;
|
|
7596
|
+
}
|
|
7597
|
+
await this.persistDocumentChange({
|
|
7598
|
+
internalDoc,
|
|
7599
|
+
newDoc,
|
|
7600
|
+
now,
|
|
7601
|
+
headsBeforeChange,
|
|
7602
|
+
useCustomKey: false,
|
|
7603
|
+
successMessage: "document updated",
|
|
7604
|
+
});
|
|
7605
|
+
const wrapped = this.wrapDocument(internalDoc);
|
|
7606
|
+
return {
|
|
7607
|
+
doc: wrapped,
|
|
7608
|
+
heads: wrapped.getHeads(),
|
|
7609
|
+
data: wrapped.getData(),
|
|
7610
|
+
};
|
|
7611
|
+
}
|
|
7612
|
+
/** The edits of one text patch, inside a change. */
|
|
7613
|
+
applyTextEditsInChange(automergeDoc, patch) {
|
|
7614
|
+
this.ensureTextPath(automergeDoc, patch.path);
|
|
7615
|
+
for (const edit of patch.edits) {
|
|
7616
|
+
automerge_adapter_1.Automerge.splice(automergeDoc, patch.path, edit.index, edit.deleteCount, edit.insert ?? "");
|
|
7617
|
+
}
|
|
7618
|
+
}
|
|
7619
|
+
/** One rich-text snapshot (or sequence), inside a change, with the reset-and-retry recovery. */
|
|
7620
|
+
applyRichTextSpansInChange(automergeDoc, patch, docId) {
|
|
7621
|
+
this.ensureRichTextPath(automergeDoc, patch.path);
|
|
7622
|
+
const spansSequence = patch.spansSequence ?? (patch.spans ? [patch.spans] : []);
|
|
7623
|
+
for (const spans of spansSequence) {
|
|
7624
|
+
const revivedSpans = this.reviveRichTextSpans(spans);
|
|
7625
|
+
try {
|
|
7626
|
+
automerge_adapter_1.Automerge.updateSpans(automergeDoc, patch.path, revivedSpans, patch.updateSpansConfig);
|
|
7627
|
+
}
|
|
7628
|
+
catch (error) {
|
|
7629
|
+
if (!this.isRichTextUpdateSpansBoundsError(error)) {
|
|
7630
|
+
throw error;
|
|
7631
|
+
}
|
|
7632
|
+
this.logger.warn(`updateSpans failed for document ${docId} at '${patch.path.map(String).join(".")}', resetting rich-text field and applying snapshot from scratch`, error);
|
|
7633
|
+
this.setJsonValueAtPath(automergeDoc, patch.path, "");
|
|
7634
|
+
automerge_adapter_1.Automerge.updateSpans(automergeDoc, patch.path, revivedSpans, patch.updateSpansConfig);
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
}
|
|
7638
|
+
/** Positional rich-text steps (splices and marks), inside a change. */
|
|
7639
|
+
applyRichTextStepsInChange(automergeDoc, patch) {
|
|
7640
|
+
this.ensureRichTextPath(automergeDoc, patch.path);
|
|
7641
|
+
for (const step of patch.steps) {
|
|
7642
|
+
automerge_adapter_1.Automerge.splice(automergeDoc, patch.path, step.index, step.deleteCount, step.insert ?? "");
|
|
7643
|
+
for (const markRange of step.marks ?? []) {
|
|
7644
|
+
for (const [name, value] of Object.entries(markRange.marks)) {
|
|
7645
|
+
automerge_adapter_1.Automerge.mark(automergeDoc, patch.path, { start: markRange.index, end: markRange.index + markRange.length, expand: "none" }, name, this.reviveRichTextValue(value));
|
|
7646
|
+
}
|
|
7647
|
+
}
|
|
7648
|
+
}
|
|
7649
|
+
}
|
|
7508
7650
|
async applyRichTextStepsPatch(doc, patch) {
|
|
7509
7651
|
this.assertWritable("applyRichTextStepsPatch");
|
|
7510
7652
|
const docId = doc.getId();
|
|
@@ -7904,6 +8046,16 @@ class BaseMindooDB {
|
|
|
7904
8046
|
// incrementCounter() calls, applied in call order after the field
|
|
7905
8047
|
// assignments so they can target counters assigned in the same callback.
|
|
7906
8048
|
const pendingCounterIncrements = [];
|
|
8049
|
+
// Assignments and deletions are applied before the increments, so an
|
|
8050
|
+
// assignment or deletion of a field supersedes the increments queued on it
|
|
8051
|
+
// (or below it) earlier in the callback; later increments still apply.
|
|
8052
|
+
const dropPendingCounterIncrements = (field) => {
|
|
8053
|
+
for (let i = pendingCounterIncrements.length - 1; i >= 0; i--) {
|
|
8054
|
+
if (pendingCounterIncrements[i].path[0] === field) {
|
|
8055
|
+
pendingCounterIncrements.splice(i, 1);
|
|
8056
|
+
}
|
|
8057
|
+
}
|
|
8058
|
+
};
|
|
7907
8059
|
// Reference to db for closures
|
|
7908
8060
|
const db = this;
|
|
7909
8061
|
// Guard flag to prevent operations after callback completes
|
|
@@ -7938,6 +8090,7 @@ class BaseMindooDB {
|
|
|
7938
8090
|
set: (target, prop, value) => {
|
|
7939
8091
|
throwIfCallbackInactive("set property");
|
|
7940
8092
|
if (typeof prop === "string") {
|
|
8093
|
+
dropPendingCounterIncrements(prop);
|
|
7941
8094
|
// If this property was marked for deletion, remove it from deletions
|
|
7942
8095
|
pendingDeletions.delete(prop);
|
|
7943
8096
|
// Track the change
|
|
@@ -7950,6 +8103,7 @@ class BaseMindooDB {
|
|
|
7950
8103
|
deleteProperty: (target, prop) => {
|
|
7951
8104
|
throwIfCallbackInactive("delete property");
|
|
7952
8105
|
if (typeof prop === "string") {
|
|
8106
|
+
dropPendingCounterIncrements(prop);
|
|
7953
8107
|
// Mark for deletion
|
|
7954
8108
|
pendingDeletions.add(prop);
|
|
7955
8109
|
// Remove from pending changes if it was there
|
|
@@ -8414,7 +8568,10 @@ class BaseMindooDB {
|
|
|
8414
8568
|
return value;
|
|
8415
8569
|
}
|
|
8416
8570
|
if (Array.isArray(value)) {
|
|
8417
|
-
|
|
8571
|
+
// Array.from, not map: map keeps the realm of an array that came from
|
|
8572
|
+
// another realm (structuredClone in a VM context, another frame), and
|
|
8573
|
+
// Automerge only assigns arrays that pass `instanceof Array`.
|
|
8574
|
+
return Array.from(value, (entry) => this.hydrateTypedValues(entry, depth + 1));
|
|
8418
8575
|
}
|
|
8419
8576
|
const record = value;
|
|
8420
8577
|
if (Object.prototype.hasOwnProperty.call(record, values_1.MINDOO_VALUE_TAG)) {
|
|
@@ -8851,6 +9008,34 @@ class BaseMindooDB {
|
|
|
8851
9008
|
* {@link applyNewEntriesToCachedDocument} (line ~6606) for the sync
|
|
8852
9009
|
* pipeline; this helper centralizes it for the patch / changeDoc paths.
|
|
8853
9010
|
*/
|
|
9011
|
+
/**
|
|
9012
|
+
* `Automerge.changeAt(doc, baseHeads, apply)` for changes that call
|
|
9013
|
+
* `updateSpans`. Automerge 3.5's `updateSpans` inside `changeAt` diffs
|
|
9014
|
+
* against the text as of `baseHeads` but applies the resulting indexes to the
|
|
9015
|
+
* current text, so once a concurrent edit of that text is in the document it
|
|
9016
|
+
* throws "out of bounds" (and the reset-and-retry recovery would then drop
|
|
9017
|
+
* the concurrent edit) or edits the wrong characters. `splice`, `updateText`
|
|
9018
|
+
* and `mark` are not affected.
|
|
9019
|
+
*
|
|
9020
|
+
* The change is made on a fork that stands exactly at `baseHeads` and then
|
|
9021
|
+
* merged back: the same causal result `changeAt` would produce. The fork
|
|
9022
|
+
* writes as this replica's actor, unless that actor changed the document
|
|
9023
|
+
* after `baseHeads` (its next sequence number is taken then); in that case a
|
|
9024
|
+
* fresh actor writes the one change.
|
|
9025
|
+
*/
|
|
9026
|
+
changeOnForkAt(doc, baseHeads, apply) {
|
|
9027
|
+
const current = automerge_adapter_1.Automerge.getHeads(doc);
|
|
9028
|
+
if (current.length === baseHeads.length &&
|
|
9029
|
+
current.every((head) => baseHeads.includes(head))) {
|
|
9030
|
+
return automerge_adapter_1.Automerge.change(doc, apply);
|
|
9031
|
+
}
|
|
9032
|
+
const base = automerge_adapter_1.Automerge.view(doc, baseHeads);
|
|
9033
|
+
const actor = automerge_adapter_1.Automerge.getActorId(doc);
|
|
9034
|
+
const ownChangeSince = automerge_adapter_1.Automerge.getChanges(base, doc).some((change) => automerge_adapter_1.Automerge.decodeChange(change).actor === actor);
|
|
9035
|
+
const fork = automerge_adapter_1.Automerge.clone(base, ownChangeSince ? undefined : { actor });
|
|
9036
|
+
const changed = automerge_adapter_1.Automerge.change(fork, apply);
|
|
9037
|
+
return automerge_adapter_1.Automerge.merge(doc, changed);
|
|
9038
|
+
}
|
|
8854
9039
|
runChangeWithOutdatedDocRecovery(internalDoc, apply) {
|
|
8855
9040
|
try {
|
|
8856
9041
|
return apply(internalDoc.doc);
|
|
@@ -8942,19 +9127,31 @@ class BaseMindooDB {
|
|
|
8942
9127
|
if (!changeBytes) {
|
|
8943
9128
|
throw new Error("Failed to get change bytes from Automerge document");
|
|
8944
9129
|
}
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
|
|
8956
|
-
|
|
8957
|
-
|
|
9130
|
+
try {
|
|
9131
|
+
await this.persistAutomergeDocumentChanges({
|
|
9132
|
+
internalDoc,
|
|
9133
|
+
newDoc,
|
|
9134
|
+
now,
|
|
9135
|
+
changeBytesList: [changeBytes],
|
|
9136
|
+
useCustomKey,
|
|
9137
|
+
signingKeyPair,
|
|
9138
|
+
signingKeyPassword,
|
|
9139
|
+
successMessage,
|
|
9140
|
+
attachmentIds,
|
|
9141
|
+
bypassPrecheck,
|
|
9142
|
+
recipients: options.recipients,
|
|
9143
|
+
});
|
|
9144
|
+
}
|
|
9145
|
+
catch (error) {
|
|
9146
|
+
// Automerge.change() outdated the cached document and moved its WASM
|
|
9147
|
+
// handle to `newDoc`, so reads of the cache slot would return the change
|
|
9148
|
+
// that was just refused (denied precheck, wrong signing password, failed
|
|
9149
|
+
// store write). Fork the cache back to the heads the change started from.
|
|
9150
|
+
if (internalDoc.doc !== newDoc && headsBeforeChange) {
|
|
9151
|
+
internalDoc.doc = automerge_adapter_1.Automerge.clone(automerge_adapter_1.Automerge.view(newDoc, headsBeforeChange));
|
|
9152
|
+
}
|
|
9153
|
+
throw error;
|
|
9154
|
+
}
|
|
8958
9155
|
}
|
|
8959
9156
|
async persistAutomergeDocumentChanges(options) {
|
|
8960
9157
|
const { internalDoc, newDoc, now, changeBytesList, headsBeforeChange, useCustomKey, signingKeyPair, signingKeyPassword, successMessage, attachmentIds, bypassPrecheck, recipients, } = options;
|
|
@@ -9221,7 +9418,7 @@ class BaseMindooDB {
|
|
|
9221
9418
|
return await this.withRateLimitBackoff("entry prefetch", () => this.store.getEntries(ids));
|
|
9222
9419
|
}
|
|
9223
9420
|
catch (error) {
|
|
9224
|
-
if (networkErrorType(error) !==
|
|
9421
|
+
if (networkErrorType(error) !== types_4.NetworkErrorType.PAYLOAD_TOO_LARGE ||
|
|
9225
9422
|
ids.length <= 1) {
|
|
9226
9423
|
throw error;
|
|
9227
9424
|
}
|
|
@@ -10550,24 +10747,19 @@ class BaseMindooDB {
|
|
|
10550
10747
|
* Whether access control is active for this tenant and should gate
|
|
10551
10748
|
* materialization. Admin-only databases (incl. the directory itself) are
|
|
10552
10749
|
* always exempt — admin is the root of trust, and exempting the directory DB
|
|
10553
|
-
* also avoids re-entrancy.
|
|
10554
|
-
*
|
|
10555
|
-
* break due to a transient directory issue (Tier 2 only gates honest clients).
|
|
10750
|
+
* also avoids re-entrancy. Not cached by wall-clock time: a policy change must
|
|
10751
|
+
* take effect on the very next write or load, independent of machine speed.
|
|
10556
10752
|
*/
|
|
10557
10753
|
async isAclEnforced() {
|
|
10558
10754
|
if (this._isAdminOnlyDb)
|
|
10559
10755
|
return false;
|
|
10560
|
-
const now = Date.now();
|
|
10561
|
-
if (this.aclActiveCache && now - this.aclActiveCache.at < 3000) {
|
|
10562
|
-
return this.aclActiveCache.value;
|
|
10563
|
-
}
|
|
10564
10756
|
try {
|
|
10565
10757
|
const directory = await this.tenant.openDirectory();
|
|
10566
10758
|
let value = false;
|
|
10567
10759
|
if (typeof directory.isAccessControlActive === "function") {
|
|
10568
10760
|
value = await directory.isAccessControlActive();
|
|
10569
10761
|
}
|
|
10570
|
-
this.
|
|
10762
|
+
this.aclActiveLastKnown = value;
|
|
10571
10763
|
return value;
|
|
10572
10764
|
}
|
|
10573
10765
|
catch (error) {
|
|
@@ -10576,9 +10768,9 @@ class BaseMindooDB {
|
|
|
10576
10768
|
// materialization gate entirely). Reuse the last known verdict if we have
|
|
10577
10769
|
// one; otherwise assume enforced so the materialization path governs the
|
|
10578
10770
|
// load and retries once the directory is reachable again.
|
|
10579
|
-
if (this.
|
|
10580
|
-
this.logger.debug(`[ACL] active-check failed, reusing last known verdict (${this.
|
|
10581
|
-
return this.
|
|
10771
|
+
if (this.aclActiveLastKnown !== null) {
|
|
10772
|
+
this.logger.debug(`[ACL] active-check failed, reusing last known verdict (${this.aclActiveLastKnown}): ${error}`);
|
|
10773
|
+
return this.aclActiveLastKnown;
|
|
10582
10774
|
}
|
|
10583
10775
|
this.logger.warn(`[ACL] active-check failed with no prior verdict, assuming enforced (fail closed): ${error}`);
|
|
10584
10776
|
return true;
|
|
@@ -12531,15 +12723,15 @@ class BaseMindooDB {
|
|
|
12531
12723
|
* Resolve a sync target to a ContentAddressedStore.
|
|
12532
12724
|
* Accepts either a raw store or a MindooDB instance (calls getStore()).
|
|
12533
12725
|
*/
|
|
12534
|
-
getStoreForKind(storeKind =
|
|
12535
|
-
return storeKind ===
|
|
12726
|
+
getStoreForKind(storeKind = types_3.StoreKind.docs) {
|
|
12727
|
+
return storeKind === types_3.StoreKind.attachments
|
|
12536
12728
|
? this.attachmentStore
|
|
12537
12729
|
: this.store;
|
|
12538
12730
|
}
|
|
12539
|
-
resolveStore(remote, storeKind =
|
|
12731
|
+
resolveStore(remote, storeKind = types_3.StoreKind.docs) {
|
|
12540
12732
|
if ("getStore" in remote &&
|
|
12541
12733
|
typeof remote.getStore === "function") {
|
|
12542
|
-
return storeKind ===
|
|
12734
|
+
return storeKind === types_3.StoreKind.attachments
|
|
12543
12735
|
? remote.getAttachmentStore()
|
|
12544
12736
|
: remote.getStore();
|
|
12545
12737
|
}
|
|
@@ -12787,7 +12979,7 @@ class BaseMindooDB {
|
|
|
12787
12979
|
*/
|
|
12788
12980
|
async pullChangesFrom(remote, options) {
|
|
12789
12981
|
this.assertWritable("pullChangesFrom");
|
|
12790
|
-
const storeKind = options?.storeKind ??
|
|
12982
|
+
const storeKind = options?.storeKind ?? types_3.StoreKind.docs;
|
|
12791
12983
|
const remoteStore = this.resolveStore(remote, storeKind);
|
|
12792
12984
|
// Entries of documents purged by an admin-signed request are refused on the
|
|
12793
12985
|
// way in, so a replica that has not executed the purge yet cannot hand the
|
|
@@ -12809,7 +13001,7 @@ class BaseMindooDB {
|
|
|
12809
13001
|
// summary buffer / full-text index materialize and extract documents
|
|
12810
13002
|
// while the next page is still on the wire, instead of all at once
|
|
12811
13003
|
// after the transfer (see docs/adhoc-queries.md, "Cold start").
|
|
12812
|
-
const syncResult = await this.syncEntriesFromStore(remoteStore, localStore, options, storeKind ===
|
|
13004
|
+
const syncResult = await this.syncEntriesFromStore(remoteStore, localStore, options, storeKind === types_3.StoreKind.docs
|
|
12813
13005
|
? () => this.syncStoreChanges()
|
|
12814
13006
|
: undefined);
|
|
12815
13007
|
const transferredBytes = syncResult.transferredBytes ?? 0;
|
|
@@ -12825,7 +13017,7 @@ class BaseMindooDB {
|
|
|
12825
13017
|
}
|
|
12826
13018
|
if (syncResult.transferred === 0) {
|
|
12827
13019
|
this.logger.debug(`No new entries to pull`);
|
|
12828
|
-
if (storeKind ===
|
|
13020
|
+
if (storeKind === types_3.StoreKind.docs) {
|
|
12829
13021
|
await this.reconcileAfterDocsPull();
|
|
12830
13022
|
}
|
|
12831
13023
|
return {
|
|
@@ -12853,7 +13045,7 @@ class BaseMindooDB {
|
|
|
12853
13045
|
cancelled: true,
|
|
12854
13046
|
};
|
|
12855
13047
|
}
|
|
12856
|
-
if (storeKind ===
|
|
13048
|
+
if (storeKind === types_3.StoreKind.docs) {
|
|
12857
13049
|
await this.syncStoreChanges();
|
|
12858
13050
|
await this.reconcileAfterDocsPull();
|
|
12859
13051
|
}
|
|
@@ -12922,7 +13114,7 @@ class BaseMindooDB {
|
|
|
12922
13114
|
*/
|
|
12923
13115
|
async pushChangesTo(remote, options) {
|
|
12924
13116
|
this.assertWritable("pushChangesTo");
|
|
12925
|
-
const storeKind = options?.storeKind ??
|
|
13117
|
+
const storeKind = options?.storeKind ?? types_3.StoreKind.docs;
|
|
12926
13118
|
const localStore = this.getStoreForKind(storeKind);
|
|
12927
13119
|
const remoteStore = this.resolveStore(remote, storeKind);
|
|
12928
13120
|
if (localStore.getId() !== remoteStore.getId() ||
|