@foretag/tanstack-db-surrealdb 0.6.11 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -75
- package/dist/index.d.mts +28 -7
- package/dist/index.d.ts +28 -7
- package/dist/index.js +342 -305
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +342 -306
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -12
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var dbSqlitePersistenceCore = require('@tanstack/db-sqlite-persistence-core');
|
|
3
4
|
var queryDbCollection = require('@tanstack/query-db-collection');
|
|
4
5
|
var loroCrdt = require('loro-crdt');
|
|
5
6
|
var surrealdb = require('surrealdb');
|
|
7
|
+
var queryCore = require('@tanstack/query-core');
|
|
6
8
|
var db = require('@tanstack/db');
|
|
7
9
|
|
|
8
10
|
// src/index.ts
|
|
@@ -290,12 +292,313 @@ var toRecordId = (tableName, id) => {
|
|
|
290
292
|
const key = normalized.startsWith(prefixed) ? normalized.slice(prefixed.length) : normalized;
|
|
291
293
|
return new surrealdb.RecordId(tableName, key);
|
|
292
294
|
};
|
|
293
|
-
var
|
|
294
|
-
var
|
|
295
|
-
|
|
296
|
-
if (
|
|
297
|
-
|
|
295
|
+
var SURREAL_COLLECTION_ID_PREFIX = "surreal";
|
|
296
|
+
var patchedCollections = /* @__PURE__ */ new WeakSet();
|
|
297
|
+
var normalizeDeleteKeyAgainstState = (state, key) => {
|
|
298
|
+
if (state.has(key)) return key;
|
|
299
|
+
const canonical = asCanonicalRecordIdString(key);
|
|
300
|
+
if (!canonical) return key;
|
|
301
|
+
return state.has(canonical) ? canonical : key;
|
|
302
|
+
};
|
|
303
|
+
var patchCollectionDeleteForRecordIds = (collection) => {
|
|
304
|
+
if (!collection || typeof collection !== "object") return;
|
|
305
|
+
if (patchedCollections.has(collection)) return;
|
|
306
|
+
const candidate = collection;
|
|
307
|
+
if (typeof candidate.delete !== "function") return;
|
|
308
|
+
const originalDelete = candidate.delete.bind(collection);
|
|
309
|
+
Object.defineProperty(collection, "delete", {
|
|
310
|
+
configurable: true,
|
|
311
|
+
writable: true,
|
|
312
|
+
value: (keys, config) => {
|
|
313
|
+
const state = collection.state ?? /* @__PURE__ */ new Map();
|
|
314
|
+
const normalizedKeys = Array.isArray(keys) ? keys.map((key) => normalizeDeleteKeyAgainstState(state, key)) : normalizeDeleteKeyAgainstState(state, keys);
|
|
315
|
+
return originalDelete(normalizedKeys, config);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
patchedCollections.add(collection);
|
|
319
|
+
};
|
|
320
|
+
var deriveCollectionId = (tableName, queryKey) => `${SURREAL_COLLECTION_ID_PREFIX}:${tableName}:${queryCore.hashKey(queryKey)}`;
|
|
321
|
+
|
|
322
|
+
// src/util.ts
|
|
323
|
+
var encoder = new TextEncoder();
|
|
324
|
+
var decoder = new TextDecoder();
|
|
325
|
+
var hasBuffer = typeof Buffer !== "undefined";
|
|
326
|
+
function toBytes(value) {
|
|
327
|
+
if (typeof value === "string") return encoder.encode(value);
|
|
328
|
+
return encoder.encode(JSON.stringify(value));
|
|
329
|
+
}
|
|
330
|
+
function fromBytes(bytes, deserialize = false) {
|
|
331
|
+
if (deserialize) return JSON.parse(decoder.decode(bytes));
|
|
332
|
+
return decoder.decode(bytes);
|
|
333
|
+
}
|
|
334
|
+
function toBase64(bytes) {
|
|
335
|
+
if (hasBuffer) return Buffer.from(bytes).toString("base64");
|
|
336
|
+
return btoa(String.fromCharCode(...bytes));
|
|
337
|
+
}
|
|
338
|
+
function fromBase64(base64) {
|
|
339
|
+
if (hasBuffer) return new Uint8Array(Buffer.from(base64, "base64"));
|
|
340
|
+
const bin = atob(base64);
|
|
341
|
+
const out = new Uint8Array(bin.length);
|
|
342
|
+
for (let i = 0; i < bin.length; i++) {
|
|
343
|
+
out[i] = bin.charCodeAt(i);
|
|
344
|
+
}
|
|
345
|
+
return out;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// src/internal/envelope.ts
|
|
349
|
+
var ENVELOPE_FIELDS = [
|
|
350
|
+
"version",
|
|
351
|
+
"algorithm",
|
|
352
|
+
"key_id",
|
|
353
|
+
"nonce",
|
|
354
|
+
"ciphertext"
|
|
355
|
+
];
|
|
356
|
+
function defaultAad(ctx) {
|
|
357
|
+
if (ctx.kind === "base") return toBytes(`${ctx.table}:${ctx.id}`);
|
|
358
|
+
const base = ctx.baseTable ?? ctx.table;
|
|
359
|
+
return toBytes(`${ctx.table}:${base}:${ctx.id}`);
|
|
360
|
+
}
|
|
361
|
+
var toEnvelope = (value) => {
|
|
362
|
+
const version = value.version;
|
|
363
|
+
const algorithm = value.algorithm;
|
|
364
|
+
const keyId = value.key_id;
|
|
365
|
+
const nonce = value.nonce;
|
|
366
|
+
const ciphertext = value.ciphertext;
|
|
367
|
+
if (typeof version !== "number" || typeof algorithm !== "string" || typeof keyId !== "string" || typeof nonce !== "string" || typeof ciphertext !== "string") {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
v: version,
|
|
372
|
+
alg: algorithm,
|
|
373
|
+
kid: keyId,
|
|
374
|
+
n: nonce,
|
|
375
|
+
ct: ciphertext
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
var toStoredEnvelope = (envelope) => ({
|
|
379
|
+
version: envelope.v,
|
|
380
|
+
algorithm: envelope.alg,
|
|
381
|
+
key_id: envelope.kid,
|
|
382
|
+
nonce: envelope.n,
|
|
383
|
+
ciphertext: envelope.ct
|
|
384
|
+
});
|
|
385
|
+
var stripEnvelopeFields = (value) => {
|
|
386
|
+
const copy = { ...value };
|
|
387
|
+
for (const key of ENVELOPE_FIELDS) delete copy[key];
|
|
388
|
+
return copy;
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// src/internal/records.ts
|
|
392
|
+
var firstRow = (result) => {
|
|
393
|
+
if (!result) return void 0;
|
|
394
|
+
if (Array.isArray(result)) return result[0];
|
|
395
|
+
return result;
|
|
396
|
+
};
|
|
397
|
+
var toRecordArray = (rows) => {
|
|
398
|
+
if (!rows) return [];
|
|
399
|
+
return Array.isArray(rows) ? rows : [rows];
|
|
400
|
+
};
|
|
401
|
+
var omitUndefined = (obj) => Object.fromEntries(
|
|
402
|
+
Object.entries(obj).filter(([, value]) => value !== void 0)
|
|
403
|
+
);
|
|
404
|
+
var isPlainObject2 = (value) => typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype;
|
|
405
|
+
async function queryRows(db, sql, bindings) {
|
|
406
|
+
const result = await db.query(sql, bindings ?? {});
|
|
407
|
+
if (Array.isArray(result)) {
|
|
408
|
+
const first = result[0];
|
|
409
|
+
if (Array.isArray(first)) return first;
|
|
410
|
+
}
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
var TEMP_ID_PREFIX = "__temp__";
|
|
414
|
+
var createTempRecordId = (tableName) => {
|
|
415
|
+
const suffix = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
416
|
+
return new surrealdb.RecordId(tableName, `${TEMP_ID_PREFIX}${suffix}`);
|
|
298
417
|
};
|
|
418
|
+
var isTempId = (id, tableName) => {
|
|
419
|
+
const normalized = toRecordIdString(id);
|
|
420
|
+
const key = normalized.startsWith(`${tableName}:`) ? normalized.slice(tableName.length + 1) : normalized;
|
|
421
|
+
return key.startsWith(TEMP_ID_PREFIX);
|
|
422
|
+
};
|
|
423
|
+
function createInsertSchema(tableName) {
|
|
424
|
+
return {
|
|
425
|
+
"~standard": {
|
|
426
|
+
version: 1,
|
|
427
|
+
vendor: "tanstack-db-surrealdb",
|
|
428
|
+
validate: (value) => {
|
|
429
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
430
|
+
return {
|
|
431
|
+
issues: [{ message: "Insert data must be an object." }]
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
const data = normalizeRecordIdLikeFields({
|
|
435
|
+
...value
|
|
436
|
+
});
|
|
437
|
+
if (!data.id)
|
|
438
|
+
data.id = createTempRecordId(tableName);
|
|
439
|
+
return { value: data };
|
|
440
|
+
},
|
|
441
|
+
types: void 0
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
var subsetCacheKey = (subset) => {
|
|
446
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
447
|
+
return JSON.stringify(subset, (_key, value) => {
|
|
448
|
+
if (value instanceof Date) return value.toISOString();
|
|
449
|
+
if (value instanceof surrealdb.RecordId) return toRecordIdString(value);
|
|
450
|
+
if (typeof value === "bigint") return value.toString();
|
|
451
|
+
if (typeof value === "function")
|
|
452
|
+
return `[fn:${value.name || "anonymous"}]`;
|
|
453
|
+
if (value && typeof value === "object") {
|
|
454
|
+
const canonical = asCanonicalRecordIdString(value);
|
|
455
|
+
if (canonical) return canonical;
|
|
456
|
+
if (seen.has(value)) return "[Circular]";
|
|
457
|
+
seen.add(value);
|
|
458
|
+
}
|
|
459
|
+
return value;
|
|
460
|
+
}) ?? "";
|
|
461
|
+
};
|
|
462
|
+
var normalizeSubsetValuesInPlace = (value, seen = /* @__PURE__ */ new WeakSet(), preferredByCanonical = /* @__PURE__ */ new Map()) => {
|
|
463
|
+
if (Array.isArray(value)) {
|
|
464
|
+
for (const entry of value) {
|
|
465
|
+
normalizeSubsetValuesInPlace(entry, seen, preferredByCanonical);
|
|
466
|
+
}
|
|
467
|
+
return preferredByCanonical;
|
|
468
|
+
}
|
|
469
|
+
if (!value || typeof value !== "object") return preferredByCanonical;
|
|
470
|
+
if (seen.has(value)) return preferredByCanonical;
|
|
471
|
+
seen.add(value);
|
|
472
|
+
const obj = value;
|
|
473
|
+
if (obj.type === "val" && "value" in obj) {
|
|
474
|
+
const canonical = asCanonicalRecordIdString(obj.value);
|
|
475
|
+
if (canonical) {
|
|
476
|
+
const preferred = preferRecordIdLikeIdentity(obj.value);
|
|
477
|
+
obj.value = preferred;
|
|
478
|
+
preferredByCanonical.set(canonical, preferred);
|
|
479
|
+
} else {
|
|
480
|
+
obj.value = preferRecordIdLikeIdentityDeep(obj.value);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
for (const child of Object.values(obj)) {
|
|
484
|
+
normalizeSubsetValuesInPlace(child, seen, preferredByCanonical);
|
|
485
|
+
}
|
|
486
|
+
return preferredByCanonical;
|
|
487
|
+
};
|
|
488
|
+
var primeRecordIdIdentityFromSubset = (subset) => {
|
|
489
|
+
if (!subset) return /* @__PURE__ */ new Map();
|
|
490
|
+
return normalizeSubsetValuesInPlace(subset);
|
|
491
|
+
};
|
|
492
|
+
var rebindRecordIdIdentityDeep = (value, preferredByCanonical) => {
|
|
493
|
+
const canonical = asCanonicalRecordIdString(value);
|
|
494
|
+
if (canonical && preferredByCanonical.has(canonical)) {
|
|
495
|
+
const preferred = preferredByCanonical.get(canonical);
|
|
496
|
+
return {
|
|
497
|
+
value: preferred,
|
|
498
|
+
changed: value !== preferred
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
if (Array.isArray(value)) {
|
|
502
|
+
let changed2 = false;
|
|
503
|
+
const out2 = value.map((entry) => {
|
|
504
|
+
const rebound = rebindRecordIdIdentityDeep(
|
|
505
|
+
entry,
|
|
506
|
+
preferredByCanonical
|
|
507
|
+
);
|
|
508
|
+
changed2 = changed2 || rebound.changed;
|
|
509
|
+
return rebound.value;
|
|
510
|
+
});
|
|
511
|
+
return changed2 ? { value: out2, changed: true } : { value, changed: false };
|
|
512
|
+
}
|
|
513
|
+
if (!isPlainObject2(value)) return { value, changed: false };
|
|
514
|
+
let changed = false;
|
|
515
|
+
const out = {};
|
|
516
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
517
|
+
const rebound = rebindRecordIdIdentityDeep(entry, preferredByCanonical);
|
|
518
|
+
if (rebound.changed) changed = true;
|
|
519
|
+
out[key] = rebound.value;
|
|
520
|
+
}
|
|
521
|
+
return changed ? { value: out, changed: true } : { value, changed: false };
|
|
522
|
+
};
|
|
523
|
+
var applyPreferredRecordIdIdentityToCollection = (ctx, preferredByCanonical) => {
|
|
524
|
+
if (!preferredByCanonical.size) return;
|
|
525
|
+
const collection = ctx.collection;
|
|
526
|
+
if (!collection || typeof collection.entries !== "function") return;
|
|
527
|
+
const rebound = [];
|
|
528
|
+
for (const [, row] of collection.entries()) {
|
|
529
|
+
const updated = rebindRecordIdIdentityDeep(row, preferredByCanonical);
|
|
530
|
+
if (!updated.changed) continue;
|
|
531
|
+
rebound.push(updated.value);
|
|
532
|
+
}
|
|
533
|
+
if (!rebound.length) return;
|
|
534
|
+
ctx.begin();
|
|
535
|
+
try {
|
|
536
|
+
for (const row of rebound) {
|
|
537
|
+
ctx.write({
|
|
538
|
+
type: "delete",
|
|
539
|
+
value: { id: row.id }
|
|
540
|
+
});
|
|
541
|
+
ctx.write({ type: "insert", value: row });
|
|
542
|
+
}
|
|
543
|
+
} finally {
|
|
544
|
+
ctx.commit();
|
|
545
|
+
}
|
|
546
|
+
const collectionWithInternals = collection;
|
|
547
|
+
const entries = collectionWithInternals._state?.entries?.();
|
|
548
|
+
const indexes = collectionWithInternals._indexes?.indexes;
|
|
549
|
+
if (entries && indexes) {
|
|
550
|
+
for (const index of indexes.values()) {
|
|
551
|
+
index.build?.(entries);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// src/internal/subset-tracker.ts
|
|
557
|
+
var ActiveSubsetTracker = class {
|
|
558
|
+
subsetIds = /* @__PURE__ */ new Map();
|
|
559
|
+
activeIds = /* @__PURE__ */ new Set();
|
|
560
|
+
get size() {
|
|
561
|
+
return this.subsetIds.size;
|
|
562
|
+
}
|
|
563
|
+
has(id) {
|
|
564
|
+
return this.activeIds.has(id);
|
|
565
|
+
}
|
|
566
|
+
set(key, ids) {
|
|
567
|
+
this.subsetIds.set(key, ids);
|
|
568
|
+
this.rebuildActiveIds();
|
|
569
|
+
}
|
|
570
|
+
delete(key) {
|
|
571
|
+
this.subsetIds.delete(key);
|
|
572
|
+
this.rebuildActiveIds();
|
|
573
|
+
}
|
|
574
|
+
deleteId(id) {
|
|
575
|
+
for (const ids of this.subsetIds.values()) ids.delete(id);
|
|
576
|
+
this.rebuildActiveIds();
|
|
577
|
+
}
|
|
578
|
+
clear() {
|
|
579
|
+
this.subsetIds.clear();
|
|
580
|
+
this.rebuildActiveIds();
|
|
581
|
+
}
|
|
582
|
+
rebuildActiveIds() {
|
|
583
|
+
this.activeIds.clear();
|
|
584
|
+
for (const ids of this.subsetIds.values()) {
|
|
585
|
+
for (const id of ids) this.activeIds.add(id);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
var isTableObject = (value) => typeof value === "object" && value !== null && "name" in value && typeof value.name === "string";
|
|
590
|
+
var toTableOptions = (table) => {
|
|
591
|
+
if (typeof table === "string") return { name: table };
|
|
592
|
+
if (table instanceof surrealdb.Table) return { name: table.name };
|
|
593
|
+
if (isTableObject(table)) return table;
|
|
594
|
+
throw new Error("Expected table as string, Table, or { name }.");
|
|
595
|
+
};
|
|
596
|
+
var toTableResource = (table) => {
|
|
597
|
+
const normalized = toTableOptions(table);
|
|
598
|
+
return new surrealdb.Table(normalized.name);
|
|
599
|
+
};
|
|
600
|
+
var tableNameOf = (table) => toTableOptions(table).name;
|
|
601
|
+
var IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
299
602
|
var toFieldPath = (value) => {
|
|
300
603
|
if (!Array.isArray(value)) {
|
|
301
604
|
throw new Error("Expected a field path array in where expression.");
|
|
@@ -505,43 +808,17 @@ function manageTable(db, config) {
|
|
|
505
808
|
if (killed) return;
|
|
506
809
|
killed = true;
|
|
507
810
|
if (live) void live.kill();
|
|
508
|
-
};
|
|
509
|
-
};
|
|
510
|
-
return {
|
|
511
|
-
listAll,
|
|
512
|
-
loadSubset,
|
|
513
|
-
create,
|
|
514
|
-
update,
|
|
515
|
-
remove,
|
|
516
|
-
softDelete: remove,
|
|
517
|
-
subscribe
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// src/util.ts
|
|
522
|
-
var encoder = new TextEncoder();
|
|
523
|
-
var decoder = new TextDecoder();
|
|
524
|
-
var hasBuffer = typeof Buffer !== "undefined";
|
|
525
|
-
function toBytes(value) {
|
|
526
|
-
if (typeof value === "string") return encoder.encode(value);
|
|
527
|
-
return encoder.encode(JSON.stringify(value));
|
|
528
|
-
}
|
|
529
|
-
function fromBytes(bytes, deserialize = false) {
|
|
530
|
-
if (deserialize) return JSON.parse(decoder.decode(bytes));
|
|
531
|
-
return decoder.decode(bytes);
|
|
532
|
-
}
|
|
533
|
-
function toBase64(bytes) {
|
|
534
|
-
if (hasBuffer) return Buffer.from(bytes).toString("base64");
|
|
535
|
-
return btoa(String.fromCharCode(...bytes));
|
|
536
|
-
}
|
|
537
|
-
function fromBase64(base64) {
|
|
538
|
-
if (hasBuffer) return new Uint8Array(Buffer.from(base64, "base64"));
|
|
539
|
-
const bin = atob(base64);
|
|
540
|
-
const out = new Uint8Array(bin.length);
|
|
541
|
-
for (let i = 0; i < bin.length; i++) {
|
|
542
|
-
out[i] = bin.charCodeAt(i);
|
|
543
|
-
}
|
|
544
|
-
return out;
|
|
811
|
+
};
|
|
812
|
+
};
|
|
813
|
+
return {
|
|
814
|
+
listAll,
|
|
815
|
+
loadSubset,
|
|
816
|
+
create,
|
|
817
|
+
update,
|
|
818
|
+
remove,
|
|
819
|
+
softDelete: remove,
|
|
820
|
+
subscribe
|
|
821
|
+
};
|
|
545
822
|
}
|
|
546
823
|
|
|
547
824
|
// src/encryption/index.ts
|
|
@@ -564,7 +841,9 @@ var WebCryptoAESGCM = class _WebCryptoAESGCM {
|
|
|
564
841
|
this.kid = options.kid ?? DEFAULT_KID;
|
|
565
842
|
this.resolveKey = options.resolveKey ?? ((incomingKid) => {
|
|
566
843
|
if (incomingKid !== this.kid) {
|
|
567
|
-
throw new Error(
|
|
844
|
+
throw new Error(
|
|
845
|
+
`No key configured for kid '${incomingKid}'.`
|
|
846
|
+
);
|
|
568
847
|
}
|
|
569
848
|
return key;
|
|
570
849
|
});
|
|
@@ -630,251 +909,10 @@ var WebCryptoAESGCM = class _WebCryptoAESGCM {
|
|
|
630
909
|
};
|
|
631
910
|
|
|
632
911
|
// src/index.ts
|
|
633
|
-
var TEMP_ID_PREFIX = "__temp__";
|
|
634
|
-
var ENVELOPE_FIELDS = [
|
|
635
|
-
"version",
|
|
636
|
-
"algorithm",
|
|
637
|
-
"key_id",
|
|
638
|
-
"nonce",
|
|
639
|
-
"ciphertext"
|
|
640
|
-
];
|
|
641
912
|
var NOOP = () => {
|
|
642
913
|
};
|
|
643
|
-
var patchedCollections = /* @__PURE__ */ new WeakSet();
|
|
644
|
-
var normalizeDeleteKeyAgainstState = (state, key) => {
|
|
645
|
-
if (state.has(key)) return key;
|
|
646
|
-
const canonical = asCanonicalRecordIdString(key);
|
|
647
|
-
if (!canonical) return key;
|
|
648
|
-
return state.has(canonical) ? canonical : key;
|
|
649
|
-
};
|
|
650
|
-
var patchCollectionDeleteForRecordIds = (collection) => {
|
|
651
|
-
if (!collection || typeof collection !== "object") return;
|
|
652
|
-
if (patchedCollections.has(collection)) return;
|
|
653
|
-
const candidate = collection;
|
|
654
|
-
if (typeof candidate.delete !== "function") return;
|
|
655
|
-
const originalDelete = candidate.delete.bind(collection);
|
|
656
|
-
Object.defineProperty(collection, "delete", {
|
|
657
|
-
configurable: true,
|
|
658
|
-
writable: true,
|
|
659
|
-
value: (keys, config) => {
|
|
660
|
-
const state = collection.state ?? /* @__PURE__ */ new Map();
|
|
661
|
-
const normalizedKeys = Array.isArray(keys) ? keys.map((key) => normalizeDeleteKeyAgainstState(state, key)) : normalizeDeleteKeyAgainstState(state, keys);
|
|
662
|
-
return originalDelete(normalizedKeys, config);
|
|
663
|
-
}
|
|
664
|
-
});
|
|
665
|
-
patchedCollections.add(collection);
|
|
666
|
-
};
|
|
667
|
-
var isTableObject = (value) => typeof value === "object" && value !== null && "name" in value && typeof value.name === "string";
|
|
668
|
-
var toTableOptions = (table) => {
|
|
669
|
-
if (typeof table === "string") return { name: table };
|
|
670
|
-
if (table instanceof surrealdb.Table) return { name: table.name };
|
|
671
|
-
if (isTableObject(table)) return table;
|
|
672
|
-
throw new Error("Expected table as string, Table, or { name }.");
|
|
673
|
-
};
|
|
674
|
-
var toTableResource = (table) => {
|
|
675
|
-
const normalized = toTableOptions(table);
|
|
676
|
-
return new surrealdb.Table(normalized.name);
|
|
677
|
-
};
|
|
678
|
-
var tableNameOf = (table) => toTableOptions(table).name;
|
|
679
914
|
var getWriteUtils = (utils) => typeof utils === "object" && utils !== null ? utils : {};
|
|
680
|
-
var firstRow2 = (result) => {
|
|
681
|
-
if (!result) return void 0;
|
|
682
|
-
if (Array.isArray(result)) return result[0];
|
|
683
|
-
return result;
|
|
684
|
-
};
|
|
685
|
-
var omitUndefined = (obj) => Object.fromEntries(
|
|
686
|
-
Object.entries(obj).filter(([, value]) => value !== void 0)
|
|
687
|
-
);
|
|
688
|
-
var createTempRecordId = (tableName) => {
|
|
689
|
-
const suffix = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
690
|
-
return new surrealdb.RecordId(tableName, `${TEMP_ID_PREFIX}${suffix}`);
|
|
691
|
-
};
|
|
692
|
-
var isTempId = (id, tableName) => {
|
|
693
|
-
const normalized = toRecordIdString(id);
|
|
694
|
-
const key = normalized.startsWith(`${tableName}:`) ? normalized.slice(tableName.length + 1) : normalized;
|
|
695
|
-
return key.startsWith(TEMP_ID_PREFIX);
|
|
696
|
-
};
|
|
697
|
-
var toEnvelope = (value) => {
|
|
698
|
-
const version = value.version;
|
|
699
|
-
const algorithm = value.algorithm;
|
|
700
|
-
const keyId = value.key_id;
|
|
701
|
-
const nonce = value.nonce;
|
|
702
|
-
const ciphertext = value.ciphertext;
|
|
703
|
-
if (typeof version !== "number" || typeof algorithm !== "string" || typeof keyId !== "string" || typeof nonce !== "string" || typeof ciphertext !== "string") {
|
|
704
|
-
return null;
|
|
705
|
-
}
|
|
706
|
-
return {
|
|
707
|
-
v: version,
|
|
708
|
-
alg: algorithm,
|
|
709
|
-
kid: keyId,
|
|
710
|
-
n: nonce,
|
|
711
|
-
ct: ciphertext
|
|
712
|
-
};
|
|
713
|
-
};
|
|
714
|
-
var toStoredEnvelope = (envelope) => ({
|
|
715
|
-
version: envelope.v,
|
|
716
|
-
algorithm: envelope.alg,
|
|
717
|
-
key_id: envelope.kid,
|
|
718
|
-
nonce: envelope.n,
|
|
719
|
-
ciphertext: envelope.ct
|
|
720
|
-
});
|
|
721
|
-
var stripEnvelopeFields = (value) => {
|
|
722
|
-
const copy = { ...value };
|
|
723
|
-
for (const key of ENVELOPE_FIELDS) delete copy[key];
|
|
724
|
-
return copy;
|
|
725
|
-
};
|
|
726
|
-
var toRecordArray = (rows) => {
|
|
727
|
-
if (!rows) return [];
|
|
728
|
-
return Array.isArray(rows) ? rows : [rows];
|
|
729
|
-
};
|
|
730
|
-
async function queryRows(db, sql, bindings) {
|
|
731
|
-
const result = await db.query(sql, bindings ?? {});
|
|
732
|
-
if (Array.isArray(result)) {
|
|
733
|
-
const first = result[0];
|
|
734
|
-
if (Array.isArray(first)) return first;
|
|
735
|
-
return [];
|
|
736
|
-
}
|
|
737
|
-
return [];
|
|
738
|
-
}
|
|
739
|
-
function createInsertSchema(tableName) {
|
|
740
|
-
return {
|
|
741
|
-
"~standard": {
|
|
742
|
-
version: 1,
|
|
743
|
-
vendor: "tanstack-db-surrealdb",
|
|
744
|
-
validate: (value) => {
|
|
745
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
746
|
-
return {
|
|
747
|
-
issues: [{ message: "Insert data must be an object." }]
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
const data = normalizeRecordIdLikeFields({
|
|
751
|
-
...value
|
|
752
|
-
});
|
|
753
|
-
if (!data.id)
|
|
754
|
-
data.id = createTempRecordId(tableName);
|
|
755
|
-
return { value: data };
|
|
756
|
-
},
|
|
757
|
-
types: void 0
|
|
758
|
-
}
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
function defaultAad(ctx) {
|
|
762
|
-
if (ctx.kind === "base") return toBytes(`${ctx.table}:${ctx.id}`);
|
|
763
|
-
const base = ctx.baseTable ?? ctx.table;
|
|
764
|
-
return toBytes(`${ctx.table}:${base}:${ctx.id}`);
|
|
765
|
-
}
|
|
766
915
|
var syncModeFrom = (syncMode) => syncMode ?? "eager";
|
|
767
|
-
var subsetCacheKey = (subset) => {
|
|
768
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
769
|
-
return JSON.stringify(subset, (_key, value) => {
|
|
770
|
-
if (value instanceof Date) return value.toISOString();
|
|
771
|
-
if (value instanceof surrealdb.RecordId) return toRecordIdString(value);
|
|
772
|
-
if (typeof value === "bigint") return value.toString();
|
|
773
|
-
if (typeof value === "function")
|
|
774
|
-
return `[fn:${value.name || "anonymous"}]`;
|
|
775
|
-
if (value && typeof value === "object") {
|
|
776
|
-
const canonical = asCanonicalRecordIdString(value);
|
|
777
|
-
if (canonical) return canonical;
|
|
778
|
-
if (seen.has(value)) return "[Circular]";
|
|
779
|
-
seen.add(value);
|
|
780
|
-
}
|
|
781
|
-
return value;
|
|
782
|
-
}) ?? "";
|
|
783
|
-
};
|
|
784
|
-
var isPlainObject2 = (value) => typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype;
|
|
785
|
-
var normalizeSubsetValuesInPlace = (value, seen = /* @__PURE__ */ new WeakSet(), preferredByCanonical = /* @__PURE__ */ new Map()) => {
|
|
786
|
-
if (Array.isArray(value)) {
|
|
787
|
-
for (const entry of value) {
|
|
788
|
-
normalizeSubsetValuesInPlace(entry, seen, preferredByCanonical);
|
|
789
|
-
}
|
|
790
|
-
return preferredByCanonical;
|
|
791
|
-
}
|
|
792
|
-
if (!value || typeof value !== "object") return preferredByCanonical;
|
|
793
|
-
if (seen.has(value)) return preferredByCanonical;
|
|
794
|
-
seen.add(value);
|
|
795
|
-
const obj = value;
|
|
796
|
-
if (obj.type === "val" && "value" in obj) {
|
|
797
|
-
const canonical = asCanonicalRecordIdString(obj.value);
|
|
798
|
-
if (canonical) {
|
|
799
|
-
const preferred = preferRecordIdLikeIdentity(obj.value);
|
|
800
|
-
obj.value = preferred;
|
|
801
|
-
preferredByCanonical.set(canonical, preferred);
|
|
802
|
-
} else {
|
|
803
|
-
obj.value = preferRecordIdLikeIdentityDeep(obj.value);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
for (const child of Object.values(obj)) {
|
|
807
|
-
normalizeSubsetValuesInPlace(child, seen, preferredByCanonical);
|
|
808
|
-
}
|
|
809
|
-
return preferredByCanonical;
|
|
810
|
-
};
|
|
811
|
-
var primeRecordIdIdentityFromSubset = (subset) => {
|
|
812
|
-
if (!subset) return /* @__PURE__ */ new Map();
|
|
813
|
-
return normalizeSubsetValuesInPlace(subset);
|
|
814
|
-
};
|
|
815
|
-
var rebindRecordIdIdentityDeep = (value, preferredByCanonical) => {
|
|
816
|
-
const canonical = asCanonicalRecordIdString(value);
|
|
817
|
-
if (canonical && preferredByCanonical.has(canonical)) {
|
|
818
|
-
const preferred = preferredByCanonical.get(canonical);
|
|
819
|
-
return {
|
|
820
|
-
value: preferred,
|
|
821
|
-
changed: value !== preferred
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
if (Array.isArray(value)) {
|
|
825
|
-
let changed2 = false;
|
|
826
|
-
const out2 = value.map((entry) => {
|
|
827
|
-
const rebound = rebindRecordIdIdentityDeep(
|
|
828
|
-
entry,
|
|
829
|
-
preferredByCanonical
|
|
830
|
-
);
|
|
831
|
-
changed2 = changed2 || rebound.changed;
|
|
832
|
-
return rebound.value;
|
|
833
|
-
});
|
|
834
|
-
return changed2 ? { value: out2, changed: true } : { value, changed: false };
|
|
835
|
-
}
|
|
836
|
-
if (!isPlainObject2(value)) return { value, changed: false };
|
|
837
|
-
let changed = false;
|
|
838
|
-
const out = {};
|
|
839
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
840
|
-
const rebound = rebindRecordIdIdentityDeep(entry, preferredByCanonical);
|
|
841
|
-
if (rebound.changed) changed = true;
|
|
842
|
-
out[key] = rebound.value;
|
|
843
|
-
}
|
|
844
|
-
return changed ? { value: out, changed: true } : { value, changed: false };
|
|
845
|
-
};
|
|
846
|
-
var applyPreferredRecordIdIdentityToCollection = (ctx, preferredByCanonical) => {
|
|
847
|
-
if (!preferredByCanonical.size) return;
|
|
848
|
-
const collection = ctx.collection;
|
|
849
|
-
if (!collection || typeof collection.entries !== "function") return;
|
|
850
|
-
const rebound = [];
|
|
851
|
-
for (const [, row] of collection.entries()) {
|
|
852
|
-
const updated = rebindRecordIdIdentityDeep(row, preferredByCanonical);
|
|
853
|
-
if (!updated.changed) continue;
|
|
854
|
-
rebound.push(updated.value);
|
|
855
|
-
}
|
|
856
|
-
if (!rebound.length) return;
|
|
857
|
-
ctx.begin();
|
|
858
|
-
try {
|
|
859
|
-
for (const row of rebound) {
|
|
860
|
-
ctx.write({
|
|
861
|
-
type: "delete",
|
|
862
|
-
value: { id: row.id }
|
|
863
|
-
});
|
|
864
|
-
ctx.write({ type: "insert", value: row });
|
|
865
|
-
}
|
|
866
|
-
} finally {
|
|
867
|
-
ctx.commit();
|
|
868
|
-
}
|
|
869
|
-
const collectionWithInternals = collection;
|
|
870
|
-
const entries = collectionWithInternals._state?.entries?.();
|
|
871
|
-
const indexes = collectionWithInternals._indexes?.indexes;
|
|
872
|
-
if (entries && indexes) {
|
|
873
|
-
for (const index of indexes.values()) {
|
|
874
|
-
index.build?.(entries);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
};
|
|
878
916
|
function modernSurrealCollectionOptions(config) {
|
|
879
917
|
const {
|
|
880
918
|
db,
|
|
@@ -896,9 +934,9 @@ function modernSurrealCollectionOptions(config) {
|
|
|
896
934
|
const queryDrivenUsesSubsets = queryDrivenSyncMode === "on-demand";
|
|
897
935
|
const tableOptions = toTableOptions(table);
|
|
898
936
|
const tableName = tableOptions.name;
|
|
937
|
+
const collectionId = config.id ?? deriveCollectionId(tableName, queryKey);
|
|
899
938
|
const tableResource = toTableResource(table);
|
|
900
|
-
const
|
|
901
|
-
const activeOnDemandIds = /* @__PURE__ */ new Set();
|
|
939
|
+
const activeSubsets = new ActiveSubsetTracker();
|
|
902
940
|
const e2eeEnabled = e2ee?.enabled === true;
|
|
903
941
|
const crdtEnabled = crdt?.enabled === true;
|
|
904
942
|
const defaultCrdtProfile = crdtEnabled ? createLoroProfile(crdt.profile) : void 0;
|
|
@@ -951,7 +989,6 @@ function modernSurrealCollectionOptions(config) {
|
|
|
951
989
|
const updatesTableName = crdtEnabled ? tableNameOf(crdt.updatesTable) : void 0;
|
|
952
990
|
const updatesTable = crdtEnabled ? toTableResource(crdt.updatesTable) : void 0;
|
|
953
991
|
const snapshotsTableName = crdtEnabled && crdt.snapshotsTable ? tableNameOf(crdt.snapshotsTable) : void 0;
|
|
954
|
-
crdtEnabled && crdt.snapshotsTable ? toTableResource(crdt.snapshotsTable) : void 0;
|
|
955
992
|
const getDoc = (id) => {
|
|
956
993
|
const existing = docs.get(id);
|
|
957
994
|
if (existing) return existing;
|
|
@@ -1092,12 +1129,6 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1092
1129
|
commit();
|
|
1093
1130
|
}
|
|
1094
1131
|
};
|
|
1095
|
-
const updateActiveOnDemandIds = () => {
|
|
1096
|
-
activeOnDemandIds.clear();
|
|
1097
|
-
for (const ids of subsetIds.values()) {
|
|
1098
|
-
for (const id of ids) activeOnDemandIds.add(id);
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
1132
|
const createSyncRuntime = (ctx) => {
|
|
1102
1133
|
let cleanupBaseLive = NOOP;
|
|
1103
1134
|
let cleanupUpdateLive = NOOP;
|
|
@@ -1116,12 +1147,11 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1116
1147
|
if (message.action === "KILLED") return;
|
|
1117
1148
|
const row = message.value;
|
|
1118
1149
|
const id = toRecordKeyString(row.id);
|
|
1119
|
-
const wasVisible =
|
|
1150
|
+
const wasVisible = activeSubsets.has(id);
|
|
1120
1151
|
if (isStrictOnDemand && !wasVisible && message.action !== "DELETE")
|
|
1121
1152
|
return;
|
|
1122
1153
|
if (message.action === "DELETE") {
|
|
1123
|
-
|
|
1124
|
-
updateActiveOnDemandIds();
|
|
1154
|
+
activeSubsets.deleteId(id);
|
|
1125
1155
|
if (isStrictOnDemand && !wasVisible) return;
|
|
1126
1156
|
ctx.begin();
|
|
1127
1157
|
try {
|
|
@@ -1167,7 +1197,7 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1167
1197
|
const value = message.value;
|
|
1168
1198
|
const id = idFromDocRef(value.doc);
|
|
1169
1199
|
if (value.actor && value.actor === resolveActor(id)) return;
|
|
1170
|
-
if (isStrictOnDemand && !
|
|
1200
|
+
if (isStrictOnDemand && !activeSubsets.has(id)) return;
|
|
1171
1201
|
const doc = getDoc(id);
|
|
1172
1202
|
const bytes = await decodeUpdateBytes(value, "update");
|
|
1173
1203
|
if (!bytes.byteLength) return;
|
|
@@ -1198,8 +1228,7 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1198
1228
|
(row) => toRecordKeyString(row.id)
|
|
1199
1229
|
)
|
|
1200
1230
|
);
|
|
1201
|
-
|
|
1202
|
-
updateActiveOnDemandIds();
|
|
1231
|
+
activeSubsets.set(key, ids);
|
|
1203
1232
|
if (!crdtEnabled) {
|
|
1204
1233
|
await hydratePlainRows(
|
|
1205
1234
|
rows,
|
|
@@ -1225,9 +1254,8 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1225
1254
|
const unloadSubset = (subset) => {
|
|
1226
1255
|
primeRecordIdIdentityFromSubset(subset);
|
|
1227
1256
|
const key = subsetCacheKey(subset);
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
if (subsetIds.size === 0) {
|
|
1257
|
+
activeSubsets.delete(key);
|
|
1258
|
+
if (activeSubsets.size === 0) {
|
|
1231
1259
|
cleanupBaseLive();
|
|
1232
1260
|
cleanupUpdateLive();
|
|
1233
1261
|
}
|
|
@@ -1241,8 +1269,7 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1241
1269
|
};
|
|
1242
1270
|
const cleanup = () => {
|
|
1243
1271
|
killed = true;
|
|
1244
|
-
|
|
1245
|
-
updateActiveOnDemandIds();
|
|
1272
|
+
activeSubsets.clear();
|
|
1246
1273
|
cleanupBaseLive();
|
|
1247
1274
|
cleanupUpdateLive();
|
|
1248
1275
|
};
|
|
@@ -1254,6 +1281,7 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1254
1281
|
};
|
|
1255
1282
|
};
|
|
1256
1283
|
const base = queryDbCollection.queryCollectionOptions({
|
|
1284
|
+
id: collectionId,
|
|
1257
1285
|
schema: createInsertSchema(tableName),
|
|
1258
1286
|
getKey,
|
|
1259
1287
|
queryKey,
|
|
@@ -1314,7 +1342,7 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1314
1342
|
const recordPayload = await encodeBaseRow(payload, idKey);
|
|
1315
1343
|
if (isTempId(normalized.id, tableName)) {
|
|
1316
1344
|
const created = await db.create(tableResource).content(recordPayload);
|
|
1317
|
-
const createdRow =
|
|
1345
|
+
const createdRow = firstRow(
|
|
1318
1346
|
toRecordArray(created)
|
|
1319
1347
|
);
|
|
1320
1348
|
const createdId = createdRow && createdRow.id ? createdRow.id : normalized.id;
|
|
@@ -1526,6 +1554,14 @@ function modernSurrealCollectionOptions(config) {
|
|
|
1526
1554
|
function surrealCollectionOptions(config) {
|
|
1527
1555
|
return modernSurrealCollectionOptions(config);
|
|
1528
1556
|
}
|
|
1557
|
+
function persistedSurrealCollectionOptions(config) {
|
|
1558
|
+
const { persistence, schemaVersion, ...surrealConfig } = config;
|
|
1559
|
+
return dbSqlitePersistenceCore.persistedCollectionOptions({
|
|
1560
|
+
persistence,
|
|
1561
|
+
schemaVersion,
|
|
1562
|
+
...modernSurrealCollectionOptions(surrealConfig)
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1529
1565
|
|
|
1530
1566
|
exports.WebCryptoAESGCM = WebCryptoAESGCM;
|
|
1531
1567
|
exports.applyLoroJsonChange = applyLoroJsonChange;
|
|
@@ -1533,6 +1569,7 @@ exports.applyLoroRichtextChange = applyLoroRichtextChange;
|
|
|
1533
1569
|
exports.createLoroProfile = createLoroProfile;
|
|
1534
1570
|
exports.materializeLoroJson = materializeLoroJson;
|
|
1535
1571
|
exports.materializeLoroRichtext = materializeLoroRichtext;
|
|
1572
|
+
exports.persistedSurrealCollectionOptions = persistedSurrealCollectionOptions;
|
|
1536
1573
|
exports.surrealCollectionOptions = surrealCollectionOptions;
|
|
1537
1574
|
exports.toRecordKeyString = toRecordKeyString;
|
|
1538
1575
|
//# sourceMappingURL=index.js.map
|