@korajs/server 1.0.0-beta.13 → 1.0.0-beta.14
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/{chunk-IRRXJ7YN.js → chunk-UKWG5T6J.js} +1 -1
- package/dist/chunk-UKWG5T6J.js.map +1 -0
- package/dist/index.cjs +1203 -379
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +416 -14
- package/dist/index.d.ts +416 -14
- package/dist/index.js +1001 -181
- package/dist/index.js.map +1 -1
- package/dist/{server-backup-WBIYHWYQ.js → server-backup-KITNPMZJ.js} +2 -2
- package/package.json +5 -4
- package/dist/chunk-IRRXJ7YN.js.map +0 -1
- /package/dist/{server-backup-WBIYHWYQ.js.map → server-backup-KITNPMZJ.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -402,6 +402,17 @@ interface ServerStore extends SyncStore {
|
|
|
402
402
|
* for custom stores; the built-in stores persist the claim.
|
|
403
403
|
*/
|
|
404
404
|
claimNode?(nodeId: string, userId: string): Promise<boolean>;
|
|
405
|
+
/**
|
|
406
|
+
* Atomically claim a node id that has no real owner for `userId` (F1): a node
|
|
407
|
+
* with operation history but no claim (written before node claims existed, by a
|
|
408
|
+
* beta.12 or older server) or one an admin released (owner `''`). A node another
|
|
409
|
+
* principal owns is never taken. One statement, so there is no gap between a
|
|
410
|
+
* release and a claim another claimant could slip into. Returns true when
|
|
411
|
+
* `userId` owns the node afterwards. The server calls it only for a node whose id
|
|
412
|
+
* equals the device id the auth provider verified for that user. Optional for
|
|
413
|
+
* custom stores; without it such nodes stay refused until an admin binds them.
|
|
414
|
+
*/
|
|
415
|
+
claimUnownedNode?(nodeId: string, userId: string): Promise<boolean>;
|
|
405
416
|
/**
|
|
406
417
|
* Admin release of a node id (RT-5): the next principal to claim it takes it
|
|
407
418
|
* over, even when the node has operation history. Returns true when the node had
|
|
@@ -1161,6 +1172,18 @@ declare class KoraSyncServer {
|
|
|
1161
1172
|
private readonly logger;
|
|
1162
1173
|
private readonly metrics;
|
|
1163
1174
|
private readonly awarenessRelay;
|
|
1175
|
+
/** Reads the records presence cursors name, for every session (F16). */
|
|
1176
|
+
private readonly presenceRecords;
|
|
1177
|
+
/** The record each session's current presence cursor names (F16). */
|
|
1178
|
+
private readonly presenceTargets;
|
|
1179
|
+
/** The sessions whose presence cursor names each record, by record key. */
|
|
1180
|
+
private readonly presenceTargetsByKey;
|
|
1181
|
+
/**
|
|
1182
|
+
* Audience re-decisions running, one per record: a write while one runs marks it
|
|
1183
|
+
* dirty, so it reads again and the last decision applied is always from a read that
|
|
1184
|
+
* began after the last write (never an older read finishing late).
|
|
1185
|
+
*/
|
|
1186
|
+
private readonly presenceRefreshes;
|
|
1164
1187
|
private readonly yjsDocRelay;
|
|
1165
1188
|
private readonly blobChunkRelay;
|
|
1166
1189
|
/** Wrapped encryption key records (ENC-1, D4b), persisted in the server store. */
|
|
@@ -1173,8 +1196,11 @@ declare class KoraSyncServer {
|
|
|
1173
1196
|
/** Per-principal ingest budget per minute; 0 when disabled. */
|
|
1174
1197
|
private readonly maxOpsPerMinutePerUser;
|
|
1175
1198
|
private readonly allowLegacyAnonymousClaims;
|
|
1199
|
+
private readonly deviceNodeHandover;
|
|
1200
|
+
private readonly unscopedSharing;
|
|
1176
1201
|
private readonly anonymousClaimTtlMs;
|
|
1177
1202
|
private readonly maxOpsPerBatch;
|
|
1203
|
+
private readonly maxScopePredicateValues;
|
|
1178
1204
|
private readonly maxMessageBytes;
|
|
1179
1205
|
private readonly heartbeatIntervalMs;
|
|
1180
1206
|
private readonly appHeartbeatIntervalMs;
|
|
@@ -1309,6 +1335,35 @@ declare class KoraSyncServer {
|
|
|
1309
1335
|
* ```
|
|
1310
1336
|
*/
|
|
1311
1337
|
revalidateSessions(): Promise<number>;
|
|
1338
|
+
/**
|
|
1339
|
+
* Re-resolve one user's grant on every live session of that user now, instead of
|
|
1340
|
+
* waiting for the next revalidation pass (`sessionRevalidationIntervalMs`). Call it
|
|
1341
|
+
* after a membership change the auth provider's grant depends on: an invitation
|
|
1342
|
+
* accepted, a collaborator removed, a role changed.
|
|
1343
|
+
*
|
|
1344
|
+
* Each of the user's sessions re-authenticates its credential with the provider. A
|
|
1345
|
+
* session whose resolved download or upload scope changed ends with a retriable
|
|
1346
|
+
* `SCOPE_CHANGED`; its client reconnects at once and receives the new grant. A
|
|
1347
|
+
* narrowed grant applies the client's `scopeExit` policy at that handshake
|
|
1348
|
+
* (`'retract'` hides the rows that left the scope), and the device's unsynced writes
|
|
1349
|
+
* outside the new upload scope are refused. A session still in its handshake
|
|
1350
|
+
* re-checks as soon as it is established, so a grant read before the change never
|
|
1351
|
+
* outlives this call. Sessions whose grant did not change are kept.
|
|
1352
|
+
*
|
|
1353
|
+
* Only this process's sessions are refreshed. Other instances apply the change at
|
|
1354
|
+
* their next revalidation pass, or call this too (for example from a pub/sub
|
|
1355
|
+
* message).
|
|
1356
|
+
*
|
|
1357
|
+
* @param userId - The user whose grant changed (the auth provider's `userId`)
|
|
1358
|
+
* @returns The number of sessions this call ended
|
|
1359
|
+
*
|
|
1360
|
+
* @example
|
|
1361
|
+
* ```typescript
|
|
1362
|
+
* await removeCollaborator(documentId, bobId)
|
|
1363
|
+
* await server.refreshScopes(bobId)
|
|
1364
|
+
* ```
|
|
1365
|
+
*/
|
|
1366
|
+
refreshScopes(userId: string): Promise<number>;
|
|
1312
1367
|
/** Run {@link revalidateSessions} from the delivery poll tick once the interval elapsed. */
|
|
1313
1368
|
private maybeRevalidateSessions;
|
|
1314
1369
|
/**
|
|
@@ -1504,6 +1559,31 @@ declare class KoraSyncServer {
|
|
|
1504
1559
|
private handleRelay;
|
|
1505
1560
|
private handleSessionClose;
|
|
1506
1561
|
private handleAwarenessRelay;
|
|
1562
|
+
/** Point a session's presence at a record (or at none), keeping the index in step. */
|
|
1563
|
+
private setPresenceTarget;
|
|
1564
|
+
/**
|
|
1565
|
+
* Records changed (`operations`, or anything when null): re-decide the audience of
|
|
1566
|
+
* every presence cursor on one of them (F16). A record that moved out of a session's
|
|
1567
|
+
* grant takes the presence on it out of that session, and one that moved in brings
|
|
1568
|
+
* it, without waiting for the sender's next update; catch-ups use the new audience.
|
|
1569
|
+
* Every write is noted first, so a presence read that began before it is never
|
|
1570
|
+
* taken as current.
|
|
1571
|
+
*/
|
|
1572
|
+
private refreshPresence;
|
|
1573
|
+
/** Re-decide the presence on one record, coalesced with a re-decision already running. */
|
|
1574
|
+
private schedulePresenceRefresh;
|
|
1575
|
+
private runPresenceRefresh;
|
|
1576
|
+
/**
|
|
1577
|
+
* Who may see a presence state (F16). A state whose cursor names a record reaches
|
|
1578
|
+
* exactly the sessions whose download scope contains that record, the rule of the
|
|
1579
|
+
* Yjs doc channel, and only when the sender may read the record too: collaborators
|
|
1580
|
+
* with different grants see each other on the documents they share, and nobody
|
|
1581
|
+
* sees presence on a record outside their grant. A malformed cursor reaches
|
|
1582
|
+
* nobody. A state without a cursor names no record: it reaches only sessions of
|
|
1583
|
+
* the same presence partition (identical download scope; anonymous sessions are
|
|
1584
|
+
* each their own partition).
|
|
1585
|
+
*/
|
|
1586
|
+
private awarenessAudience;
|
|
1507
1587
|
private handleYjsDocRelay;
|
|
1508
1588
|
/** Open a new HTTP long-poll session bound to `principal`, under a fresh random id. */
|
|
1509
1589
|
private openHttpSession;
|
|
@@ -1936,6 +2016,14 @@ interface KoraSyncServerConfig {
|
|
|
1936
2016
|
* sends batches of 100 by default).
|
|
1937
2017
|
*/
|
|
1938
2018
|
maxOpsPerBatch?: number;
|
|
2019
|
+
/**
|
|
2020
|
+
* Most values one `$in` scope predicate may hold, in either direction. A grant
|
|
2021
|
+
* with more is refused at handshake with `SCOPE_PREDICATE_LIMIT`, so an auth
|
|
2022
|
+
* provider bug cannot hand one session an unbounded predicate that every delivery
|
|
2023
|
+
* and revalidation then evaluates. Defaults to 100. See the production server
|
|
2024
|
+
* guide for the measured cost of larger values before raising it.
|
|
2025
|
+
*/
|
|
2026
|
+
maxScopePredicateValues?: number;
|
|
1939
2027
|
/**
|
|
1940
2028
|
* Accept anonymous devices whose node claim predates confirmed claims (RT-21):
|
|
1941
2029
|
* nodes whose operation history predates node claims (a database written by a
|
|
@@ -1953,6 +2041,29 @@ interface KoraSyncServerConfig {
|
|
|
1953
2041
|
* devices syncing.
|
|
1954
2042
|
*/
|
|
1955
2043
|
allowLegacyAnonymousClaims?: boolean;
|
|
2044
|
+
/**
|
|
2045
|
+
* Automatic device handover after an upgrade from beta.12 (F1). When a signed-in
|
|
2046
|
+
* device presents a node id that has operation history but no owner (beta.12
|
|
2047
|
+
* recorded no node claims) or that an administrator released, and the node id
|
|
2048
|
+
* equals the device id the auth provider verified for that user
|
|
2049
|
+
* (`AuthContext.metadata.deviceId`, set by the built-in `KoraAuthProvider` from the
|
|
2050
|
+
* token), the node is claimed for that user in one atomic step instead of being
|
|
2051
|
+
* refused `NODE_ID_CLAIMED`. A node another principal owns is never taken.
|
|
2052
|
+
* Defaults to `true`. A custom auth provider must set `metadata.deviceId` only to
|
|
2053
|
+
* a device id it verified as registered to the user; set this to `false` if yours
|
|
2054
|
+
* cannot guarantee that.
|
|
2055
|
+
*/
|
|
2056
|
+
deviceNodeHandover?: boolean;
|
|
2057
|
+
/**
|
|
2058
|
+
* What to do when a signed-in session's grant restricts no collection, so every user
|
|
2059
|
+
* syncs every other user's data (F4). That happens when the auth provider returns
|
|
2060
|
+
* a claims grant (the built-in provider's default) and the schema declares no sync
|
|
2061
|
+
* rule binding it, or when a provider returns no scopes. `'warn'` (default) logs it
|
|
2062
|
+
* once per provider; `'allow'` silences it for apps whose users all share one data
|
|
2063
|
+
* set; `'refuse'` refuses such handshakes with `UNSCOPED_SHARING_REFUSED`.
|
|
2064
|
+
* Anonymous sessions are not judged: their grant is the app's own choice.
|
|
2065
|
+
*/
|
|
2066
|
+
unscopedSharing?: 'warn' | 'allow' | 'refuse';
|
|
1956
2067
|
/**
|
|
1957
2068
|
* How long an anonymous device's provisional node claim may stay unconfirmed and
|
|
1958
2069
|
* still be re-issued to a device that presents no token (a handshake response lost
|
|
@@ -2129,6 +2240,78 @@ declare class HttpServerTransport implements ServerTransport {
|
|
|
2129
2240
|
private makeEtag;
|
|
2130
2241
|
}
|
|
2131
2242
|
|
|
2243
|
+
/** One read of a record for a presence decision. */
|
|
2244
|
+
interface PresenceRecordRead {
|
|
2245
|
+
/** The stored row (soft-deleted rows included), or null when the server holds none */
|
|
2246
|
+
stored: MaterializedRecord | null;
|
|
2247
|
+
/**
|
|
2248
|
+
* The reader's clock when the read began. A write that touched the record after
|
|
2249
|
+
* it ({@link PresenceRecords.touchedSince}) means the row may predate that write.
|
|
2250
|
+
*/
|
|
2251
|
+
asOf: number;
|
|
2252
|
+
}
|
|
2253
|
+
/**
|
|
2254
|
+
* Reads the records presence cursors name, for every session of one sync server (F16).
|
|
2255
|
+
*
|
|
2256
|
+
* Presence decides who may see a cursor from the record it names, so the row must be
|
|
2257
|
+
* the store's latest, never a copy another code path holds (a session's delivery
|
|
2258
|
+
* pass caches rows for the whole chunk it filters). Every write the server commits
|
|
2259
|
+
* {@link touch}es the records it wrote; a read is current when no touch of its record
|
|
2260
|
+
* came after it began. Reads of one record are shared while current (many cursors on
|
|
2261
|
+
* one busy document cost one read per write burst, not one per cursor per write), a
|
|
2262
|
+
* read is never shared across a touch, and reads are bounded in number at once.
|
|
2263
|
+
*
|
|
2264
|
+
* Presence is ephemeral and nothing here is persisted.
|
|
2265
|
+
*/
|
|
2266
|
+
declare class PresenceRecords {
|
|
2267
|
+
private readonly store;
|
|
2268
|
+
private readonly now;
|
|
2269
|
+
private clock;
|
|
2270
|
+
/** The clock value of each tracked record's last touch, oldest first. */
|
|
2271
|
+
private readonly lastTouch;
|
|
2272
|
+
/** Touches forgotten to bound memory count as having happened at this clock. */
|
|
2273
|
+
private forgottenTouchesAt;
|
|
2274
|
+
private readonly inFlight;
|
|
2275
|
+
private readonly cache;
|
|
2276
|
+
private running;
|
|
2277
|
+
private readonly waiting;
|
|
2278
|
+
constructor(store: ServerStore, now?: () => number);
|
|
2279
|
+
/**
|
|
2280
|
+
* Record that writes to these records committed: reads that began before are no
|
|
2281
|
+
* longer current. Null means any record may have changed.
|
|
2282
|
+
*
|
|
2283
|
+
* @param keys - Record keys from {@link presenceRecordKey}, or null for every record
|
|
2284
|
+
*/
|
|
2285
|
+
touch(keys: Iterable<string> | null): void;
|
|
2286
|
+
/**
|
|
2287
|
+
* True when a write touched the record after a read that began at `asOf`.
|
|
2288
|
+
*
|
|
2289
|
+
* @param key - Record key from {@link presenceRecordKey}
|
|
2290
|
+
* @param asOf - The read's {@link PresenceRecordRead.asOf}
|
|
2291
|
+
*/
|
|
2292
|
+
touchedSince(key: string, asOf: number): boolean;
|
|
2293
|
+
/**
|
|
2294
|
+
* A current read of the record that is still fresh enough to reuse, without a store
|
|
2295
|
+
* read; undefined when the record must be read.
|
|
2296
|
+
*
|
|
2297
|
+
* @param collection - The record's collection
|
|
2298
|
+
* @param recordId - The record's id
|
|
2299
|
+
*/
|
|
2300
|
+
peek(collection: string, recordId: string): PresenceRecordRead | undefined;
|
|
2301
|
+
/**
|
|
2302
|
+
* Read the record from the store, joining a read of it already running when no
|
|
2303
|
+
* write touched the record since that read began. Rejects when the store read fails.
|
|
2304
|
+
*
|
|
2305
|
+
* @param collection - The record's collection
|
|
2306
|
+
* @param recordId - The record's id
|
|
2307
|
+
*/
|
|
2308
|
+
read(collection: string, recordId: string): Promise<PresenceRecordRead>;
|
|
2309
|
+
/** Forget every read and touch (the server stopped). */
|
|
2310
|
+
clear(): void;
|
|
2311
|
+
private readStore;
|
|
2312
|
+
private forget;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2132
2315
|
/** Outcome of one key-service message. */
|
|
2133
2316
|
interface KeyServiceOutcome {
|
|
2134
2317
|
response: EncryptionKeyResponseMessage;
|
|
@@ -2207,7 +2390,23 @@ type RelayCallback = (sourceSessionId: string, operations: Operation[]) => void;
|
|
|
2207
2390
|
/**
|
|
2208
2391
|
* Callback invoked when a session receives an awareness update to relay to other sessions.
|
|
2209
2392
|
*/
|
|
2210
|
-
type AwarenessRelayCallback = (sourceSessionId: string, message: AwarenessUpdateMessage) => void;
|
|
2393
|
+
type AwarenessRelayCallback = (sourceSessionId: string, message: AwarenessUpdateMessage, cursorTarget?: AwarenessCursorTarget) => void;
|
|
2394
|
+
/**
|
|
2395
|
+
* The record an awareness state's cursor names, as the sending session resolved it
|
|
2396
|
+
* from the store. `stored` is null for a record the server does not hold. A cursor
|
|
2397
|
+
* that is not a `{ collection, recordId }` pair of strings is `{ invalid: true }`;
|
|
2398
|
+
* a state without a cursor has no target.
|
|
2399
|
+
*/
|
|
2400
|
+
type AwarenessCursorTarget = {
|
|
2401
|
+
invalid?: false;
|
|
2402
|
+
collection: string;
|
|
2403
|
+
recordId: string;
|
|
2404
|
+
stored: MaterializedRecord | null;
|
|
2405
|
+
/** When the read of `stored` began, on the server's presence reader clock. */
|
|
2406
|
+
asOf?: number;
|
|
2407
|
+
} | {
|
|
2408
|
+
invalid: true;
|
|
2409
|
+
};
|
|
2211
2410
|
/**
|
|
2212
2411
|
* Callback invoked when a session receives a Yjs doc channel update to relay.
|
|
2213
2412
|
*/
|
|
@@ -2259,6 +2458,11 @@ interface ClientSessionOptions {
|
|
|
2259
2458
|
onRelay?: RelayCallback;
|
|
2260
2459
|
/** Called when this session receives an awareness update to broadcast */
|
|
2261
2460
|
onAwarenessUpdate?: AwarenessRelayCallback;
|
|
2461
|
+
/**
|
|
2462
|
+
* The reader of the records presence cursors name, shared by the server's sessions
|
|
2463
|
+
* (F16). Defaults to one of this session's own.
|
|
2464
|
+
*/
|
|
2465
|
+
presenceRecords?: PresenceRecords;
|
|
2262
2466
|
/** Called when this session receives a Yjs doc channel update to broadcast */
|
|
2263
2467
|
onYjsDocUpdate?: YjsDocRelayCallback;
|
|
2264
2468
|
/** Called when this session receives a blob chunk request to route */
|
|
@@ -2314,6 +2518,12 @@ interface ClientSessionOptions {
|
|
|
2314
2518
|
* (`BATCH_TOO_LARGE`) before it is decoded or the store is read. Defaults to 1000.
|
|
2315
2519
|
*/
|
|
2316
2520
|
maxOpsPerBatch?: number;
|
|
2521
|
+
/**
|
|
2522
|
+
* Most values one `$in` scope predicate may hold. A grant over the limit is
|
|
2523
|
+
* refused at handshake (`SCOPE_PREDICATE_LIMIT`). Defaults to
|
|
2524
|
+
* {@link DEFAULT_MAX_SCOPE_PREDICATE_VALUES} (100).
|
|
2525
|
+
*/
|
|
2526
|
+
maxScopePredicateValues?: number;
|
|
2317
2527
|
/**
|
|
2318
2528
|
* Adjudicate untrusted client operations before materialization. When present,
|
|
2319
2529
|
* each incoming operation is passed to this validator; a `reject` decision
|
|
@@ -2330,6 +2540,10 @@ interface ClientSessionOptions {
|
|
|
2330
2540
|
blobAccess?: BlobAccessIndex;
|
|
2331
2541
|
/** See `KoraSyncServerConfig.allowLegacyAnonymousClaims` (RT-21). Defaults to true. */
|
|
2332
2542
|
allowLegacyAnonymousClaims?: boolean;
|
|
2543
|
+
/** See `KoraSyncServerConfig.deviceNodeHandover` (F1). Defaults to true. */
|
|
2544
|
+
deviceNodeHandover?: boolean;
|
|
2545
|
+
/** See `KoraSyncServerConfig.unscopedSharing` (F4). Defaults to `'warn'`. */
|
|
2546
|
+
unscopedSharing?: 'warn' | 'allow' | 'refuse';
|
|
2333
2547
|
/** See `KoraSyncServerConfig.anonymousClaimTtlMs` (RT-21). Defaults to 24 hours. */
|
|
2334
2548
|
anonymousClaimTtlMs?: number;
|
|
2335
2549
|
/**
|
|
@@ -2419,6 +2633,8 @@ declare class ClientSession {
|
|
|
2419
2633
|
/** A provisional anonymous claim awaiting the device's confirmation (RT-21). */
|
|
2420
2634
|
private pendingNodeClaim;
|
|
2421
2635
|
private readonly allowLegacyAnonymousClaims;
|
|
2636
|
+
private readonly deviceNodeHandover;
|
|
2637
|
+
private readonly unscopedSharing;
|
|
2422
2638
|
private readonly anonymousClaimTtlMs;
|
|
2423
2639
|
private readonly isNodeLive;
|
|
2424
2640
|
/** The credential presented at handshake, kept to re-validate the session (RT-18). */
|
|
@@ -2491,7 +2707,6 @@ declare class ClientSession {
|
|
|
2491
2707
|
* `collection\u0000id`; null marks a record known to be absent. Only set while a
|
|
2492
2708
|
* chunk is filtered.
|
|
2493
2709
|
*/
|
|
2494
|
-
private recordLookupCache;
|
|
2495
2710
|
private readonly deliveryHighWaterBytes;
|
|
2496
2711
|
private readonly handshakeTimeoutMs;
|
|
2497
2712
|
private handshakeTimer;
|
|
@@ -2542,6 +2757,15 @@ declare class ClientSession {
|
|
|
2542
2757
|
private readonly maxOperationBytes;
|
|
2543
2758
|
private readonly maxOpsPerMinute;
|
|
2544
2759
|
private readonly maxOpsPerBatch;
|
|
2760
|
+
private readonly maxScopePredicateValues;
|
|
2761
|
+
/** {@link getScopePartitionKey}, cached for the scope map it was computed from. */
|
|
2762
|
+
private scopePartitionKeyCache;
|
|
2763
|
+
/** Store reads for presence cursors (F16), per minute. */
|
|
2764
|
+
private readonly presenceLookupLimiter;
|
|
2765
|
+
/** Reads the records presence cursors name (shared by the server's sessions). */
|
|
2766
|
+
private readonly presenceRecords;
|
|
2767
|
+
/** A {@link refreshScopes} request arrived during the handshake: re-check once streaming. */
|
|
2768
|
+
private scopeRefreshPending;
|
|
2545
2769
|
private rateLimiter;
|
|
2546
2770
|
/** Separate budget for blob chunk requests (RT-24). */
|
|
2547
2771
|
private readonly blobRateLimiter;
|
|
@@ -2689,6 +2913,22 @@ declare class ClientSession {
|
|
|
2689
2913
|
* provider threw (nothing is ended; the caller retries later), else `'valid'`
|
|
2690
2914
|
*/
|
|
2691
2915
|
revalidateCredential(): Promise<'valid' | 'terminated' | 'error'>;
|
|
2916
|
+
/**
|
|
2917
|
+
* Re-resolve this session's grant on request (`KoraSyncServer.refreshScopes`), for
|
|
2918
|
+
* the user named. A streaming session whose principal is that user re-authenticates
|
|
2919
|
+
* now and ends with a retriable `SCOPE_CHANGED` when its grant changed (or
|
|
2920
|
+
* `AUTH_REVOKED` when the credential is no longer accepted). A session still in its
|
|
2921
|
+
* handshake may have resolved its grant from membership read before the change, so
|
|
2922
|
+
* it re-checks as soon as it reaches streaming; a session whose principal is not
|
|
2923
|
+
* known yet does the same (the re-check is a no-op for a grant that did not change).
|
|
2924
|
+
*
|
|
2925
|
+
* @param userId - The user whose grant changed
|
|
2926
|
+
* @returns The revalidation outcome, `'deferred'` when the check waits for the
|
|
2927
|
+
* handshake, or `'skipped'` for another user's (or a closed) session
|
|
2928
|
+
*/
|
|
2929
|
+
refreshScopes(userId: string): Promise<'valid' | 'terminated' | 'error' | 'deferred' | 'skipped'>;
|
|
2930
|
+
/** Run a re-check deferred by {@link refreshScopes} once the session streams. */
|
|
2931
|
+
private runDeferredScopeRefresh;
|
|
2692
2932
|
/**
|
|
2693
2933
|
* True when `context` (a fresh authentication of this session's principal)
|
|
2694
2934
|
* resolves to download or upload scopes other than the ones this session holds.
|
|
@@ -2751,14 +2991,21 @@ declare class ClientSession {
|
|
|
2751
2991
|
* not stored yet is judged by its id alone.
|
|
2752
2992
|
*/
|
|
2753
2993
|
canReceiveRecord(collection: string, recordId: string, storedRecord: Record<string, unknown> | null): boolean;
|
|
2754
|
-
/**
|
|
2755
|
-
* A stable key for this session's download scope. Presence (awareness) is only
|
|
2756
|
-
* relayed between sessions that share exactly the same key, so it never crosses a
|
|
2757
|
-
* tenant boundary. Unscoped sessions share the key `"*"`.
|
|
2758
|
-
*/
|
|
2759
2994
|
/** This session's download scope, or undefined when it is unscoped. */
|
|
2760
2995
|
getDownlinkScopes(): ScopeMap | undefined;
|
|
2996
|
+
/**
|
|
2997
|
+
* A stable key for this session's download scope: sessions with the same key see
|
|
2998
|
+
* exactly the same data. Unscoped sessions share the key `"*"`. Cached per scope
|
|
2999
|
+
* map, since a large `$in` grant makes the key costly and the relays read it often.
|
|
3000
|
+
*/
|
|
2761
3001
|
getScopePartitionKey(): string;
|
|
3002
|
+
/**
|
|
3003
|
+
* Partition for presence without a cursor (a "who is online" state that names no
|
|
3004
|
+
* record): only sessions with the same key see each other's. Signed-in sessions
|
|
3005
|
+
* use their download scope key; every anonymous session is its own partition,
|
|
3006
|
+
* because sessions holding the same anonymous grant are unrelated people.
|
|
3007
|
+
*/
|
|
3008
|
+
getPresencePartitionKey(): string;
|
|
2762
3009
|
/**
|
|
2763
3010
|
* Get the transport for this session.
|
|
2764
3011
|
* Used by the awareness relay to send messages to this client.
|
|
@@ -2801,6 +3048,32 @@ declare class ClientSession {
|
|
|
2801
3048
|
* are re-issued only with `allowLegacyAnonymousClaims`, with a deprecation warning.
|
|
2802
3049
|
*/
|
|
2803
3050
|
private claimAnonymousNode;
|
|
3051
|
+
/**
|
|
3052
|
+
* Automatic device handover after an upgrade from beta.12 (F1). A node with
|
|
3053
|
+
* history but no owner (written before node claims existed) or released by an
|
|
3054
|
+
* admin is claimed for the signed-in user when the node id IS the device id the
|
|
3055
|
+
* auth provider verified for this credential (`metadata.deviceId`; the built-in
|
|
3056
|
+
* provider takes it from the token's `dev` claim, which names a device registered
|
|
3057
|
+
* to that user). `@korajs/auth` clients use that device id as their node id and
|
|
3058
|
+
* cannot change it, so without this they stay refused until an operator binds the
|
|
3059
|
+
* node. The claim is one atomic store step; a node another principal owns is never
|
|
3060
|
+
* taken, and another user presenting the node id is still refused.
|
|
3061
|
+
*
|
|
3062
|
+
* The claim decides ownership from now on only. History written under the node on
|
|
3063
|
+
* beta.12 may include operations another user forged (beta.12 did not verify node
|
|
3064
|
+
* ids); the operation log integrity scan is the tool for auditing it.
|
|
3065
|
+
*/
|
|
3066
|
+
private handOverDeviceNode;
|
|
3067
|
+
/**
|
|
3068
|
+
* The download grant the server itself gives this session, before the client's
|
|
3069
|
+
* handshake scope narrows it (F4). A client may narrow its own view, but that does
|
|
3070
|
+
* not isolate tenants: another client of the same user set can ask for everything.
|
|
3071
|
+
* `null` when the grant cannot be resolved here (the handshake already refused or
|
|
3072
|
+
* accepted it on the full path); then nothing is judged.
|
|
3073
|
+
*/
|
|
3074
|
+
private grantWithoutHandshakeNarrowing;
|
|
3075
|
+
/** Who holds a refused node id, as `NODE_ID_CLAIMED` reports it (F9). */
|
|
3076
|
+
private nodeOwnershipOf;
|
|
2804
3077
|
/** The deprecation warning for an anonymous device adopted under a legacy claim (RT-21, RT-91). */
|
|
2805
3078
|
private warnLegacyAnonymousClaim;
|
|
2806
3079
|
/**
|
|
@@ -3089,8 +3362,15 @@ declare class ClientSession {
|
|
|
3089
3362
|
* query-subset backfill. Includes soft-deleted rows so a relayed delete (whose op
|
|
3090
3363
|
* carries no fields) is still judged against the record's actual scope. Returns
|
|
3091
3364
|
* undefined when the record cannot be read (never materialized, or no schema).
|
|
3365
|
+
* `rows` are the rows one delivery pass prefetched for its own decisions.
|
|
3092
3366
|
*/
|
|
3093
3367
|
private lookupRecordFields;
|
|
3368
|
+
/**
|
|
3369
|
+
* Hand an awareness update to the server's relay, with the record its cursor
|
|
3370
|
+
* names, read from the store, so the relay can deliver it only to sessions whose
|
|
3371
|
+
* download scope contains that record (the rule of the Yjs doc channel).
|
|
3372
|
+
* Awareness is purely ephemeral: nothing is persisted.
|
|
3373
|
+
*/
|
|
3094
3374
|
private handleAwarenessUpdate;
|
|
3095
3375
|
/**
|
|
3096
3376
|
* A Yjs doc-channel update is a write to a richtext field: the sender must be
|
|
@@ -3112,6 +3392,54 @@ declare class ClientSession {
|
|
|
3112
3392
|
private handleTransportClose;
|
|
3113
3393
|
}
|
|
3114
3394
|
|
|
3395
|
+
/** {@link findJsonStringValues} was given a page or sample size it cannot use. */
|
|
3396
|
+
declare class InvalidDiagnosticOptionsError extends KoraError {
|
|
3397
|
+
constructor(option: string, value: unknown);
|
|
3398
|
+
}
|
|
3399
|
+
/** Rows of one json/object field whose stored value is a string that itself holds JSON. */
|
|
3400
|
+
interface JsonStringValueReport {
|
|
3401
|
+
collection: string;
|
|
3402
|
+
field: string;
|
|
3403
|
+
/** How many live rows hold such a string. */
|
|
3404
|
+
count: number;
|
|
3405
|
+
/** Ids of the first such rows, to inspect. */
|
|
3406
|
+
sampleIds: string[];
|
|
3407
|
+
}
|
|
3408
|
+
/** Options for {@link findJsonStringValues}. */
|
|
3409
|
+
interface FindJsonStringValuesOptions {
|
|
3410
|
+
/** Ids reported per field. Defaults to 10. */
|
|
3411
|
+
sampleSize?: number;
|
|
3412
|
+
/** Rows read per page. Defaults to 1,000. */
|
|
3413
|
+
pageSize?: number;
|
|
3414
|
+
}
|
|
3415
|
+
/**
|
|
3416
|
+
* Find `t.json()` / `t.object()` fields whose stored value is a JSON-encoded string
|
|
3417
|
+
* (`'{"a":1}'` instead of `{ a: 1 }`), after an upgrade from a server older than
|
|
3418
|
+
* 1.0.0-beta.13 (F14).
|
|
3419
|
+
*
|
|
3420
|
+
* Servers before beta.13 decoded one JSON-string layer of such values when they built
|
|
3421
|
+
* rows; since beta.13 the rows hold exactly what the operations wrote. A client that
|
|
3422
|
+
* wrote a json field as a string (or double-encoded it) therefore reads back a string
|
|
3423
|
+
* where the old server returned an object. Kora does not rewrite these values: a string
|
|
3424
|
+
* is also a legitimate json value, so no rule can tell a real string from an encoded
|
|
3425
|
+
* object. Fix them with server-authored updates (`server.kora.apply`) once you know
|
|
3426
|
+
* which shape your app expects.
|
|
3427
|
+
*
|
|
3428
|
+
* @param store - The server store, with its schema set
|
|
3429
|
+
* @param options - Sample and page sizes
|
|
3430
|
+
* @returns One report per field that holds at least one such value
|
|
3431
|
+
* @throws {InvalidDiagnosticOptionsError} When `pageSize` is not a positive integer or
|
|
3432
|
+
* `sampleSize` not a non-negative one
|
|
3433
|
+
*
|
|
3434
|
+
* @example
|
|
3435
|
+
* ```typescript
|
|
3436
|
+
* for (const report of await findJsonStringValues(store)) {
|
|
3437
|
+
* console.warn(`${report.collection}.${report.field}: ${report.count} rows`, report.sampleIds)
|
|
3438
|
+
* }
|
|
3439
|
+
* ```
|
|
3440
|
+
*/
|
|
3441
|
+
declare function findJsonStringValues(store: ServerStore, options?: FindJsonStringValuesOptions): Promise<JsonStringValueReport[]>;
|
|
3442
|
+
|
|
3115
3443
|
/**
|
|
3116
3444
|
* Configuration for the production server that serves both
|
|
3117
3445
|
* static files and WebSocket sync on a single port.
|
|
@@ -3169,6 +3497,13 @@ interface ProductionServerConfig {
|
|
|
3169
3497
|
* Largest backup accepted by `/__kora/backup/import`, in bytes. Defaults to 256 MiB.
|
|
3170
3498
|
*/
|
|
3171
3499
|
maxBackupBytes?: number;
|
|
3500
|
+
/**
|
|
3501
|
+
* Which requests for a missing path get the app shell (`index.html`). `'navigation'`
|
|
3502
|
+
* (default): browser navigations only, so a missing API path is a real 404.
|
|
3503
|
+
* `'extensionless'`: also any path without a file extension, for a service worker
|
|
3504
|
+
* that warms app routes with a plain `fetch(url)`. Never under `/assets/`.
|
|
3505
|
+
*/
|
|
3506
|
+
spaFallback?: 'navigation' | 'extensionless';
|
|
3172
3507
|
}
|
|
3173
3508
|
interface ProductionOperationalAuth {
|
|
3174
3509
|
/** Protects /__kora, /__kora/status, and /__kora/events. */
|
|
@@ -3177,6 +3512,14 @@ interface ProductionOperationalAuth {
|
|
|
3177
3512
|
metricsToken?: string;
|
|
3178
3513
|
/** Protects /__kora/backup/*. Falls back to adminToken when omitted. */
|
|
3179
3514
|
backupToken?: string;
|
|
3515
|
+
/**
|
|
3516
|
+
* With `NODE_ENV=production`, an endpoint group whose token is unset is disabled
|
|
3517
|
+
* (`403 OPERATIONAL_ENDPOINT_DISABLED`): backups export or replace every user's data,
|
|
3518
|
+
* and the dashboard lists connected devices. Set this to `true` to serve such groups
|
|
3519
|
+
* without a token anyway (for example behind a network you control). Outside
|
|
3520
|
+
* production, groups without a token stay public, with a startup warning.
|
|
3521
|
+
*/
|
|
3522
|
+
allowPublic?: boolean;
|
|
3180
3523
|
}
|
|
3181
3524
|
interface ProductionHttpRouteRequest {
|
|
3182
3525
|
method: string;
|
|
@@ -3237,6 +3580,25 @@ interface ProductionServer {
|
|
|
3237
3580
|
* @returns Every live blob reference the server can currently see.
|
|
3238
3581
|
*/
|
|
3239
3582
|
getLiveBlobRefs(): Promise<BlobRef[]>;
|
|
3583
|
+
/**
|
|
3584
|
+
* Re-resolve one user's grant on their live sync sessions now. Call it after a
|
|
3585
|
+
* membership change (an invitation accepted, a collaborator removed): a session
|
|
3586
|
+
* whose scope changed ends with a retriable `SCOPE_CHANGED` and its client
|
|
3587
|
+
* reconnects with the new grant, applying its `scopeExit` policy. See
|
|
3588
|
+
* `KoraSyncServer.refreshScopes`.
|
|
3589
|
+
*
|
|
3590
|
+
* @param userId - The user whose grant changed
|
|
3591
|
+
* @returns The number of sessions ended
|
|
3592
|
+
*/
|
|
3593
|
+
refreshScopes(userId: string): Promise<number>;
|
|
3594
|
+
/**
|
|
3595
|
+
* Re-validate every live sync session's credential and grant now (the pass that
|
|
3596
|
+
* otherwise runs every `sessionRevalidationIntervalMs`). See
|
|
3597
|
+
* `KoraSyncServer.revalidateSessions`.
|
|
3598
|
+
*
|
|
3599
|
+
* @returns The number of sessions ended
|
|
3600
|
+
*/
|
|
3601
|
+
revalidateSessions(): Promise<number>;
|
|
3240
3602
|
}
|
|
3241
3603
|
/**
|
|
3242
3604
|
* Creates a production server that serves both static files and WebSocket sync
|
|
@@ -3627,6 +3989,7 @@ declare class MemoryServerStore implements ServerStore {
|
|
|
3627
3989
|
listEncryptionKeyRecords(owner?: string): Promise<EncryptionKeyRecordRow[]>;
|
|
3628
3990
|
getEncryptedKeyIds(nodeOwner: string | null, limit: number): Promise<string[]>;
|
|
3629
3991
|
claimNode(nodeId: string, userId: string): Promise<boolean>;
|
|
3992
|
+
claimUnownedNode(nodeId: string, userId: string): Promise<boolean>;
|
|
3630
3993
|
getNodeClaimOwner(nodeId: string): Promise<string | null>;
|
|
3631
3994
|
replaceNodeClaim(nodeId: string, expectedOwner: string, newOwner: string): Promise<boolean>;
|
|
3632
3995
|
releaseNodeClaim(nodeId: string): Promise<boolean>;
|
|
@@ -3991,6 +4354,7 @@ declare class PostgresServerStore implements ServerStore {
|
|
|
3991
4354
|
listEncryptionKeyRecords(owner?: string): Promise<EncryptionKeyRecordRow[]>;
|
|
3992
4355
|
getEncryptedKeyIds(nodeOwner: string | null, limit: number): Promise<string[]>;
|
|
3993
4356
|
claimNode(nodeId: string, userId: string): Promise<boolean>;
|
|
4357
|
+
claimUnownedNode(nodeId: string, userId: string): Promise<boolean>;
|
|
3994
4358
|
getNodeClaimOwner(nodeId: string): Promise<string | null>;
|
|
3995
4359
|
replaceNodeClaim(nodeId: string, expectedOwner: string, newOwner: string): Promise<boolean>;
|
|
3996
4360
|
releaseNodeClaim(nodeId: string): Promise<boolean>;
|
|
@@ -4248,6 +4612,7 @@ declare class SqliteServerStore implements ServerStore {
|
|
|
4248
4612
|
listEncryptionKeyRecords(owner?: string): Promise<EncryptionKeyRecordRow[]>;
|
|
4249
4613
|
getEncryptedKeyIds(nodeOwner: string | null, limit: number): Promise<string[]>;
|
|
4250
4614
|
claimNode(nodeId: string, userId: string): Promise<boolean>;
|
|
4615
|
+
claimUnownedNode(nodeId: string, userId: string): Promise<boolean>;
|
|
4251
4616
|
getNodeClaimOwner(nodeId: string): Promise<string | null>;
|
|
4252
4617
|
replaceNodeClaim(nodeId: string, expectedOwner: string, newOwner: string): Promise<boolean>;
|
|
4253
4618
|
releaseNodeClaim(nodeId: string): Promise<boolean>;
|
|
@@ -4522,13 +4887,21 @@ declare function resolveSessionScopes(schema: SchemaDefinition | null, options:
|
|
|
4522
4887
|
*/
|
|
4523
4888
|
declare function resolveSessionScopeGrant(schema: SchemaDefinition | null, options: ResolveSessionScopesOptions): ResolvedSessionScopeGrant;
|
|
4524
4889
|
|
|
4890
|
+
/**
|
|
4891
|
+
* Decides whether one client's current awareness state may reach another session.
|
|
4892
|
+
* Called with the receiving session's id; returning false keeps the state from it.
|
|
4893
|
+
* The sync server builds one per update from the record named in the state's cursor.
|
|
4894
|
+
*/
|
|
4895
|
+
type AwarenessAudience = (targetSessionId: string) => boolean;
|
|
4525
4896
|
/**
|
|
4526
4897
|
* Server-side awareness relay. Broadcasts ephemeral awareness states
|
|
4527
4898
|
* (cursor positions, user presence) between connected clients.
|
|
4528
4899
|
*
|
|
4529
4900
|
* Awareness data is never persisted. Each session's awareness `clientId` is bound on
|
|
4530
4901
|
* registration: a session may only publish (or clear) its own state, never another
|
|
4531
|
-
* client's
|
|
4902
|
+
* client's. A state reaches exactly the sessions its audience admits (the sync server
|
|
4903
|
+
* admits sessions whose download scope contains the record named in the cursor), or,
|
|
4904
|
+
* for an update without an audience, the clients of the same partition.
|
|
4532
4905
|
*/
|
|
4533
4906
|
declare class AwarenessRelay {
|
|
4534
4907
|
private readonly clients;
|
|
@@ -4537,10 +4910,14 @@ declare class AwarenessRelay {
|
|
|
4537
4910
|
* calls for an already-registered session are ignored, so a client cannot rebind
|
|
4538
4911
|
* itself to another client's id.
|
|
4539
4912
|
*
|
|
4913
|
+
* The new client is sent every existing state it may see (catch-up): a state with
|
|
4914
|
+
* an audience when the audience admits the new session, otherwise a state of the
|
|
4915
|
+
* same partition.
|
|
4916
|
+
*
|
|
4540
4917
|
* @param sessionId - Unique session identifier
|
|
4541
4918
|
* @param clientId - Client-assigned awareness ID
|
|
4542
4919
|
* @param transport - Transport for sending messages to this client
|
|
4543
|
-
* @param partition - Presence partition
|
|
4920
|
+
* @param partition - Presence partition for states relayed without an audience
|
|
4544
4921
|
*/
|
|
4545
4922
|
addClient(sessionId: string, clientId: number, transport: ServerTransport, partition?: string): void;
|
|
4546
4923
|
/**
|
|
@@ -4550,23 +4927,46 @@ declare class AwarenessRelay {
|
|
|
4550
4927
|
*/
|
|
4551
4928
|
hasClient(sessionId: string): boolean;
|
|
4552
4929
|
/**
|
|
4553
|
-
* Remove a client and
|
|
4930
|
+
* Remove a client and send its removal to every client that was shown its state.
|
|
4554
4931
|
*
|
|
4555
4932
|
* @param sessionId - Session ID of the disconnecting client
|
|
4556
4933
|
*/
|
|
4557
4934
|
removeClient(sessionId: string): void;
|
|
4935
|
+
/**
|
|
4936
|
+
* True when {@link handleUpdate} would take this update: the session is registered,
|
|
4937
|
+
* the update is stamped with its bound `clientId` and carries that client's entry.
|
|
4938
|
+
*
|
|
4939
|
+
* @param sessionId - Session ID of the sending client
|
|
4940
|
+
* @param message - The awareness update message
|
|
4941
|
+
*/
|
|
4942
|
+
accepts(sessionId: string, message: AwarenessUpdateMessage): boolean;
|
|
4558
4943
|
/**
|
|
4559
4944
|
* Handle an incoming awareness update from a registered client.
|
|
4560
4945
|
*
|
|
4561
4946
|
* Only the sender's own entry is accepted: the message must be stamped with the
|
|
4562
4947
|
* sender's bound `clientId`, and only `states[clientId]` is stored and relayed.
|
|
4563
4948
|
* Entries for other clients are dropped, so a sender cannot overwrite or remove
|
|
4564
|
-
* anyone else's presence.
|
|
4949
|
+
* anyone else's presence.
|
|
4950
|
+
*
|
|
4951
|
+
* The state is sent to every other client the audience admits (without an
|
|
4952
|
+
* audience: every client of the sender's partition). A client that was shown an
|
|
4953
|
+
* earlier state of the sender but is not admitted now receives a removal.
|
|
4565
4954
|
*
|
|
4566
4955
|
* @param sessionId - Session ID of the sending client
|
|
4567
4956
|
* @param message - The awareness update message
|
|
4957
|
+
* @param audience - Who may see this state; omitted means the sender's partition
|
|
4958
|
+
*/
|
|
4959
|
+
handleUpdate(sessionId: string, message: AwarenessUpdateMessage, audience?: AwarenessAudience): void;
|
|
4960
|
+
/**
|
|
4961
|
+
* Re-decide who may see a client's current state after the record its cursor names
|
|
4962
|
+
* changed (F16): it moved into or out of a session's grant. Sessions that may no
|
|
4963
|
+
* longer see the state get a removal; sessions that may see it now and were not
|
|
4964
|
+
* shown it get the state. Later catch-ups use the new audience.
|
|
4965
|
+
*
|
|
4966
|
+
* @param sessionId - The client whose audience changed
|
|
4967
|
+
* @param audience - The new audience
|
|
4568
4968
|
*/
|
|
4569
|
-
|
|
4969
|
+
updateAudience(sessionId: string, audience: AwarenessAudience): void;
|
|
4570
4970
|
/**
|
|
4571
4971
|
* Get the number of registered awareness clients.
|
|
4572
4972
|
*/
|
|
@@ -4575,7 +4975,9 @@ declare class AwarenessRelay {
|
|
|
4575
4975
|
* Remove all clients and clear all state.
|
|
4576
4976
|
*/
|
|
4577
4977
|
clear(): void;
|
|
4578
|
-
|
|
4978
|
+
/** True when `target` may see `source`'s current state. Fails closed. */
|
|
4979
|
+
private mayReceive;
|
|
4980
|
+
private removalMessage;
|
|
4579
4981
|
}
|
|
4580
4982
|
|
|
4581
4983
|
/**
|
|
@@ -4595,4 +4997,4 @@ declare class AwarenessRelay {
|
|
|
4595
4997
|
*/
|
|
4596
4998
|
declare function createKoraServer(config: KoraSyncServerConfig): KoraSyncServer;
|
|
4597
4999
|
|
|
4598
|
-
export { type ApplyRemoteOptions, type AuthContext, type AuthProvider, AwarenessRelay, type AwarenessRelayCallback, type ClientMetrics, ClientSession, type ClientSessionOptions, type CollectionQueryOptions, DEFAULT_MAX_SCOPE_PREDICATE_VALUES, type DeniedScopeCollection, type FoldMigrationReport, type HttpPollResponse, HttpServerTransport, type HttpSyncRequest, type HttpSyncResponse, InvalidScopePredicateError, KoraAuthProvider, type KoraAuthProviderOptions, KoraSyncServer, type KoraSyncServerConfig, type LogEntry, type LogLevel, type Logger, type MaterializedRecord, MemoryServerStore, type MemoryServerStoreOptions, MixedAuthProvider, type MixedAuthProviderOptions, NoAuthProvider, type OperationDecision, type OperationRejection, type OperationValidationContext, type OperationValidator, PostgresServerStore, type ProductionHttpRoute, type ProductionHttpRouteContext, type ProductionHttpRouteRequest, type ProductionHttpRouteResponse, type ProductionServer, type ProductionServerConfig, RETRIABLE_REJECTION_CODES, type RelayCallback, type ResolveSessionScopesOptions, type ResolvedSessionScopeGrant, type RouteApplyResult, type RouteConditionalApply, type RouteConditionalResult, type RouteMutation, type RoutePredicate, type RoutePredicateOperators, type RouteScopeOptions, SERVER_NODE_PREFIX, ScopePredicateLimitError, ScopeRequiredError, ServerCloseHandler, ServerErrorHandler, ServerIdentityError, type ServerIdentityOptions, ServerMessageHandler, ServerMetricsCollector, type ServerMetricsSnapshot, type ServerSchemaOptions, type ServerStatus, type ServerStore, ServerStoreUnavailableError, ServerTransport, type SessionRevocation, type SessionState, type SessionTerminationCode, SqliteServerStore, type StoredOperationKey, type TerminateSessionsFilter, TokenAuthProvider, type TokenAuthProviderOptions, type TrustProxySetting, type UplinkAuthorizationCode, UplinkAuthorizationError, type UplinkAuthorizationResult, type WsServerConstructor, type WsServerLike, WsServerTransport, type WsServerTransportOptions, type WsWebSocket, authorizeUplinkWrite, createDefaultLogger, createJsonLogger, createKoraServer, createPostgresServerStore, createPrettyLogger, createProductionServer, createSilentLogger, createSqliteServerStore, isRetriableRejection, isServerNodeId, normalizeScopeMap, operationMatchesScopes, resolveSessionScopeGrant, resolveSessionScopes };
|
|
5000
|
+
export { type ApplyRemoteOptions, type AuthContext, type AuthProvider, type AwarenessAudience, type AwarenessCursorTarget, AwarenessRelay, type AwarenessRelayCallback, type ClientMetrics, ClientSession, type ClientSessionOptions, type CollectionQueryOptions, DEFAULT_MAX_SCOPE_PREDICATE_VALUES, type DeniedScopeCollection, type FindJsonStringValuesOptions, type FoldMigrationReport, type HttpPollResponse, HttpServerTransport, type HttpSyncRequest, type HttpSyncResponse, InvalidDiagnosticOptionsError, InvalidScopePredicateError, type JsonStringValueReport, KoraAuthProvider, type KoraAuthProviderOptions, KoraSyncServer, type KoraSyncServerConfig, type LogEntry, type LogLevel, type Logger, type MaterializedRecord, MemoryServerStore, type MemoryServerStoreOptions, MixedAuthProvider, type MixedAuthProviderOptions, NoAuthProvider, type OperationDecision, type OperationRejection, type OperationValidationContext, type OperationValidator, PostgresServerStore, type ProductionHttpRoute, type ProductionHttpRouteContext, type ProductionHttpRouteRequest, type ProductionHttpRouteResponse, type ProductionServer, type ProductionServerConfig, RETRIABLE_REJECTION_CODES, type RelayCallback, type ResolveSessionScopesOptions, type ResolvedSessionScopeGrant, type RouteApplyResult, type RouteConditionalApply, type RouteConditionalResult, type RouteMutation, type RoutePredicate, type RoutePredicateOperators, type RouteScopeOptions, SERVER_NODE_PREFIX, ScopePredicateLimitError, ScopeRequiredError, ServerCloseHandler, ServerErrorHandler, ServerIdentityError, type ServerIdentityOptions, ServerMessageHandler, ServerMetricsCollector, type ServerMetricsSnapshot, type ServerSchemaOptions, type ServerStatus, type ServerStore, ServerStoreUnavailableError, ServerTransport, type SessionRevocation, type SessionState, type SessionTerminationCode, SqliteServerStore, type StoredOperationKey, type TerminateSessionsFilter, TokenAuthProvider, type TokenAuthProviderOptions, type TrustProxySetting, type UplinkAuthorizationCode, UplinkAuthorizationError, type UplinkAuthorizationResult, type WsServerConstructor, type WsServerLike, WsServerTransport, type WsServerTransportOptions, type WsWebSocket, authorizeUplinkWrite, createDefaultLogger, createJsonLogger, createKoraServer, createPostgresServerStore, createPrettyLogger, createProductionServer, createSilentLogger, createSqliteServerStore, findJsonStringValues, isRetriableRejection, isServerNodeId, normalizeScopeMap, operationMatchesScopes, resolveSessionScopeGrant, resolveSessionScopes };
|