@foretag/tanstack-db-surrealdb 0.1.8 → 0.1.10

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Note: Please note this Software is Pre-release pending testing and not yet recommended for production use.
4
4
 
5
- Add Offline / Local First Caching & Syncing to your SurrealDB app with TanstackDB and Loro (CRDTs).
5
+ Add Offline / Local First Caching & Syncing to your SurrealDB app with TanstackDB and Loro (CRDTs). For SurrealDB v3 and SurrealDB JS SDK v2.
6
6
 
7
7
  - Local / Offline first applications with TanstackDB and Loro
8
8
  - High performance with Low resource consumption
package/dist/index.d.mts CHANGED
@@ -1,22 +1,22 @@
1
1
  import { CollectionConfig, UtilsRecord } from '@tanstack/db';
2
2
  import { Container } from 'loro-crdt';
3
- import { Surreal, Expr } from 'surrealdb';
3
+ import { RecordId, Surreal, Expr } from 'surrealdb';
4
4
 
5
- type Id = string;
6
- type SurrealObject<T> = T & {
7
- id: Id;
5
+ type WithId<T> = T & {
6
+ id: string | RecordId;
8
7
  };
9
- type SurrealField<I> = keyof I;
10
- type SyncedRow = SurrealObject<{
8
+ type SyncedTable<T> = WithId<T & {
11
9
  sync_deleted?: boolean;
12
10
  updated_at?: Date;
13
11
  }>;
14
12
  type TableOptions<T> = {
15
13
  name: string;
16
14
  where?: Expr;
17
- fields?: SurrealField<T>[];
15
+ fields?: (keyof T)[];
18
16
  };
19
- type SurrealCollectionConfig<T extends SurrealObject<object>> = {
17
+ type SurrealCollectionConfig<T extends {
18
+ id: string | RecordId;
19
+ }> = {
20
20
  id?: string;
21
21
  db: Surreal;
22
22
  table: TableOptions<T>;
@@ -24,7 +24,7 @@ type SurrealCollectionConfig<T extends SurrealObject<object>> = {
24
24
  onError?: (e: unknown) => void;
25
25
  };
26
26
 
27
- declare function surrealCollectionOptions<T extends SyncedRow, S extends Record<string, Container> = {
27
+ declare function surrealCollectionOptions<T extends SyncedTable<object>, S extends Record<string, Container> = {
28
28
  [k: string]: never;
29
29
  }>({ id, useLoro, onError, db, ...config }: SurrealCollectionConfig<T>): CollectionConfig<T, string | number, never, UtilsRecord>;
30
30
 
package/dist/index.d.ts CHANGED
@@ -1,22 +1,22 @@
1
1
  import { CollectionConfig, UtilsRecord } from '@tanstack/db';
2
2
  import { Container } from 'loro-crdt';
3
- import { Surreal, Expr } from 'surrealdb';
3
+ import { RecordId, Surreal, Expr } from 'surrealdb';
4
4
 
5
- type Id = string;
6
- type SurrealObject<T> = T & {
7
- id: Id;
5
+ type WithId<T> = T & {
6
+ id: string | RecordId;
8
7
  };
9
- type SurrealField<I> = keyof I;
10
- type SyncedRow = SurrealObject<{
8
+ type SyncedTable<T> = WithId<T & {
11
9
  sync_deleted?: boolean;
12
10
  updated_at?: Date;
13
11
  }>;
14
12
  type TableOptions<T> = {
15
13
  name: string;
16
14
  where?: Expr;
17
- fields?: SurrealField<T>[];
15
+ fields?: (keyof T)[];
18
16
  };
19
- type SurrealCollectionConfig<T extends SurrealObject<object>> = {
17
+ type SurrealCollectionConfig<T extends {
18
+ id: string | RecordId;
19
+ }> = {
20
20
  id?: string;
21
21
  db: Surreal;
22
22
  table: TableOptions<T>;
@@ -24,7 +24,7 @@ type SurrealCollectionConfig<T extends SurrealObject<object>> = {
24
24
  onError?: (e: unknown) => void;
25
25
  };
26
26
 
27
- declare function surrealCollectionOptions<T extends SyncedRow, S extends Record<string, Container> = {
27
+ declare function surrealCollectionOptions<T extends SyncedTable<object>, S extends Record<string, Container> = {
28
28
  [k: string]: never;
29
29
  }>({ id, useLoro, onError, db, ...config }: SurrealCollectionConfig<T>): CollectionConfig<T, string | number, never, UtilsRecord>;
30
30
 
package/dist/index.js CHANGED
@@ -63,19 +63,9 @@ function manageTable(db, { name, ...args }) {
63
63
  cb({ type: "delete", row: { id: value.id } });
64
64
  };
65
65
  const start = async () => {
66
- if (!args.where) {
67
- live = await db.live(new import_surrealdb.Table(name));
68
- live.subscribe(on);
69
- } else {
70
- const ctx = {
71
- def() {
72
- return "";
73
- }
74
- };
75
- const [id] = await db.query(
76
- `LIVE SELECT * FROM ${name} WHERE ${args.where.toSQL(ctx)}`
77
- ).collect();
78
- live = await db.liveOf(new import_surrealdb.Uuid(id));
66
+ const isLiveSupported = db.isFeatureSupported(import_surrealdb.Features.LiveQueries);
67
+ if (isLiveSupported) {
68
+ live = await db.live(new import_surrealdb.Table(name)).where(args.where);
79
69
  live.subscribe(on);
80
70
  }
81
71
  };
@@ -106,7 +96,8 @@ function surrealCollectionOptions({
106
96
  }) {
107
97
  let loro;
108
98
  if (useLoro) loro = { doc: new import_loro_crdt.LoroDoc(), key: id };
109
- const getKey = (row) => row.id;
99
+ const keyOf = (id2) => typeof id2 === "string" ? id2 : id2.toString();
100
+ const getKey = (row) => keyOf(row.id);
110
101
  const loroKey = loro?.key ?? id ?? "surreal";
111
102
  const loroMap = useLoro ? loro?.doc?.getMap?.(loroKey) ?? null : null;
112
103
  const loroToArray = () => {
@@ -116,22 +107,25 @@ function surrealCollectionOptions({
116
107
  };
117
108
  const loroPut = (row) => {
118
109
  if (!loroMap) return;
119
- loroMap.set(String(getKey(row)), row);
110
+ loroMap.set(getKey(row), row);
120
111
  loro?.doc?.commit?.();
121
112
  };
122
113
  const loroRemove = (id2) => {
123
114
  if (!loroMap) return;
124
- loroMap.delete(String(id2));
115
+ loroMap.delete(id2);
125
116
  loro?.doc?.commit?.();
126
117
  };
127
118
  const flushPushQueue = async () => {
128
119
  const ops = pushQueue.splice(0, pushQueue.length);
129
120
  for (const op of ops) {
130
121
  if (op.kind === "upsert") {
131
- const rid = new import_surrealdb2.RecordId(config.table.name, op.row.id);
122
+ const rid = new import_surrealdb2.RecordId(
123
+ config.table.name,
124
+ op.row.id.toString()
125
+ );
132
126
  await table.upsert(rid, op.row);
133
127
  } else {
134
- const rid = new import_surrealdb2.RecordId(config.table.name, op.id);
128
+ const rid = new import_surrealdb2.RecordId(config.table.name, op.id.toString());
135
129
  await table.softDelete(rid);
136
130
  }
137
131
  }
@@ -141,15 +135,13 @@ function surrealCollectionOptions({
141
135
  const newer = (a, b) => (a?.getTime() ?? -1) > (b?.getTime() ?? -1);
142
136
  const reconcileBoot = (serverRows, write) => {
143
137
  const localRows = useLoro ? loroToArray() : [];
144
- const serverById = new Map(
145
- serverRows.map((r) => [getKey(r), r])
146
- );
138
+ const serverById = new Map(serverRows.map((r) => [getKey(r), r]));
147
139
  const localById = new Map(localRows.map((r) => [getKey(r), r]));
148
140
  const ids = /* @__PURE__ */ new Set([...serverById.keys(), ...localById.keys()]);
149
141
  const current = [];
150
142
  const applyLocal = (row) => {
151
143
  if (!useLoro || !row) return;
152
- if (row.sync_deleted) loroRemove(row.id);
144
+ if (row.sync_deleted) loroRemove(getKey(row));
153
145
  else loroPut(row);
154
146
  };
155
147
  for (const id2 of ids) {
@@ -242,7 +234,11 @@ function surrealCollectionOptions({
242
234
  markReady
243
235
  }) => {
244
236
  let offLive = null;
245
- const makeTombstone = (id2) => ({ id: id2, updated_at: /* @__PURE__ */ new Date(), sync_deleted: true });
237
+ const makeTombstone = (id2) => ({
238
+ id: new import_surrealdb2.RecordId(config.table.name, id2).toString(),
239
+ updated_at: /* @__PURE__ */ new Date(),
240
+ sync_deleted: true
241
+ });
246
242
  const start = async () => {
247
243
  try {
248
244
  const serverRows = await table.listAll();
@@ -258,18 +254,18 @@ function surrealCollectionOptions({
258
254
  if (evt.type === "insert" || evt.type === "update") {
259
255
  const row = evt.row;
260
256
  if (row.sync_deleted) {
261
- if (useLoro) loroRemove(row.id);
262
- const prev = prevById.get(row.id) ?? makeTombstone(row.id);
257
+ if (useLoro) loroRemove(getKey(row));
258
+ const prev = prevById.get(getKey(row)) ?? makeTombstone(getKey(row));
263
259
  write({ type: "delete", value: prev });
264
- prevById.delete(row.id);
260
+ prevById.delete(getKey(row));
265
261
  } else {
266
262
  if (useLoro) loroPut(row);
267
- const had = prevById.has(row.id);
263
+ const had = prevById.has(getKey(row));
268
264
  write({
269
265
  type: had ? "update" : "insert",
270
266
  value: row
271
267
  });
272
- prevById.set(row.id, row);
268
+ prevById.set(getKey(row), row);
273
269
  }
274
270
  } else if (evt.type === "delete") {
275
271
  const id2 = getKey(evt.row);
@@ -303,7 +299,7 @@ function surrealCollectionOptions({
303
299
  deleted: false
304
300
  };
305
301
  if (useLoro) loroPut(row);
306
- const rid = new import_surrealdb2.RecordId(config.table.name, row.id);
302
+ const rid = new import_surrealdb2.RecordId(config.table.name, getKey(row));
307
303
  await table.upsert(rid, row);
308
304
  resultRows.push(row);
309
305
  }
@@ -316,7 +312,7 @@ function surrealCollectionOptions({
316
312
  const id2 = m.key;
317
313
  const merged = { ...m.modified, id: id2, updated_at: now() };
318
314
  if (useLoro) loroPut(merged);
319
- const rid = new import_surrealdb2.RecordId(config.table.name, id2);
315
+ const rid = new import_surrealdb2.RecordId(config.table.name, keyOf(id2));
320
316
  await table.upsert(rid, merged);
321
317
  resultRows.push(merged);
322
318
  }
@@ -327,8 +323,8 @@ function surrealCollectionOptions({
327
323
  for (const m of p.transaction.mutations) {
328
324
  if (m.type !== "delete") continue;
329
325
  const id2 = m.key;
330
- if (useLoro) loroRemove(id2);
331
- await table.softDelete(new import_surrealdb2.RecordId(config.table.name, id2));
326
+ if (useLoro) loroRemove(keyOf(id2));
327
+ await table.softDelete(new import_surrealdb2.RecordId(config.table.name, keyOf(id2)));
332
328
  }
333
329
  return resultRows;
334
330
  };
package/dist/index.mjs CHANGED
@@ -6,8 +6,8 @@ import { RecordId } from "surrealdb";
6
6
  import {
7
7
  and,
8
8
  eq,
9
- Table,
10
- Uuid
9
+ Features,
10
+ Table
11
11
  } from "surrealdb";
12
12
  function manageTable(db, { name, ...args }) {
13
13
  const fields = args.fields?.join(", ") ?? "*";
@@ -45,19 +45,9 @@ function manageTable(db, { name, ...args }) {
45
45
  cb({ type: "delete", row: { id: value.id } });
46
46
  };
47
47
  const start = async () => {
48
- if (!args.where) {
49
- live = await db.live(new Table(name));
50
- live.subscribe(on);
51
- } else {
52
- const ctx = {
53
- def() {
54
- return "";
55
- }
56
- };
57
- const [id] = await db.query(
58
- `LIVE SELECT * FROM ${name} WHERE ${args.where.toSQL(ctx)}`
59
- ).collect();
60
- live = await db.liveOf(new Uuid(id));
48
+ const isLiveSupported = db.isFeatureSupported(Features.LiveQueries);
49
+ if (isLiveSupported) {
50
+ live = await db.live(new Table(name)).where(args.where);
61
51
  live.subscribe(on);
62
52
  }
63
53
  };
@@ -88,7 +78,8 @@ function surrealCollectionOptions({
88
78
  }) {
89
79
  let loro;
90
80
  if (useLoro) loro = { doc: new LoroDoc(), key: id };
91
- const getKey = (row) => row.id;
81
+ const keyOf = (id2) => typeof id2 === "string" ? id2 : id2.toString();
82
+ const getKey = (row) => keyOf(row.id);
92
83
  const loroKey = loro?.key ?? id ?? "surreal";
93
84
  const loroMap = useLoro ? loro?.doc?.getMap?.(loroKey) ?? null : null;
94
85
  const loroToArray = () => {
@@ -98,22 +89,25 @@ function surrealCollectionOptions({
98
89
  };
99
90
  const loroPut = (row) => {
100
91
  if (!loroMap) return;
101
- loroMap.set(String(getKey(row)), row);
92
+ loroMap.set(getKey(row), row);
102
93
  loro?.doc?.commit?.();
103
94
  };
104
95
  const loroRemove = (id2) => {
105
96
  if (!loroMap) return;
106
- loroMap.delete(String(id2));
97
+ loroMap.delete(id2);
107
98
  loro?.doc?.commit?.();
108
99
  };
109
100
  const flushPushQueue = async () => {
110
101
  const ops = pushQueue.splice(0, pushQueue.length);
111
102
  for (const op of ops) {
112
103
  if (op.kind === "upsert") {
113
- const rid = new RecordId(config.table.name, op.row.id);
104
+ const rid = new RecordId(
105
+ config.table.name,
106
+ op.row.id.toString()
107
+ );
114
108
  await table.upsert(rid, op.row);
115
109
  } else {
116
- const rid = new RecordId(config.table.name, op.id);
110
+ const rid = new RecordId(config.table.name, op.id.toString());
117
111
  await table.softDelete(rid);
118
112
  }
119
113
  }
@@ -123,15 +117,13 @@ function surrealCollectionOptions({
123
117
  const newer = (a, b) => (a?.getTime() ?? -1) > (b?.getTime() ?? -1);
124
118
  const reconcileBoot = (serverRows, write) => {
125
119
  const localRows = useLoro ? loroToArray() : [];
126
- const serverById = new Map(
127
- serverRows.map((r) => [getKey(r), r])
128
- );
120
+ const serverById = new Map(serverRows.map((r) => [getKey(r), r]));
129
121
  const localById = new Map(localRows.map((r) => [getKey(r), r]));
130
122
  const ids = /* @__PURE__ */ new Set([...serverById.keys(), ...localById.keys()]);
131
123
  const current = [];
132
124
  const applyLocal = (row) => {
133
125
  if (!useLoro || !row) return;
134
- if (row.sync_deleted) loroRemove(row.id);
126
+ if (row.sync_deleted) loroRemove(getKey(row));
135
127
  else loroPut(row);
136
128
  };
137
129
  for (const id2 of ids) {
@@ -224,7 +216,11 @@ function surrealCollectionOptions({
224
216
  markReady
225
217
  }) => {
226
218
  let offLive = null;
227
- const makeTombstone = (id2) => ({ id: id2, updated_at: /* @__PURE__ */ new Date(), sync_deleted: true });
219
+ const makeTombstone = (id2) => ({
220
+ id: new RecordId(config.table.name, id2).toString(),
221
+ updated_at: /* @__PURE__ */ new Date(),
222
+ sync_deleted: true
223
+ });
228
224
  const start = async () => {
229
225
  try {
230
226
  const serverRows = await table.listAll();
@@ -240,18 +236,18 @@ function surrealCollectionOptions({
240
236
  if (evt.type === "insert" || evt.type === "update") {
241
237
  const row = evt.row;
242
238
  if (row.sync_deleted) {
243
- if (useLoro) loroRemove(row.id);
244
- const prev = prevById.get(row.id) ?? makeTombstone(row.id);
239
+ if (useLoro) loroRemove(getKey(row));
240
+ const prev = prevById.get(getKey(row)) ?? makeTombstone(getKey(row));
245
241
  write({ type: "delete", value: prev });
246
- prevById.delete(row.id);
242
+ prevById.delete(getKey(row));
247
243
  } else {
248
244
  if (useLoro) loroPut(row);
249
- const had = prevById.has(row.id);
245
+ const had = prevById.has(getKey(row));
250
246
  write({
251
247
  type: had ? "update" : "insert",
252
248
  value: row
253
249
  });
254
- prevById.set(row.id, row);
250
+ prevById.set(getKey(row), row);
255
251
  }
256
252
  } else if (evt.type === "delete") {
257
253
  const id2 = getKey(evt.row);
@@ -285,7 +281,7 @@ function surrealCollectionOptions({
285
281
  deleted: false
286
282
  };
287
283
  if (useLoro) loroPut(row);
288
- const rid = new RecordId(config.table.name, row.id);
284
+ const rid = new RecordId(config.table.name, getKey(row));
289
285
  await table.upsert(rid, row);
290
286
  resultRows.push(row);
291
287
  }
@@ -298,7 +294,7 @@ function surrealCollectionOptions({
298
294
  const id2 = m.key;
299
295
  const merged = { ...m.modified, id: id2, updated_at: now() };
300
296
  if (useLoro) loroPut(merged);
301
- const rid = new RecordId(config.table.name, id2);
297
+ const rid = new RecordId(config.table.name, keyOf(id2));
302
298
  await table.upsert(rid, merged);
303
299
  resultRows.push(merged);
304
300
  }
@@ -309,8 +305,8 @@ function surrealCollectionOptions({
309
305
  for (const m of p.transaction.mutations) {
310
306
  if (m.type !== "delete") continue;
311
307
  const id2 = m.key;
312
- if (useLoro) loroRemove(id2);
313
- await table.softDelete(new RecordId(config.table.name, id2));
308
+ if (useLoro) loroRemove(keyOf(id2));
309
+ await table.softDelete(new RecordId(config.table.name, keyOf(id2)));
314
310
  }
315
311
  return resultRows;
316
312
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@foretag/tanstack-db-surrealdb",
3
3
  "description": "Add Offline / Local First Caching & Syncing to your SurrealDB app with TanstackDB and Loro (CRDTs)",
4
- "version": "0.1.8",
4
+ "version": "0.1.10",
5
5
  "files": [
6
6
  "dist"
7
7
  ],
@@ -40,7 +40,8 @@
40
40
  "build": "tsup src/index.ts --dts --format esm,cjs"
41
41
  },
42
42
  "dependencies": {
43
- "@tanstack/db": "^0.4.19",
43
+ "@tanstack/db": "^0.4.20",
44
+ "@tanstack/query-db-collection": "^0.3.0",
44
45
  "loro-crdt": "^1.8.9"
45
46
  },
46
47
  "peerDependencies": {