@foretag/tanstack-db-surrealdb 0.5.8 → 0.6.1

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
@@ -1,137 +1,353 @@
1
- # TanstackDB SurrealDB Collections
1
+ # @foretag/tanstack-db-surrealdb
2
2
 
3
- Add Offline / Local First Caching & Syncing to your SurrealDB app with TanstackDB and Loro (CRDTs). Designed for SurrealDB v3 and SurrealDB JS SDK v2.
3
+ TanStack DB collection adapter for SurrealDB JS with:
4
4
 
5
- - Local / Offline first applications with TanstackDB and Loro
6
- - High performance with Low resource consumption
7
- - Works with Web, Desktop or Native (WASM based)
8
- - Support for React, Svelte, Vue and any Framework!
5
+ - Realtime replication (`LIVE`)
6
+ - Local-first writes
7
+ - Optional E2EE envelopes (`version/algorithm/key_id/nonce/ciphertext`)
8
+ - Optional Loro CRDT replication (`json`, `richtext`)
9
+ - Query-driven sync modes (`eager`, `on-demand`, `progressive`)
9
10
 
10
- ## Installation
11
+ ## Install
11
12
 
12
- ### NPM
13
13
  ```sh
14
- # NPM
15
14
  npm install @foretag/tanstack-db-surrealdb
16
- # Bun
17
- bun install @foretag/tanstack-db-surrealdb
15
+ # or
16
+ bun add @foretag/tanstack-db-surrealdb
18
17
  ```
19
18
 
20
- ## Usage
19
+ ## Quick Start
20
+
21
21
  ```ts
22
- // db.ts
23
- import { QueryClient } from '@tanstack/svelte-query'; // Can also use '@tanstack/react-query' etc.
22
+ import { createCollection } from '@tanstack/db';
23
+ import { QueryClient } from '@tanstack/query-core';
24
24
  import { Surreal } from 'surrealdb';
25
+ import { surrealCollectionOptions } from '@foretag/tanstack-db-surrealdb';
25
26
 
26
- export const db = new Surreal();
27
- await db.connect('ws://localhost:8000/rpc');
28
- await db.use({ ns: 'ns', db: 'db' });
27
+ const db = new Surreal();
28
+ const queryClient = new QueryClient();
29
29
 
30
- export const queryClient = new QueryClient();
30
+ type Product = { id: string; name: string; price: number };
31
31
 
32
- // collections/products.ts
33
- import { eq } from '@tanstack/db';
34
- import { db, queryClient } from '../db';
35
- import { createCollection } from '@tanstack/db';
36
- import { surrealCollectionOptions } from '@foretag/tanstack-db-surrealdb';
37
- import { useLiveQuery } from '@tanstack/react-db';
38
-
39
- // Collection Type, could also be generated
40
- type Product = {
41
- id: string;
42
- name: string;
43
- price: number;
44
- store?: string;
32
+ export const products = createCollection(
33
+ surrealCollectionOptions<Product>({
34
+ db,
35
+ table: { name: 'product' },
36
+ queryClient,
37
+ queryKey: ['product'],
38
+ syncMode: 'eager',
39
+ }),
40
+ );
41
+ ```
42
+
43
+ ## Adapter API
44
+
45
+ ```ts
46
+ type SurrealCollectionOptions<T> = {
47
+ db: Surreal;
48
+ table: Table | { name: string; relation?: boolean } | string;
49
+ queryClient: QueryClient;
50
+ queryKey: readonly unknown[];
51
+ syncMode?: 'eager' | 'on-demand' | 'progressive';
52
+ e2ee?: {
53
+ enabled: boolean;
54
+ crypto: CryptoProvider;
55
+ aad?: (ctx: { table: string; id: string; kind: 'base'|'update'|'snapshot'; baseTable?: string }) => Uint8Array;
56
+ };
57
+ crdt?: {
58
+ enabled: boolean;
59
+ profile: 'json' | 'richtext';
60
+ updatesTable: Table | { name: string } | string;
61
+ snapshotsTable?: Table | { name: string } | string;
62
+ // Optional overrides. If omitted, adapter uses built-in handlers for `profile`.
63
+ materialize?: (doc: LoroDoc, id: string) => T;
64
+ applyLocalChange?: (doc: LoroDoc, change: { type: 'insert'|'update'|'delete'; value: T }) => void;
65
+ persistMaterializedView?: boolean;
66
+ actor?: string | ((ctx: { id: string; change?: { type: 'insert'|'update'|'delete'; value: T } }) => string | undefined);
67
+ localActorId?: string; // deprecated
68
+ };
45
69
  };
70
+ ```
46
71
 
47
- export const products = createCollection(
48
- surrealCollectionOptions<Product>({
49
- db,
50
- queryKey: ['products'],
51
- queryClient,
52
- useLoro: true, // Optional if you need CRDTs
53
- table: { name: 'products' },
54
- }),
55
- )
56
-
57
- const data = useLiveQuery((q) =>
58
- q
59
- .from({ products })
60
- .where(({ products }) => eq(products.store, '123'))
61
- )
72
+ ## E2EE
73
+
74
+ Envelope fields stored in Surreal records:
75
+
76
+ ```ts
77
+ type EncryptedEnvelope = {
78
+ version: number;
79
+ algorithm: string;
80
+ key_id: string;
81
+ nonce: string;
82
+ ciphertext: string;
83
+ };
62
84
  ```
63
85
 
64
- For syncModes, please see [Example](https://github.com/ForetagInc/tanstack-db-surrealdb/blob/master/examples/syncMode.ts)
86
+ Default AAD:
65
87
 
66
- ## Vite / Next.JS
88
+ - Base records: `<table>:<record_id>`
89
+ - CRDT updates/snapshots: `<updates_or_snapshots_table>:<base_table>:<doc_id>`
67
90
 
68
- ### Vite
69
- ```sh
70
- bun install vite-plugin-wasm vite-plugin-top-level-await -D
91
+ Included provider:
92
+
93
+ - `WebCryptoAESGCM` (`AES-256-GCM`, versioned envelope)
94
+
95
+ ## CRDT Profiles
96
+
97
+ CRDT is managed by profile by default:
98
+
99
+ - `profile: 'json'` uses built-in JSON handlers
100
+ - `profile: 'richtext'` uses built-in richtext handlers
101
+
102
+ Advanced overrides are still available:
103
+
104
+ - `createLoroProfile('json' | 'richtext')`
105
+ - `materialize` and `applyLocalChange` in `crdt` options
106
+
107
+ For CRDT loop-prevention metadata, prefer `crdt.actor` so actor identity can be resolved per doc/write. `localActorId` remains only for backwards compatibility.
108
+
109
+ ## CRDT Table Requirements
110
+
111
+ For `crdt.enabled: true`, users must provide:
112
+
113
+ - Base table (`table`) for record identity and optional materialized metadata.
114
+ - Updates table (`crdt.updatesTable`) as append-only CRDT log.
115
+
116
+ Optional:
117
+
118
+ - Snapshots table (`crdt.snapshotsTable`) for compaction and faster hydration.
119
+
120
+ If `crdt.updatesTable` is missing, CRDT mode cannot function.
121
+
122
+ ## SQL Templates
123
+
124
+ ### Plain
125
+
126
+ ```sql
127
+ DEFINE TABLE note SCHEMAFULL;
128
+ DEFINE FIELD title ON note TYPE string;
129
+ DEFINE FIELD body ON note TYPE string;
130
+ DEFINE FIELD updated_at ON note TYPE datetime VALUE time::now();
131
+ DEFINE INDEX note_updated ON note FIELDS updated_at;
132
+ ```
133
+
134
+ ### E2EE-only
135
+
136
+ ```sql
137
+ DEFINE TABLE secret_note SCHEMAFULL;
138
+ DEFINE FIELD owner ON secret_note TYPE record<account>;
139
+ DEFINE FIELD updated_at ON secret_note TYPE datetime;
140
+ DEFINE FIELD version ON secret_note TYPE int;
141
+ DEFINE FIELD algorithm ON secret_note TYPE string;
142
+ DEFINE FIELD key_id ON secret_note TYPE string;
143
+ DEFINE FIELD nonce ON secret_note TYPE string;
144
+ DEFINE FIELD ciphertext ON secret_note TYPE string;
145
+ DEFINE INDEX secret_note_owner_updated ON secret_note FIELDS owner, updated_at;
146
+ ```
147
+
148
+ ### CRDT-only
149
+
150
+ ```sql
151
+ DEFINE TABLE doc SCHEMAFULL;
152
+ DEFINE FIELD owner ON doc TYPE record<account>;
153
+ DEFINE FIELD updated_at ON doc TYPE datetime;
154
+ DEFINE INDEX doc_owner_updated ON doc FIELDS owner, updated_at;
155
+
156
+ -- Necessary for CRDT updates
157
+ DEFINE TABLE crdt_update SCHEMAFULL;
158
+ DEFINE FIELD doc ON crdt_update TYPE record<doc>;
159
+ DEFINE FIELD ts ON crdt_update TYPE datetime;
160
+ DEFINE FIELD update_bytes ON crdt_update TYPE string;
161
+ DEFINE FIELD actor ON crdt_update TYPE string;
162
+ DEFINE INDEX crdt_doc_ts ON crdt_update FIELDS doc, ts;
163
+
164
+ DEFINE TABLE crdt_snapshot SCHEMAFULL;
165
+ DEFINE FIELD doc ON crdt_snapshot TYPE record<doc>;
166
+ DEFINE FIELD ts ON crdt_snapshot TYPE datetime;
167
+ DEFINE FIELD snapshot_bytes ON crdt_snapshot TYPE string;
168
+ DEFINE INDEX snap_doc_ts ON crdt_snapshot FIELDS doc, ts;
71
169
  ```
72
170
 
73
- `vite.config.ts`
171
+ ### CRDT + E2EE
172
+
173
+ ```sql
174
+ DEFINE TABLE secure_doc SCHEMAFULL;
175
+ DEFINE FIELD owner ON secure_doc TYPE record<account>;
176
+ DEFINE FIELD updated_at ON secure_doc TYPE datetime;
177
+ DEFINE INDEX secure_doc_owner_updated ON secure_doc FIELDS owner, updated_at;
178
+
179
+ DEFINE TABLE crdt_update SCHEMAFULL;
180
+ DEFINE FIELD doc ON crdt_update TYPE record<secure_doc>;
181
+ DEFINE FIELD ts ON crdt_update TYPE datetime;
182
+ DEFINE FIELD actor ON crdt_update TYPE string;
183
+ DEFINE FIELD version ON crdt_update TYPE int;
184
+ DEFINE FIELD algorithm ON crdt_update TYPE string;
185
+ DEFINE FIELD key_id ON crdt_update TYPE string;
186
+ DEFINE FIELD nonce ON crdt_update TYPE string;
187
+ DEFINE FIELD ciphertext ON crdt_update TYPE string;
188
+ DEFINE INDEX crdt_doc_ts ON crdt_update FIELDS doc, ts;
189
+ ```
190
+
191
+ If a single `crdt_update` table is shared across multiple base tables, use a union type such as `record<doc> | record<sheet>`.
192
+
193
+ ## Permissions Templates
194
+
195
+ The adapter does not manage Surreal table permissions. Define them in schema.
196
+
197
+ ### E2EE-only table permissions
198
+
199
+ ```sql
200
+ DEFINE TABLE secret_note SCHEMAFULL
201
+ PERMISSIONS
202
+ FOR select, create, update, delete WHERE owner = $auth.id;
203
+ ```
204
+
205
+ ### CRDT updates table permissions (append-only)
206
+
207
+ ```sql
208
+ DEFINE TABLE crdt_update SCHEMAFULL
209
+ PERMISSIONS
210
+ FOR select, create WHERE owner = $auth.id
211
+ FOR update, delete NONE;
212
+
213
+ -- Add owner metadata on update rows for simple ACL checks
214
+ DEFINE FIELD owner ON crdt_update TYPE record<account>;
215
+ DEFINE INDEX crdt_owner_doc_ts ON crdt_update FIELDS owner, doc, ts;
216
+ ```
217
+
218
+ ### CRDT snapshots table permissions
219
+
220
+ ```sql
221
+ DEFINE TABLE crdt_snapshot SCHEMAFULL
222
+ PERMISSIONS
223
+ FOR select WHERE owner = $auth.id
224
+ FOR create, update, delete NONE;
225
+
226
+ -- Common pattern: clients read snapshots; only trusted backend writes/prunes them
227
+ DEFINE FIELD owner ON crdt_snapshot TYPE record<account>;
228
+ DEFINE INDEX snap_owner_doc_ts ON crdt_snapshot FIELDS owner, doc, ts;
229
+ ```
230
+
231
+ If you run snapshot compaction from a trusted backend/service account, grant create/delete to that account only.
232
+
233
+ ## Usage Snippets
234
+
235
+ ### E2EE-only secret table
74
236
 
75
237
  ```ts
76
- // Plugins
77
- import wasm from 'vite-plugin-wasm';
78
- import topLevelAwait from 'vite-plugin-top-level-await';
238
+ const provider = await WebCryptoAESGCM.fromRawKey(rawKey, { kid: 'org-key-2026-01' });
79
239
 
80
- export default defineConfig({
81
- plugins: [...otherConfigures, wasm(), topLevelAwait()],
82
- });
240
+ const secrets = createCollection(
241
+ surrealCollectionOptions<{ id: string; title: string; body: string }>({
242
+ db,
243
+ table: { name: 'secret_note' },
244
+ queryClient,
245
+ queryKey: ['secret-note'],
246
+ syncMode: 'eager',
247
+ e2ee: { enabled: true, crypto: provider },
248
+ }),
249
+ );
83
250
  ```
84
251
 
85
- ### NextJS
86
- `next.config.js`
252
+ ### CRDT richtext docs
87
253
 
88
254
  ```ts
89
- module.exports = {
90
- webpack: function (config) {
91
- config.experiments = {
92
- layers: true,
93
- asyncWebAssembly: true,
94
- };
95
- return config;
96
- },
255
+ const docs = createCollection(
256
+ surrealCollectionOptions<{ id: string; content: string; title?: string }>({
257
+ db,
258
+ table: { name: 'doc' },
259
+ queryClient,
260
+ queryKey: ['doc'],
261
+ syncMode: 'on-demand',
262
+ crdt: {
263
+ enabled: true,
264
+ profile: 'richtext',
265
+ updatesTable: { name: 'crdt_update' },
266
+ snapshotsTable: { name: 'crdt_snapshot' },
267
+ actor: ({ id }) => id.startsWith('team-a') ? 'device:team-a:abc' : 'device:team-b:abc',
268
+ },
269
+ }),
270
+ );
271
+ ```
272
+
273
+ ### RecordId model example
274
+
275
+ ```ts
276
+ import { RecordId } from 'surrealdb';
277
+
278
+ type CalendarEvent = {
279
+ id: RecordId<'calendar_event'>;
280
+ owner: RecordId<'account'>;
281
+ title: string;
282
+ start_at: string;
97
283
  };
284
+
285
+ await calendarEvents.insert({
286
+ id: new RecordId('calendar_event', 'evt-001'),
287
+ owner: new RecordId('account', 'user-123'),
288
+ title: 'Planning',
289
+ start_at: '2026-02-23T10:00:00.000Z',
290
+ });
98
291
  ```
99
292
 
100
- ## CRDTs
293
+ Full runnable example: `examples/record-id.ts`.
101
294
 
102
- If you need to use CRDTs for your application consider adding the following fields to the specific tables and set `useLoro: true` for the respective table. Please note these fields are opinionated, therefore fixed and required:
295
+ ### On-demand drive listing (query-driven)
103
296
 
104
- ```sql
105
- DEFINE FIELD OVERWRITE sync_deleted ON <table>
106
- TYPE bool
107
- DEFAULT false
108
- COMMENT 'Tombstone for CRDTs';
109
-
110
- DEFINE FIELD OVERWRITE updated_at ON <table>
111
- TYPE datetime
112
- VALUE time::now();
297
+ ```ts
298
+ import { createLiveQueryCollection, eq } from '@tanstack/db';
299
+
300
+ const files = createCollection(
301
+ surrealCollectionOptions<{ id: string; owner: string; updated_at: string; name: string }>({
302
+ db,
303
+ table: { name: 'file' },
304
+ queryClient,
305
+ queryKey: ['file'],
306
+ syncMode: 'on-demand',
307
+ }),
308
+ );
309
+
310
+ const ownerFiles = createLiveQueryCollection((q) =>
311
+ q
312
+ .from({ files })
313
+ .where(({ files }) => eq(files.owner, 'account:abc'))
314
+ .select(({ files }) => files),
315
+ );
316
+
317
+ await ownerFiles.preload();
113
318
  ```
114
319
 
115
- > While using SurrealDB as a Web Database, please remember to allow `SELECT` & `UPDATE` permissions for the `sync_deleted` and `updated_at` fields for the respective access.
320
+ ## Key Wrapping / Multi-Principal Access
321
+
322
+ This adapter expects key management to be provided by your app or KMS. For production shared access (users, teams, orgs), keep using wrapped keys:
323
+
324
+ - Encrypt entity data with a data key.
325
+ - Wrap that data key for each authorized principal (user/team/service/device).
326
+ - Resolve the active key by `kid` at decrypt time.
327
+ - Rotate by issuing a new `kid` and re-wrapping/re-encrypting progressively.
328
+
329
+ The adapter consumes derived keys through `CryptoProvider`; it does not manage wrapping policy for you.
330
+
331
+ ## Testing
332
+
333
+ Unit tests (`bun test`) cover:
334
+
335
+ - id/query translation behavior
336
+ - modern eager + on-demand sync controls
337
+ - E2EE envelope/AAD behavior
338
+ - CRDT update append, snapshot hydration, and actor loop prevention
116
339
 
117
- ## FAQ
340
+ Real SurrealDB integration tests are available and run against a live instance:
118
341
 
119
- <details>
120
- <summary><strong>When do I need CRDTs?</strong></summary>
121
- <p>In most cases Tanstack DB is sufficient to handle CRUD operations. However, if you need to implement a distributed system that is offline first, CRDTs are the way to go. Think: Google Docs, Figma Pages, Notion Blocks etc. We recommend you check out <a href='https://www.loro.dev/' target='_blank'>Loro</a> for a deeper understanding.</p>
122
- </details>
342
+ 1. Copy `.env.example` to `.env` and fill connection/auth values.
343
+ 2. Run `bun run test:integration`.
123
344
 
124
- <details>
125
- <summary><strong>How do I achieve type safety?</strong></summary>
126
- <p>Using Codegen tools that generate types from your SurrealDB Schema, this means you don't have to manually maintain types for each Collection.</p>
127
- </details>
345
+ Required env:
128
346
 
129
- <details>
130
- <summary><strong>Can I use GraphQL alongside this Library?</strong></summary>
131
- <p>GraphQL workflow is in the works as SurrealDB's own implementation of the GraphQL protocol matures, we'll be able to provide a seamless integration. Since this library only targets TanstackDB, you can also use GraphQL for direct querying through Tanstack Query.</p>
132
- </details>
347
+ - `SURREAL_URL`
348
+ - `SURREAL_NAMESPACE`
349
+ - `SURREAL_DATABASE`
350
+ - `SURREAL_USERNAME`
351
+ - `SURREAL_PASSWORD`
133
352
 
134
- <details>
135
- <summary><strong>Can I reduce the package sizes?</strong></summary>
136
- <p>They can be reduced, but these steps are very unique based on use-case. Loro ships a WASM binary thats 1 MB Gzipped in size, it's one of the tradeoffs of using this approach. The maintainers up-stream are working on reducing the size of the WASM binary.</p>
137
- </details>
353
+ `SURREAL_REQUIRE_LIVE=true` (default) enforces LIVE query assertions; set it to `false` if you intentionally use a connection without LIVE support.
package/dist/index.d.mts CHANGED
@@ -1,12 +1,67 @@
1
1
  import { StandardSchemaV1 } from '@standard-schema/spec';
2
- import { IR, UtilsRecord, OperationConfig, Transaction, CollectionConfig } from '@tanstack/db';
3
- import { Container } from 'loro-crdt';
4
- import { RecordId, Surreal } from 'surrealdb';
2
+ import { CollectionConfig, UtilsRecord, LoadSubsetOptions, OperationConfig, Transaction } from '@tanstack/db';
3
+ import { Table, Surreal, RecordId } from 'surrealdb';
5
4
  import { QueryClient } from '@tanstack/query-core';
5
+ import { LoroDoc } from 'loro-crdt';
6
6
 
7
- type RecordIdLike = RecordId | string;
8
- declare const eqRecordId: (field: unknown, value: RecordIdLike) => IR.BasicExpression<boolean>;
7
+ type EncryptInput = {
8
+ plaintext: Bytes;
9
+ aad?: Bytes;
10
+ v?: number;
11
+ alg?: string;
12
+ kid?: string;
13
+ };
14
+ type DecryptInput = {
15
+ envelope: EncryptedEnvelope;
16
+ aad?: Bytes;
17
+ };
18
+ interface CryptoProvider {
19
+ encrypt(input: EncryptInput): Promise<EncryptedEnvelope>;
20
+ decrypt(input: DecryptInput): Promise<Bytes>;
21
+ }
22
+
23
+ /**
24
+ * @deprecated Use SurrealE2EEOptions from ../types.
25
+ */
26
+ interface E2EEConfig<TItem extends object> {
27
+ enabled: boolean;
28
+ serialize?: (item: TItem) => Bytes;
29
+ deserialize?: (bytes: Bytes) => TItem;
30
+ crypto: CryptoProvider;
31
+ fields?: {
32
+ ciphertext: string;
33
+ nonce: string;
34
+ version: string;
35
+ };
36
+ aad?: (ctx: {
37
+ table: string;
38
+ id: string;
39
+ }) => Bytes;
40
+ }
41
+ type EncryptionEnvelope = EncryptedEnvelope;
42
+ type EncryptionAADContext = AADContext;
43
+ type AdapterE2EEOptions = SurrealE2EEOptions;
44
+
45
+ type KeyResolver = (kid: string) => Promise<CryptoKey> | CryptoKey;
46
+ type WebCryptoAESGCMOptions = {
47
+ alg?: string;
48
+ version?: number;
49
+ kid?: string;
50
+ resolveKey?: KeyResolver;
51
+ };
52
+ declare class WebCryptoAESGCM implements CryptoProvider {
53
+ private readonly alg;
54
+ private readonly version;
55
+ private readonly kid;
56
+ private readonly resolveKey;
57
+ constructor(key: CryptoKey, options?: WebCryptoAESGCMOptions);
58
+ static fromRawKey(rawKey: Bytes, options?: Omit<WebCryptoAESGCMOptions, 'resolveKey'>): Promise<WebCryptoAESGCM>;
59
+ private keyFor;
60
+ encrypt(input: EncryptInput): Promise<EncryptedEnvelope>;
61
+ decrypt({ envelope, aad }: DecryptInput): Promise<Bytes>;
62
+ }
9
63
 
64
+ type Bytes = Uint8Array;
10
65
  type WithId<T> = T & {
11
66
  id: string | RecordId;
12
67
  };
@@ -18,17 +73,80 @@ type TableOptions = {
18
73
  name: string;
19
74
  relation?: boolean;
20
75
  };
21
- type SyncMode = 'eager' | 'on-demand';
22
- type SurrealCollectionConfig = {
23
- id?: string;
76
+ type TableLike = Table | TableOptions | string;
77
+ type SurrealSubset = LoadSubsetOptions;
78
+ type EncryptedEnvelope = {
79
+ v: number;
80
+ alg: string;
81
+ kid: string;
82
+ n: string;
83
+ ct: string;
84
+ };
85
+ type EnvelopeKind = 'base' | 'update' | 'snapshot';
86
+ type AADContext = {
87
+ table: string;
88
+ id: string;
89
+ kind: EnvelopeKind;
90
+ baseTable?: string;
91
+ };
92
+ type SurrealE2EEOptions = {
93
+ enabled: boolean;
94
+ crypto: CryptoProvider;
95
+ aad?: (ctx: AADContext) => Bytes;
96
+ };
97
+ type LocalChange<T> = {
98
+ type: 'insert' | 'update' | 'delete';
99
+ value: T;
100
+ };
101
+ type CRDTActorContext<T> = {
102
+ id: string;
103
+ change?: LocalChange<T>;
104
+ };
105
+ type SurrealCRDTOptions<T extends object> = {
106
+ enabled: boolean;
107
+ profile: 'json' | 'richtext';
108
+ updatesTable: TableLike;
109
+ snapshotsTable?: TableLike;
110
+ materialize?: (doc: LoroDoc, id: string) => T;
111
+ applyLocalChange?: (doc: LoroDoc, change: LocalChange<T>) => void;
112
+ persistMaterializedView?: boolean;
113
+ actor?: string | ((ctx: CRDTActorContext<T>) => string | undefined);
114
+ /** @deprecated Use `actor` instead. */
115
+ localActorId?: string;
116
+ };
117
+ type AdapterSyncMode = 'eager' | 'on-demand' | 'progressive';
118
+ type SurrealCollectionOptions<T extends object> = Omit<CollectionConfig<T>, 'onInsert' | 'onUpdate' | 'onDelete' | 'sync' | 'getKey' | 'syncMode'> & {
24
119
  db: Surreal;
25
- table: TableOptions;
26
- syncMode?: SyncMode;
120
+ table: TableLike;
27
121
  queryKey: readonly unknown[];
28
122
  queryClient: QueryClient;
29
- useLoro?: boolean;
30
- onError?: (e: unknown) => void;
123
+ syncMode?: AdapterSyncMode;
124
+ e2ee?: SurrealE2EEOptions;
125
+ crdt?: SurrealCRDTOptions<T>;
126
+ onError?: (error: unknown) => void;
31
127
  };
128
+ type SurrealCollectionOptionsReturn<T extends {
129
+ id: string | RecordId;
130
+ }> = CollectionConfig<T, string, StandardSchemaV1<Omit<T, 'id'> & {
131
+ id?: T['id'];
132
+ }, T>, UtilsRecord> & {
133
+ schema: StandardSchemaV1<Omit<T, 'id'> & {
134
+ id?: T['id'];
135
+ }, T>;
136
+ utils: UtilsRecord;
137
+ };
138
+
139
+ interface CRDTProfileAdapter<T extends object> {
140
+ materialize: (doc: LoroDoc, id: string) => T;
141
+ applyLocalChange: (doc: LoroDoc, change: LocalChange<T>) => void;
142
+ }
143
+
144
+ type LoroProfile = 'json' | 'richtext';
145
+ declare const materializeLoroJson: <T extends object>(doc: LoroDoc, id: string) => T;
146
+ declare const applyLoroJsonChange: <T extends object>(doc: LoroDoc, change: LocalChange<T>) => void;
147
+ declare const materializeLoroRichtext: <T extends object>(doc: LoroDoc, id: string) => T;
148
+ declare const applyLoroRichtextChange: <T extends object>(doc: LoroDoc, change: LocalChange<T>) => void;
149
+ declare const createLoroProfile: <T extends object = Record<string, unknown>>(profile: LoroProfile) => CRDTProfileAdapter<T>;
32
150
 
33
151
  declare const toRecordKeyString: (rid: RecordId | string) => string;
34
152
 
@@ -37,17 +155,14 @@ type MutationInput<T extends {
37
155
  }> = Omit<T, 'id'> & {
38
156
  id?: T['id'];
39
157
  };
40
-
158
+ declare function surrealCollectionOptions<T extends SyncedTable<object>>(config: SurrealCollectionOptions<T>): CollectionConfig<T, string, StandardSchemaV1<MutationInput<T>, T>, UtilsRecord> & {
159
+ schema: StandardSchemaV1<MutationInput<T>, T>;
160
+ utils: UtilsRecord;
161
+ };
41
162
  declare module '@tanstack/db' {
42
163
  interface Collection<T extends object = Record<string, unknown>, TKey extends string | number = string | number, TUtils extends UtilsRecord = UtilsRecord, TSchema extends StandardSchemaV1 = StandardSchemaV1, TInsertInput extends object = T> {
43
164
  delete(keys: Array<TKey | RecordId | string> | TKey | RecordId | string, config?: OperationConfig): Transaction<any>;
44
165
  }
45
166
  }
46
- declare function surrealCollectionOptions<T extends SyncedTable<object>, S extends Record<string, Container> = {
47
- [k: string]: never;
48
- }>({ id, useLoro, onError, db, queryClient, queryKey, syncMode, ...config }: SurrealCollectionConfig): CollectionConfig<T, string, StandardSchemaV1<MutationInput<T>, T>, UtilsRecord> & {
49
- schema: StandardSchemaV1<MutationInput<T>, T>;
50
- utils: UtilsRecord;
51
- };
52
167
 
53
- export { eqRecordId, surrealCollectionOptions, toRecordKeyString };
168
+ export { type AADContext, type AdapterE2EEOptions, type AdapterSyncMode, type Bytes, type CRDTActorContext, type CryptoProvider, type DecryptInput, type E2EEConfig, type EncryptInput, type EncryptedEnvelope, type EncryptionAADContext, type EncryptionEnvelope, type EnvelopeKind, type LocalChange, type LoroProfile, type SurrealCRDTOptions, type SurrealCollectionOptions, type SurrealCollectionOptionsReturn, type SurrealE2EEOptions, type SurrealSubset, type SyncedTable, type TableLike, type TableOptions, WebCryptoAESGCM, type WithId, applyLoroJsonChange, applyLoroRichtextChange, createLoroProfile, materializeLoroJson, materializeLoroRichtext, surrealCollectionOptions, toRecordKeyString };