@spooky-sync/core 0.0.1-canary.81 → 0.0.1-canary.83
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.d.ts +7 -0
- package/dist/index.js +39 -5
- package/dist/types.d.ts +10 -0
- package/package.json +3 -3
- package/src/modules/ref-tables.test.ts +11 -1
- package/src/modules/ref-tables.ts +12 -0
- package/src/modules/sync/sync.ts +53 -4
- package/src/sp00ky.ts +4 -1
- package/src/types.ts +10 -0
package/dist/index.d.ts
CHANGED
|
@@ -580,6 +580,12 @@ interface Sp00kySyncOptions {
|
|
|
580
580
|
* {@link resolveListRefPollInterval}.
|
|
581
581
|
*/
|
|
582
582
|
refSyncIntervalMs?: number;
|
|
583
|
+
/**
|
|
584
|
+
* Enable realtime sync for unauthenticated clients against the shared
|
|
585
|
+
* `_00_list_ref_anon` table. See {@link Sp00kyConfig.enableAnonymousLiveQueries}.
|
|
586
|
+
* Defaults to `false`.
|
|
587
|
+
*/
|
|
588
|
+
anonymousLiveQueries?: boolean;
|
|
583
589
|
}
|
|
584
590
|
/**
|
|
585
591
|
* The main synchronization engine for Sp00ky.
|
|
@@ -607,6 +613,7 @@ declare class Sp00kySync<S extends SchemaStructure> {
|
|
|
607
613
|
events: SyncEventSystem;
|
|
608
614
|
private currentUserId;
|
|
609
615
|
private refMode;
|
|
616
|
+
private readonly anonLiveEnabled;
|
|
610
617
|
private currentLiveQueryUuid;
|
|
611
618
|
private liveQueryUnsubscribe;
|
|
612
619
|
private listRefPollTimer;
|
package/dist/index.js
CHANGED
|
@@ -2551,6 +2551,13 @@ var SyncScheduler = class {
|
|
|
2551
2551
|
//#endregion
|
|
2552
2552
|
//#region src/modules/ref-tables.ts
|
|
2553
2553
|
/**
|
|
2554
|
+
* Sentinel user id for unauthenticated clients when anonymous live queries are
|
|
2555
|
+
* enabled. Mirrors `ssp_protocol::ANON_AUTH_ID`. It carries no `user:` prefix
|
|
2556
|
+
* so it can never collide with a real user id (those arrive as `user:<id>`);
|
|
2557
|
+
* both sides resolve it to the shared `_00_list_ref_anon` table.
|
|
2558
|
+
*/
|
|
2559
|
+
const ANON_USER_ID = "anon";
|
|
2560
|
+
/**
|
|
2554
2561
|
* Default ref-storage mode for this client build. Mirrors the SSP's
|
|
2555
2562
|
* default (`RefMode::Dedicated`) so cross-session sync works out of the
|
|
2556
2563
|
* box.
|
|
@@ -2582,6 +2589,7 @@ function sanitizeUserId(userId) {
|
|
|
2582
2589
|
* single mode.
|
|
2583
2590
|
*/
|
|
2584
2591
|
function listRefTableFor(mode, userId) {
|
|
2592
|
+
if (userId === ANON_USER_ID) return "_00_list_ref_anon";
|
|
2585
2593
|
if (mode === "single") return "_00_list_ref";
|
|
2586
2594
|
const uid = sanitizeUserId(userId);
|
|
2587
2595
|
return uid ? `_00_list_ref_user_${uid}` : "_00_list_ref";
|
|
@@ -2612,6 +2620,7 @@ var Sp00kySync = class {
|
|
|
2612
2620
|
events = createSyncEventSystem();
|
|
2613
2621
|
currentUserId = null;
|
|
2614
2622
|
refMode = DEFAULT_REF_MODE;
|
|
2623
|
+
anonLiveEnabled;
|
|
2615
2624
|
currentLiveQueryUuid = null;
|
|
2616
2625
|
liveQueryUnsubscribe = null;
|
|
2617
2626
|
listRefPollTimer = null;
|
|
@@ -2650,6 +2659,7 @@ var Sp00kySync = class {
|
|
|
2650
2659
|
this.syncEngine = new SyncEngine(this.remote, this.cache, this.schema, this.logger);
|
|
2651
2660
|
this.scheduler = new SyncScheduler(this.upQueue, this.downQueue, this.processUpEvent.bind(this), this.processDownEvent.bind(this), this.logger, this.handleRollback.bind(this));
|
|
2652
2661
|
this.refSyncIntervalMs = resolveListRefPollInterval(options?.refSyncIntervalMs);
|
|
2662
|
+
this.anonLiveEnabled = options?.anonymousLiveQueries ?? false;
|
|
2653
2663
|
}
|
|
2654
2664
|
/**
|
|
2655
2665
|
* Initializes the synchronization system.
|
|
@@ -2663,6 +2673,15 @@ var Sp00kySync = class {
|
|
|
2663
2673
|
this.subscribeToReconnect();
|
|
2664
2674
|
this.scheduler.syncUp();
|
|
2665
2675
|
this.scheduler.syncDown();
|
|
2676
|
+
if (this.anonLiveEnabled && !this.currentUserId) {
|
|
2677
|
+
this.startListRefPoll();
|
|
2678
|
+
this.restartRefLiveQuery().catch((err) => {
|
|
2679
|
+
this.logger.debug({
|
|
2680
|
+
err,
|
|
2681
|
+
Category: "sp00ky-client::Sp00kySync::init"
|
|
2682
|
+
}, "Anonymous ref LIVE start failed; relying on periodic poll fallback");
|
|
2683
|
+
});
|
|
2684
|
+
}
|
|
2666
2685
|
}
|
|
2667
2686
|
/**
|
|
2668
2687
|
* Push the authenticated user's record id from the parent client's
|
|
@@ -2681,6 +2700,16 @@ var Sp00kySync = class {
|
|
|
2681
2700
|
if (this.currentUserId === userId) return;
|
|
2682
2701
|
this.currentUserId = userId;
|
|
2683
2702
|
if (!userId) {
|
|
2703
|
+
if (this.anonLiveEnabled) {
|
|
2704
|
+
this.startListRefPoll();
|
|
2705
|
+
await this.restartRefLiveQuery().catch((err) => {
|
|
2706
|
+
this.logger.debug({
|
|
2707
|
+
err,
|
|
2708
|
+
Category: "sp00ky-client::Sp00kySync::setCurrentUserId"
|
|
2709
|
+
}, "Anonymous ref LIVE restart failed; relying on periodic poll fallback");
|
|
2710
|
+
});
|
|
2711
|
+
return;
|
|
2712
|
+
}
|
|
2684
2713
|
await this.killRefLiveQuery();
|
|
2685
2714
|
this.stopListRefPoll();
|
|
2686
2715
|
return;
|
|
@@ -2821,7 +2850,9 @@ var Sp00kySync = class {
|
|
|
2821
2850
|
* two points and we need the correct table name immediately.
|
|
2822
2851
|
*/
|
|
2823
2852
|
listRefTable() {
|
|
2824
|
-
|
|
2853
|
+
const userId = this.dataModule.getCurrentUserId();
|
|
2854
|
+
if (userId == null && this.anonLiveEnabled) return listRefTableFor(this.refMode, ANON_USER_ID);
|
|
2855
|
+
return listRefTableFor(this.refMode, userId);
|
|
2825
2856
|
}
|
|
2826
2857
|
async killRefLiveQuery() {
|
|
2827
2858
|
if (this.liveQueryUnsubscribe) {
|
|
@@ -2860,7 +2891,7 @@ var Sp00kySync = class {
|
|
|
2860
2891
|
type: "register",
|
|
2861
2892
|
payload: { hash }
|
|
2862
2893
|
});
|
|
2863
|
-
if (this.currentUserId) this.restartRefLiveQuery().catch((err) => {
|
|
2894
|
+
if (this.currentUserId || this.anonLiveEnabled) this.restartRefLiveQuery().catch((err) => {
|
|
2864
2895
|
this.logger.debug({
|
|
2865
2896
|
err,
|
|
2866
2897
|
Category: "sp00ky-client::Sp00kySync::onReconnect"
|
|
@@ -3312,8 +3343,8 @@ function parseBackendInfo(raw) {
|
|
|
3312
3343
|
|
|
3313
3344
|
//#endregion
|
|
3314
3345
|
//#region src/modules/devtools/index.ts
|
|
3315
|
-
const CORE_VERSION = "0.0.1-canary.
|
|
3316
|
-
const WASM_VERSION = "0.0.1-canary.
|
|
3346
|
+
const CORE_VERSION = "0.0.1-canary.83";
|
|
3347
|
+
const WASM_VERSION = "0.0.1-canary.83";
|
|
3317
3348
|
const SURREAL_VERSION = "3.0.3";
|
|
3318
3349
|
var DevToolsService = class {
|
|
3319
3350
|
eventsHistory = [];
|
|
@@ -5164,7 +5195,10 @@ var Sp00kyClient = class {
|
|
|
5164
5195
|
this.crdtManager = new CrdtManager(this.config.schema, this.local, this.remote, logger, config.crdtDebounceMs ?? 500);
|
|
5165
5196
|
this.dataModule = new DataModule(this.cache, this.local, this.config.schema, logger, this.config.streamDebounceTime);
|
|
5166
5197
|
this.auth = new AuthService(this.config.schema, this.remote, this.persistenceClient, logger);
|
|
5167
|
-
this.sync = new Sp00kySync(this.local, this.remote, this.cache, this.dataModule, this.config.schema, this.logger, {
|
|
5198
|
+
this.sync = new Sp00kySync(this.local, this.remote, this.cache, this.dataModule, this.config.schema, this.logger, {
|
|
5199
|
+
refSyncIntervalMs: this.config.refSyncIntervalMs,
|
|
5200
|
+
anonymousLiveQueries: this.config.enableAnonymousLiveQueries
|
|
5201
|
+
});
|
|
5168
5202
|
this.featureFlags = new FeatureFlagModule({
|
|
5169
5203
|
dataModule: this.dataModule,
|
|
5170
5204
|
sync: this.sync,
|
package/dist/types.d.ts
CHANGED
|
@@ -291,6 +291,16 @@ interface Sp00kyConfig<S extends SchemaStructure> {
|
|
|
291
291
|
* Defaults to `true`; set `false` to keep the old wait-for-registration path.
|
|
292
292
|
*/
|
|
293
293
|
instantHydrate?: boolean;
|
|
294
|
+
/**
|
|
295
|
+
* Enable realtime sync while signed out. When `true`, the client starts its
|
|
296
|
+
* `_00_list_ref` poll (and a LIVE subscription) against the shared
|
|
297
|
+
* `_00_list_ref_anon` table even with no authenticated user, so a logged-out
|
|
298
|
+
* page gets live `useQuery` updates over world-readable tables. Requires the
|
|
299
|
+
* server to be deployed with `anonymousLiveQueries: true` in `sp00ky.yml`
|
|
300
|
+
* (this flag must match it). Defaults to `false`: anonymous clients can read
|
|
301
|
+
* one-shot but never sync live.
|
|
302
|
+
*/
|
|
303
|
+
enableAnonymousLiveQueries?: boolean;
|
|
294
304
|
}
|
|
295
305
|
type QueryHash = string;
|
|
296
306
|
type RecordVersionArray = Array<[string, number]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spooky-sync/core",
|
|
3
|
-
"version": "0.0.1-canary.
|
|
3
|
+
"version": "0.0.1-canary.83",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@spooky-sync/query-builder": "0.0.1-canary.
|
|
63
|
-
"@spooky-sync/ssp-wasm": "0.0.1-canary.
|
|
62
|
+
"@spooky-sync/query-builder": "0.0.1-canary.83",
|
|
63
|
+
"@spooky-sync/ssp-wasm": "0.0.1-canary.83",
|
|
64
64
|
"@surrealdb/wasm": "^3.0.3",
|
|
65
65
|
"fast-json-patch": "^3.1.1",
|
|
66
66
|
"loro-crdt": "^1.5.6",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { RecordId } from 'surrealdb';
|
|
3
|
-
import { listRefTableFor, sanitizeUserId } from './ref-tables';
|
|
3
|
+
import { ANON_USER_ID, listRefTableFor, sanitizeUserId } from './ref-tables';
|
|
4
4
|
|
|
5
5
|
describe('listRefTableFor', () => {
|
|
6
6
|
it('returns global table in single mode regardless of user', () => {
|
|
@@ -32,6 +32,16 @@ describe('listRefTableFor', () => {
|
|
|
32
32
|
);
|
|
33
33
|
expect(listRefTableFor('dedicated', 'user:abc.dot')).toBe('_00_list_ref');
|
|
34
34
|
});
|
|
35
|
+
|
|
36
|
+
it('routes the anon sentinel to the shared anon table in both modes', () => {
|
|
37
|
+
expect(listRefTableFor('dedicated', ANON_USER_ID)).toBe('_00_list_ref_anon');
|
|
38
|
+
expect(listRefTableFor('single', ANON_USER_ID)).toBe('_00_list_ref_anon');
|
|
39
|
+
// A real user whose id sanitizes to "anon" still carries the user: prefix,
|
|
40
|
+
// so it never collides with the bare sentinel.
|
|
41
|
+
expect(listRefTableFor('dedicated', 'user:anon')).toBe(
|
|
42
|
+
'_00_list_ref_user_anon'
|
|
43
|
+
);
|
|
44
|
+
});
|
|
35
45
|
});
|
|
36
46
|
|
|
37
47
|
describe('sanitizeUserId', () => {
|
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
|
|
13
13
|
export type RefMode = 'single' | 'dedicated';
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Sentinel user id for unauthenticated clients when anonymous live queries are
|
|
17
|
+
* enabled. Mirrors `ssp_protocol::ANON_AUTH_ID`. It carries no `user:` prefix
|
|
18
|
+
* so it can never collide with a real user id (those arrive as `user:<id>`);
|
|
19
|
+
* both sides resolve it to the shared `_00_list_ref_anon` table.
|
|
20
|
+
*/
|
|
21
|
+
export const ANON_USER_ID = 'anon';
|
|
22
|
+
|
|
15
23
|
/**
|
|
16
24
|
* Default ref-storage mode for this client build. Mirrors the SSP's
|
|
17
25
|
* default (`RefMode::Dedicated`) so cross-session sync works out of the
|
|
@@ -51,6 +59,10 @@ export function sanitizeUserId(userId: unknown): string | null {
|
|
|
51
59
|
* single mode.
|
|
52
60
|
*/
|
|
53
61
|
export function listRefTableFor(mode: RefMode, userId: unknown): string {
|
|
62
|
+
// Anonymous clients (flag-enabled) share one dedicated table in both modes —
|
|
63
|
+
// checked before the mode split so it never lands on the per-user or the
|
|
64
|
+
// auth-gated global table. Matches `ssp_protocol::list_ref_table_for`.
|
|
65
|
+
if (userId === ANON_USER_ID) return '_00_list_ref_anon';
|
|
54
66
|
if (mode === 'single') return '_00_list_ref';
|
|
55
67
|
const uid = sanitizeUserId(userId);
|
|
56
68
|
return uid ? `_00_list_ref_user_${uid}` : '_00_list_ref';
|
package/src/modules/sync/sync.ts
CHANGED
|
@@ -21,7 +21,7 @@ import type { SchemaStructure } from '@spooky-sync/query-builder';
|
|
|
21
21
|
import type { CacheModule } from '../cache/index';
|
|
22
22
|
import type { DataModule } from '../data/index';
|
|
23
23
|
import { encodeRecordId, extractIdPart, extractTablePart, surql } from '../../utils/index';
|
|
24
|
-
import { DEFAULT_REF_MODE, listRefTableFor, RefMode } from '../ref-tables';
|
|
24
|
+
import { ANON_USER_ID, DEFAULT_REF_MODE, listRefTableFor, RefMode } from '../ref-tables';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Tunables for `Sp00kySync` construction.
|
|
@@ -34,6 +34,12 @@ export interface Sp00kySyncOptions {
|
|
|
34
34
|
* {@link resolveListRefPollInterval}.
|
|
35
35
|
*/
|
|
36
36
|
refSyncIntervalMs?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Enable realtime sync for unauthenticated clients against the shared
|
|
39
|
+
* `_00_list_ref_anon` table. See {@link Sp00kyConfig.enableAnonymousLiveQueries}.
|
|
40
|
+
* Defaults to `false`.
|
|
41
|
+
*/
|
|
42
|
+
anonymousLiveQueries?: boolean;
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
/**
|
|
@@ -65,6 +71,11 @@ export class Sp00kySync<S extends SchemaStructure> {
|
|
|
65
71
|
|
|
66
72
|
private refMode: RefMode = DEFAULT_REF_MODE;
|
|
67
73
|
|
|
74
|
+
// When true, an unauthenticated client still runs the `_00_list_ref` poll
|
|
75
|
+
// and LIVE subscription, routed to the shared `_00_list_ref_anon` table, so
|
|
76
|
+
// a logged-out page gets realtime `useQuery` updates. Off by default.
|
|
77
|
+
private readonly anonLiveEnabled: boolean;
|
|
78
|
+
|
|
68
79
|
// Bookkeeping for the LIVE subscription on `_00_list_ref[_user_*]`.
|
|
69
80
|
// SurrealDB binds the permission context at LIVE-registration time and
|
|
70
81
|
// the table name in dedicated mode depends on the authenticated user,
|
|
@@ -165,6 +176,7 @@ export class Sp00kySync<S extends SchemaStructure> {
|
|
|
165
176
|
this.handleRollback.bind(this)
|
|
166
177
|
);
|
|
167
178
|
this.refSyncIntervalMs = resolveListRefPollInterval(options?.refSyncIntervalMs);
|
|
179
|
+
this.anonLiveEnabled = options?.anonymousLiveQueries ?? false;
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
/**
|
|
@@ -183,6 +195,23 @@ export class Sp00kySync<S extends SchemaStructure> {
|
|
|
183
195
|
// from the auth subscription. In dedicated mode the table name
|
|
184
196
|
// depends on the authenticated user, and an unauthenticated
|
|
185
197
|
// subscription wouldn't match any of the per-user tables anyway.
|
|
198
|
+
//
|
|
199
|
+
// Exception: when anonymous live queries are enabled, start realtime now
|
|
200
|
+
// against the shared `_00_list_ref_anon` table so a logged-out client
|
|
201
|
+
// syncs immediately. `setCurrentUserId` re-points LIVE to the per-user
|
|
202
|
+
// table on sign-in. Guard on `currentUserId` because the auth callback can
|
|
203
|
+
// fire (and authenticate) before `init()` runs — don't clobber that back
|
|
204
|
+
// to the anon table. `setCurrentUserId(null)` is a no-op on first load
|
|
205
|
+
// (it's already null), so this is the only place anon realtime starts.
|
|
206
|
+
if (this.anonLiveEnabled && !this.currentUserId) {
|
|
207
|
+
this.startListRefPoll();
|
|
208
|
+
this.restartRefLiveQuery().catch((err) => {
|
|
209
|
+
this.logger.debug(
|
|
210
|
+
{ err, Category: 'sp00ky-client::Sp00kySync::init' },
|
|
211
|
+
'Anonymous ref LIVE start failed; relying on periodic poll fallback'
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
186
215
|
}
|
|
187
216
|
|
|
188
217
|
/**
|
|
@@ -202,6 +231,20 @@ export class Sp00kySync<S extends SchemaStructure> {
|
|
|
202
231
|
if (this.currentUserId === userId) return;
|
|
203
232
|
this.currentUserId = userId;
|
|
204
233
|
if (!userId) {
|
|
234
|
+
if (this.anonLiveEnabled) {
|
|
235
|
+
// Signed out but anonymous realtime is on: keep the poll running and
|
|
236
|
+
// re-point LIVE from the (now stale) per-user table to the shared
|
|
237
|
+
// `_00_list_ref_anon`. `startListRefPoll` is idempotent; the poll
|
|
238
|
+
// re-resolves `listRefTable()` each tick so it follows automatically.
|
|
239
|
+
this.startListRefPoll();
|
|
240
|
+
await this.restartRefLiveQuery().catch((err) => {
|
|
241
|
+
this.logger.debug(
|
|
242
|
+
{ err, Category: 'sp00ky-client::Sp00kySync::setCurrentUserId' },
|
|
243
|
+
'Anonymous ref LIVE restart failed; relying on periodic poll fallback'
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
205
248
|
await this.killRefLiveQuery();
|
|
206
249
|
this.stopListRefPoll();
|
|
207
250
|
return;
|
|
@@ -391,7 +434,12 @@ export class Sp00kySync<S extends SchemaStructure> {
|
|
|
391
434
|
* two points and we need the correct table name immediately.
|
|
392
435
|
*/
|
|
393
436
|
public listRefTable(): string {
|
|
394
|
-
|
|
437
|
+
const userId = this.dataModule.getCurrentUserId();
|
|
438
|
+
// Unauthenticated with the flag on → the shared `_00_list_ref_anon` table.
|
|
439
|
+
if (userId == null && this.anonLiveEnabled) {
|
|
440
|
+
return listRefTableFor(this.refMode, ANON_USER_ID);
|
|
441
|
+
}
|
|
442
|
+
return listRefTableFor(this.refMode, userId);
|
|
395
443
|
}
|
|
396
444
|
|
|
397
445
|
private async killRefLiveQuery(): Promise<void> {
|
|
@@ -443,8 +491,9 @@ export class Sp00kySync<S extends SchemaStructure> {
|
|
|
443
491
|
// re-enqueued `register` events only re-fetch initial state, they don't
|
|
444
492
|
// re-subscribe. Without this, LIVE never recovers after a reconnect and
|
|
445
493
|
// the poll silently becomes the sole sync path (and never backs off).
|
|
446
|
-
//
|
|
447
|
-
|
|
494
|
+
// Authenticated → per-user table; signed-out with anon live enabled →
|
|
495
|
+
// the shared `_00_list_ref_anon`. Otherwise there's no table to re-bind.
|
|
496
|
+
if (this.currentUserId || this.anonLiveEnabled) {
|
|
448
497
|
this.restartRefLiveQuery().catch((err) => {
|
|
449
498
|
this.logger.debug(
|
|
450
499
|
{ err, Category: 'sp00ky-client::Sp00kySync::onReconnect' },
|
package/src/sp00ky.ts
CHANGED
|
@@ -203,7 +203,10 @@ export class Sp00kyClient<S extends SchemaStructure> {
|
|
|
203
203
|
this.dataModule,
|
|
204
204
|
this.config.schema,
|
|
205
205
|
this.logger,
|
|
206
|
-
{
|
|
206
|
+
{
|
|
207
|
+
refSyncIntervalMs: this.config.refSyncIntervalMs,
|
|
208
|
+
anonymousLiveQueries: this.config.enableAnonymousLiveQueries,
|
|
209
|
+
}
|
|
207
210
|
);
|
|
208
211
|
|
|
209
212
|
// Initialize feature flags. Reuses the down-queue to register SSP plans
|
package/src/types.ts
CHANGED
|
@@ -143,6 +143,16 @@ export interface Sp00kyConfig<S extends SchemaStructure> {
|
|
|
143
143
|
* Defaults to `true`; set `false` to keep the old wait-for-registration path.
|
|
144
144
|
*/
|
|
145
145
|
instantHydrate?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Enable realtime sync while signed out. When `true`, the client starts its
|
|
148
|
+
* `_00_list_ref` poll (and a LIVE subscription) against the shared
|
|
149
|
+
* `_00_list_ref_anon` table even with no authenticated user, so a logged-out
|
|
150
|
+
* page gets live `useQuery` updates over world-readable tables. Requires the
|
|
151
|
+
* server to be deployed with `anonymousLiveQueries: true` in `sp00ky.yml`
|
|
152
|
+
* (this flag must match it). Defaults to `false`: anonymous clients can read
|
|
153
|
+
* one-shot but never sync live.
|
|
154
|
+
*/
|
|
155
|
+
enableAnonymousLiveQueries?: boolean;
|
|
146
156
|
}
|
|
147
157
|
|
|
148
158
|
export type QueryHash = string;
|