@spooky-sync/client-solid 0.0.1-canary.8 → 0.0.1-canary.81
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/AGENTS.md +66 -0
- package/dist/index.cjs +177 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -21
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +57 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +176 -66
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
- package/skills/sp00ky-solid/SKILL.md +264 -0
- package/skills/sp00ky-solid/references/file-hooks.md +112 -0
- package/src/cache/index.ts +1 -1
- package/src/cache/surrealdb-wasm-factory.ts +4 -1
- package/src/index.ts +84 -55
- package/src/lib/{SpookyProvider.ts → Sp00kyProvider.ts} +9 -7
- package/src/lib/context.ts +3 -3
- package/src/lib/models.ts +1 -1
- package/src/lib/use-crdt-field.ts +68 -0
- package/src/lib/use-download-file.ts +2 -2
- package/src/lib/use-feature-flag.ts +50 -0
- package/src/lib/use-file-upload.ts +2 -1
- package/src/lib/use-query.ts +130 -28
- package/src/types/index.ts +3 -4
package/AGENTS.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# `@spooky-sync/client-solid` — agent guide
|
|
2
|
+
|
|
3
|
+
## What this package is
|
|
4
|
+
|
|
5
|
+
The SolidJS binding for sp00ky. Exposes a `Sp00kyProvider` that initializes a `Sp00kyClient` and a set of reactive hooks (`useDb`, `useQuery`, `useCrdtField`, `useFileUpload`, `useDownloadFile`). All hooks expect to be called inside a `<Sp00kyProvider>` boundary.
|
|
6
|
+
|
|
7
|
+
## Setup pattern
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// db.ts
|
|
11
|
+
import type { SyncedDbConfig } from '@spooky-sync/client-solid';
|
|
12
|
+
import { schema, SURQL_SCHEMA } from './schema.gen'; // generated by `spky generate`
|
|
13
|
+
|
|
14
|
+
export const dbConfig: SyncedDbConfig<typeof schema> = {
|
|
15
|
+
schema,
|
|
16
|
+
schemaSurql: SURQL_SCHEMA,
|
|
17
|
+
database: {
|
|
18
|
+
namespace: 'main',
|
|
19
|
+
database: 'app',
|
|
20
|
+
endpoint: 'ws://localhost:8666/rpc',
|
|
21
|
+
store: 'memory', // or 'indexeddb' for persistence
|
|
22
|
+
persistenceClient: 'localstorage',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
// App.tsx
|
|
29
|
+
<Sp00kyProvider config={dbConfig}>{/* app */}</Sp00kyProvider>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Key hooks
|
|
33
|
+
|
|
34
|
+
- **`useDb<typeof schema>()`** — returns the `SyncedDb<S>` instance. Methods:
|
|
35
|
+
- `db.create(id, payload)` — `id` is a full record ID like `'thread:abc'`.
|
|
36
|
+
- `db.update(table, id, payload, options?)` — `options.debounced` coalesces updates.
|
|
37
|
+
- `db.delete(table, idOrSelector)`.
|
|
38
|
+
- `db.query(table)` — returns a `QueryBuilder`. Chain `.related()`, `.orderBy()`, `.limit()`, etc., end with `.build()`.
|
|
39
|
+
- `db.run(backend, route, payload)` — call a backend RPC route.
|
|
40
|
+
- `db.bucket(name)` — get a `BucketHandle` for file storage.
|
|
41
|
+
- `db.useRemote(fn)` — escape hatch to the raw `Surreal` client (skips cache).
|
|
42
|
+
- `db.authenticate(token)`, `db.signOut()`, `db.auth`.
|
|
43
|
+
- `db.pendingMutationCount`, `db.subscribeToPendingMutations(cb)`.
|
|
44
|
+
- **`useQuery(() => db.query(...).build())`** — reactive query. Returns `{ data, status, error, ... }` accessors. The factory function is tracked, so passing reactive params (signals) re-runs the query.
|
|
45
|
+
- **`useCrdtField(table, () => recordId, field, () => valueAccessor)`** — wires a CRDT text field to a Loro doc. Pair with `db.update(table, id, { [field]: newValue }, { debounced: true })` so rapid keystrokes don't flood the queue. *All four arguments take accessor functions where reactive — that's deliberate, for SolidJS tracking.*
|
|
46
|
+
- **`useFileUpload()`** / **`useDownloadFile()`** — bucket helpers; the upload result includes the storage path you write into a record column.
|
|
47
|
+
|
|
48
|
+
## Re-exports for convenience
|
|
49
|
+
|
|
50
|
+
- `RecordId`, `Uuid` from `surrealdb`.
|
|
51
|
+
- Query-builder types: `TableModel`, `TableNames`, `GetTable`, `QueryResult`, etc. (see `@spooky-sync/query-builder/AGENTS.md`).
|
|
52
|
+
- `Model<S, T>`, `GenericModel`, `ModelPayload` — typed row shapes.
|
|
53
|
+
|
|
54
|
+
## Common gotchas
|
|
55
|
+
|
|
56
|
+
- **`useDb()` requires `<typeof schema>`.** Without the generic, all calls fall back to `unknown` and you lose type safety.
|
|
57
|
+
- **CRDT fields are not regular columns.** Don't read or write them via `useQuery` — read with `useCrdtField`, write via `db.update` with `{ debounced: true }`.
|
|
58
|
+
- **Generate IDs explicitly.** `const id = new Uuid().toString()`, then `db.create(\`thread:\${id}\`, ...)`. SurrealDB's auto-id only fires on direct DB writes, not through the sync queue.
|
|
59
|
+
- **`useQuery` factories must call `.build()` (or `.all()`, `.first()`, etc.).** A bare `db.query('thread')` is a builder, not a query — `useQuery` will throw or return forever-loading.
|
|
60
|
+
- **Provider is mandatory.** Calling any hook outside `<Sp00kyProvider>` throws.
|
|
61
|
+
|
|
62
|
+
## Pointers
|
|
63
|
+
|
|
64
|
+
- Sync engine: `node_modules/@spooky-sync/core/AGENTS.md`
|
|
65
|
+
- Query builder DSL: `node_modules/@spooky-sync/query-builder/AGENTS.md`
|
|
66
|
+
- Schema authoring + codegen: `node_modules/@spooky-sync/cli/AGENTS.md`
|
package/dist/index.cjs
CHANGED
|
@@ -2,12 +2,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
let _spooky_sync_core = require("@spooky-sync/core");
|
|
3
3
|
let surrealdb = require("surrealdb");
|
|
4
4
|
let solid_js = require("solid-js");
|
|
5
|
+
let solid_js_store = require("solid-js/store");
|
|
5
6
|
|
|
6
7
|
//#region src/lib/context.ts
|
|
7
|
-
const
|
|
8
|
+
const Sp00kyContext = (0, solid_js.createContext)();
|
|
8
9
|
function useDb() {
|
|
9
|
-
const db = (0, solid_js.useContext)(
|
|
10
|
-
if (!db) throw new Error("useDb must be used within a <
|
|
10
|
+
const db = (0, solid_js.useContext)(Sp00kyContext);
|
|
11
|
+
if (!db) throw new Error("useDb must be used within a <Sp00kyProvider>. Wrap your app in <Sp00kyProvider config={...}>.");
|
|
11
12
|
return db;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -22,30 +23,56 @@ function useQuery(dbOrQuery, queryOrOptions, maybeOptions) {
|
|
|
22
23
|
finalQuery = queryOrOptions;
|
|
23
24
|
options = maybeOptions;
|
|
24
25
|
} else {
|
|
25
|
-
const contextDb = (0, solid_js.useContext)(
|
|
26
|
-
if (!contextDb) throw new Error("useQuery: No db argument provided and no
|
|
26
|
+
const contextDb = (0, solid_js.useContext)(Sp00kyContext);
|
|
27
|
+
if (!contextDb) throw new Error("useQuery: No db argument provided and no Sp00kyContext found. Either pass a SyncedDb instance or wrap your app in <Sp00kyProvider>.");
|
|
27
28
|
db = contextDb;
|
|
28
29
|
finalQuery = dbOrQuery;
|
|
29
30
|
options = queryOrOptions;
|
|
30
31
|
}
|
|
31
|
-
const [data, setData] = (0, solid_js.createSignal)(void 0);
|
|
32
32
|
const [error, setError] = (0, solid_js.createSignal)(void 0);
|
|
33
33
|
const [isFetched, setIsFetched] = (0, solid_js.createSignal)(false);
|
|
34
|
-
const [
|
|
34
|
+
const [isFetching, setIsFetching] = (0, solid_js.createSignal)(false);
|
|
35
|
+
const [state, setState] = (0, solid_js_store.createStore)({ value: void 0 });
|
|
36
|
+
const [version, setVersion] = (0, solid_js.createSignal)(0);
|
|
37
|
+
const data = () => {
|
|
38
|
+
version();
|
|
39
|
+
return state.value;
|
|
40
|
+
};
|
|
35
41
|
let prevQueryString;
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
let runId = 0;
|
|
43
|
+
let activeUnsub;
|
|
44
|
+
let activeHash;
|
|
45
|
+
const teardownActive = () => {
|
|
46
|
+
activeUnsub?.();
|
|
47
|
+
activeUnsub = void 0;
|
|
48
|
+
};
|
|
49
|
+
const sp00ky = db.getSp00ky();
|
|
50
|
+
const initQuery = async (query, myRun) => {
|
|
38
51
|
const { hash } = await query.run();
|
|
52
|
+
if (myRun !== runId) return;
|
|
53
|
+
activeHash = hash;
|
|
39
54
|
setError(void 0);
|
|
40
55
|
let isFirstCall = true;
|
|
41
|
-
const unsub = await
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
const unsub = await sp00ky.subscribe(hash, (e) => {
|
|
57
|
+
const queryData = query.isOne ? e[0] : e;
|
|
58
|
+
const reconcileStart = performance.now();
|
|
59
|
+
setState("value", (0, solid_js_store.reconcile)(queryData, { key: "id" }));
|
|
60
|
+
setVersion((v) => v + 1);
|
|
61
|
+
sp00ky.reportFrontendTiming(hash, performance.now() - reconcileStart);
|
|
62
|
+
const hasData = query.isOne ? queryData !== null && queryData !== void 0 : e.length > 0;
|
|
45
63
|
if (!isFirstCall || hasData) setIsFetched(true);
|
|
46
64
|
isFirstCall = false;
|
|
47
65
|
}, { immediate: true });
|
|
48
|
-
|
|
66
|
+
const unsubStatus = sp00ky.subscribeQueryStatus(hash, (status) => setIsFetching(status === "fetching"), { immediate: true });
|
|
67
|
+
const teardown = () => {
|
|
68
|
+
unsub();
|
|
69
|
+
unsubStatus();
|
|
70
|
+
};
|
|
71
|
+
if (myRun !== runId) {
|
|
72
|
+
teardown();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
activeUnsub = teardown;
|
|
49
76
|
};
|
|
50
77
|
(0, solid_js.createEffect)(() => {
|
|
51
78
|
if (!(options?.enabled?.() ?? true)) {
|
|
@@ -54,14 +81,18 @@ function useQuery(dbOrQuery, queryOrOptions, maybeOptions) {
|
|
|
54
81
|
}
|
|
55
82
|
const query = typeof finalQuery === "function" ? finalQuery() : finalQuery;
|
|
56
83
|
if (!query) return;
|
|
57
|
-
const queryString =
|
|
84
|
+
const queryString = String(query.hash);
|
|
58
85
|
if (queryString === prevQueryString) return;
|
|
59
86
|
prevQueryString = queryString;
|
|
87
|
+
const myRun = ++runId;
|
|
88
|
+
teardownActive();
|
|
60
89
|
setIsFetched(false);
|
|
61
|
-
initQuery(query);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
initQuery(query, myRun);
|
|
91
|
+
});
|
|
92
|
+
(0, solid_js.onCleanup)(() => {
|
|
93
|
+
runId++;
|
|
94
|
+
teardownActive();
|
|
95
|
+
if (options?.deregisterOnCleanup && activeHash) sp00ky.deregisterQuery(activeHash);
|
|
65
96
|
});
|
|
66
97
|
const isLoading = () => {
|
|
67
98
|
return !isFetched() && error() === void 0;
|
|
@@ -69,7 +100,78 @@ function useQuery(dbOrQuery, queryOrOptions, maybeOptions) {
|
|
|
69
100
|
return {
|
|
70
101
|
data,
|
|
71
102
|
error,
|
|
72
|
-
isLoading
|
|
103
|
+
isLoading,
|
|
104
|
+
isFetching
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/lib/use-crdt-field.ts
|
|
110
|
+
function useCrdtField(table, recordId, field, fallbackText) {
|
|
111
|
+
const db = (0, solid_js.useContext)(Sp00kyContext);
|
|
112
|
+
if (!db) throw new Error("useCrdtField must be used within a <Sp00kyProvider>");
|
|
113
|
+
const [crdtField, setCrdtField] = (0, solid_js.createSignal)(null);
|
|
114
|
+
let currentId;
|
|
115
|
+
let initialized = false;
|
|
116
|
+
(0, solid_js.createEffect)(() => {
|
|
117
|
+
const id = recordId();
|
|
118
|
+
if (initialized && id === currentId) return;
|
|
119
|
+
if (currentId && crdtField()) {
|
|
120
|
+
db.getSp00ky().closeCrdtField(table, currentId, field);
|
|
121
|
+
setCrdtField(null);
|
|
122
|
+
}
|
|
123
|
+
currentId = id;
|
|
124
|
+
initialized = true;
|
|
125
|
+
if (!id) return;
|
|
126
|
+
const sp00ky = db.getSp00ky();
|
|
127
|
+
const text = fallbackText?.();
|
|
128
|
+
sp00ky.openCrdtField(table, id, field, text).then((cf) => {
|
|
129
|
+
if (currentId === id) setCrdtField(cf);
|
|
130
|
+
}).catch((err) => {
|
|
131
|
+
console.error(`[useCrdtField] Failed to open CRDT field ${table}.${field} on ${id}:`, err);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
(0, solid_js.onCleanup)(() => {
|
|
135
|
+
if (currentId && crdtField()) {
|
|
136
|
+
db.getSp00ky().closeCrdtField(table, currentId, field);
|
|
137
|
+
setCrdtField(null);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
return crdtField;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/lib/use-feature-flag.ts
|
|
145
|
+
/**
|
|
146
|
+
* Subscribe to a feature flag for the currently authenticated user.
|
|
147
|
+
*
|
|
148
|
+
* Returns three Solid accessors that update reactively whenever the
|
|
149
|
+
* server-materialized assignment in `_00_user_feature` changes. Backed by
|
|
150
|
+
* the same SSP + sync pipeline that powers `useQuery`, so toggling a flag
|
|
151
|
+
* via `spky flag enable <key>` propagates to the UI without a refresh.
|
|
152
|
+
*
|
|
153
|
+
* `enabled()` is `true` when the resolved variant exists and is not 'off'.
|
|
154
|
+
* For multi-variant flags, prefer `variant()` directly.
|
|
155
|
+
*/
|
|
156
|
+
function useFeatureFlag(key, options) {
|
|
157
|
+
const handle = useDb().getSp00ky().feature(key, options);
|
|
158
|
+
const [variant, setVariant] = (0, solid_js.createSignal)(handle.variant());
|
|
159
|
+
const [payload, setPayload] = (0, solid_js.createSignal)(handle.payload());
|
|
160
|
+
const unsub = handle.subscribe((s) => {
|
|
161
|
+
setVariant(s.variant ?? options?.fallback);
|
|
162
|
+
setPayload(s.payload);
|
|
163
|
+
});
|
|
164
|
+
(0, solid_js.onCleanup)(() => {
|
|
165
|
+
unsub();
|
|
166
|
+
handle.close();
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
variant,
|
|
170
|
+
payload,
|
|
171
|
+
enabled: () => {
|
|
172
|
+
const v = variant();
|
|
173
|
+
return v !== void 0 && v !== "off";
|
|
174
|
+
}
|
|
73
175
|
};
|
|
74
176
|
}
|
|
75
177
|
|
|
@@ -95,7 +197,7 @@ function useFileUpload(dbOrBucketName, maybeBucketName) {
|
|
|
95
197
|
const validate = (file) => {
|
|
96
198
|
const config = db.getBucketConfig(bucketName);
|
|
97
199
|
if (!config) return;
|
|
98
|
-
if (config.maxSize
|
|
200
|
+
if (config.maxSize !== null && config.maxSize !== void 0 && file.size > config.maxSize) {
|
|
99
201
|
const maxMB = (config.maxSize / (1024 * 1024)).toFixed(1);
|
|
100
202
|
throw new Error(`File exceeds maximum size of ${maxMB} MB.`);
|
|
101
203
|
}
|
|
@@ -204,9 +306,8 @@ function useDownloadFile(dbOrBucketName, bucketNameOrPath, pathOrOptions, maybeO
|
|
|
204
306
|
const [error, setError] = (0, solid_js.createSignal)(null);
|
|
205
307
|
let currentKey = null;
|
|
206
308
|
let privateUrl = null;
|
|
207
|
-
let refetchTrigger;
|
|
208
309
|
const [refetchSignal, setRefetchSignal] = (0, solid_js.createSignal)(0);
|
|
209
|
-
refetchTrigger = () => setRefetchSignal((n) => n + 1);
|
|
310
|
+
const refetchTrigger = () => setRefetchSignal((n) => n + 1);
|
|
210
311
|
async function doDownload(key, filePath) {
|
|
211
312
|
if (useCache) {
|
|
212
313
|
const cached = downloadCache.get(key);
|
|
@@ -326,8 +427,8 @@ function useDownloadFile(dbOrBucketName, bucketNameOrPath, pathOrOptions, maybeO
|
|
|
326
427
|
}
|
|
327
428
|
|
|
328
429
|
//#endregion
|
|
329
|
-
//#region src/lib/
|
|
330
|
-
function
|
|
430
|
+
//#region src/lib/Sp00kyProvider.ts
|
|
431
|
+
function Sp00kyProvider(props) {
|
|
331
432
|
const merged = (0, solid_js.mergeProps)({ fallback: void 0 }, props);
|
|
332
433
|
const [db, setDb] = (0, solid_js.createSignal)(void 0);
|
|
333
434
|
(0, solid_js.onMount)(async () => {
|
|
@@ -339,13 +440,13 @@ function SpookyProvider(props) {
|
|
|
339
440
|
} catch (e) {
|
|
340
441
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
341
442
|
if (merged.onError) merged.onError(error);
|
|
342
|
-
else console.error("
|
|
443
|
+
else console.error("Sp00kyProvider: Failed to initialize database", error);
|
|
343
444
|
}
|
|
344
445
|
});
|
|
345
446
|
return (0, solid_js.createMemo)(() => {
|
|
346
447
|
const instance = db();
|
|
347
448
|
if (!instance) return merged.fallback;
|
|
348
|
-
return (0, solid_js.createComponent)(
|
|
449
|
+
return (0, solid_js.createComponent)(Sp00kyContext.Provider, {
|
|
349
450
|
value: instance,
|
|
350
451
|
get children() {
|
|
351
452
|
return merged.children;
|
|
@@ -357,69 +458,73 @@ function SpookyProvider(props) {
|
|
|
357
458
|
//#endregion
|
|
358
459
|
//#region src/index.ts
|
|
359
460
|
/**
|
|
360
|
-
* SyncedDb - A thin wrapper around
|
|
361
|
-
* Delegates all logic to the underlying
|
|
461
|
+
* SyncedDb - A thin wrapper around sp00ky-ts for Solid.js integration
|
|
462
|
+
* Delegates all logic to the underlying sp00ky-ts instance
|
|
362
463
|
*/
|
|
363
464
|
var SyncedDb = class {
|
|
364
465
|
constructor(config) {
|
|
365
|
-
this.
|
|
466
|
+
this.sp00ky = null;
|
|
366
467
|
this._initialized = false;
|
|
367
468
|
this.config = config;
|
|
368
469
|
}
|
|
369
|
-
|
|
370
|
-
if (!this.
|
|
371
|
-
return this.
|
|
470
|
+
getSp00ky() {
|
|
471
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
472
|
+
return this.sp00ky;
|
|
372
473
|
}
|
|
373
474
|
/**
|
|
374
|
-
* Initialize the
|
|
475
|
+
* Initialize the sp00ky-ts instance
|
|
375
476
|
*/
|
|
376
477
|
async init() {
|
|
377
478
|
if (this._initialized) return;
|
|
378
|
-
this.
|
|
379
|
-
await this.
|
|
479
|
+
this.sp00ky = new _spooky_sync_core.Sp00kyClient(this.config);
|
|
480
|
+
await this.sp00ky.init();
|
|
380
481
|
this._initialized = true;
|
|
381
482
|
}
|
|
382
483
|
/**
|
|
383
484
|
* Create a new record in the database
|
|
384
485
|
*/
|
|
385
486
|
async create(id, payload) {
|
|
386
|
-
if (!this.
|
|
387
|
-
await this.
|
|
487
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
488
|
+
await this.sp00ky.create(id, payload);
|
|
388
489
|
}
|
|
389
490
|
/**
|
|
390
491
|
* Update an existing record in the database
|
|
391
492
|
*/
|
|
392
493
|
async update(tableName, recordId, payload, options) {
|
|
393
|
-
if (!this.
|
|
394
|
-
await this.
|
|
494
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
495
|
+
await this.sp00ky.update(tableName, recordId, payload, options);
|
|
395
496
|
}
|
|
396
497
|
/**
|
|
397
498
|
* Delete an existing record in the database
|
|
398
499
|
*/
|
|
399
500
|
async delete(tableName, selector) {
|
|
400
|
-
if (!this.
|
|
401
|
-
|
|
402
|
-
|
|
501
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
502
|
+
const isRecordId = selector instanceof surrealdb.RecordId || selector?.constructor?.name === "RecordId";
|
|
503
|
+
let id;
|
|
504
|
+
if (typeof selector === "string") id = selector;
|
|
505
|
+
else if (isRecordId) id = `${tableName}:${selector.id}`;
|
|
506
|
+
else throw new Error("Only string ID or RecordId selectors are supported currently with core");
|
|
507
|
+
await this.sp00ky.delete(tableName, id);
|
|
403
508
|
}
|
|
404
509
|
/**
|
|
405
510
|
* Query data from the database
|
|
406
511
|
*/
|
|
407
512
|
query(table) {
|
|
408
|
-
if (!this.
|
|
409
|
-
return this.
|
|
513
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
514
|
+
return this.sp00ky.query(table, {});
|
|
410
515
|
}
|
|
411
516
|
/**
|
|
412
517
|
* Run a backend operation
|
|
413
518
|
*/
|
|
414
519
|
async run(backend, path, payload, options) {
|
|
415
|
-
if (!this.
|
|
416
|
-
await this.
|
|
520
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
521
|
+
await this.sp00ky.run(backend, path, payload, options);
|
|
417
522
|
}
|
|
418
523
|
/**
|
|
419
524
|
* Authenticate with the database
|
|
420
525
|
*/
|
|
421
526
|
async authenticate(token) {
|
|
422
|
-
await this.
|
|
527
|
+
await this.sp00ky?.authenticate(token);
|
|
423
528
|
return new surrealdb.RecordId("user", "me");
|
|
424
529
|
}
|
|
425
530
|
/**
|
|
@@ -433,48 +538,53 @@ var SyncedDb = class {
|
|
|
433
538
|
* Sign out, clear session and local storage
|
|
434
539
|
*/
|
|
435
540
|
async signOut() {
|
|
436
|
-
if (!this.
|
|
437
|
-
await this.
|
|
541
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
542
|
+
await this.sp00ky.auth.signOut();
|
|
438
543
|
}
|
|
439
544
|
/**
|
|
440
545
|
* Execute a function with direct access to the remote database connection
|
|
441
546
|
*/
|
|
442
547
|
async useRemote(fn) {
|
|
443
|
-
if (!this.
|
|
444
|
-
return await this.
|
|
548
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
549
|
+
return await this.sp00ky.useRemote(fn);
|
|
445
550
|
}
|
|
446
551
|
/**
|
|
447
552
|
* Access the remote database service directly
|
|
448
553
|
*/
|
|
449
554
|
get remote() {
|
|
450
|
-
if (!this.
|
|
451
|
-
return this.
|
|
555
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
556
|
+
return this.sp00ky.remoteClient;
|
|
452
557
|
}
|
|
453
558
|
/**
|
|
454
559
|
* Access the local database service directly
|
|
455
560
|
*/
|
|
456
561
|
get local() {
|
|
457
|
-
if (!this.
|
|
458
|
-
return this.
|
|
562
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
563
|
+
return this.sp00ky.localClient;
|
|
459
564
|
}
|
|
460
565
|
/**
|
|
461
566
|
* Access the auth service
|
|
462
567
|
*/
|
|
463
568
|
get auth() {
|
|
464
|
-
if (!this.
|
|
465
|
-
return this.
|
|
569
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
570
|
+
return this.sp00ky.auth;
|
|
466
571
|
}
|
|
467
572
|
get pendingMutationCount() {
|
|
468
|
-
if (!this.
|
|
469
|
-
return this.
|
|
573
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
574
|
+
return this.sp00ky.pendingMutationCount;
|
|
575
|
+
}
|
|
576
|
+
/** Diagnostic — see `Sp00kyClient.liveRetryCount`. */
|
|
577
|
+
get liveRetryCount() {
|
|
578
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
579
|
+
return this.sp00ky.liveRetryCount;
|
|
470
580
|
}
|
|
471
581
|
subscribeToPendingMutations(cb) {
|
|
472
|
-
if (!this.
|
|
473
|
-
return this.
|
|
582
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
583
|
+
return this.sp00ky.subscribeToPendingMutations(cb);
|
|
474
584
|
}
|
|
475
585
|
bucket(name) {
|
|
476
|
-
if (!this.
|
|
477
|
-
return this.
|
|
586
|
+
if (!this.sp00ky) throw new Error("SyncedDb not initialized");
|
|
587
|
+
return this.sp00ky.bucket(name);
|
|
478
588
|
}
|
|
479
589
|
getBucketConfig(name) {
|
|
480
590
|
return this.config.schema.buckets?.find((b) => b.name === name);
|
|
@@ -483,11 +593,13 @@ var SyncedDb = class {
|
|
|
483
593
|
|
|
484
594
|
//#endregion
|
|
485
595
|
exports.RecordId = surrealdb.RecordId;
|
|
486
|
-
exports.
|
|
596
|
+
exports.Sp00kyProvider = Sp00kyProvider;
|
|
487
597
|
exports.SyncedDb = SyncedDb;
|
|
488
598
|
exports.Uuid = surrealdb.Uuid;
|
|
599
|
+
exports.useCrdtField = useCrdtField;
|
|
489
600
|
exports.useDb = useDb;
|
|
490
601
|
exports.useDownloadFile = useDownloadFile;
|
|
602
|
+
exports.useFeatureFlag = useFeatureFlag;
|
|
491
603
|
exports.useFileUpload = useFileUpload;
|
|
492
604
|
exports.useQuery = useQuery;
|
|
493
605
|
//# sourceMappingURL=index.cjs.map
|