@foretag/tanstack-db-surrealdb 0.6.12 → 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/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 IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
294
- var firstRow = (res) => {
295
- if (!res) return void 0;
296
- if (Array.isArray(res)) return res[0];
297
- return res;
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(`No key configured for kid '${incomingKid}'.`);
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 subsetIds = /* @__PURE__ */ new Map();
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 = activeOnDemandIds.has(id);
1150
+ const wasVisible = activeSubsets.has(id);
1120
1151
  if (isStrictOnDemand && !wasVisible && message.action !== "DELETE")
1121
1152
  return;
1122
1153
  if (message.action === "DELETE") {
1123
- for (const ids of subsetIds.values()) ids.delete(id);
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 && !activeOnDemandIds.has(id)) return;
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
- subsetIds.set(key, ids);
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
- subsetIds.delete(key);
1229
- updateActiveOnDemandIds();
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
- subsetIds.clear();
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 = firstRow2(
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