@spooky-sync/core 0.0.1-canary.279 → 0.0.1-canary.281
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 +2 -0
- package/dist/index.d.ts +7 -329
- package/dist/index.js +748 -39
- package/dist/live.d.ts +141 -0
- package/dist/live.js +709 -0
- package/dist/pure.d.ts +322 -0
- package/dist/pure.js +24 -0
- package/dist/sw.d.ts +207 -0
- package/dist/sw.js +393 -0
- package/dist/types.d.ts +742 -3
- package/dist/worker-edges.js +415 -0
- package/dist/worker-impersonation.js +60 -0
- package/dist/worker-ref-tables.d.ts +46 -0
- package/dist/worker-types.d.ts +112 -0
- package/dist/worker-types.js +73 -0
- package/package.json +16 -4
- package/scripts/check-worker-entries.mjs +172 -0
- package/src/client/services.ts +10 -38
- package/src/client/sp00ky-client.ts +13 -0
- package/src/index.ts +32 -0
- package/src/live/index.test.ts +478 -0
- package/src/live/index.ts +1013 -0
- package/src/modules/auth/index.ts +52 -0
- package/src/modules/web-push/index.test.ts +797 -0
- package/src/modules/web-push/index.ts +997 -0
- package/src/pure.ts +65 -0
- package/src/push/types.ts +174 -0
- package/src/sw/index.test.ts +582 -0
- package/src/sw/index.ts +607 -0
- package/src/sw/store.ts +96 -0
- package/src/testing/fake-services.ts +1 -1
- package/src/types.ts +11 -0
- package/src/utils/edges.ts +39 -0
- package/src/utils/sha256.ts +15 -0
- package/tsdown.config.ts +31 -2
package/AGENTS.md
CHANGED
|
@@ -41,6 +41,8 @@ re-materialized from state, never patched in place.
|
|
|
41
41
|
- `CrdtManager`, `CrdtField`, `cursorColorFromName`, `CURSOR_COLORS` — Loro-CRDT integration.
|
|
42
42
|
- Types: `Sp00kyConfig` (client-solid wraps it as `SyncedDbConfig`), `QueryTimeToLive`, `PersistenceClient`, `StoreType`, `UpdateOptions`, `RunOptions`, `PreloadOptions`.
|
|
43
43
|
- Subpath: `@spooky-sync/core/otel` — `createOtelTransmit(endpoint)` for piping pino logs to OpenTelemetry.
|
|
44
|
+
- `client.webPush` (`WebPushModule`, `db.webPush` in the Solid bindings) - Web Push on the page: `support()`, `info()`, `subscribe(opts)` (call from a click), `unsubscribe(opts)`, `sync()`, `isSubscribed()`, `update(opts)`, `devices()`, `notify(msg)`, `cancel(id)`, `test()`, `bridge()`, `onMessage(cb)`. Server calls are `fn::push::*`; typed `WebPushError`; config `webPush` in `types.ts`. Sign-out runs through `AuthService.onBeforeSignOut`.
|
|
45
|
+
- Subpaths for service workers, workers and Node (no wasm, no pino, no DOM; `scripts/check-worker-entries.mjs` enforces it in `build`): `@spooky-sync/core/pure` (protocol builders), `@spooky-sync/core/live` (`createLiveFeed`, the live subscriber over the pure-JS SDK), `@spooky-sync/core/sw` (`installPushHandlers`, `getBridgedToken`). Built by the second tsdown config; chunks are prefixed `worker-`. See `docs/web-push-design.md` at the repo root.
|
|
44
46
|
|
|
45
47
|
## Common gotchas
|
|
46
48
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import {
|
|
1
|
+
import { $ as WebPushSupport, A as RunOptions, At as SealedQuery, B as SyncHealthStatus, Bt as decodeTokenClaims, C as QueryTimeToLive, Ct as AuthEventSystem, D as RecordVersionArray, Dt as RemoteDatabaseService, E as ReconnectConfig, Et as createAuthEventSystem, F as StorageHealth, Ft as ImpersonationTimerHost, G as WebPushDevice, H as UpdateOptions, Ht as renewDelayMs, I as StorageHealthStatus, It as ImpersonationTimers, J as WebPushInfo, K as WebPushError, L as StoreType, Lt as ORIGIN_TOKEN_KEY, M as Sp00kyConfig, Mt as EventSystem, N as Sp00kyQueryResult, Nt as IMPERSONATION_ACCESS, O as RecordVersionDiff, Ot as Logger$1, P as Sp00kyQueryResultPromise, Pt as ImpersonationInfo, Q as WebPushSubscribeOptions, R as SyncHealth, Rt as SESSION_POLL_MS, S as QueryStatusCallback, St as SignOutHook, T as QueryUpdateCallback, Tt as AuthEventTypes, U as PUSH_ENDPOINT_KEY, Ut as sameImpersonation, V as TimingPhase, Vt as impersonationFromToken, W as WebPushConfig, X as WebPushMessageInput, Y as WebPushMessage, Z as WebPushModule, _ as QueryConfig, _t as ActiveImpersonation, a as Level, at as detectWebPushSupport, b as QueryState, bt as SIGN_OUT_HOOK_TIMEOUT_MS, c as MutationCallback, ct as PUSH_PAYLOAD_VERSION, d as PersistenceClient, dt as PushOp, et as WebPushSyncOptions, f as PhaseStat, ft as PushPayload, g as QueryAuthorityCallback, gt as isPushPayload, h as PreloadRefresh, ht as WebPushClientMessage, i as InlineRow, it as WebPushUpdateOptions, j as ServerViewMeta, jt as EventDefinition, k as RegistrationTimings, kt as LocalStore, l as MutationEvent, lt as PushNotification, m as PreloadOptions, mt as PushUrgency, n as DebounceOptions, nt as WebPushUnsubscribeOptions, o as MATERIALIZATION_SAMPLE_WINDOW, ot as BridgeSignOutMessage, p as PinoTransmit, pt as PushPayloadKind, q as WebPushErrorCode, r as EventSubscriptionOptions, rt as WebPushUnsupportedReason, s as MembershipOutcome, st as BridgeTokenMessage, t as ConnectionState, tt as WebPushSyncStatus, u as MutationEventType, ut as PushNotificationAction, v as QueryConfigRecord, vt as AuthService, w as QueryTimings, wt as AuthEventTypeMap, x as QueryStatus, xt as SignOutContext, y as QueryHash, yt as ImpersonationCandidate, z as SyncHealthConfig, zt as TokenClaims } from "./types.js";
|
|
2
|
+
import { BackendNames, BackendRoutes, BucketNames, FinalQuery, GetTable, QueryBuilder, QueryOptions, QueryPlan, RecordId, RoutePayload, SchemaStructure, TableModel, TableNames } from "@spooky-sync/query-builder";
|
|
3
3
|
import * as surrealdb0 from "surrealdb";
|
|
4
|
-
import { Duration, RecordId as RecordId$1, Surreal
|
|
5
|
-
import {
|
|
4
|
+
import { Duration, RecordId as RecordId$1, Surreal } from "surrealdb";
|
|
5
|
+
import { Logger } from "pino";
|
|
6
6
|
import { decode, encode, isBlurhashValid } from "blurhash";
|
|
7
7
|
import { LoroDoc } from "loro-crdt";
|
|
8
8
|
|
|
@@ -87,188 +87,6 @@ type LeaderToFollowerMessage = {
|
|
|
87
87
|
count: number;
|
|
88
88
|
};
|
|
89
89
|
//#endregion
|
|
90
|
-
//#region src/services/logger/index.d.ts
|
|
91
|
-
type Logger$1 = Logger;
|
|
92
|
-
//#endregion
|
|
93
|
-
//#region src/services/database/database.d.ts
|
|
94
|
-
declare abstract class AbstractDatabaseService {
|
|
95
|
-
protected client: Surreal;
|
|
96
|
-
protected logger: Logger$1;
|
|
97
|
-
protected events: DatabaseEventSystem;
|
|
98
|
-
/**
|
|
99
|
-
* Per-query deadline in ms; `0` disables. The remote service sets it from
|
|
100
|
-
* `queryTimeoutMs` (see `RemoteDatabaseService`), the local one from
|
|
101
|
-
* `localOpTimeoutMs` (see `LocalDatabaseService`): a local query can be
|
|
102
|
-
* legitimately slow, but it must never be endless - every query waits on the
|
|
103
|
-
* previous link of {@link query}'s chain, and one that never settled wedged
|
|
104
|
-
* every later local op behind it.
|
|
105
|
-
*/
|
|
106
|
-
protected queryTimeoutMs: number;
|
|
107
|
-
/** The error a deadline expiry rejects with; the local service substitutes
|
|
108
|
-
* its typed `LocalOpTimeoutError`. "timed out" in the message is
|
|
109
|
-
* load-bearing either way: `classifySyncError` keys off it. */
|
|
110
|
-
protected timeoutError(_query: string): Error;
|
|
111
|
-
protected abstract eventType: typeof DatabaseEventTypes.LocalQuery | typeof DatabaseEventTypes.RemoteQuery;
|
|
112
|
-
constructor(client: Surreal, logger: Logger$1, events: DatabaseEventSystem);
|
|
113
|
-
abstract connect(): Promise<void>;
|
|
114
|
-
getClient(): Surreal;
|
|
115
|
-
getEvents(): DatabaseEventSystem;
|
|
116
|
-
tx(): Promise<SurrealTransaction>;
|
|
117
|
-
/**
|
|
118
|
-
* How many statements may be in flight at once.
|
|
119
|
-
*
|
|
120
|
-
* `1` serializes every statement behind the previous one. The local engines
|
|
121
|
-
* need that: overlapping ops trip the WASM / SQLite transaction layer. The
|
|
122
|
-
* remote service raises it (`RemoteDatabaseService`): a SurrealDB socket
|
|
123
|
-
* multiplexes requests by id, and serializing them capped the client at one
|
|
124
|
-
* statement per round trip (~5/s at 170ms RTT), so the `_00_list_ref` poll
|
|
125
|
-
* alone could hold every registration behind it and one slow one-shot read
|
|
126
|
-
* stalled the whole client. The scheduler's `MAX_CONCURRENT_DOWN` only means
|
|
127
|
-
* something when this is above 1.
|
|
128
|
-
*/
|
|
129
|
-
protected maxConcurrentQueries: number;
|
|
130
|
-
private inFlightQueries;
|
|
131
|
-
private queryWaiters;
|
|
132
|
-
/** FIFO slot acquisition, so `maxConcurrentQueries = 1` keeps strict order. */
|
|
133
|
-
private acquireQuerySlot;
|
|
134
|
-
private releaseQuerySlot;
|
|
135
|
-
/**
|
|
136
|
-
* Hook run right before a statement is sent, inside its slot. The remote
|
|
137
|
-
* service uses it to hold statements while a connect is in flight, so a
|
|
138
|
-
* query never runs on a socket that is open but has not had its namespace
|
|
139
|
-
* and token applied yet. The default does nothing.
|
|
140
|
-
*/
|
|
141
|
-
protected beforeQuery(): Promise<void>;
|
|
142
|
-
/**
|
|
143
|
-
* Execute a statement under {@link maxConcurrentQueries}.
|
|
144
|
-
*
|
|
145
|
-
* A statement that never settles would hold its slot forever, and with a
|
|
146
|
-
* limit of 1 that blocks every later statement behind it. {@link
|
|
147
|
-
* queryTimeoutMs} bounds each one: on expiry this promise rejects and the
|
|
148
|
-
* slot is released, even though the underlying RPC is still parked in the
|
|
149
|
-
* SDK's pending map.
|
|
150
|
-
*/
|
|
151
|
-
query<T extends unknown[]>(query: string, vars?: Record<string, unknown>): Promise<T>;
|
|
152
|
-
/**
|
|
153
|
-
* Like {@link query} but never rejects on a statement error: every
|
|
154
|
-
* statement answers on its own as `{ status: 'OK', result }` or
|
|
155
|
-
* `{ status: 'ERR', error }`. This is what lets a batched outbox push judge
|
|
156
|
-
* each mutation separately.
|
|
157
|
-
*/
|
|
158
|
-
queryResponses(query: string, vars?: Record<string, unknown>): Promise<Array<{
|
|
159
|
-
status: 'OK';
|
|
160
|
-
result: unknown;
|
|
161
|
-
} | {
|
|
162
|
-
status: 'ERR';
|
|
163
|
-
error: string;
|
|
164
|
-
}>>;
|
|
165
|
-
private runStatement;
|
|
166
|
-
execute<T>(query: SealedQuery<T>, vars?: Record<string, unknown>): Promise<T>;
|
|
167
|
-
close(): Promise<void>;
|
|
168
|
-
}
|
|
169
|
-
//#endregion
|
|
170
|
-
//#region src/services/database/remote.d.ts
|
|
171
|
-
/** Transport events the SDK publishes, mapped 1:1 to {@link ConnectionState}. */
|
|
172
|
-
type RemoteConnectionEvent = ConnectionState | 'error';
|
|
173
|
-
declare class RemoteDatabaseService extends AbstractDatabaseService {
|
|
174
|
-
private config;
|
|
175
|
-
protected eventType: "DATABASE_REMOTE_QUERY";
|
|
176
|
-
private readonly reconnectConfig;
|
|
177
|
-
/**
|
|
178
|
-
* In-flight `connect()`, so concurrent callers (boot + supervisor revive +
|
|
179
|
-
* an `online` event landing at the same moment) share one attempt instead of
|
|
180
|
-
* racing two sockets. Cleared on settle, so a later call always reconnects.
|
|
181
|
-
*/
|
|
182
|
-
private connecting;
|
|
183
|
-
/**
|
|
184
|
-
* The token to re-authenticate a freshly opened socket with, kept current by
|
|
185
|
-
* {@link setAuthToken}.
|
|
186
|
-
*
|
|
187
|
-
* `config.token` is fixed at construction and most apps never set it: they
|
|
188
|
-
* sign in later, which authenticates the socket that happens to be open at
|
|
189
|
-
* the time. That is enough for the SDK's OWN reconnects (it replays
|
|
190
|
-
* `version`/`use`/`authenticate` itself), but not for the supervisor's revive
|
|
191
|
-
* loop, which builds a socket from scratch. Without this the revived socket
|
|
192
|
-
* came back UNAUTHENTICATED and stayed that way for the life of the page,
|
|
193
|
-
* while the client's `currentUserId` — restored from local storage — kept
|
|
194
|
-
* reporting the user as signed in.
|
|
195
|
-
*
|
|
196
|
-
* The visible damage is silent and total: `fn::query::register` sends
|
|
197
|
-
* `<string>($auth.id OR '')`, so every view registered afterwards is stamped
|
|
198
|
-
* with an empty identity, and every `$auth.id` predicate in it resolves
|
|
199
|
-
* false. Public tables keep returning rows while everything owned by the user
|
|
200
|
-
* returns nothing, on a page that still looks signed in.
|
|
201
|
-
*/
|
|
202
|
-
private authToken;
|
|
203
|
-
constructor(config: Sp00kyConfig<any>['database'], logger: Logger$1);
|
|
204
|
-
getConfig(): Sp00kyConfig<any>['database'];
|
|
205
|
-
/**
|
|
206
|
-
* Send one SurrealQL statement so that it survives the page going away.
|
|
207
|
-
*
|
|
208
|
-
* A WebSocket `send()` during `pagehide` is not guaranteed to flush — the
|
|
209
|
-
* browser may tear the socket down first, and the frame is simply lost.
|
|
210
|
-
* Measured: an unload-time release over the live socket reached the server
|
|
211
|
-
* zero times out of one. `fetch` with `keepalive` is the primitive the
|
|
212
|
-
* platform actually guarantees here, so this goes over SurrealDB's HTTP
|
|
213
|
-
* `/sql` endpoint instead of the RPC socket.
|
|
214
|
-
*
|
|
215
|
-
* Best-effort by design: no await, no retry, errors swallowed. Every caller
|
|
216
|
-
* must have a server-side fallback that makes a lost beacon a non-event.
|
|
217
|
-
*/
|
|
218
|
-
beaconSql(sql: string): void;
|
|
219
|
-
/**
|
|
220
|
-
* Record the token every future connect should authenticate with, or `null`
|
|
221
|
-
* on sign-out. See {@link authToken}.
|
|
222
|
-
*
|
|
223
|
-
* Does not touch the CURRENT socket: callers authenticate that themselves
|
|
224
|
-
* (sign-in and session restore both already do). This only makes the next
|
|
225
|
-
* from-scratch connect reproduce that state.
|
|
226
|
-
*/
|
|
227
|
-
setAuthToken(token: string | null): void;
|
|
228
|
-
/** Resolved reconnect tunables; the supervisor reads its own knobs here. */
|
|
229
|
-
getReconnectConfig(): Required<ReconnectConfig>;
|
|
230
|
-
/** Current transport state as reported by the SDK. */
|
|
231
|
-
getStatus(): ConnectionState;
|
|
232
|
-
/**
|
|
233
|
-
* Observe transport events. Thin passthrough so callers (the supervisor,
|
|
234
|
-
* sync, CRDT) don't have to reach through `getClient()`.
|
|
235
|
-
*/
|
|
236
|
-
subscribeConnection<K extends RemoteConnectionEvent>(event: K, cb: (...payload: SurrealEvents[K]) => void): () => void;
|
|
237
|
-
/**
|
|
238
|
-
* Tear the socket down on purpose. Used by the heartbeat watchdog when a
|
|
239
|
-
* socket stops answering but never closes: `close()` makes the SDK publish
|
|
240
|
-
* `disconnected`, which is what drives the supervisor's revive loop.
|
|
241
|
-
*/
|
|
242
|
-
forceClose(): Promise<void>;
|
|
243
|
-
/**
|
|
244
|
-
* Hold statements while a connect is in flight.
|
|
245
|
-
*
|
|
246
|
-
* `connect()` opens the socket, then selects the namespace/database, then
|
|
247
|
-
* authenticates - three round trips. The SDK considers the connection ready
|
|
248
|
-
* after the first, so a query queued during the other two ran on a socket
|
|
249
|
-
* with no namespace ("Specify a namespace to use") or, worse, no identity.
|
|
250
|
-
* Seen 2026-09-06 after the supervisor rebuilt a socket: a collection
|
|
251
|
-
* recount failed with exactly that error. Waiting on the in-flight connect
|
|
252
|
-
* costs nothing when no connect is running; a failed connect is not
|
|
253
|
-
* swallowed here - the query then fails on its own, as before.
|
|
254
|
-
*/
|
|
255
|
-
protected beforeQuery(): Promise<void>;
|
|
256
|
-
/**
|
|
257
|
-
* Open (or re-open) the remote connection.
|
|
258
|
-
*
|
|
259
|
-
* Safe to call repeatedly: concurrent calls share the in-flight attempt, and
|
|
260
|
-
* a call after a `disconnected` builds a fresh socket. `use()` and
|
|
261
|
-
* `authenticate()` are re-applied here for the cold path; the SDK also
|
|
262
|
-
* replays them itself on its own internal reconnects.
|
|
263
|
-
*/
|
|
264
|
-
connect(): Promise<void>;
|
|
265
|
-
private doConnect;
|
|
266
|
-
signin(params: any): Promise<any>;
|
|
267
|
-
signup(params: any): Promise<any>;
|
|
268
|
-
authenticate(token: string): Promise<any>;
|
|
269
|
-
invalidate(): Promise<void>;
|
|
270
|
-
}
|
|
271
|
-
//#endregion
|
|
272
90
|
//#region src/services/database/connection-supervisor.d.ts
|
|
273
91
|
/**
|
|
274
92
|
* Keeps the remote WebSocket alive for the whole life of the page.
|
|
@@ -674,148 +492,6 @@ declare class StreamProcessorService {
|
|
|
674
492
|
private normalizeValue;
|
|
675
493
|
}
|
|
676
494
|
//#endregion
|
|
677
|
-
//#region src/modules/auth/events/index.d.ts
|
|
678
|
-
declare const AuthEventTypes: {
|
|
679
|
-
readonly AuthStateChanged: "AUTH_STATE_CHANGED";
|
|
680
|
-
readonly ImpersonationChanged: "IMPERSONATION_CHANGED";
|
|
681
|
-
};
|
|
682
|
-
type AuthEventTypeMap = {
|
|
683
|
-
[AuthEventTypes.AuthStateChanged]: EventDefinition<typeof AuthEventTypes.AuthStateChanged, string | null>;
|
|
684
|
-
[AuthEventTypes.ImpersonationChanged]: EventDefinition<typeof AuthEventTypes.ImpersonationChanged, ImpersonationInfo | null>;
|
|
685
|
-
};
|
|
686
|
-
type AuthEventSystem = EventSystem<AuthEventTypeMap>;
|
|
687
|
-
declare function createAuthEventSystem(): AuthEventSystem;
|
|
688
|
-
//#endregion
|
|
689
|
-
//#region src/modules/auth/index.d.ts
|
|
690
|
-
/** What `fn::_00_impersonate::list_users` returns per row. */
|
|
691
|
-
interface ImpersonationCandidate {
|
|
692
|
-
id: string;
|
|
693
|
-
is_admin: boolean;
|
|
694
|
-
[field: string]: unknown;
|
|
695
|
-
}
|
|
696
|
-
/** An open session, as `fn::_00_impersonate::active` lists it. */
|
|
697
|
-
interface ActiveImpersonation {
|
|
698
|
-
session: string;
|
|
699
|
-
target: string;
|
|
700
|
-
admin: string;
|
|
701
|
-
reason: string;
|
|
702
|
-
started_at: unknown;
|
|
703
|
-
expires_at: unknown;
|
|
704
|
-
}
|
|
705
|
-
type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
706
|
-
type MapColumnType<T extends ColumnSchema> = T['optional'] extends true ? TypeNameToTypeMap[T['type']] | undefined : TypeNameToTypeMap[T['type']];
|
|
707
|
-
type ExtractAccessParams<S extends SchemaStructure, Name extends keyof S['access'], Method extends 'signIn' | 'signup'> = S['access'] extends undefined ? never : S['access'][Name] extends AccessDefinition ? Prettify<{ [K in keyof S['access'][Name][Method]['params']]: MapColumnType<S['access'][Name][Method]['params'][K]> }> : never;
|
|
708
|
-
declare class AuthService<S extends SchemaStructure> {
|
|
709
|
-
private schema;
|
|
710
|
-
private remote;
|
|
711
|
-
private persistenceClient;
|
|
712
|
-
private logger;
|
|
713
|
-
token: string | null;
|
|
714
|
-
currentUser: any | null;
|
|
715
|
-
isAuthenticated: boolean;
|
|
716
|
-
/**
|
|
717
|
-
* The record-access method name for the current session (e.g. `"account"`),
|
|
718
|
-
* derived from the token's `AC` claim. Consumed by the in-browser SSP's
|
|
719
|
-
* permission injection so `$access`-gated table predicates resolve locally,
|
|
720
|
-
* mirroring the server's `$access`. Null when logged out.
|
|
721
|
-
*/
|
|
722
|
-
access: string | null;
|
|
723
|
-
isLoading: boolean;
|
|
724
|
-
private events;
|
|
725
|
-
/** The impersonation last announced, for change detection. */
|
|
726
|
-
private announcedImpersonation;
|
|
727
|
-
/** Target of an impersonation that just ended, until the client purges its
|
|
728
|
-
* local bucket (see `consumeEndedImpersonation`). */
|
|
729
|
-
private endedImpersonationTarget;
|
|
730
|
-
private impersonationTimers;
|
|
731
|
-
get eventSystem(): AuthEventSystem;
|
|
732
|
-
constructor(schema: S, remote: RemoteDatabaseService, persistenceClient: PersistenceClient, logger: Logger$1);
|
|
733
|
-
init(): Promise<void>;
|
|
734
|
-
getAccessDefinition<Name extends keyof S['access']>(name: Name): AccessDefinition | undefined;
|
|
735
|
-
/**
|
|
736
|
-
* Subscribe to auth state changes.
|
|
737
|
-
* callback is called immediately with current value and whenever validation status changes.
|
|
738
|
-
*/
|
|
739
|
-
subscribe(cb: (userId: string | null) => void): () => void;
|
|
740
|
-
private notifyListeners;
|
|
741
|
-
/**
|
|
742
|
-
* The impersonation the current session is, or null. Derived from the
|
|
743
|
-
* token in use, so it always describes the identity the server sees.
|
|
744
|
-
*/
|
|
745
|
-
get impersonation(): ImpersonationInfo | null;
|
|
746
|
-
/** Subscribe to impersonation changes; called immediately with the current value. */
|
|
747
|
-
subscribeImpersonation(cb: (info: ImpersonationInfo | null) => void): () => void;
|
|
748
|
-
/**
|
|
749
|
-
* Act as `targetId` (a record id such as `user:abc`). Admins only, and only
|
|
750
|
-
* when the project enabled `impersonation` in sp00ky.yml: the server refuses
|
|
751
|
-
* everything else. `reason` is recorded in the audit log.
|
|
752
|
-
*
|
|
753
|
-
* The admin's session is kept aside and restored by
|
|
754
|
-
* {@link stopImpersonating}. Local data switches to the target's bucket
|
|
755
|
-
* exactly as on a sign-in, and that bucket is removed on stop.
|
|
756
|
-
*/
|
|
757
|
-
impersonate(targetId: string, reason: string): Promise<ImpersonationInfo>;
|
|
758
|
-
/**
|
|
759
|
-
* Return to the admin session. Always leaves the impersonated identity,
|
|
760
|
-
* even when the server cannot be reached: the admin token is restored
|
|
761
|
-
* locally first and verified afterwards, and a rejected admin token ends in
|
|
762
|
-
* a full sign-out rather than staying on the target.
|
|
763
|
-
*/
|
|
764
|
-
stopImpersonating(opts?: {
|
|
765
|
-
serverEnded?: boolean;
|
|
766
|
-
}): Promise<void>;
|
|
767
|
-
/** Re-sign the impersonation token before it expires. */
|
|
768
|
-
renewImpersonation(): Promise<void>;
|
|
769
|
-
/** Users an admin may pick from. Admin-only on the server. */
|
|
770
|
-
searchImpersonationTargets(search: string): Promise<ImpersonationCandidate[]>;
|
|
771
|
-
/** Open impersonation sessions. Admin-only on the server. */
|
|
772
|
-
listActiveImpersonations(): Promise<ActiveImpersonation[]>;
|
|
773
|
-
/**
|
|
774
|
-
* The target of an impersonation that ended, once. The bucket switch calls
|
|
775
|
-
* this after leaving a bucket so it can delete that user's local data.
|
|
776
|
-
*/
|
|
777
|
-
consumeEndedImpersonation(): string | null;
|
|
778
|
-
/**
|
|
779
|
-
* Restore a session from the locally cached JWT, with NO network.
|
|
780
|
-
*
|
|
781
|
-
* This is what makes a warm boot paint instantly and what makes an offline
|
|
782
|
-
* boot possible at all: the token is in local storage, and it already carries
|
|
783
|
-
* both the access method and the `$auth.id` record id. Everything the client
|
|
784
|
-
* needs to route queries (`setCurrentUserId`) and to satisfy `$auth`-gated
|
|
785
|
-
* permission predicates in the in-browser SSP (`setSessionAuth`) is therefore
|
|
786
|
-
* available before a socket exists.
|
|
787
|
-
*
|
|
788
|
-
* The session is OPTIMISTIC: the token is unverified here. `check()` runs
|
|
789
|
-
* afterwards in the background and downgrades to a real sign-out if the
|
|
790
|
-
* server rejects it. Nothing is trusted that the server has not also seen -
|
|
791
|
-
* the local store only ever holds rows the server previously sent.
|
|
792
|
-
*
|
|
793
|
-
* Returns the restored user id, or null when there is no usable token.
|
|
794
|
-
*/
|
|
795
|
-
restoreSessionFromToken(): Promise<string | null>;
|
|
796
|
-
/**
|
|
797
|
-
* Check for existing session and validate
|
|
798
|
-
*/
|
|
799
|
-
check(accessToken?: string): Promise<void>;
|
|
800
|
-
/**
|
|
801
|
-
* The server refused `token`. A refused impersonation token (stopped,
|
|
802
|
-
* expired, or revoked) returns to the admin session instead of signing the
|
|
803
|
-
* admin out; anything else signs out.
|
|
804
|
-
*/
|
|
805
|
-
private rejectToken;
|
|
806
|
-
/**
|
|
807
|
-
* Sign out and clear session. While impersonating this ends the
|
|
808
|
-
* impersonation and signs the admin out too.
|
|
809
|
-
*/
|
|
810
|
-
signOut(): Promise<void>;
|
|
811
|
-
private setSession;
|
|
812
|
-
/** Fallback when the token carries no `AC` claim: if the schema defines
|
|
813
|
-
* exactly one record-access method, assume the session used it. */
|
|
814
|
-
private defaultAccessName;
|
|
815
|
-
signUp<Name extends keyof S['access'] & string>(accessName: Name, params: ExtractAccessParams<S, Name, 'signup'>): Promise<void>;
|
|
816
|
-
signIn<Name extends keyof S['access'] & string>(accessName: Name, params: ExtractAccessParams<S, Name, 'signIn'>): Promise<void>;
|
|
817
|
-
}
|
|
818
|
-
//#endregion
|
|
819
495
|
//#region src/modules/crdt/crdt-field.d.ts
|
|
820
496
|
declare const CURSOR_COLORS: string[];
|
|
821
497
|
declare function cursorColorFromName(name: string): string;
|
|
@@ -2314,6 +1990,8 @@ declare class Sp00kyClient<S extends SchemaStructure> {
|
|
|
2314
1990
|
private readonly config;
|
|
2315
1991
|
readonly auth: AuthService<S>;
|
|
2316
1992
|
readonly streamProcessor: StreamProcessorService;
|
|
1993
|
+
/** Web Push for this browser: subscribe, devices, self-pushes, service worker bridge. */
|
|
1994
|
+
readonly webPush: WebPushModule;
|
|
2317
1995
|
private readonly services;
|
|
2318
1996
|
private readonly env;
|
|
2319
1997
|
private readonly runtime;
|
|
@@ -2457,4 +2135,4 @@ declare function textToHtml(text: string): string;
|
|
|
2457
2135
|
*/
|
|
2458
2136
|
|
|
2459
2137
|
//#endregion
|
|
2460
|
-
export { ActiveImpersonation, AppReleaseHandle, AppReleaseModule, type AppReleaseOptions, type AppReleaseSnapshot, AuthEventSystem, AuthEventTypeMap, AuthEventTypes, AuthService, BLURHASH_IMAGE_EXTENSIONS, type BlobCacheStats, type BlobEntry, type BlobKey, type BlobReadOptions, type BlobUrlLease, type BlurhashEncodeOptions, type BlurhashSetting, BucketHandle, BucketPutOptions, BucketPutResult, CURSOR_COLORS, ConnectionState, CrdtField, CrdtManager, DEFAULT_LOCAL_OP_TIMEOUT_MS, DebounceOptions, EventSubscriptionOptions, type FailedMutationRow as FailedMutation, FeatureFlagHandle, FeatureFlagModule, type FeatureFlagOptions, type FeatureFlagOverride, type FeatureFlagSnapshot, IMPERSONATION_ACCESS, ImpersonationCandidate, ImpersonationInfo, ImpersonationTimerHost, ImpersonationTimers, InlineRow, Level, LocalOpTimeoutError, MATERIALIZATION_SAMPLE_WINDOW, MembershipOutcome, MutationCallback, MutationEvent, MutationEventType, ORIGIN_TOKEN_KEY, PersistenceClient, PhaseStat, PinoTransmit, PreloadOptions, PreloadRefresh, QueryAuthorityCallback, QueryConfig, QueryConfigRecord, QueryHash, QueryState, QueryStatus, QueryStatusCallback, QueryTimeToLive, QueryTimings, QueryUpdateCallback, ReconnectConfig, RecordVersionArray, RecordVersionDiff, RegistrationTimings, RunOptions, SESSION_POLL_MS, ServerViewMeta, Sp00kyClient, Sp00kyClientDeps, Sp00kyConfig, Sp00kyQueryResult, Sp00kyQueryResultPromise, StorageHealth, StorageHealthStatus, StoreType, SyncHealth, SyncHealthConfig, SyncHealthStatus, TimingPhase, TokenClaims, UpdateOptions, blurhashSidecarPath, bucketContentToBlob, createAuthEventSystem, cursorColorFromName, decode as decodeBlurhash, decodeTokenClaims, encode as encodeBlurhash, encodeImageToBlurhash, fileToUint8Array, impersonationFromToken, isBlurhashValid, isImagePath, renewDelayMs, sameImpersonation, semverGt, textToHtml };
|
|
2138
|
+
export { ActiveImpersonation, AppReleaseHandle, AppReleaseModule, type AppReleaseOptions, type AppReleaseSnapshot, AuthEventSystem, AuthEventTypeMap, AuthEventTypes, AuthService, BLURHASH_IMAGE_EXTENSIONS, type BlobCacheStats, type BlobEntry, type BlobKey, type BlobReadOptions, type BlobUrlLease, type BlurhashEncodeOptions, type BlurhashSetting, type BridgeSignOutMessage, type BridgeTokenMessage, BucketHandle, BucketPutOptions, BucketPutResult, CURSOR_COLORS, ConnectionState, CrdtField, CrdtManager, DEFAULT_LOCAL_OP_TIMEOUT_MS, DebounceOptions, EventSubscriptionOptions, type FailedMutationRow as FailedMutation, FeatureFlagHandle, FeatureFlagModule, type FeatureFlagOptions, type FeatureFlagOverride, type FeatureFlagSnapshot, IMPERSONATION_ACCESS, ImpersonationCandidate, ImpersonationInfo, ImpersonationTimerHost, ImpersonationTimers, InlineRow, Level, LocalOpTimeoutError, MATERIALIZATION_SAMPLE_WINDOW, MembershipOutcome, MutationCallback, MutationEvent, MutationEventType, ORIGIN_TOKEN_KEY, PUSH_ENDPOINT_KEY, PUSH_PAYLOAD_VERSION, PersistenceClient, PhaseStat, PinoTransmit, PreloadOptions, PreloadRefresh, type PushNotification, type PushNotificationAction, type PushOp, type PushPayload, type PushPayloadKind, type PushUrgency, QueryAuthorityCallback, QueryConfig, QueryConfigRecord, QueryHash, QueryState, QueryStatus, QueryStatusCallback, QueryTimeToLive, QueryTimings, QueryUpdateCallback, ReconnectConfig, RecordVersionArray, RecordVersionDiff, RegistrationTimings, RunOptions, SESSION_POLL_MS, SIGN_OUT_HOOK_TIMEOUT_MS, ServerViewMeta, SignOutContext, SignOutHook, Sp00kyClient, Sp00kyClientDeps, Sp00kyConfig, Sp00kyQueryResult, Sp00kyQueryResultPromise, StorageHealth, StorageHealthStatus, StoreType, SyncHealth, SyncHealthConfig, SyncHealthStatus, TimingPhase, TokenClaims, UpdateOptions, type WebPushClientMessage, type WebPushConfig, type WebPushDevice, WebPushError, type WebPushErrorCode, type WebPushInfo, type WebPushMessage, type WebPushMessageInput, WebPushModule, type WebPushSubscribeOptions, type WebPushSupport, type WebPushSyncOptions, type WebPushSyncStatus, type WebPushUnsubscribeOptions, type WebPushUnsupportedReason, type WebPushUpdateOptions, blurhashSidecarPath, bucketContentToBlob, createAuthEventSystem, cursorColorFromName, decode as decodeBlurhash, decodeTokenClaims, detectWebPushSupport, encode as encodeBlurhash, encodeImageToBlurhash, fileToUint8Array, impersonationFromToken, isBlurhashValid, isImagePath, isPushPayload, renewDelayMs, sameImpersonation, semverGt, textToHtml };
|