@korajs/store 1.0.0-beta.1 → 1.0.0-beta.11
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/adapters/better-sqlite3.cjs.map +1 -1
- package/dist/adapters/better-sqlite3.d.cts +1 -1
- package/dist/adapters/better-sqlite3.d.ts +1 -1
- package/dist/adapters/better-sqlite3.js +1 -1
- package/dist/adapters/indexeddb.cjs +523 -148
- package/dist/adapters/indexeddb.cjs.map +1 -1
- package/dist/adapters/indexeddb.d.cts +4 -2
- package/dist/adapters/indexeddb.d.ts +4 -2
- package/dist/adapters/indexeddb.js +55 -11
- package/dist/adapters/indexeddb.js.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.cjs +207 -187
- package/dist/adapters/sqlite-wasm-worker.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm-worker.js +208 -188
- package/dist/adapters/sqlite-wasm-worker.js.map +1 -1
- package/dist/adapters/sqlite-wasm.cjs +474 -140
- package/dist/adapters/sqlite-wasm.cjs.map +1 -1
- package/dist/adapters/sqlite-wasm.d.cts +45 -8
- package/dist/adapters/sqlite-wasm.d.ts +45 -8
- package/dist/adapters/sqlite-wasm.js +3 -3
- package/dist/{backup-ZV4Y424B.js → backup-5S7K2Z35.js} +3 -3
- package/dist/{chunk-FFYA7J5H.js → chunk-CYO3YKFL.js} +4 -3
- package/dist/chunk-CYO3YKFL.js.map +1 -0
- package/dist/{chunk-6NKLDBTY.js → chunk-GSJ7EEUC.js} +2 -1
- package/dist/chunk-GSJ7EEUC.js.map +1 -0
- package/dist/{chunk-X57MWW35.js → chunk-HS6DBMST.js} +13 -10
- package/dist/chunk-HS6DBMST.js.map +1 -0
- package/dist/chunk-RJIEKEN4.js +751 -0
- package/dist/chunk-RJIEKEN4.js.map +1 -0
- package/dist/{chunk-QL2XVZRN.js → chunk-TUR7RGEP.js} +12 -1
- package/dist/{chunk-QL2XVZRN.js.map → chunk-TUR7RGEP.js.map} +1 -1
- package/dist/{chunk-IOEFNHHP.js → chunk-VDBJQ75K.js} +2 -2
- package/dist/chunk-VDBJQ75K.js.map +1 -0
- package/dist/{chunk-ZLWAYQEQ.js → chunk-YT7MRFCP.js} +36 -32
- package/dist/chunk-YT7MRFCP.js.map +1 -0
- package/dist/{export-audit-AJ7RORNK.js → export-audit-ODGQTQIK.js} +3 -3
- package/dist/index.cjs +313 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -5
- package/dist/index.d.ts +51 -5
- package/dist/index.js +212 -59
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +46 -40
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +3 -3
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +3 -3
- package/dist/sqlite-wasm-channel-GGHA2BXU.js +12 -0
- package/dist/{sqlite-wasm-channel-DUDPclTE.d.cts → sqlite-wasm-channel-L6o3bWQK.d.cts} +1 -1
- package/dist/{sqlite-wasm-channel-DUDPclTE.d.ts → sqlite-wasm-channel-L6o3bWQK.d.ts} +1 -1
- package/dist/{types-5h4Hqcwc.d.ts → types-BOO9EPt1.d.ts} +1 -1
- package/dist/{types-k6AZgiH4.d.ts → types-BslDOTk0.d.cts} +26 -1
- package/dist/{types-k6AZgiH4.d.cts → types-BslDOTk0.d.ts} +26 -1
- package/dist/{types-DfPiPwKr.d.cts → types-C_GDavG-.d.cts} +1 -1
- package/package.json +2 -12
- package/dist/adapters/sqlite-wasm-shared-host.cjs +0 -68
- package/dist/adapters/sqlite-wasm-shared-host.cjs.map +0 -1
- package/dist/adapters/sqlite-wasm-shared-host.d.cts +0 -2
- package/dist/adapters/sqlite-wasm-shared-host.d.ts +0 -2
- package/dist/adapters/sqlite-wasm-shared-host.js +0 -66
- package/dist/adapters/sqlite-wasm-shared-host.js.map +0 -1
- package/dist/chunk-6NKLDBTY.js.map +0 -1
- package/dist/chunk-FFYA7J5H.js.map +0 -1
- package/dist/chunk-IOEFNHHP.js.map +0 -1
- package/dist/chunk-RBPVEAVM.js +0 -425
- package/dist/chunk-RBPVEAVM.js.map +0 -1
- package/dist/chunk-X57MWW35.js.map +0 -1
- package/dist/chunk-ZLWAYQEQ.js.map +0 -1
- package/dist/sqlite-wasm-channel-H43KEZLM.js +0 -12
- /package/dist/{backup-ZV4Y424B.js.map → backup-5S7K2Z35.js.map} +0 -0
- /package/dist/{export-audit-AJ7RORNK.js.map → export-audit-ODGQTQIK.js.map} +0 -0
- /package/dist/{sqlite-wasm-channel-H43KEZLM.js.map → sqlite-wasm-channel-GGHA2BXU.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -69,6 +69,7 @@ function encodeRichtext(value) {
|
|
|
69
69
|
}
|
|
70
70
|
if (typeof value === "string") {
|
|
71
71
|
const doc = new Y.Doc();
|
|
72
|
+
doc.clientID = 0;
|
|
72
73
|
doc.getText(TEXT_KEY).insert(0, value);
|
|
73
74
|
return Y.encodeStateAsUpdate(doc);
|
|
74
75
|
}
|
|
@@ -528,7 +529,7 @@ async function restoreBackup(adapter, schema, data, options) {
|
|
|
528
529
|
schema_version: op.schemaVersion
|
|
529
530
|
};
|
|
530
531
|
await tx.execute(
|
|
531
|
-
`INSERT OR IGNORE INTO _kora_ops_${collection} (id, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
532
|
+
`INSERT OR IGNORE INTO ${(0, import_core6.quoteIdent)(`_kora_ops_${collection}`)} (id, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
532
533
|
[
|
|
533
534
|
opRow.id,
|
|
534
535
|
opRow.node_id,
|
|
@@ -547,8 +548,8 @@ async function restoreBackup(adapter, schema, data, options) {
|
|
|
547
548
|
} else {
|
|
548
549
|
await adapter.transaction(async (tx) => {
|
|
549
550
|
for (const collection of Object.keys(schema.collections)) {
|
|
550
|
-
await tx.execute(`DELETE FROM _kora_ops_${collection}`);
|
|
551
|
-
await tx.execute(`DELETE FROM ${collection}`);
|
|
551
|
+
await tx.execute(`DELETE FROM ${(0, import_core6.quoteIdent)(`_kora_ops_${collection}`)}`);
|
|
552
|
+
await tx.execute(`DELETE FROM ${(0, import_core6.quoteIdent)(collection)}`);
|
|
552
553
|
}
|
|
553
554
|
await tx.execute("DELETE FROM _kora_version_vector");
|
|
554
555
|
await tx.execute("DELETE FROM _kora_meta");
|
|
@@ -568,7 +569,7 @@ async function restoreBackup(adapter, schema, data, options) {
|
|
|
568
569
|
for (const op of operations) {
|
|
569
570
|
const collection = op.collection;
|
|
570
571
|
await tx.execute(
|
|
571
|
-
`INSERT INTO _kora_ops_${collection} (id, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
572
|
+
`INSERT INTO ${(0, import_core6.quoteIdent)(`_kora_ops_${collection}`)} (id, node_id, type, record_id, data, previous_data, timestamp, sequence_number, causal_deps, schema_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
572
573
|
[
|
|
573
574
|
op.id,
|
|
574
575
|
op.nodeId,
|
|
@@ -600,6 +601,7 @@ async function restoreBackup(adapter, schema, data, options) {
|
|
|
600
601
|
for (const record of records) {
|
|
601
602
|
const keys = Object.keys(record);
|
|
602
603
|
const placeholders = keys.map(() => "?").join(", ");
|
|
604
|
+
const quotedKeys = keys.map((k) => (0, import_core6.quoteIdent)(k)).join(", ");
|
|
603
605
|
const values = keys.map((k) => {
|
|
604
606
|
const v = record[k];
|
|
605
607
|
if (typeof v === "boolean") return v ? 1 : 0;
|
|
@@ -607,7 +609,7 @@ async function restoreBackup(adapter, schema, data, options) {
|
|
|
607
609
|
return v;
|
|
608
610
|
});
|
|
609
611
|
await tx.execute(
|
|
610
|
-
`INSERT OR REPLACE INTO ${col} (${
|
|
612
|
+
`INSERT OR REPLACE INTO ${(0, import_core6.quoteIdent)(col)} (${quotedKeys}) VALUES (${placeholders})`,
|
|
611
613
|
values
|
|
612
614
|
);
|
|
613
615
|
}
|
|
@@ -640,7 +642,7 @@ async function readAllOperations(adapter, schema) {
|
|
|
640
642
|
const allOps = [];
|
|
641
643
|
for (const collectionName of Object.keys(schema.collections)) {
|
|
642
644
|
const rows = await adapter.query(
|
|
643
|
-
`SELECT * FROM _kora_ops_${collectionName} ORDER BY sequence_number ASC`
|
|
645
|
+
`SELECT * FROM ${(0, import_core6.quoteIdent)(`_kora_ops_${collectionName}`)} ORDER BY sequence_number ASC`
|
|
644
646
|
);
|
|
645
647
|
for (const row of rows) {
|
|
646
648
|
allOps.push(deserializeOperationWithCollection(row, collectionName));
|
|
@@ -649,7 +651,9 @@ async function readAllOperations(adapter, schema) {
|
|
|
649
651
|
return allOps;
|
|
650
652
|
}
|
|
651
653
|
async function readCollectionRecords(adapter, collection) {
|
|
652
|
-
return adapter.query(
|
|
654
|
+
return adapter.query(
|
|
655
|
+
`SELECT * FROM ${(0, import_core6.quoteIdent)(collection)} WHERE _deleted = 0`
|
|
656
|
+
);
|
|
653
657
|
}
|
|
654
658
|
async function computeSha256(data) {
|
|
655
659
|
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
@@ -717,7 +721,7 @@ __export(audit_trace_store_exports, {
|
|
|
717
721
|
});
|
|
718
722
|
function persistedAuditTraceFromEvent(event) {
|
|
719
723
|
return {
|
|
720
|
-
id: (0,
|
|
724
|
+
id: (0, import_core21.generateUUIDv7)(),
|
|
721
725
|
recordedAt: Date.now(),
|
|
722
726
|
eventType: event.type,
|
|
723
727
|
constraint: event.type === "constraint:violated" ? event.constraint : void 0,
|
|
@@ -783,11 +787,11 @@ function auditTraceIndexFields(trace) {
|
|
|
783
787
|
recordId: trace.operationA.recordId
|
|
784
788
|
};
|
|
785
789
|
}
|
|
786
|
-
var
|
|
790
|
+
var import_core21;
|
|
787
791
|
var init_audit_trace_store = __esm({
|
|
788
792
|
"src/audit/audit-trace-store.ts"() {
|
|
789
793
|
"use strict";
|
|
790
|
-
|
|
794
|
+
import_core21 = require("@korajs/core");
|
|
791
795
|
init_audit_json();
|
|
792
796
|
}
|
|
793
797
|
});
|
|
@@ -859,7 +863,7 @@ async function readAllOperations2(adapter, schema, collectionFilter) {
|
|
|
859
863
|
const allOps = [];
|
|
860
864
|
for (const collectionName of collections) {
|
|
861
865
|
const rows = await adapter.query(
|
|
862
|
-
`SELECT * FROM _kora_ops_${collectionName} ORDER BY sequence_number ASC`
|
|
866
|
+
`SELECT * FROM ${(0, import_core22.quoteIdent)(`_kora_ops_${collectionName}`)} ORDER BY sequence_number ASC`
|
|
863
867
|
);
|
|
864
868
|
for (const row of rows) {
|
|
865
869
|
allOps.push(deserializeOperationWithCollection(row, collectionName));
|
|
@@ -970,9 +974,11 @@ function parseNdjsonSection(content) {
|
|
|
970
974
|
}
|
|
971
975
|
return text.split("\n").map((line) => deserializeAuditJson(line));
|
|
972
976
|
}
|
|
977
|
+
var import_core22;
|
|
973
978
|
var init_export_audit = __esm({
|
|
974
979
|
"src/audit/export-audit.ts"() {
|
|
975
980
|
"use strict";
|
|
981
|
+
import_core22 = require("@korajs/core");
|
|
976
982
|
init_serializer();
|
|
977
983
|
init_audit_json();
|
|
978
984
|
init_audit_trace_store();
|
|
@@ -990,6 +996,7 @@ __export(index_exports, {
|
|
|
990
996
|
InvalidStateTransitionError: () => InvalidStateTransitionError,
|
|
991
997
|
LAST_ACKED_SERVER_VECTOR_META_KEY: () => LAST_ACKED_SERVER_VECTOR_META_KEY,
|
|
992
998
|
MemoryBlobStore: () => MemoryBlobStore,
|
|
999
|
+
NoLeaderError: () => NoLeaderError,
|
|
993
1000
|
OpfsBlobStore: () => OpfsBlobStore,
|
|
994
1001
|
OptimisticLockError: () => OptimisticLockError,
|
|
995
1002
|
PersistenceError: () => PersistenceError,
|
|
@@ -1108,6 +1115,16 @@ var WorkerTimeoutError = class extends import_core.KoraError {
|
|
|
1108
1115
|
this.name = "WorkerTimeoutError";
|
|
1109
1116
|
}
|
|
1110
1117
|
};
|
|
1118
|
+
var NoLeaderError = class extends import_core.KoraError {
|
|
1119
|
+
constructor(operation) {
|
|
1120
|
+
super(
|
|
1121
|
+
`No live leader tab is answering multi-tab storage RPC for operation "${operation}"`,
|
|
1122
|
+
"NO_LEADER",
|
|
1123
|
+
{ operation }
|
|
1124
|
+
);
|
|
1125
|
+
this.name = "NoLeaderError";
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1111
1128
|
var PersistenceError = class extends import_core.KoraError {
|
|
1112
1129
|
constructor(message, context) {
|
|
1113
1130
|
super(`Persistence error: ${message}`, "PERSISTENCE_ERROR", context);
|
|
@@ -1147,7 +1164,7 @@ async function compactOperationLog(adapter, schema, strategy, serverVector) {
|
|
|
1147
1164
|
const collectionNames = Object.keys(schema.collections);
|
|
1148
1165
|
await adapter.transaction(async (tx) => {
|
|
1149
1166
|
for (const collectionName of collectionNames) {
|
|
1150
|
-
const table = `_kora_ops_${collectionName}
|
|
1167
|
+
const table = (0, import_core2.quoteIdent)(`_kora_ops_${collectionName}`);
|
|
1151
1168
|
for (const [nodeId, maxSeq] of watermark) {
|
|
1152
1169
|
if (maxSeq <= 0) continue;
|
|
1153
1170
|
const countSql = buildCountSql(table, ageCutoffSerialized !== null);
|
|
@@ -1182,6 +1199,7 @@ function buildDeleteSql(table, withAge) {
|
|
|
1182
1199
|
var import_core3 = require("@korajs/core");
|
|
1183
1200
|
var LAST_ACKED_SERVER_VECTOR_META_KEY = "last_acked_server_vector";
|
|
1184
1201
|
var DELTA_CURSOR_META_KEY = "delta_cursor";
|
|
1202
|
+
var DELIVERY_WATERMARK_META_KEY = "delivery_watermark";
|
|
1185
1203
|
function serializeVersionVectorToMeta(vector) {
|
|
1186
1204
|
const record = {};
|
|
1187
1205
|
for (const [nodeId, seq] of vector) {
|
|
@@ -1254,13 +1272,55 @@ async function saveDeltaCursor(adapter, cursor) {
|
|
|
1254
1272
|
cursor
|
|
1255
1273
|
]);
|
|
1256
1274
|
}
|
|
1275
|
+
function deliveryWatermarkKey(signature) {
|
|
1276
|
+
return signature === "" ? DELIVERY_WATERMARK_META_KEY : `${DELIVERY_WATERMARK_META_KEY}:${signature}`;
|
|
1277
|
+
}
|
|
1278
|
+
async function loadDeliveryWatermark(adapter, signature) {
|
|
1279
|
+
const rows = await adapter.query("SELECT value FROM _kora_meta WHERE key = ?", [
|
|
1280
|
+
deliveryWatermarkKey(signature)
|
|
1281
|
+
]);
|
|
1282
|
+
const value = rows[0]?.value;
|
|
1283
|
+
if (value === void 0 || value === null) {
|
|
1284
|
+
return 0;
|
|
1285
|
+
}
|
|
1286
|
+
const parsed = Number(value);
|
|
1287
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
|
|
1288
|
+
}
|
|
1289
|
+
async function saveDeliveryWatermark(adapter, signature, watermark) {
|
|
1290
|
+
await adapter.execute("INSERT OR REPLACE INTO _kora_meta (key, value) VALUES (?, ?)", [
|
|
1291
|
+
deliveryWatermarkKey(signature),
|
|
1292
|
+
String(watermark)
|
|
1293
|
+
]);
|
|
1294
|
+
}
|
|
1295
|
+
async function deleteDeliveryWatermark(adapter, signature) {
|
|
1296
|
+
await adapter.execute("DELETE FROM _kora_meta WHERE key = ?", [deliveryWatermarkKey(signature)]);
|
|
1297
|
+
}
|
|
1298
|
+
async function loadAllDeliveryWatermarks(adapter) {
|
|
1299
|
+
const rows = await adapter.query(
|
|
1300
|
+
"SELECT key, value FROM _kora_meta WHERE key = ? OR key LIKE ?",
|
|
1301
|
+
[DELIVERY_WATERMARK_META_KEY, `${DELIVERY_WATERMARK_META_KEY}:%`]
|
|
1302
|
+
);
|
|
1303
|
+
const result = {};
|
|
1304
|
+
const prefix = `${DELIVERY_WATERMARK_META_KEY}:`;
|
|
1305
|
+
for (const row of rows) {
|
|
1306
|
+
const signature = row.key === DELIVERY_WATERMARK_META_KEY ? "" : row.key.slice(prefix.length);
|
|
1307
|
+
const parsed = Number(row.value);
|
|
1308
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
1309
|
+
result[signature] = parsed;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
return result;
|
|
1313
|
+
}
|
|
1257
1314
|
|
|
1258
1315
|
// src/store/store.ts
|
|
1259
|
-
var
|
|
1316
|
+
var import_core23 = require("@korajs/core");
|
|
1260
1317
|
init_backup();
|
|
1261
1318
|
|
|
1319
|
+
// src/collection/collection.ts
|
|
1320
|
+
var import_core13 = require("@korajs/core");
|
|
1321
|
+
|
|
1262
1322
|
// src/mutations/execute-delete.ts
|
|
1263
|
-
var
|
|
1323
|
+
var import_core9 = require("@korajs/core");
|
|
1264
1324
|
|
|
1265
1325
|
// src/lww/row-version.ts
|
|
1266
1326
|
var import_core7 = require("@korajs/core");
|
|
@@ -1286,9 +1346,10 @@ function lwwVersionWhereClause(remoteVersion) {
|
|
|
1286
1346
|
}
|
|
1287
1347
|
|
|
1288
1348
|
// src/query/sql-builder.ts
|
|
1349
|
+
var import_core8 = require("@korajs/core");
|
|
1289
1350
|
function buildSelectQuery(descriptor, fields) {
|
|
1290
1351
|
const params = [];
|
|
1291
|
-
const parts = [`SELECT * FROM ${descriptor.collection}`];
|
|
1352
|
+
const parts = [`SELECT * FROM ${(0, import_core8.quoteIdent)(descriptor.collection)}`];
|
|
1292
1353
|
const whereClause = buildWhereClauseParts(descriptor.where, fields, params);
|
|
1293
1354
|
const deletedFilter = "_deleted = 0";
|
|
1294
1355
|
if (whereClause) {
|
|
@@ -1299,7 +1360,7 @@ function buildSelectQuery(descriptor, fields) {
|
|
|
1299
1360
|
if (descriptor.orderBy.length > 0) {
|
|
1300
1361
|
const orderParts = descriptor.orderBy.map((o) => {
|
|
1301
1362
|
validateFieldName(o.field, fields);
|
|
1302
|
-
return `${o.field} ${o.direction.toUpperCase()}`;
|
|
1363
|
+
return `${(0, import_core8.quoteIdent)(o.field)} ${o.direction.toUpperCase()}`;
|
|
1303
1364
|
});
|
|
1304
1365
|
parts.push(`ORDER BY ${orderParts.join(", ")}`);
|
|
1305
1366
|
}
|
|
@@ -1313,7 +1374,7 @@ function buildSelectQuery(descriptor, fields) {
|
|
|
1313
1374
|
}
|
|
1314
1375
|
function buildCountQuery(descriptor, fields) {
|
|
1315
1376
|
const params = [];
|
|
1316
|
-
const parts = [`SELECT COUNT(*) as count FROM ${descriptor.collection}`];
|
|
1377
|
+
const parts = [`SELECT COUNT(*) as count FROM ${(0, import_core8.quoteIdent)(descriptor.collection)}`];
|
|
1317
1378
|
const whereClause = buildWhereClauseParts(descriptor.where, fields, params);
|
|
1318
1379
|
const deletedFilter = "_deleted = 0";
|
|
1319
1380
|
if (whereClause) {
|
|
@@ -1327,17 +1388,18 @@ function buildInsertQuery(collection, record) {
|
|
|
1327
1388
|
const columns = Object.keys(record);
|
|
1328
1389
|
const placeholders = columns.map(() => "?");
|
|
1329
1390
|
const params = Object.values(record);
|
|
1330
|
-
const
|
|
1391
|
+
const quotedColumns = columns.map((col) => (0, import_core8.quoteIdent)(col));
|
|
1392
|
+
const sql = `INSERT INTO ${(0, import_core8.quoteIdent)(collection)} (${quotedColumns.join(", ")}) VALUES (${placeholders.join(", ")})`;
|
|
1331
1393
|
return { sql, params };
|
|
1332
1394
|
}
|
|
1333
1395
|
function buildUpdateQuery(collection, id, changes) {
|
|
1334
|
-
const setClauses = Object.keys(changes).map((col) => `${col} = ?`);
|
|
1396
|
+
const setClauses = Object.keys(changes).map((col) => `${(0, import_core8.quoteIdent)(col)} = ?`);
|
|
1335
1397
|
const params = [...Object.values(changes), id];
|
|
1336
|
-
const sql = `UPDATE ${collection} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1398
|
+
const sql = `UPDATE ${(0, import_core8.quoteIdent)(collection)} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1337
1399
|
return { sql, params };
|
|
1338
1400
|
}
|
|
1339
1401
|
function buildFieldFastForwardUpdateQuery(collection, id, fieldChanges, remoteVersion, wallTime, options) {
|
|
1340
|
-
const fieldClauses = Object.keys(fieldChanges).map((col) => `${col} = ?`);
|
|
1402
|
+
const fieldClauses = Object.keys(fieldChanges).map((col) => `${(0, import_core8.quoteIdent)(col)} = ?`);
|
|
1341
1403
|
const setClauses = [
|
|
1342
1404
|
...fieldClauses,
|
|
1343
1405
|
"_version = CASE WHEN _version >= ? THEN _version ELSE ? END",
|
|
@@ -1355,25 +1417,25 @@ function buildFieldFastForwardUpdateQuery(collection, id, fieldChanges, remoteVe
|
|
|
1355
1417
|
params.push(options.maxCreatedAt, options.maxCreatedAt);
|
|
1356
1418
|
}
|
|
1357
1419
|
params.push(id);
|
|
1358
|
-
const sql = `UPDATE ${collection} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1420
|
+
const sql = `UPDATE ${(0, import_core8.quoteIdent)(collection)} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1359
1421
|
return { sql, params };
|
|
1360
1422
|
}
|
|
1361
1423
|
function buildSoftDeleteQuery(collection, id, updatedAt, version) {
|
|
1362
1424
|
if (version !== void 0) {
|
|
1363
1425
|
return {
|
|
1364
|
-
sql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ?`,
|
|
1426
|
+
sql: `UPDATE ${(0, import_core8.quoteIdent)(collection)} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ?`,
|
|
1365
1427
|
params: [updatedAt, version, id]
|
|
1366
1428
|
};
|
|
1367
1429
|
}
|
|
1368
1430
|
return {
|
|
1369
|
-
sql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ? WHERE id = ?`,
|
|
1431
|
+
sql: `UPDATE ${(0, import_core8.quoteIdent)(collection)} SET _deleted = 1, _updated_at = ? WHERE id = ?`,
|
|
1370
1432
|
params: [updatedAt, id]
|
|
1371
1433
|
};
|
|
1372
1434
|
}
|
|
1373
1435
|
function buildLwwSoftDeleteQuery(collection, id, updatedAt, version) {
|
|
1374
1436
|
const lww = lwwVersionWhereClause(version);
|
|
1375
1437
|
return {
|
|
1376
|
-
sql: `UPDATE ${collection} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ? AND ${lww.sql}`,
|
|
1438
|
+
sql: `UPDATE ${(0, import_core8.quoteIdent)(collection)} SET _deleted = 1, _updated_at = ?, _version = ? WHERE id = ? AND ${lww.sql}`,
|
|
1377
1439
|
params: [updatedAt, version, id, ...lww.params]
|
|
1378
1440
|
};
|
|
1379
1441
|
}
|
|
@@ -1404,31 +1466,32 @@ function buildWhereClauseParts(where, fields, params) {
|
|
|
1404
1466
|
}
|
|
1405
1467
|
function buildOperatorCondition(fieldName, operator, value, descriptor, params) {
|
|
1406
1468
|
const sqlValue = descriptor?.kind === "boolean" && typeof value === "boolean" ? value ? 1 : 0 : value;
|
|
1469
|
+
const column = (0, import_core8.quoteIdent)(fieldName);
|
|
1407
1470
|
switch (operator) {
|
|
1408
1471
|
case "$eq":
|
|
1409
1472
|
if (sqlValue === null) {
|
|
1410
|
-
return `${
|
|
1473
|
+
return `${column} IS NULL`;
|
|
1411
1474
|
}
|
|
1412
1475
|
params.push(sqlValue);
|
|
1413
|
-
return `${
|
|
1476
|
+
return `${column} = ?`;
|
|
1414
1477
|
case "$ne":
|
|
1415
1478
|
if (sqlValue === null) {
|
|
1416
|
-
return `${
|
|
1479
|
+
return `${column} IS NOT NULL`;
|
|
1417
1480
|
}
|
|
1418
1481
|
params.push(sqlValue);
|
|
1419
|
-
return `${
|
|
1482
|
+
return `${column} != ?`;
|
|
1420
1483
|
case "$gt":
|
|
1421
1484
|
params.push(sqlValue);
|
|
1422
|
-
return `${
|
|
1485
|
+
return `${column} > ?`;
|
|
1423
1486
|
case "$gte":
|
|
1424
1487
|
params.push(sqlValue);
|
|
1425
|
-
return `${
|
|
1488
|
+
return `${column} >= ?`;
|
|
1426
1489
|
case "$lt":
|
|
1427
1490
|
params.push(sqlValue);
|
|
1428
|
-
return `${
|
|
1491
|
+
return `${column} < ?`;
|
|
1429
1492
|
case "$lte":
|
|
1430
1493
|
params.push(sqlValue);
|
|
1431
|
-
return `${
|
|
1494
|
+
return `${column} <= ?`;
|
|
1432
1495
|
case "$in": {
|
|
1433
1496
|
if (!Array.isArray(sqlValue)) {
|
|
1434
1497
|
throw new QueryError(`$in operator requires an array value for field "${fieldName}"`, {
|
|
@@ -1442,7 +1505,7 @@ function buildOperatorCondition(fieldName, operator, value, descriptor, params)
|
|
|
1442
1505
|
descriptor?.kind === "boolean" && typeof item === "boolean" ? item ? 1 : 0 : item
|
|
1443
1506
|
);
|
|
1444
1507
|
}
|
|
1445
|
-
return `${
|
|
1508
|
+
return `${column} IN (${placeholders.join(", ")})`;
|
|
1446
1509
|
}
|
|
1447
1510
|
default:
|
|
1448
1511
|
throw new QueryError(`Unknown operator "${operator}"`, { operator });
|
|
@@ -1522,7 +1585,7 @@ function resolveCausalDeps(ctx) {
|
|
|
1522
1585
|
// src/mutations/execute-delete.ts
|
|
1523
1586
|
async function executeDelete(ctx, id, options) {
|
|
1524
1587
|
const currentRows = await ctx.adapter.query(
|
|
1525
|
-
`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,
|
|
1588
|
+
`SELECT * FROM ${(0, import_core9.quoteIdent)(ctx.collection)} WHERE id = ? AND _deleted = 0`,
|
|
1526
1589
|
[id]
|
|
1527
1590
|
);
|
|
1528
1591
|
if (!currentRows[0]) {
|
|
@@ -1534,7 +1597,7 @@ async function executeDelete(ctx, id, options) {
|
|
|
1534
1597
|
await ctx.adapter.transaction(async (tx) => {
|
|
1535
1598
|
if (!operation) {
|
|
1536
1599
|
const sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId);
|
|
1537
|
-
operation = await (0,
|
|
1600
|
+
operation = await (0, import_core9.createOperation)(
|
|
1538
1601
|
{
|
|
1539
1602
|
nodeId: ctx.nodeId,
|
|
1540
1603
|
type: "delete",
|
|
@@ -1581,7 +1644,7 @@ async function executeDelete(ctx, id, options) {
|
|
|
1581
1644
|
}
|
|
1582
1645
|
|
|
1583
1646
|
// src/mutations/execute-insert.ts
|
|
1584
|
-
var
|
|
1647
|
+
var import_core10 = require("@korajs/core");
|
|
1585
1648
|
|
|
1586
1649
|
// src/lww/field-versions.ts
|
|
1587
1650
|
function parseFieldVersions(raw) {
|
|
@@ -1638,14 +1701,14 @@ function resolvePerFieldLww(current, incomingFields, incomingVersion, rowVersion
|
|
|
1638
1701
|
init_op_data_encoding();
|
|
1639
1702
|
init_serializer();
|
|
1640
1703
|
async function executeInsert(ctx, data) {
|
|
1641
|
-
const validated = (0,
|
|
1642
|
-
const recordId = (0,
|
|
1704
|
+
const validated = (0, import_core10.validateRecord)(ctx.collection, ctx.definition, data, "insert");
|
|
1705
|
+
const recordId = (0, import_core10.generateUUIDv7)();
|
|
1643
1706
|
for (const [fieldName, descriptor] of Object.entries(ctx.definition.fields)) {
|
|
1644
1707
|
if (descriptor.auto && descriptor.kind === "timestamp") {
|
|
1645
1708
|
validated[fieldName] = Date.now();
|
|
1646
1709
|
}
|
|
1647
1710
|
}
|
|
1648
|
-
const writeData = await (0,
|
|
1711
|
+
const writeData = await (0, import_core10.transformSecretFieldsForWrite)(
|
|
1649
1712
|
validated,
|
|
1650
1713
|
ctx.definition,
|
|
1651
1714
|
ctx.secretKeyProvider
|
|
@@ -1655,7 +1718,7 @@ async function executeInsert(ctx, data) {
|
|
|
1655
1718
|
let record;
|
|
1656
1719
|
await ctx.adapter.transaction(async (tx) => {
|
|
1657
1720
|
const sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId);
|
|
1658
|
-
operation = await (0,
|
|
1721
|
+
operation = await (0, import_core10.createOperation)(
|
|
1659
1722
|
{
|
|
1660
1723
|
nodeId: ctx.nodeId,
|
|
1661
1724
|
type: "insert",
|
|
@@ -1705,13 +1768,13 @@ async function executeInsert(ctx, data) {
|
|
|
1705
1768
|
}
|
|
1706
1769
|
|
|
1707
1770
|
// src/mutations/execute-update.ts
|
|
1708
|
-
var
|
|
1771
|
+
var import_core12 = require("@korajs/core");
|
|
1709
1772
|
init_op_data_encoding();
|
|
1710
1773
|
init_serializer();
|
|
1711
1774
|
|
|
1712
1775
|
// src/state-machine/state-validator.ts
|
|
1713
|
-
var
|
|
1714
|
-
var InvalidStateTransitionError = class extends
|
|
1776
|
+
var import_core11 = require("@korajs/core");
|
|
1777
|
+
var InvalidStateTransitionError = class extends import_core11.KoraError {
|
|
1715
1778
|
constructor(collection, recordId, field, fromState, toState, allowedStates) {
|
|
1716
1779
|
super(
|
|
1717
1780
|
`Invalid state transition in collection "${collection}": cannot transition field "${field}" from "${fromState}" to "${toState}". Allowed transitions from "${fromState}": ${allowedStates.length > 0 ? allowedStates.join(", ") : "(none -- terminal state)"}`,
|
|
@@ -1745,7 +1808,7 @@ function validateStateTransition(collectionName, recordId, stateMachine, current
|
|
|
1745
1808
|
collection: collectionName,
|
|
1746
1809
|
transitions: stateMachine.transitions
|
|
1747
1810
|
};
|
|
1748
|
-
const transitionResult = (0,
|
|
1811
|
+
const transitionResult = (0, import_core11.validateTransition)(constraint, currentState, newState);
|
|
1749
1812
|
if (transitionResult.valid) {
|
|
1750
1813
|
return { valid: true, allowedStates: transitionResult.allowedTargets };
|
|
1751
1814
|
}
|
|
@@ -1794,14 +1857,14 @@ function validateUpdateStateMachine(collectionName, recordId, collectionDef, cur
|
|
|
1794
1857
|
// src/mutations/execute-update.ts
|
|
1795
1858
|
async function executeUpdate(ctx, id, data) {
|
|
1796
1859
|
const currentRows = await ctx.adapter.query(
|
|
1797
|
-
`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,
|
|
1860
|
+
`SELECT * FROM ${(0, import_core12.quoteIdent)(ctx.collection)} WHERE id = ? AND _deleted = 0`,
|
|
1798
1861
|
[id]
|
|
1799
1862
|
);
|
|
1800
1863
|
const currentRow = currentRows[0];
|
|
1801
1864
|
if (!currentRow) {
|
|
1802
1865
|
throw new RecordNotFoundError(ctx.collection, id);
|
|
1803
1866
|
}
|
|
1804
|
-
let validated = (0,
|
|
1867
|
+
let validated = (0, import_core12.validateRecord)(ctx.collection, ctx.definition, data, "update");
|
|
1805
1868
|
const currentRecord = deserializeRecord(currentRow, ctx.definition.fields);
|
|
1806
1869
|
validated = validateUpdateStateMachine(
|
|
1807
1870
|
ctx.collection,
|
|
@@ -1819,14 +1882,14 @@ async function executeUpdate(ctx, id, data) {
|
|
|
1819
1882
|
for (const key of Object.keys(validated)) {
|
|
1820
1883
|
const value = validated[key];
|
|
1821
1884
|
previousData[key] = currentRecord[key];
|
|
1822
|
-
if ((0,
|
|
1823
|
-
resolvedData[key] = (0,
|
|
1824
|
-
atomicOps[key] = (0,
|
|
1885
|
+
if ((0, import_core12.isAtomicOp)(value)) {
|
|
1886
|
+
resolvedData[key] = (0, import_core12.resolveAtomicOp)(currentRecord[key], value);
|
|
1887
|
+
atomicOps[key] = (0, import_core12.toAtomicOp)(value);
|
|
1825
1888
|
} else {
|
|
1826
1889
|
resolvedData[key] = value;
|
|
1827
1890
|
}
|
|
1828
1891
|
}
|
|
1829
|
-
const writeData = await (0,
|
|
1892
|
+
const writeData = await (0, import_core12.transformSecretFieldsForWrite)(
|
|
1830
1893
|
resolvedData,
|
|
1831
1894
|
ctx.definition,
|
|
1832
1895
|
ctx.secretKeyProvider
|
|
@@ -1836,7 +1899,7 @@ async function executeUpdate(ctx, id, data) {
|
|
|
1836
1899
|
let operation;
|
|
1837
1900
|
await ctx.adapter.transaction(async (tx) => {
|
|
1838
1901
|
const sequenceNumber = await allocateNextSequenceInTransaction(tx, ctx.nodeId);
|
|
1839
|
-
operation = await (0,
|
|
1902
|
+
operation = await (0, import_core12.createOperation)(
|
|
1840
1903
|
{
|
|
1841
1904
|
nodeId: ctx.nodeId,
|
|
1842
1905
|
type: "update",
|
|
@@ -1876,7 +1939,7 @@ async function executeUpdate(ctx, id, data) {
|
|
|
1876
1939
|
});
|
|
1877
1940
|
ctx.onMutation(ctx.collection, operation);
|
|
1878
1941
|
const rows = await ctx.adapter.query(
|
|
1879
|
-
`SELECT * FROM ${ctx.collection} WHERE id = ? AND _deleted = 0`,
|
|
1942
|
+
`SELECT * FROM ${(0, import_core12.quoteIdent)(ctx.collection)} WHERE id = ? AND _deleted = 0`,
|
|
1880
1943
|
[id]
|
|
1881
1944
|
);
|
|
1882
1945
|
const row = rows[0];
|
|
@@ -1939,7 +2002,7 @@ var Collection = class {
|
|
|
1939
2002
|
}
|
|
1940
2003
|
async findById(id) {
|
|
1941
2004
|
const rows = await this.adapter.query(
|
|
1942
|
-
`SELECT * FROM ${this.name} WHERE id = ? AND _deleted = 0`,
|
|
2005
|
+
`SELECT * FROM ${(0, import_core13.quoteIdent)(this.name)} WHERE id = ? AND _deleted = 0`,
|
|
1943
2006
|
[id]
|
|
1944
2007
|
);
|
|
1945
2008
|
const row = rows[0];
|
|
@@ -1972,6 +2035,7 @@ var Collection = class {
|
|
|
1972
2035
|
};
|
|
1973
2036
|
|
|
1974
2037
|
// src/query/query-builder.ts
|
|
2038
|
+
var import_core14 = require("@korajs/core");
|
|
1975
2039
|
init_serializer();
|
|
1976
2040
|
|
|
1977
2041
|
// src/query/pluralize.ts
|
|
@@ -2203,7 +2267,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
2203
2267
|
const relatedDef = this.schema?.collections[relatedCollection];
|
|
2204
2268
|
if (!relatedDef) return;
|
|
2205
2269
|
const placeholders = uniqueFks.map(() => "?").join(", ");
|
|
2206
|
-
const sql = `SELECT * FROM ${relatedCollection} WHERE id IN (${placeholders}) AND _deleted = 0`;
|
|
2270
|
+
const sql = `SELECT * FROM ${(0, import_core14.quoteIdent)(relatedCollection)} WHERE id IN (${placeholders}) AND _deleted = 0`;
|
|
2207
2271
|
const rows = await this.adapter.query(sql, uniqueFks);
|
|
2208
2272
|
const relatedRecords = rows.map((row) => deserializeRecord(row, relatedDef.fields));
|
|
2209
2273
|
const lookup = /* @__PURE__ */ new Map();
|
|
@@ -2226,7 +2290,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
2226
2290
|
if (!relatedDef) return;
|
|
2227
2291
|
const fkField = relation.field;
|
|
2228
2292
|
const placeholders = primaryIds.map(() => "?").join(", ");
|
|
2229
|
-
const sql = `SELECT * FROM ${relatedCollection} WHERE ${fkField} IN (${placeholders}) AND _deleted = 0`;
|
|
2293
|
+
const sql = `SELECT * FROM ${(0, import_core14.quoteIdent)(relatedCollection)} WHERE ${(0, import_core14.quoteIdent)(fkField)} IN (${placeholders}) AND _deleted = 0`;
|
|
2230
2294
|
const rows = await this.adapter.query(sql, primaryIds);
|
|
2231
2295
|
const relatedRecords = rows.map((row) => deserializeRecord(row, relatedDef.fields));
|
|
2232
2296
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -2268,7 +2332,7 @@ var QueryError2 = class extends Error {
|
|
|
2268
2332
|
};
|
|
2269
2333
|
|
|
2270
2334
|
// src/relations/relation-enforcer.ts
|
|
2271
|
-
var
|
|
2335
|
+
var import_core15 = require("@korajs/core");
|
|
2272
2336
|
init_serializer();
|
|
2273
2337
|
|
|
2274
2338
|
// src/relations/relation-lookup.ts
|
|
@@ -2293,7 +2357,7 @@ function getIncomingRelations(lookup, collection) {
|
|
|
2293
2357
|
}
|
|
2294
2358
|
|
|
2295
2359
|
// src/relations/relation-enforcer.ts
|
|
2296
|
-
var ReferentialIntegrityError = class extends
|
|
2360
|
+
var ReferentialIntegrityError = class extends import_core15.KoraError {
|
|
2297
2361
|
constructor(collection, recordId, referencingCollection, relationName, referencingCount) {
|
|
2298
2362
|
super(
|
|
2299
2363
|
`Cannot delete record "${recordId}" from "${collection}": ${referencingCount} record(s) in "${referencingCollection}" reference it via relation "${relationName}" with onDelete: 'restrict'. Delete or reassign the referencing records first.`,
|
|
@@ -2372,7 +2436,7 @@ var RelationEnforcer = class {
|
|
|
2372
2436
|
async enforceCascade(incoming, deletedRecordId, tx, causalDeps) {
|
|
2373
2437
|
const { sourceCollection, foreignKeyField } = incoming;
|
|
2374
2438
|
const referencingRows = await tx.query(
|
|
2375
|
-
`SELECT id FROM ${sourceCollection} WHERE ${foreignKeyField} = ? AND _deleted = 0`,
|
|
2439
|
+
`SELECT id FROM ${(0, import_core15.quoteIdent)(sourceCollection)} WHERE ${(0, import_core15.quoteIdent)(foreignKeyField)} = ? AND _deleted = 0`,
|
|
2376
2440
|
[deletedRecordId]
|
|
2377
2441
|
);
|
|
2378
2442
|
if (referencingRows.length === 0) {
|
|
@@ -2382,7 +2446,7 @@ var RelationEnforcer = class {
|
|
|
2382
2446
|
for (const row of referencingRows) {
|
|
2383
2447
|
const now = Date.now();
|
|
2384
2448
|
const sequenceNumber = await allocateNextSequenceInTransaction(tx, this.nodeId);
|
|
2385
|
-
const operation = await (0,
|
|
2449
|
+
const operation = await (0, import_core15.createOperation)(
|
|
2386
2450
|
{
|
|
2387
2451
|
nodeId: this.nodeId,
|
|
2388
2452
|
type: "delete",
|
|
@@ -2419,7 +2483,7 @@ var RelationEnforcer = class {
|
|
|
2419
2483
|
return [];
|
|
2420
2484
|
}
|
|
2421
2485
|
const referencingRows = await tx.query(
|
|
2422
|
-
`SELECT id FROM ${sourceCollection} WHERE ${foreignKeyField} = ? AND _deleted = 0`,
|
|
2486
|
+
`SELECT id FROM ${(0, import_core15.quoteIdent)(sourceCollection)} WHERE ${(0, import_core15.quoteIdent)(foreignKeyField)} = ? AND _deleted = 0`,
|
|
2423
2487
|
[deletedRecordId]
|
|
2424
2488
|
);
|
|
2425
2489
|
if (referencingRows.length === 0) {
|
|
@@ -2431,7 +2495,7 @@ var RelationEnforcer = class {
|
|
|
2431
2495
|
const sequenceNumber = await allocateNextSequenceInTransaction(tx, this.nodeId);
|
|
2432
2496
|
const updateData = { [foreignKeyField]: null };
|
|
2433
2497
|
const previousData = { [foreignKeyField]: deletedRecordId };
|
|
2434
|
-
const operation = await (0,
|
|
2498
|
+
const operation = await (0, import_core15.createOperation)(
|
|
2435
2499
|
{
|
|
2436
2500
|
nodeId: this.nodeId,
|
|
2437
2501
|
type: "update",
|
|
@@ -2467,7 +2531,7 @@ var RelationEnforcer = class {
|
|
|
2467
2531
|
async enforceRestrict(incoming, deletedRecordId, tx) {
|
|
2468
2532
|
const { sourceCollection, foreignKeyField, relationName } = incoming;
|
|
2469
2533
|
const countRows = await tx.query(
|
|
2470
|
-
`SELECT COUNT(*) as cnt FROM ${sourceCollection} WHERE ${foreignKeyField} = ? AND _deleted = 0`,
|
|
2534
|
+
`SELECT COUNT(*) as cnt FROM ${(0, import_core15.quoteIdent)(sourceCollection)} WHERE ${(0, import_core15.quoteIdent)(foreignKeyField)} = ? AND _deleted = 0`,
|
|
2471
2535
|
[deletedRecordId]
|
|
2472
2536
|
);
|
|
2473
2537
|
const count = countRows[0]?.cnt ?? 0;
|
|
@@ -2492,7 +2556,7 @@ var RelationEnforcer = class {
|
|
|
2492
2556
|
};
|
|
2493
2557
|
|
|
2494
2558
|
// src/replay/replay-to.ts
|
|
2495
|
-
var
|
|
2559
|
+
var import_core16 = require("@korajs/core");
|
|
2496
2560
|
var import_internal = require("@korajs/core/internal");
|
|
2497
2561
|
init_op_data_encoding();
|
|
2498
2562
|
function collectCausalClosure(allOps, targetOperationId) {
|
|
@@ -2502,7 +2566,7 @@ function collectCausalClosure(allOps, targetOperationId) {
|
|
|
2502
2566
|
}
|
|
2503
2567
|
const target = opMap.get(targetOperationId);
|
|
2504
2568
|
if (!target) {
|
|
2505
|
-
throw new
|
|
2569
|
+
throw new import_core16.OperationError(
|
|
2506
2570
|
`Operation "${targetOperationId}" not found in the local operation log`,
|
|
2507
2571
|
{
|
|
2508
2572
|
operationId: targetOperationId
|
|
@@ -2534,7 +2598,7 @@ function buildReplaySnapshot(schema, allOps, targetOperationId) {
|
|
|
2534
2598
|
const operationsApplied = collectCausalClosure(allOps, targetOperationId);
|
|
2535
2599
|
const targetOperation = operationsApplied.find((op) => op.id === targetOperationId);
|
|
2536
2600
|
if (!targetOperation) {
|
|
2537
|
-
throw new
|
|
2601
|
+
throw new import_core16.OperationError(`Operation "${targetOperationId}" not found after causal sort`, {
|
|
2538
2602
|
operationId: targetOperationId
|
|
2539
2603
|
});
|
|
2540
2604
|
}
|
|
@@ -2660,7 +2724,7 @@ function toCollectionRecord(record, definition) {
|
|
|
2660
2724
|
}
|
|
2661
2725
|
|
|
2662
2726
|
// src/sequences/sequence-manager.ts
|
|
2663
|
-
var
|
|
2727
|
+
var import_core17 = require("@korajs/core");
|
|
2664
2728
|
var SequenceManager = class {
|
|
2665
2729
|
adapter;
|
|
2666
2730
|
nodeId;
|
|
@@ -2678,7 +2742,7 @@ var SequenceManager = class {
|
|
|
2678
2742
|
async next(name, config) {
|
|
2679
2743
|
const scope = config?.scope ?? "";
|
|
2680
2744
|
const startAt = config?.startAt ?? 1;
|
|
2681
|
-
const format = config?.format ?? (0,
|
|
2745
|
+
const format = config?.format ?? (0, import_core17.defaultSequenceFormat)(name);
|
|
2682
2746
|
let counter = 0;
|
|
2683
2747
|
await this.adapter.transaction(async (tx) => {
|
|
2684
2748
|
const rows = await tx.query(
|
|
@@ -2700,7 +2764,7 @@ var SequenceManager = class {
|
|
|
2700
2764
|
);
|
|
2701
2765
|
}
|
|
2702
2766
|
});
|
|
2703
|
-
return (0,
|
|
2767
|
+
return (0, import_core17.formatSequenceValue)(format, counter, this.nodeId);
|
|
2704
2768
|
}
|
|
2705
2769
|
/**
|
|
2706
2770
|
* Get the current counter value without incrementing.
|
|
@@ -3159,10 +3223,10 @@ var SubscriptionManager = class {
|
|
|
3159
3223
|
};
|
|
3160
3224
|
|
|
3161
3225
|
// src/sync/rebase-unsynced-operations.ts
|
|
3162
|
-
var
|
|
3226
|
+
var import_core18 = require("@korajs/core");
|
|
3163
3227
|
var import_internal2 = require("@korajs/core/internal");
|
|
3164
3228
|
init_serializer();
|
|
3165
|
-
var LOGICAL_COUNTER_LIMIT =
|
|
3229
|
+
var LOGICAL_COUNTER_LIMIT = import_core18.MAX_LOGICAL + 1;
|
|
3166
3230
|
function emptyResult() {
|
|
3167
3231
|
return { operations: [], idMapping: {}, rebasedCount: 0, newMaxTimestamp: null };
|
|
3168
3232
|
}
|
|
@@ -3174,7 +3238,9 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
3174
3238
|
const rebased = [];
|
|
3175
3239
|
let maxOtherSerializedTs = null;
|
|
3176
3240
|
for (const collectionName of Object.keys(schema.collections)) {
|
|
3177
|
-
const rows = await adapter.query(
|
|
3241
|
+
const rows = await adapter.query(
|
|
3242
|
+
`SELECT * FROM ${(0, import_core18.quoteIdent)(`_kora_ops_${collectionName}`)}`
|
|
3243
|
+
);
|
|
3178
3244
|
for (const row of rows) {
|
|
3179
3245
|
if (rebaseIds.has(row.id)) {
|
|
3180
3246
|
rebased.push(deserializeOperationWithCollection(row, collectionName));
|
|
@@ -3186,9 +3252,9 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
3186
3252
|
if (rebased.length === 0) {
|
|
3187
3253
|
return emptyResult();
|
|
3188
3254
|
}
|
|
3189
|
-
const maxOtherWallTime = maxOtherSerializedTs === null ? Number.NEGATIVE_INFINITY :
|
|
3255
|
+
const maxOtherWallTime = maxOtherSerializedTs === null ? Number.NEGATIVE_INFINITY : import_core18.HybridLogicalClock.deserialize(maxOtherSerializedTs).wallTime;
|
|
3190
3256
|
const baseWallTime = Math.max(correctedNowMs, maxOtherWallTime + 1);
|
|
3191
|
-
rebased.sort((a, b) =>
|
|
3257
|
+
rebased.sort((a, b) => import_core18.HybridLogicalClock.compare(a.timestamp, b.timestamp));
|
|
3192
3258
|
const newTimestamps = rebased.map((op, i) => ({
|
|
3193
3259
|
// Spill into wallTime past the 5-digit logical serialization limit so the
|
|
3194
3260
|
// serialized order stays correct even for enormous offline queues.
|
|
@@ -3216,7 +3282,7 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
3216
3282
|
schemaVersion: op.schemaVersion,
|
|
3217
3283
|
...op.atomicOps !== void 0 ? { atomicOps: op.atomicOps } : {}
|
|
3218
3284
|
};
|
|
3219
|
-
const newId = await (0, import_internal2.computeOperationId)(input,
|
|
3285
|
+
const newId = await (0, import_internal2.computeOperationId)(input, import_core18.HybridLogicalClock.serialize(ts));
|
|
3220
3286
|
idMapping[op.id] = newId;
|
|
3221
3287
|
newIds.push(newId);
|
|
3222
3288
|
}
|
|
@@ -3243,7 +3309,7 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
3243
3309
|
continue;
|
|
3244
3310
|
}
|
|
3245
3311
|
const opsTable = `_kora_ops_${oldOp.collection}`;
|
|
3246
|
-
await tx.execute(`DELETE FROM ${opsTable} WHERE id = ?`, [oldOp.id]);
|
|
3312
|
+
await tx.execute(`DELETE FROM ${(0, import_core18.quoteIdent)(opsTable)} WHERE id = ?`, [oldOp.id]);
|
|
3247
3313
|
const opInsert = buildInsertQuery(
|
|
3248
3314
|
opsTable,
|
|
3249
3315
|
serializeOperation(newOp)
|
|
@@ -3252,11 +3318,11 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
3252
3318
|
const oldVersion = serializeRowVersion(oldOp.timestamp);
|
|
3253
3319
|
const newVersion = serializeRowVersion(newOp.timestamp);
|
|
3254
3320
|
await tx.execute(
|
|
3255
|
-
`UPDATE ${oldOp.collection} SET _version = ?, _updated_at = ? WHERE id = ? AND _version = ?`,
|
|
3321
|
+
`UPDATE ${(0, import_core18.quoteIdent)(oldOp.collection)} SET _version = ?, _updated_at = ? WHERE id = ? AND _version = ?`,
|
|
3256
3322
|
[newVersion, newOp.timestamp.wallTime, oldOp.recordId, oldVersion]
|
|
3257
3323
|
);
|
|
3258
3324
|
const rows = await tx.query(
|
|
3259
|
-
`SELECT _field_versions FROM ${oldOp.collection} WHERE id = ?`,
|
|
3325
|
+
`SELECT _field_versions FROM ${(0, import_core18.quoteIdent)(oldOp.collection)} WHERE id = ?`,
|
|
3260
3326
|
[oldOp.recordId]
|
|
3261
3327
|
);
|
|
3262
3328
|
const fieldVersions = parseFieldVersions(rows[0]?._field_versions);
|
|
@@ -3268,14 +3334,14 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
3268
3334
|
}
|
|
3269
3335
|
}
|
|
3270
3336
|
if (changed) {
|
|
3271
|
-
await tx.execute(
|
|
3272
|
-
|
|
3273
|
-
oldOp.recordId
|
|
3274
|
-
|
|
3337
|
+
await tx.execute(
|
|
3338
|
+
`UPDATE ${(0, import_core18.quoteIdent)(oldOp.collection)} SET _field_versions = ? WHERE id = ?`,
|
|
3339
|
+
[serializeFieldVersions(fieldVersions), oldOp.recordId]
|
|
3340
|
+
);
|
|
3275
3341
|
}
|
|
3276
3342
|
if (oldOp.type === "insert") {
|
|
3277
3343
|
await tx.execute(
|
|
3278
|
-
`UPDATE ${oldOp.collection} SET _created_at = ? WHERE id = ? AND _created_at = ?`,
|
|
3344
|
+
`UPDATE ${(0, import_core18.quoteIdent)(oldOp.collection)} SET _created_at = ? WHERE id = ? AND _created_at = ?`,
|
|
3279
3345
|
[newOp.timestamp.wallTime, oldOp.recordId, oldOp.timestamp.wallTime]
|
|
3280
3346
|
);
|
|
3281
3347
|
}
|
|
@@ -3291,7 +3357,7 @@ async function rebaseUnsyncedOperationsInLog(adapter, schema, unsyncedOpIds, cor
|
|
|
3291
3357
|
}
|
|
3292
3358
|
|
|
3293
3359
|
// src/transaction/transaction-context.ts
|
|
3294
|
-
var
|
|
3360
|
+
var import_core19 = require("@korajs/core");
|
|
3295
3361
|
init_op_data_encoding();
|
|
3296
3362
|
init_serializer();
|
|
3297
3363
|
var TransactionContext = class {
|
|
@@ -3303,7 +3369,7 @@ var TransactionContext = class {
|
|
|
3303
3369
|
config;
|
|
3304
3370
|
constructor(config) {
|
|
3305
3371
|
this.config = config;
|
|
3306
|
-
this.transactionId = (0,
|
|
3372
|
+
this.transactionId = (0, import_core19.generateUUIDv7)();
|
|
3307
3373
|
}
|
|
3308
3374
|
/**
|
|
3309
3375
|
* Set a human-readable mutation name for this transaction.
|
|
@@ -3418,8 +3484,8 @@ var TransactionContext = class {
|
|
|
3418
3484
|
}
|
|
3419
3485
|
async insert(collectionName, definition, data) {
|
|
3420
3486
|
this.ensureActive();
|
|
3421
|
-
const validated = (0,
|
|
3422
|
-
const recordId = (0,
|
|
3487
|
+
const validated = (0, import_core19.validateRecord)(collectionName, definition, data, "insert");
|
|
3488
|
+
const recordId = (0, import_core19.generateUUIDv7)();
|
|
3423
3489
|
const now = Date.now();
|
|
3424
3490
|
for (const [fieldName, descriptor] of Object.entries(definition.fields)) {
|
|
3425
3491
|
if (descriptor.auto && descriptor.kind === "timestamp") {
|
|
@@ -3428,7 +3494,7 @@ var TransactionContext = class {
|
|
|
3428
3494
|
}
|
|
3429
3495
|
const sequenceNumber = await this.config.sequenceAllocator.allocate();
|
|
3430
3496
|
const causalDeps = this.config.causalTracker?.nextCausalDeps(collectionName, true) ?? [];
|
|
3431
|
-
const operation = await (0,
|
|
3497
|
+
const operation = await (0, import_core19.createOperation)(
|
|
3432
3498
|
{
|
|
3433
3499
|
nodeId: this.config.nodeId,
|
|
3434
3500
|
type: "insert",
|
|
@@ -3483,7 +3549,7 @@ var TransactionContext = class {
|
|
|
3483
3549
|
if (!currentRecord) {
|
|
3484
3550
|
throw new RecordNotFoundError(collectionName, id);
|
|
3485
3551
|
}
|
|
3486
|
-
const validated = (0,
|
|
3552
|
+
const validated = (0, import_core19.validateRecord)(collectionName, definition, data, "update");
|
|
3487
3553
|
const now = Date.now();
|
|
3488
3554
|
const previousData = {};
|
|
3489
3555
|
const resolvedData = {};
|
|
@@ -3491,9 +3557,9 @@ var TransactionContext = class {
|
|
|
3491
3557
|
for (const key of Object.keys(validated)) {
|
|
3492
3558
|
const value = validated[key];
|
|
3493
3559
|
previousData[key] = currentRecord[key];
|
|
3494
|
-
if ((0,
|
|
3495
|
-
resolvedData[key] = (0,
|
|
3496
|
-
atomicOps[key] = (0,
|
|
3560
|
+
if ((0, import_core19.isAtomicOp)(value)) {
|
|
3561
|
+
resolvedData[key] = (0, import_core19.resolveAtomicOp)(currentRecord[key], value);
|
|
3562
|
+
atomicOps[key] = (0, import_core19.toAtomicOp)(value);
|
|
3497
3563
|
} else {
|
|
3498
3564
|
resolvedData[key] = value;
|
|
3499
3565
|
}
|
|
@@ -3501,7 +3567,7 @@ var TransactionContext = class {
|
|
|
3501
3567
|
const hasAtomicOps = Object.keys(atomicOps).length > 0;
|
|
3502
3568
|
const sequenceNumber = await this.config.sequenceAllocator.allocate();
|
|
3503
3569
|
const causalDeps = this.config.causalTracker?.nextCausalDeps(collectionName, true) ?? [];
|
|
3504
|
-
const operation = await (0,
|
|
3570
|
+
const operation = await (0, import_core19.createOperation)(
|
|
3505
3571
|
{
|
|
3506
3572
|
nodeId: this.config.nodeId,
|
|
3507
3573
|
type: "update",
|
|
@@ -3556,7 +3622,7 @@ var TransactionContext = class {
|
|
|
3556
3622
|
const now = Date.now();
|
|
3557
3623
|
const sequenceNumber = await this.config.sequenceAllocator.allocate();
|
|
3558
3624
|
const causalDeps = this.config.causalTracker?.nextCausalDeps(collectionName, true) ?? [];
|
|
3559
|
-
const operation = await (0,
|
|
3625
|
+
const operation = await (0, import_core19.createOperation)(
|
|
3560
3626
|
{
|
|
3561
3627
|
nodeId: this.config.nodeId,
|
|
3562
3628
|
type: "delete",
|
|
@@ -3606,7 +3672,7 @@ var TransactionContext = class {
|
|
|
3606
3672
|
}
|
|
3607
3673
|
}
|
|
3608
3674
|
const rows = await this.config.adapter.query(
|
|
3609
|
-
`SELECT * FROM ${collectionName} WHERE id = ? AND _deleted = 0`,
|
|
3675
|
+
`SELECT * FROM ${(0, import_core19.quoteIdent)(collectionName)} WHERE id = ? AND _deleted = 0`,
|
|
3610
3676
|
[id]
|
|
3611
3677
|
);
|
|
3612
3678
|
let record = rows[0] ? deserializeRecord(rows[0], definition.fields) : null;
|
|
@@ -3661,7 +3727,7 @@ var TransactionSequenceAllocator = class {
|
|
|
3661
3727
|
};
|
|
3662
3728
|
|
|
3663
3729
|
// src/store/tab-node-id.ts
|
|
3664
|
-
var
|
|
3730
|
+
var import_core20 = require("@korajs/core");
|
|
3665
3731
|
function perTabStorageKey(dbName) {
|
|
3666
3732
|
return `kora-tab-node-${dbName}`;
|
|
3667
3733
|
}
|
|
@@ -3682,7 +3748,7 @@ function resolvePerTabNodeId(dbName) {
|
|
|
3682
3748
|
if (existing) {
|
|
3683
3749
|
return existing;
|
|
3684
3750
|
}
|
|
3685
|
-
const nodeId = (0,
|
|
3751
|
+
const nodeId = (0, import_core20.generateUUIDv7)();
|
|
3686
3752
|
savePerTabNodeId(dbName, nodeId);
|
|
3687
3753
|
return nodeId;
|
|
3688
3754
|
}
|
|
@@ -3692,7 +3758,7 @@ var Store = class {
|
|
|
3692
3758
|
opened = false;
|
|
3693
3759
|
nodeId = "";
|
|
3694
3760
|
sequenceNumber = 0;
|
|
3695
|
-
versionVector = (0,
|
|
3761
|
+
versionVector = (0, import_core23.createVersionVector)();
|
|
3696
3762
|
clock = null;
|
|
3697
3763
|
collections = /* @__PURE__ */ new Map();
|
|
3698
3764
|
subscriptionManager;
|
|
@@ -3728,8 +3794,8 @@ var Store = class {
|
|
|
3728
3794
|
await this.adapter.open(this.schema);
|
|
3729
3795
|
await this.runMigrationsIfNeeded();
|
|
3730
3796
|
this.nodeId = await this.loadOrGenerateNodeId();
|
|
3731
|
-
this.clock = new
|
|
3732
|
-
this.causalTracker = new
|
|
3797
|
+
this.clock = new import_core23.HybridLogicalClock(this.nodeId);
|
|
3798
|
+
this.causalTracker = new import_core23.CausalTracker();
|
|
3733
3799
|
this.sequenceManager = new SequenceManager(this.adapter, this.nodeId);
|
|
3734
3800
|
this.sequenceNumber = await this.loadSequenceNumber();
|
|
3735
3801
|
this.versionVector = await this.loadVersionVector();
|
|
@@ -3841,7 +3907,7 @@ var Store = class {
|
|
|
3841
3907
|
return "skipped";
|
|
3842
3908
|
}
|
|
3843
3909
|
const existing = await this.adapter.query(
|
|
3844
|
-
`SELECT id FROM _kora_ops_${collection} WHERE id = ?`,
|
|
3910
|
+
`SELECT id FROM ${(0, import_core23.quoteIdent)(`_kora_ops_${collection}`)} WHERE id = ?`,
|
|
3845
3911
|
[op.id]
|
|
3846
3912
|
);
|
|
3847
3913
|
if (existing.length > 0) {
|
|
@@ -3866,7 +3932,8 @@ var Store = class {
|
|
|
3866
3932
|
throw new OptimisticLockError(collection, op.recordId);
|
|
3867
3933
|
}
|
|
3868
3934
|
};
|
|
3869
|
-
if (
|
|
3935
|
+
if (options?.logOnly) {
|
|
3936
|
+
} else if (op.type === "insert" && materializeSource) {
|
|
3870
3937
|
const serializedData = serializeRecord(materializeSource, definition.fields);
|
|
3871
3938
|
const existing2 = await tx.query(
|
|
3872
3939
|
`SELECT _updated_at, _version, _field_versions, _deleted FROM ${collection} WHERE id = ?`,
|
|
@@ -3888,7 +3955,7 @@ var Store = class {
|
|
|
3888
3955
|
};
|
|
3889
3956
|
const insertQuery = buildInsertQuery(collection, record);
|
|
3890
3957
|
await tx.execute(insertQuery.sql, insertQuery.params);
|
|
3891
|
-
await this.foldOrphanedOperations(tx, collection, definition, op.recordId);
|
|
3958
|
+
await this.foldOrphanedOperations(tx, collection, definition, op.recordId, op);
|
|
3892
3959
|
} else if (row._deleted === 1) {
|
|
3893
3960
|
if (isIncomingNewerThanRow(materializeTimestamp, row)) {
|
|
3894
3961
|
const fieldChanges = {
|
|
@@ -3946,7 +4013,7 @@ var Store = class {
|
|
|
3946
4013
|
const serializedChanges = serializeRecord(materializeSource, definition.fields);
|
|
3947
4014
|
const changedFields = Object.keys(serializedChanges);
|
|
3948
4015
|
const currentRows = await tx.query(
|
|
3949
|
-
`SELECT _version, _field_versions FROM ${collection} WHERE id = ?`,
|
|
4016
|
+
`SELECT _version, _field_versions FROM ${(0, import_core23.quoteIdent)(collection)} WHERE id = ?`,
|
|
3950
4017
|
[op.recordId]
|
|
3951
4018
|
);
|
|
3952
4019
|
const currentRow = currentRows[0];
|
|
@@ -4040,22 +4107,22 @@ var Store = class {
|
|
|
4040
4107
|
* necessarily an orphan (rows are soft-deleted, never removed, so a row
|
|
4041
4108
|
* that is absent now was never materialized).
|
|
4042
4109
|
*/
|
|
4043
|
-
async foldOrphanedOperations(tx, collection, definition, recordId) {
|
|
4110
|
+
async foldOrphanedOperations(tx, collection, definition, recordId, insertOp) {
|
|
4044
4111
|
const orphanRows = await tx.query(
|
|
4045
|
-
`SELECT * FROM _kora_ops_${collection} WHERE record_id = ? AND type IN ('update', 'delete')`,
|
|
4112
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(`_kora_ops_${collection}`)} WHERE record_id = ? AND type IN ('update', 'delete')`,
|
|
4046
4113
|
[recordId]
|
|
4047
4114
|
);
|
|
4048
4115
|
if (orphanRows.length === 0) {
|
|
4049
4116
|
return;
|
|
4050
4117
|
}
|
|
4051
|
-
const orphans = orphanRows.map((r) => deserializeOperationWithCollection(r, collection)).sort((a, b) =>
|
|
4118
|
+
const orphans = orphanRows.map((r) => deserializeOperationWithCollection(r, collection)).sort((a, b) => import_core23.HybridLogicalClock.compare(a.timestamp, b.timestamp));
|
|
4052
4119
|
for (const orphan of orphans) {
|
|
4053
4120
|
const orphanVersion = serializeRowVersion(orphan.timestamp);
|
|
4054
4121
|
const orphanWall = orphan.timestamp.wallTime;
|
|
4055
4122
|
if (orphan.type === "update" && orphan.data) {
|
|
4056
4123
|
const orphanChanges = serializeRecord(orphan.data, definition.fields);
|
|
4057
4124
|
const rows = await tx.query(
|
|
4058
|
-
`SELECT _version, _field_versions FROM ${collection} WHERE id = ?`,
|
|
4125
|
+
`SELECT _version, _field_versions FROM ${(0, import_core23.quoteIdent)(collection)} WHERE id = ?`,
|
|
4059
4126
|
[recordId]
|
|
4060
4127
|
);
|
|
4061
4128
|
const current = rows[0];
|
|
@@ -4089,6 +4156,37 @@ var Store = class {
|
|
|
4089
4156
|
await tx.execute(query.sql, query.params);
|
|
4090
4157
|
}
|
|
4091
4158
|
}
|
|
4159
|
+
const atomicFields = /* @__PURE__ */ new Set();
|
|
4160
|
+
for (const orphan of orphans) {
|
|
4161
|
+
if (orphan.type === "update" && orphan.atomicOps) {
|
|
4162
|
+
for (const field of Object.keys(orphan.atomicOps)) {
|
|
4163
|
+
atomicFields.add(field);
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
if (atomicFields.size > 0) {
|
|
4168
|
+
const ordered = [insertOp, ...orphans].sort(
|
|
4169
|
+
(a, b) => import_core23.HybridLogicalClock.compare(a.timestamp, b.timestamp)
|
|
4170
|
+
);
|
|
4171
|
+
const folded = (0, import_core23.replayOperationsForRecord)(ordered);
|
|
4172
|
+
if (folded) {
|
|
4173
|
+
const composed = {};
|
|
4174
|
+
for (const field of atomicFields) {
|
|
4175
|
+
if (field in folded) {
|
|
4176
|
+
composed[field] = folded[field];
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
const serialized = serializeRecord(composed, definition.fields);
|
|
4180
|
+
const cols = Object.keys(serialized);
|
|
4181
|
+
if (cols.length > 0) {
|
|
4182
|
+
const setClause = cols.map((c) => `${(0, import_core23.quoteIdent)(c)} = ?`).join(", ");
|
|
4183
|
+
await tx.execute(`UPDATE ${(0, import_core23.quoteIdent)(collection)} SET ${setClause} WHERE id = ?`, [
|
|
4184
|
+
...cols.map((c) => serialized[c]),
|
|
4185
|
+
recordId
|
|
4186
|
+
]);
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4092
4190
|
}
|
|
4093
4191
|
/**
|
|
4094
4192
|
* Get operations from a node within a sequence number range.
|
|
@@ -4105,7 +4203,7 @@ var Store = class {
|
|
|
4105
4203
|
const allOps = [];
|
|
4106
4204
|
for (const collectionName of Object.keys(this.schema.collections)) {
|
|
4107
4205
|
const rows = await this.adapter.query(
|
|
4108
|
-
`SELECT * FROM _kora_ops_${collectionName} WHERE node_id = ? AND sequence_number >= ? AND sequence_number <= ? ORDER BY sequence_number ASC`,
|
|
4206
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(`_kora_ops_${collectionName}`)} WHERE node_id = ? AND sequence_number >= ? AND sequence_number <= ? ORDER BY sequence_number ASC`,
|
|
4109
4207
|
[nodeId, fromSeq, toSeq]
|
|
4110
4208
|
);
|
|
4111
4209
|
for (const row of rows) {
|
|
@@ -4124,7 +4222,7 @@ var Store = class {
|
|
|
4124
4222
|
const allOps = [];
|
|
4125
4223
|
for (const collectionName of Object.keys(this.schema.collections)) {
|
|
4126
4224
|
const rows = await this.adapter.query(
|
|
4127
|
-
`SELECT * FROM _kora_ops_${collectionName} ORDER BY sequence_number ASC`
|
|
4225
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(`_kora_ops_${collectionName}`)} ORDER BY sequence_number ASC`
|
|
4128
4226
|
);
|
|
4129
4227
|
for (const row of rows) {
|
|
4130
4228
|
allOps.push(deserializeOperationWithCollection(row, collectionName));
|
|
@@ -4193,6 +4291,22 @@ var Store = class {
|
|
|
4193
4291
|
col.setMutationHandler(handler);
|
|
4194
4292
|
}
|
|
4195
4293
|
}
|
|
4294
|
+
/**
|
|
4295
|
+
* Notify this store that another same-origin runtime committed an operation to
|
|
4296
|
+
* the shared local database. The operation has already been persisted and
|
|
4297
|
+
* materialized by the database owner; this method only advances in-memory causal
|
|
4298
|
+
* watermarks and invalidates local reactive queries so already-open tabs stay
|
|
4299
|
+
* live without reapplying or rewriting the operation.
|
|
4300
|
+
*/
|
|
4301
|
+
notifyExternalOperation(operation) {
|
|
4302
|
+
this.ensureOpen();
|
|
4303
|
+
const definition = this.schema.collections[operation.collection];
|
|
4304
|
+
if (!definition) {
|
|
4305
|
+
return;
|
|
4306
|
+
}
|
|
4307
|
+
this.recordOperationSequence(operation);
|
|
4308
|
+
this.subscriptionManager.notify(operation.collection, operation);
|
|
4309
|
+
}
|
|
4196
4310
|
/**
|
|
4197
4311
|
* Build mutation context for a collection (used by ApplyPipeline side effects).
|
|
4198
4312
|
*/
|
|
@@ -4234,7 +4348,7 @@ var Store = class {
|
|
|
4234
4348
|
return null;
|
|
4235
4349
|
}
|
|
4236
4350
|
const rows = await this.adapter.query(
|
|
4237
|
-
`SELECT * FROM ${collection} WHERE id = ?`,
|
|
4351
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(collection)} WHERE id = ?`,
|
|
4238
4352
|
[recordId]
|
|
4239
4353
|
);
|
|
4240
4354
|
const row = rows[0];
|
|
@@ -4259,7 +4373,7 @@ var Store = class {
|
|
|
4259
4373
|
return null;
|
|
4260
4374
|
}
|
|
4261
4375
|
const rows = await this.adapter.query(
|
|
4262
|
-
`SELECT _version, _field_versions FROM ${collection} WHERE id = ?`,
|
|
4376
|
+
`SELECT _version, _field_versions FROM ${(0, import_core23.quoteIdent)(collection)} WHERE id = ?`,
|
|
4263
4377
|
[recordId]
|
|
4264
4378
|
);
|
|
4265
4379
|
const row = rows[0];
|
|
@@ -4302,6 +4416,35 @@ var Store = class {
|
|
|
4302
4416
|
this.ensureOpen();
|
|
4303
4417
|
await saveDeltaCursor(this.adapter, cursor);
|
|
4304
4418
|
}
|
|
4419
|
+
/**
|
|
4420
|
+
* Load the persisted delivery watermark for a view signature (0 when none recorded).
|
|
4421
|
+
* Defaults to the unfiltered view so existing single-watermark reads keep working.
|
|
4422
|
+
*/
|
|
4423
|
+
async loadDeliveryWatermark(signature = "") {
|
|
4424
|
+
this.ensureOpen();
|
|
4425
|
+
return loadDeliveryWatermark(this.adapter, signature);
|
|
4426
|
+
}
|
|
4427
|
+
/**
|
|
4428
|
+
* Persist the delivery watermark for a view signature so it survives a client restart.
|
|
4429
|
+
*/
|
|
4430
|
+
async saveDeliveryWatermark(signature, watermark) {
|
|
4431
|
+
this.ensureOpen();
|
|
4432
|
+
await saveDeliveryWatermark(this.adapter, signature, watermark);
|
|
4433
|
+
}
|
|
4434
|
+
/**
|
|
4435
|
+
* Load every persisted view watermark, keyed by signature.
|
|
4436
|
+
*/
|
|
4437
|
+
async loadAllDeliveryWatermarks() {
|
|
4438
|
+
this.ensureOpen();
|
|
4439
|
+
return loadAllDeliveryWatermarks(this.adapter);
|
|
4440
|
+
}
|
|
4441
|
+
/**
|
|
4442
|
+
* Delete a persisted view watermark (safe: the view back-fills from 0 when next visited).
|
|
4443
|
+
*/
|
|
4444
|
+
async deleteDeliveryWatermark(signature) {
|
|
4445
|
+
this.ensureOpen();
|
|
4446
|
+
await deleteDeliveryWatermark(this.adapter, signature);
|
|
4447
|
+
}
|
|
4305
4448
|
/**
|
|
4306
4449
|
* Local operations not yet reflected on the server version vector.
|
|
4307
4450
|
*/
|
|
@@ -4351,7 +4494,7 @@ var Store = class {
|
|
|
4351
4494
|
async compact(strategy) {
|
|
4352
4495
|
this.ensureOpen();
|
|
4353
4496
|
if (strategy.mode === "never") {
|
|
4354
|
-
return compactOperationLog(this.adapter, this.schema, strategy, (0,
|
|
4497
|
+
return compactOperationLog(this.adapter, this.schema, strategy, (0, import_core23.createVersionVector)());
|
|
4355
4498
|
}
|
|
4356
4499
|
const serverVector = strategy.serverVector ?? await loadLastAckedServerVector(this.adapter);
|
|
4357
4500
|
return compactOperationLog(this.adapter, this.schema, strategy, serverVector);
|
|
@@ -4365,7 +4508,7 @@ var Store = class {
|
|
|
4365
4508
|
async getLatestLocalOperationForRecord(collection, recordId) {
|
|
4366
4509
|
this.ensureOpen();
|
|
4367
4510
|
const rows = await this.adapter.query(
|
|
4368
|
-
`SELECT * FROM _kora_ops_${collection} WHERE node_id = ? AND record_id = ? ORDER BY sequence_number DESC LIMIT 1`,
|
|
4511
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(`_kora_ops_${collection}`)} WHERE node_id = ? AND record_id = ? ORDER BY sequence_number DESC LIMIT 1`,
|
|
4369
4512
|
[this.nodeId, recordId]
|
|
4370
4513
|
);
|
|
4371
4514
|
const row = rows[0];
|
|
@@ -4380,18 +4523,33 @@ var Store = class {
|
|
|
4380
4523
|
async getLatestOperationForRecord(collection, recordId) {
|
|
4381
4524
|
this.ensureOpen();
|
|
4382
4525
|
const rows = await this.adapter.query(
|
|
4383
|
-
`SELECT * FROM _kora_ops_${collection} WHERE record_id = ?`,
|
|
4526
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(`_kora_ops_${collection}`)} WHERE record_id = ?`,
|
|
4384
4527
|
[recordId]
|
|
4385
4528
|
);
|
|
4386
4529
|
let latest = null;
|
|
4387
4530
|
for (const row of rows) {
|
|
4388
4531
|
const op = deserializeOperationWithCollection(row, collection);
|
|
4389
|
-
if (!latest ||
|
|
4532
|
+
if (!latest || import_core23.HybridLogicalClock.compare(op.timestamp, latest.timestamp) > 0) {
|
|
4390
4533
|
latest = op;
|
|
4391
4534
|
}
|
|
4392
4535
|
}
|
|
4393
4536
|
return latest;
|
|
4394
4537
|
}
|
|
4538
|
+
/**
|
|
4539
|
+
* All operations for a record, sorted in HLC total order (wallTime, logical,
|
|
4540
|
+
* nodeId). Used by the apply pipeline to materialize atomic-op fields by folding
|
|
4541
|
+
* the record's log, matching the server's materialization exactly.
|
|
4542
|
+
*/
|
|
4543
|
+
async getOperationsForRecord(collection, recordId) {
|
|
4544
|
+
this.ensureOpen();
|
|
4545
|
+
const rows = await this.adapter.query(
|
|
4546
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(`_kora_ops_${collection}`)} WHERE record_id = ?`,
|
|
4547
|
+
[recordId]
|
|
4548
|
+
);
|
|
4549
|
+
const ops = rows.map((row) => deserializeOperationWithCollection(row, collection));
|
|
4550
|
+
ops.sort((a, b) => import_core23.HybridLogicalClock.compare(a.timestamp, b.timestamp));
|
|
4551
|
+
return ops;
|
|
4552
|
+
}
|
|
4395
4553
|
/** Expose the subscription manager for direct access (e.g., by QueryBuilder) */
|
|
4396
4554
|
getSubscriptionManager() {
|
|
4397
4555
|
return this.subscriptionManager;
|
|
@@ -4529,7 +4687,7 @@ var Store = class {
|
|
|
4529
4687
|
for (let v = storedVersion + 1; v <= targetVersion; v++) {
|
|
4530
4688
|
const migration = migrations[v];
|
|
4531
4689
|
if (!migration) continue;
|
|
4532
|
-
const sqlStatements = (0,
|
|
4690
|
+
const sqlStatements = (0, import_core23.migrationStepsToSQL)(migration.steps);
|
|
4533
4691
|
for (const sql of sqlStatements) {
|
|
4534
4692
|
try {
|
|
4535
4693
|
await this.adapter.execute(sql);
|
|
@@ -4567,14 +4725,14 @@ var Store = class {
|
|
|
4567
4725
|
*/
|
|
4568
4726
|
async runBackfill(collection, transform) {
|
|
4569
4727
|
const rows = await this.adapter.query(
|
|
4570
|
-
`SELECT * FROM ${collection} WHERE _deleted = 0`
|
|
4728
|
+
`SELECT * FROM ${(0, import_core23.quoteIdent)(collection)} WHERE _deleted = 0`
|
|
4571
4729
|
);
|
|
4572
4730
|
await this.adapter.transaction(async (tx) => {
|
|
4573
4731
|
for (const row of rows) {
|
|
4574
4732
|
const updates = transform(row);
|
|
4575
4733
|
const fields = Object.keys(updates);
|
|
4576
4734
|
if (fields.length === 0) continue;
|
|
4577
|
-
const setClauses = fields.map((f) => `${f} = ?`).join(", ");
|
|
4735
|
+
const setClauses = fields.map((f) => `${(0, import_core23.quoteIdent)(f)} = ?`).join(", ");
|
|
4578
4736
|
const values = fields.map((f) => {
|
|
4579
4737
|
const val = updates[f];
|
|
4580
4738
|
if (typeof val === "boolean") return val ? 1 : 0;
|
|
@@ -4584,7 +4742,7 @@ var Store = class {
|
|
|
4584
4742
|
return val;
|
|
4585
4743
|
});
|
|
4586
4744
|
values.push(row.id);
|
|
4587
|
-
await tx.execute(`UPDATE ${collection} SET ${setClauses} WHERE id = ?`, values);
|
|
4745
|
+
await tx.execute(`UPDATE ${(0, import_core23.quoteIdent)(collection)} SET ${setClauses} WHERE id = ?`, values);
|
|
4588
4746
|
}
|
|
4589
4747
|
});
|
|
4590
4748
|
}
|
|
@@ -4607,7 +4765,7 @@ var Store = class {
|
|
|
4607
4765
|
if (rows[0]) {
|
|
4608
4766
|
return rows[0].value;
|
|
4609
4767
|
}
|
|
4610
|
-
const newNodeId = (0,
|
|
4768
|
+
const newNodeId = (0, import_core23.generateUUIDv7)();
|
|
4611
4769
|
await this.adapter.execute("INSERT INTO _kora_meta (key, value) VALUES ('node_id', ?)", [
|
|
4612
4770
|
newNodeId
|
|
4613
4771
|
]);
|
|
@@ -4624,7 +4782,7 @@ var Store = class {
|
|
|
4624
4782
|
const rows = await this.adapter.query(
|
|
4625
4783
|
"SELECT node_id, sequence_number FROM _kora_version_vector"
|
|
4626
4784
|
);
|
|
4627
|
-
const vector = (0,
|
|
4785
|
+
const vector = (0, import_core23.createVersionVector)();
|
|
4628
4786
|
for (const row of rows) {
|
|
4629
4787
|
vector.set(row.node_id, row.sequence_number);
|
|
4630
4788
|
}
|
|
@@ -4644,6 +4802,7 @@ var QueryStore = class {
|
|
|
4644
4802
|
listeners = /* @__PURE__ */ new Set();
|
|
4645
4803
|
unsubscribeQuery = null;
|
|
4646
4804
|
active = false;
|
|
4805
|
+
hasEmittedSnapshot = false;
|
|
4647
4806
|
queryBuilder;
|
|
4648
4807
|
constructor(queryBuilder) {
|
|
4649
4808
|
this.queryBuilder = queryBuilder;
|
|
@@ -4669,16 +4828,25 @@ var QueryStore = class {
|
|
|
4669
4828
|
getSnapshot = () => {
|
|
4670
4829
|
return this.snapshot;
|
|
4671
4830
|
};
|
|
4831
|
+
/**
|
|
4832
|
+
* Whether the underlying query subscription has delivered at least one
|
|
4833
|
+
* authoritative result for the current subscription lifecycle.
|
|
4834
|
+
*/
|
|
4835
|
+
hasSnapshot = () => {
|
|
4836
|
+
return this.hasEmittedSnapshot;
|
|
4837
|
+
};
|
|
4672
4838
|
/** Tear down listeners and the underlying query subscription. */
|
|
4673
4839
|
destroy() {
|
|
4674
4840
|
this.stopSubscription();
|
|
4675
4841
|
this.listeners.clear();
|
|
4676
4842
|
this.snapshot = EMPTY_ARRAY;
|
|
4843
|
+
this.hasEmittedSnapshot = false;
|
|
4677
4844
|
}
|
|
4678
4845
|
startSubscription() {
|
|
4679
4846
|
this.active = true;
|
|
4680
4847
|
this.unsubscribeQuery = this.queryBuilder.subscribe((results) => {
|
|
4681
4848
|
if (!this.active) return;
|
|
4849
|
+
this.hasEmittedSnapshot = true;
|
|
4682
4850
|
this.snapshot = Object.freeze([...results]);
|
|
4683
4851
|
this.notifyListeners();
|
|
4684
4852
|
});
|
|
@@ -4698,12 +4866,12 @@ var QueryStore = class {
|
|
|
4698
4866
|
};
|
|
4699
4867
|
|
|
4700
4868
|
// src/reactivity/assert-query-ready.ts
|
|
4701
|
-
var
|
|
4869
|
+
var import_core24 = require("@korajs/core");
|
|
4702
4870
|
var LEGACY_PENDING_COLLECTION = "__pending__";
|
|
4703
4871
|
function assertQueryReady(query) {
|
|
4704
4872
|
const descriptor = query.getDescriptor();
|
|
4705
4873
|
if (descriptor.collection === LEGACY_PENDING_COLLECTION) {
|
|
4706
|
-
throw new
|
|
4874
|
+
throw new import_core24.AppNotReadyError(
|
|
4707
4875
|
"Cannot use useQuery() before app.ready. Await app.ready or wrap your UI in <KoraProvider app={app}>."
|
|
4708
4876
|
);
|
|
4709
4877
|
}
|
|
@@ -5126,7 +5294,7 @@ init_audit_json();
|
|
|
5126
5294
|
init_export_audit();
|
|
5127
5295
|
|
|
5128
5296
|
// src/blob/content-addressed-blob-store.ts
|
|
5129
|
-
var
|
|
5297
|
+
var import_core25 = require("@korajs/core");
|
|
5130
5298
|
var BlobIntegrityError = class extends Error {
|
|
5131
5299
|
constructor(expectedHash, actualHash) {
|
|
5132
5300
|
super(`Blob integrity check failed: content under hash ${expectedHash} hashes to ${actualHash}`);
|
|
@@ -5140,7 +5308,7 @@ var BlobIntegrityError = class extends Error {
|
|
|
5140
5308
|
var MemoryBlobStore = class {
|
|
5141
5309
|
blobs = /* @__PURE__ */ new Map();
|
|
5142
5310
|
async put(bytes, metadata = {}) {
|
|
5143
|
-
const ref = await (0,
|
|
5311
|
+
const ref = await (0, import_core25.createBlobRef)(bytes, metadata);
|
|
5144
5312
|
if (!this.blobs.has(ref.hash)) {
|
|
5145
5313
|
const stored = new Uint8Array(bytes.byteLength);
|
|
5146
5314
|
stored.set(bytes);
|
|
@@ -5153,7 +5321,7 @@ var MemoryBlobStore = class {
|
|
|
5153
5321
|
if (stored === void 0) {
|
|
5154
5322
|
return null;
|
|
5155
5323
|
}
|
|
5156
|
-
const actualHash = await (0,
|
|
5324
|
+
const actualHash = await (0, import_core25.hashBlob)(stored);
|
|
5157
5325
|
if (actualHash !== hash) {
|
|
5158
5326
|
throw new BlobIntegrityError(hash, actualHash);
|
|
5159
5327
|
}
|
|
@@ -5176,7 +5344,7 @@ var MemoryBlobStore = class {
|
|
|
5176
5344
|
};
|
|
5177
5345
|
|
|
5178
5346
|
// src/blob/opfs-blob-store.ts
|
|
5179
|
-
var
|
|
5347
|
+
var import_core26 = require("@korajs/core");
|
|
5180
5348
|
var OpfsBlobStore = class {
|
|
5181
5349
|
constructor(dir) {
|
|
5182
5350
|
this.dir = dir;
|
|
@@ -5186,7 +5354,7 @@ var OpfsBlobStore = class {
|
|
|
5186
5354
|
return hash.slice(0, 2);
|
|
5187
5355
|
}
|
|
5188
5356
|
async put(bytes, metadata = {}) {
|
|
5189
|
-
const ref = await (0,
|
|
5357
|
+
const ref = await (0, import_core26.createBlobRef)(bytes, metadata);
|
|
5190
5358
|
const shard = this.shardFor(ref.hash);
|
|
5191
5359
|
if (await this.dir.has(shard, ref.hash)) {
|
|
5192
5360
|
return ref;
|
|
@@ -5201,7 +5369,7 @@ var OpfsBlobStore = class {
|
|
|
5201
5369
|
if (bytes === null) {
|
|
5202
5370
|
return null;
|
|
5203
5371
|
}
|
|
5204
|
-
const actual = await (0,
|
|
5372
|
+
const actual = await (0, import_core26.hashBlob)(bytes);
|
|
5205
5373
|
if (actual !== hash) {
|
|
5206
5374
|
throw new BlobIntegrityError(hash, actual);
|
|
5207
5375
|
}
|
|
@@ -5347,7 +5515,7 @@ async function createOpfsBlobStore(rootDirName = "kora-blobs") {
|
|
|
5347
5515
|
}
|
|
5348
5516
|
|
|
5349
5517
|
// src/blob/blob-chunking.ts
|
|
5350
|
-
var
|
|
5518
|
+
var import_core27 = require("@korajs/core");
|
|
5351
5519
|
var DEFAULT_CHUNK_SIZE = 256 * 1024;
|
|
5352
5520
|
async function chunkBlob(bytes, chunkSize = DEFAULT_CHUNK_SIZE, metadata = {}) {
|
|
5353
5521
|
if (chunkSize <= 0) {
|
|
@@ -5359,13 +5527,13 @@ async function chunkBlob(bytes, chunkSize = DEFAULT_CHUNK_SIZE, metadata = {}) {
|
|
|
5359
5527
|
const end = Math.min(offset + chunkSize, bytes.byteLength);
|
|
5360
5528
|
const chunk = new Uint8Array(end - offset);
|
|
5361
5529
|
chunk.set(bytes.subarray(offset, end));
|
|
5362
|
-
const hash = await (0,
|
|
5530
|
+
const hash = await (0, import_core27.hashBlob)(chunk);
|
|
5363
5531
|
chunkHashes.push(hash);
|
|
5364
5532
|
if (!chunks.has(hash)) {
|
|
5365
5533
|
chunks.set(hash, chunk);
|
|
5366
5534
|
}
|
|
5367
5535
|
}
|
|
5368
|
-
const blobHash = await (0,
|
|
5536
|
+
const blobHash = await (0, import_core27.hashBlob)(bytes);
|
|
5369
5537
|
const manifest = {
|
|
5370
5538
|
blobHash,
|
|
5371
5539
|
size: bytes.byteLength,
|
|
@@ -5397,7 +5565,7 @@ async function reassembleBlob(manifest, chunkStore) {
|
|
|
5397
5565
|
out.set(part, offset);
|
|
5398
5566
|
offset += part.byteLength;
|
|
5399
5567
|
}
|
|
5400
|
-
const actual = await (0,
|
|
5568
|
+
const actual = await (0, import_core27.hashBlob)(out);
|
|
5401
5569
|
if (actual !== manifest.blobHash) {
|
|
5402
5570
|
throw new BlobIntegrityError(manifest.blobHash, actual);
|
|
5403
5571
|
}
|
|
@@ -5405,7 +5573,7 @@ async function reassembleBlob(manifest, chunkStore) {
|
|
|
5405
5573
|
}
|
|
5406
5574
|
|
|
5407
5575
|
// src/blob/blob-transfer.ts
|
|
5408
|
-
var
|
|
5576
|
+
var import_core28 = require("@korajs/core");
|
|
5409
5577
|
async function receiveBlob(manifest, provider, stores) {
|
|
5410
5578
|
let chunksFetched = 0;
|
|
5411
5579
|
let chunksSkipped = 0;
|
|
@@ -5423,7 +5591,7 @@ async function receiveBlob(manifest, provider, stores) {
|
|
|
5423
5591
|
if (bytes === null) {
|
|
5424
5592
|
throw new Error(`Blob transfer failed: provider could not supply chunk ${hash}`);
|
|
5425
5593
|
}
|
|
5426
|
-
const actual = await (0,
|
|
5594
|
+
const actual = await (0, import_core28.hashBlob)(bytes);
|
|
5427
5595
|
if (actual !== hash) {
|
|
5428
5596
|
throw new BlobIntegrityError(hash, actual);
|
|
5429
5597
|
}
|
|
@@ -5452,7 +5620,7 @@ async function prepareBlobForSend(bytes, chunkStore, options = {}) {
|
|
|
5452
5620
|
}
|
|
5453
5621
|
|
|
5454
5622
|
// src/blob/blob-manifest-transfer.ts
|
|
5455
|
-
var
|
|
5623
|
+
var import_core29 = require("@korajs/core");
|
|
5456
5624
|
function serializeBlobManifest(manifest) {
|
|
5457
5625
|
const canonical = {
|
|
5458
5626
|
blobHash: manifest.blobHash,
|
|
@@ -5517,7 +5685,7 @@ async function fetchBlobManifest(provider, manifestHash) {
|
|
|
5517
5685
|
if (bytes === null) {
|
|
5518
5686
|
throw new Error(`Blob manifest ${manifestHash} could not be fetched from the provider`);
|
|
5519
5687
|
}
|
|
5520
|
-
const actual = await (0,
|
|
5688
|
+
const actual = await (0, import_core29.hashBlob)(bytes);
|
|
5521
5689
|
if (actual !== manifestHash) {
|
|
5522
5690
|
throw new BlobIntegrityError(manifestHash, actual);
|
|
5523
5691
|
}
|
|
@@ -5533,12 +5701,12 @@ async function resolveBlobManifest(provider, ref) {
|
|
|
5533
5701
|
}
|
|
5534
5702
|
|
|
5535
5703
|
// src/blob/server-blob-callbacks.ts
|
|
5536
|
-
var
|
|
5704
|
+
var import_core30 = require("@korajs/core");
|
|
5537
5705
|
function toServerBlobCallbacks(store) {
|
|
5538
5706
|
return {
|
|
5539
5707
|
resolveBlobChunk: (hash) => store.get(hash),
|
|
5540
5708
|
async persistBlobChunk(hash, bytes) {
|
|
5541
|
-
const actual = await (0,
|
|
5709
|
+
const actual = await (0, import_core30.hashBlob)(bytes);
|
|
5542
5710
|
if (actual !== hash) {
|
|
5543
5711
|
return;
|
|
5544
5712
|
}
|
|
@@ -5552,11 +5720,11 @@ function createMemoryServerBlobStore() {
|
|
|
5552
5720
|
}
|
|
5553
5721
|
|
|
5554
5722
|
// src/blob/blob-gc.ts
|
|
5555
|
-
var
|
|
5723
|
+
var import_core31 = require("@korajs/core");
|
|
5556
5724
|
function extractBlobRefs(record) {
|
|
5557
5725
|
const refs = [];
|
|
5558
5726
|
for (const value of Object.values(record)) {
|
|
5559
|
-
if ((0,
|
|
5727
|
+
if ((0, import_core31.isBlobRef)(value)) {
|
|
5560
5728
|
refs.push(value);
|
|
5561
5729
|
}
|
|
5562
5730
|
}
|
|
@@ -5601,7 +5769,7 @@ async function collectBlobGarbage(store, liveRefs, options = {}) {
|
|
|
5601
5769
|
}
|
|
5602
5770
|
|
|
5603
5771
|
// src/blob/blob-chunk-transport.ts
|
|
5604
|
-
var
|
|
5772
|
+
var import_core32 = require("@korajs/core");
|
|
5605
5773
|
function createRemoteChunkProvider(port, options = {}) {
|
|
5606
5774
|
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
5607
5775
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -5620,7 +5788,7 @@ function createRemoteChunkProvider(port, options = {}) {
|
|
|
5620
5788
|
return {
|
|
5621
5789
|
pendingCount: () => pending.size,
|
|
5622
5790
|
getChunk(hash) {
|
|
5623
|
-
const requestId = (0,
|
|
5791
|
+
const requestId = (0, import_core32.generateUUIDv7)();
|
|
5624
5792
|
return new Promise((resolve, reject) => {
|
|
5625
5793
|
const timer = setTimeout(() => {
|
|
5626
5794
|
pending.delete(requestId);
|
|
@@ -5686,6 +5854,7 @@ function createChunkPortPair() {
|
|
|
5686
5854
|
InvalidStateTransitionError,
|
|
5687
5855
|
LAST_ACKED_SERVER_VECTOR_META_KEY,
|
|
5688
5856
|
MemoryBlobStore,
|
|
5857
|
+
NoLeaderError,
|
|
5689
5858
|
OpfsBlobStore,
|
|
5690
5859
|
OptimisticLockError,
|
|
5691
5860
|
PersistenceError,
|