@lunora/do 1.0.0-alpha.8 → 1.0.0-alpha.9
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.mts +536 -11
- package/dist/index.d.ts +536 -11
- package/dist/index.mjs +7 -7
- package/dist/packem_shared/{CDC_LOG_TABLE-Ctdmxmrv.mjs → CDC_LOG_TABLE-DSycmnDf.mjs} +5 -1
- package/dist/packem_shared/{DEFAULT_MAX_RELATION_KEYS-Dou2PWdO.mjs → DEFAULT_MAX_RELATION_KEYS-CHEvKjZt.mjs} +50 -1
- package/dist/packem_shared/{NotUniqueError-h_thNFSZ.mjs → NotUniqueError-Cwv7Pe7J.mjs} +9 -7
- package/dist/packem_shared/{rank-CrkEIpF4.mjs → RANK_TIEBREAK-CXhdcA1o.mjs} +2 -13
- package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-BCz6GIDw.mjs → ROOT_DO_SIZE_WARN_BYTES-DKwBF3Jp.mjs} +993 -16
- package/dist/packem_shared/{backfillAggregateIndexes-BbVPvciS.mjs → backfillAggregateIndexes-BZsOqDXP.mjs} +2 -1
- package/dist/packem_shared/ctx-db-idempotency-BdcNpvY4.mjs +108 -0
- package/dist/packem_shared/ctx-db-shapes-DVoeZpo-.mjs +53 -0
- package/dist/packem_shared/{runShardMigrations-PabobOjF.mjs → runShardMigrations-nIwoQeOK.mjs} +5 -3
- package/dist/packem_shared/serialize-sql-BlRUoiQe.mjs +14 -0
- package/package.json +1 -1
- package/dist/packem_shared/RANK_TIEBREAK-C6blLR5K.mjs +0 -1
- package/dist/packem_shared/ctx-db-idempotency-DkC9rP91.mjs +0 -35
package/dist/index.d.mts
CHANGED
|
@@ -984,7 +984,32 @@ interface SubscriptionQuery {
|
|
|
984
984
|
*/
|
|
985
985
|
table?: string;
|
|
986
986
|
}
|
|
987
|
+
/**
|
|
988
|
+
* A live shape subscription registered on a socket — the partial-replication
|
|
989
|
+
* parallel to {@link SubscriptionQuery}. The client names a `defineShape` shape
|
|
990
|
+
* and supplies validated `args`; the DO resolves it to a table + RLS-composed
|
|
991
|
+
* `effectiveWhere` under the socket's verified identity (never the client's
|
|
992
|
+
* word) and pokes the membership diff. `sinceSeq`/`sinceEpoch` carry the
|
|
993
|
+
* client's last applied checkpoint for resume.
|
|
994
|
+
*/
|
|
995
|
+
interface ShapeSubscriptionQuery {
|
|
996
|
+
/** Validated shape arguments (e.g. `{ channelId }`); forwarded to `resolveShape`. */
|
|
997
|
+
args?: Record<string, unknown>;
|
|
998
|
+
/** Registered shape name (the `defineShape` export the codegen subclass resolves). */
|
|
999
|
+
name: string;
|
|
1000
|
+
/** Resume epoch the client persisted alongside {@link ShapeSubscriptionQuery.sinceSeq} (see {@link SubscriptionQuery.sinceEpoch}). */
|
|
1001
|
+
sinceEpoch?: string;
|
|
1002
|
+
/** Resume checkpoint: the `__cdc_log` cursor the client's view of this shape last reflected (see {@link SubscriptionQuery.sinceSeq}). */
|
|
1003
|
+
sinceSeq?: number;
|
|
1004
|
+
}
|
|
987
1005
|
interface SubscriptionEnvelope {
|
|
1006
|
+
/**
|
|
1007
|
+
* Stable per-client id carried by the `connect` envelope. Recorded on the
|
|
1008
|
+
* socket attachment so a shape poke can echo this client's
|
|
1009
|
+
* `__client_watermark` as its `lastMutationId`. Ignored on other envelope
|
|
1010
|
+
* types; absent for clients that don't use custom mutators.
|
|
1011
|
+
*/
|
|
1012
|
+
clientId?: string;
|
|
988
1013
|
/**
|
|
989
1014
|
* App-supplied connection context carried by the `connect` envelope (e.g.
|
|
990
1015
|
* `{ roomId, sessionId }`). Merged into the socket attachment and forwarded
|
|
@@ -999,6 +1024,19 @@ interface SubscriptionEnvelope {
|
|
|
999
1024
|
id: string;
|
|
1000
1025
|
query?: SubscriptionQuery;
|
|
1001
1026
|
/**
|
|
1027
|
+
* Shape descriptor of a `shape_subscribe` envelope: the named shape + its
|
|
1028
|
+
* validated args. Carries the client's resume checkpoint via
|
|
1029
|
+
* {@link SubscriptionEnvelope.sinceCheckpoint}/{@link SubscriptionEnvelope.sinceEpoch}.
|
|
1030
|
+
*/
|
|
1031
|
+
shape?: {
|
|
1032
|
+
args?: Record<string, unknown>;
|
|
1033
|
+
name: string;
|
|
1034
|
+
};
|
|
1035
|
+
/** Resume checkpoint on a `shape_subscribe` envelope (the `__cdc_log` cursor the client's shape view is at). */
|
|
1036
|
+
sinceCheckpoint?: number;
|
|
1037
|
+
/** CDC epoch the {@link SubscriptionEnvelope.sinceCheckpoint} belongs to. */
|
|
1038
|
+
sinceEpoch?: string;
|
|
1039
|
+
/**
|
|
1002
1040
|
* Topic of a `whisper`/`whisper_subscribe`/`whisper_unsubscribe` envelope —
|
|
1003
1041
|
* an app-chosen channel name (e.g. `"room:42:cursors"`) scoped to this shard.
|
|
1004
1042
|
*/
|
|
@@ -1016,7 +1054,7 @@ interface SubscriptionEnvelope {
|
|
|
1016
1054
|
* this shard with NO SQLite/CDC write (AnyCable-style whispering — typing
|
|
1017
1055
|
* indicators, live cursors). The sender never receives its own whisper.
|
|
1018
1056
|
*/
|
|
1019
|
-
type: "ack" | "connect" | "stream" | "subscribe" | "unsubscribe" | "whisper" | "whisper_subscribe" | "whisper_unsubscribe";
|
|
1057
|
+
type: "ack" | "connect" | "shape_subscribe" | "shape_unsubscribe" | "stream" | "subscribe" | "unsubscribe" | "whisper" | "whisper_subscribe" | "whisper_unsubscribe";
|
|
1020
1058
|
}
|
|
1021
1059
|
/**
|
|
1022
1060
|
* The argument a connection-lifecycle hook receives. Structurally matches
|
|
@@ -1091,6 +1129,15 @@ interface SocketAttachment {
|
|
|
1091
1129
|
*/
|
|
1092
1130
|
admin?: boolean;
|
|
1093
1131
|
/**
|
|
1132
|
+
* Stable per-client id from the `connect` envelope (the same id the client
|
|
1133
|
+
* stamps on its custom-mutator pushes). Lets a shape poke echo this client's
|
|
1134
|
+
* `__client_watermark` as the poke's `lastMutationId`, so a `@lunora/db`
|
|
1135
|
+
* collection can drop the optimistic overlay for writes this poke has
|
|
1136
|
+
* synced. Absent for clients that don't use custom mutators. Persisted so it
|
|
1137
|
+
* survives hibernation.
|
|
1138
|
+
*/
|
|
1139
|
+
clientId?: string;
|
|
1140
|
+
/**
|
|
1094
1141
|
* `true` once the socket's `connect` envelope has fired the `onConnect`
|
|
1095
1142
|
* hooks. Gates the dispatch so a client that re-sends `connect` (or a
|
|
1096
1143
|
* duplicate frame) can't re-fire the hooks for an already-announced socket —
|
|
@@ -1124,6 +1171,14 @@ interface SocketAttachment {
|
|
|
1124
1171
|
* hooks so they run under the connecting user.
|
|
1125
1172
|
*/
|
|
1126
1173
|
identity?: Record<string, unknown>;
|
|
1174
|
+
/**
|
|
1175
|
+
* Live shape subscriptions registered on this socket, keyed by the
|
|
1176
|
+
* client-supplied subscription id. The partial-replication parallel to
|
|
1177
|
+
* {@link SocketAttachment.subs}: the poke protocol fans membership diffs to
|
|
1178
|
+
* these, while `subs` drives the legacy `data`/`delta` re-execution path.
|
|
1179
|
+
* Absent until the socket sends its first `shape_subscribe`.
|
|
1180
|
+
*/
|
|
1181
|
+
shapes?: Record<string, ShapeSubscriptionQuery>;
|
|
1127
1182
|
subs: Record<string, SubscriptionQuery>;
|
|
1128
1183
|
/**
|
|
1129
1184
|
* Verified user id resolved at upgrade (from `x-lunora-userid`), or absent
|
|
@@ -1180,10 +1235,16 @@ interface CdcChange {
|
|
|
1180
1235
|
* Read changelog entries newer than `sinceSeq` in commit order, up to `limit`
|
|
1181
1236
|
* (clamped to [1, 10000]). Returns the rows plus the cursor to resume from (the
|
|
1182
1237
|
* last `seq`, or `sinceSeq` when the page is empty).
|
|
1238
|
+
*
|
|
1239
|
+
* The optional `tables` set narrows the page to changes on those tables — the
|
|
1240
|
+
* shape/poke path reads one filtered page per flush so it never scans op-log
|
|
1241
|
+
* entries for tables no live shape is watching. Omit it (or pass an empty set)
|
|
1242
|
+
* for the full, unfiltered page (the existing streaming-export/resume callers).
|
|
1183
1243
|
*/
|
|
1184
1244
|
declare const readCdcChanges: (sql: SqlExec, options?: {
|
|
1185
1245
|
limit?: number;
|
|
1186
1246
|
sinceSeq?: number;
|
|
1247
|
+
tables?: ReadonlySet<string>;
|
|
1187
1248
|
}) => {
|
|
1188
1249
|
changes: CdcChange[];
|
|
1189
1250
|
cursor: number;
|
|
@@ -1219,6 +1280,11 @@ declare const applyCdcChanges: (writer: DatabaseWriterLike, changes: ReadonlyArr
|
|
|
1219
1280
|
declare const runShardMigrations: (sql: SqlExec, schema: SchemaLike, options?: {
|
|
1220
1281
|
cdc?: boolean;
|
|
1221
1282
|
}) => void;
|
|
1283
|
+
/** One shape member: its `_id` key plus the decoded document (id + creationTime merged in). */
|
|
1284
|
+
interface ShapeRow {
|
|
1285
|
+
doc: Record<string, unknown>;
|
|
1286
|
+
id: string;
|
|
1287
|
+
}
|
|
1222
1288
|
/**
|
|
1223
1289
|
* Structural projection of `state.storage.sql` (workerd's SqlStorage). We
|
|
1224
1290
|
* only require the `exec` overload — the cursor it returns is iterable and
|
|
@@ -3409,6 +3475,16 @@ declare const assertFlatPredicate: (where: WhereInput | undefined, schema: Resol
|
|
|
3409
3475
|
* and issues no extra query).
|
|
3410
3476
|
*/
|
|
3411
3477
|
declare const resolveRelationPredicates: (where: WhereInput | undefined, options: ResolveRelationPredicatesOptions) => Promise<WhereInput | undefined>;
|
|
3478
|
+
/**
|
|
3479
|
+
* Registration-time guard for partial-replication shapes. A live shape can only
|
|
3480
|
+
* be poked from the op-log of its OWN shard Durable Object, so an
|
|
3481
|
+
* `effectiveWhere` that joins to a `.shardBy()` table reaches rows that live in
|
|
3482
|
+
* other DOs the poke loop can never observe. Reject such a shape up front with
|
|
3483
|
+
* the two supported remedies. Called from the generated `resolveShape` override
|
|
3484
|
+
* the moment a socket subscribes (the first point the compiled predicate and the
|
|
3485
|
+
* schema's shard modes are both in hand).
|
|
3486
|
+
*/
|
|
3487
|
+
declare const assertShapeShardable: (effectiveWhere: WhereInput | undefined, schema: ResolveContext["schema"], table: string) => void;
|
|
3412
3488
|
/** Severity of a `ctx.log.*` call, mirroring the console method names (`log` is the default level, distinct from `info`). */
|
|
3413
3489
|
type ContextLogLevel = "debug" | "error" | "info" | "log" | "warn";
|
|
3414
3490
|
/** The fields {@link emitLogEvent} ships for one `ctx.log.*` call. */
|
|
@@ -3797,6 +3873,13 @@ interface ShardDOState {
|
|
|
3797
3873
|
getCurrentBookmark?: () => Promise<string>;
|
|
3798
3874
|
/** Native PITR: arm a restore to `bookmark` on next restart; returns the undo bookmark. */
|
|
3799
3875
|
onNextSessionRestoreBookmark?: (bookmark: string) => Promise<string>;
|
|
3876
|
+
/**
|
|
3877
|
+
* Arm the DO's single alarm to fire at `scheduledTime` (ms epoch),
|
|
3878
|
+
* waking {@link ShardDO.alarm}. Used by the global-shape poll loop.
|
|
3879
|
+
* Optional: present on the real runtime, absent in the unit harness
|
|
3880
|
+
* (where the poll loop degrades to seed-only).
|
|
3881
|
+
*/
|
|
3882
|
+
setAlarm?: (scheduledTime: Date | number) => Promise<void>;
|
|
3800
3883
|
sql: {
|
|
3801
3884
|
[key: string]: unknown;
|
|
3802
3885
|
/**
|
|
@@ -3841,6 +3924,41 @@ interface SubscriptionOutcome {
|
|
|
3841
3924
|
tables: Set<string>;
|
|
3842
3925
|
}
|
|
3843
3926
|
/**
|
|
3927
|
+
* A shape resolved to its concrete query plan, the return of the
|
|
3928
|
+
* {@link ShardDO.resolveShape} hook. The codegen subclass composes the shape's
|
|
3929
|
+
* own predicate with the caller's RLS read base-where into `effectiveWhere`
|
|
3930
|
+
* under the socket's verified identity (the client never supplies it), so the
|
|
3931
|
+
* membership query the poke protocol runs is RLS-correct by construction.
|
|
3932
|
+
*
|
|
3933
|
+
* `columns`, when present, projects each row-op's `value` to that subset (the
|
|
3934
|
+
* shape's declared column allow-list); absent ⇒ the full document is shipped.
|
|
3935
|
+
*/
|
|
3936
|
+
interface ResolvedShape {
|
|
3937
|
+
columns?: ReadonlyArray<string>;
|
|
3938
|
+
effectiveWhere?: WhereInput;
|
|
3939
|
+
/**
|
|
3940
|
+
* `true` when the shape's table is `.global()` (lives in D1, not this DO's
|
|
3941
|
+
* SQLite). A global shape has **no per-DO op-log** to diff, so it is served
|
|
3942
|
+
* by the **latency-tiered poll path** ({@link ShardDO.seedGlobalShape} +
|
|
3943
|
+
* {@link ShardDO.refreshGlobalShape}) instead of the CDC poke path — seeded
|
|
3944
|
+
* from {@link ShardDO.readGlobalShapeRows} and refreshed on an alarm tick.
|
|
3945
|
+
* The codegen subclass sets it from the schema's `shardMode`; absent ⇒ a
|
|
3946
|
+
* shard-local (poke-live) shape.
|
|
3947
|
+
*/
|
|
3948
|
+
global?: boolean;
|
|
3949
|
+
table: string;
|
|
3950
|
+
}
|
|
3951
|
+
/**
|
|
3952
|
+
* Classification of a watermarked custom-mutator push against the shard's
|
|
3953
|
+
* `__client_watermark`: `expected` is the next in-order sequence, `kind`
|
|
3954
|
+
* whether the push is a replay (`"already"`), the next one (`"next"`), or an
|
|
3955
|
+
* out-of-order arrival (`"gap"`).
|
|
3956
|
+
*/
|
|
3957
|
+
type ClientMutationClass = {
|
|
3958
|
+
expected: number;
|
|
3959
|
+
kind: "already" | "gap" | "next";
|
|
3960
|
+
};
|
|
3961
|
+
/**
|
|
3844
3962
|
* Identity a subscription query is executed under, threaded EXPLICITLY into
|
|
3845
3963
|
* `executeSubscription` → `buildCtx` rather than read from the shared,
|
|
3846
3964
|
* per-request `currentRequestUserId`/`currentRequestIdentity` instance fields.
|
|
@@ -4049,6 +4167,28 @@ declare abstract class ShardDO {
|
|
|
4049
4167
|
*/
|
|
4050
4168
|
protected static readonly MAX_SUBSCRIPTIONS_PER_SOCKET = 32;
|
|
4051
4169
|
/**
|
|
4170
|
+
* Poll interval (ms) for `.global()`-table shapes. A global table lives in
|
|
4171
|
+
* D1 with no per-DO op-log, so its shapes can't be poke-live; the DO re-reads
|
|
4172
|
+
* each subscribed global shape's membership from D1 on an alarm every
|
|
4173
|
+
* `GLOBAL_SHAPE_POLL_INTERVAL_MS` and pokes only the diff. This is the
|
|
4174
|
+
* latency floor for a global-shape update — deliberately coarse (seconds, not
|
|
4175
|
+
* the sub-millisecond poke-live path) since the D1 read fans out per tick.
|
|
4176
|
+
*/
|
|
4177
|
+
protected static readonly GLOBAL_SHAPE_POLL_INTERVAL_MS = 2e3;
|
|
4178
|
+
/**
|
|
4179
|
+
* Upper bound on a `.global()`-shape's materialized membership. Each global
|
|
4180
|
+
* shape keeps its ENTIRE current membership as a per-socket snapshot
|
|
4181
|
+
* (`Map<rowKey, hash>`) so the poll loop can diff it; that snapshot — and the
|
|
4182
|
+
* read buffer feeding it — scale with the membership size, multiplied by every
|
|
4183
|
+
* subscribed socket. An unbounded membership (a global table with no narrowing
|
|
4184
|
+
* shape predicate or RLS read scope) would grow them without limit and evict
|
|
4185
|
+
* the DO. A shape whose membership exceeds this cap is failed closed (left
|
|
4186
|
+
* empty, logged) rather than retained — the developer must narrow it. Sized
|
|
4187
|
+
* well above any reasonable per-identity replicated set so legitimate shapes
|
|
4188
|
+
* never trip it.
|
|
4189
|
+
*/
|
|
4190
|
+
protected static readonly GLOBAL_SHAPE_MAX_ROWS = 5e4;
|
|
4191
|
+
/**
|
|
4052
4192
|
* Per-socket whisper-topic cap. Topic membership rides the same hibernation
|
|
4053
4193
|
* attachment as `subs`, so bound it for the same reason — a runaway
|
|
4054
4194
|
* `whisper_subscribe` loop must not wedge the attachment past the runtime's
|
|
@@ -4148,6 +4288,39 @@ declare abstract class ShardDO {
|
|
|
4148
4288
|
*/
|
|
4149
4289
|
private currentRequestMutationId;
|
|
4150
4290
|
/**
|
|
4291
|
+
* Stable per-device client id for the in-flight custom-mutator push,
|
|
4292
|
+
* forwarded via the `x-lunora-client-id` header. Backs the
|
|
4293
|
+
* `__client_watermark` table: the dispatch path classifies the paired
|
|
4294
|
+
* `currentRequestClientSeq` against the stored high-watermark (already
|
|
4295
|
+
* processed / next / out-of-order gap). Absent on legacy mutations and
|
|
4296
|
+
* queries (those keep the `__idempotency` path). Cleared in `fetch`'s
|
|
4297
|
+
* `finally`.
|
|
4298
|
+
*/
|
|
4299
|
+
private currentRequestClientId;
|
|
4300
|
+
/**
|
|
4301
|
+
* Monotonic per-client mutation sequence for the in-flight custom-mutator
|
|
4302
|
+
* push, forwarded via the `x-lunora-client-seq` header (numeric). Paired
|
|
4303
|
+
* with `currentRequestClientId` to drive the watermark classification.
|
|
4304
|
+
* `undefined` when absent or non-numeric.
|
|
4305
|
+
*/
|
|
4306
|
+
private currentRequestClientSeq;
|
|
4307
|
+
/**
|
|
4308
|
+
* The in-flight push's custom-mutator classification, stashed by `fetch`
|
|
4309
|
+
* before `handleRpc` so the in-transaction bookkeeping ({@link
|
|
4310
|
+
* ShardDO.commitMutationBookkeeping}) can advance the `__client_watermark` for
|
|
4311
|
+
* a `"next"` push inside the same commit as the writes. `undefined` for an
|
|
4312
|
+
* ordinary mutation / non-mutator push. Cleared per request.
|
|
4313
|
+
*/
|
|
4314
|
+
private currentMutatorClass;
|
|
4315
|
+
/**
|
|
4316
|
+
* Set once a mutation's replay bookkeeping (idempotency row + watermark
|
|
4317
|
+
* advance) has committed INSIDE the handler transaction, so the post-dispatch
|
|
4318
|
+
* path skips the now-redundant best-effort writes. Cleared per request; stays
|
|
4319
|
+
* `false` for actions/queries (no transaction wrapper) so their dispatch-level
|
|
4320
|
+
* idempotency persist still runs.
|
|
4321
|
+
*/
|
|
4322
|
+
private mutationBookkeepingCommitted;
|
|
4323
|
+
/**
|
|
4151
4324
|
* Wall-clock millis of the last `__idempotency` GC sweep on this warm
|
|
4152
4325
|
* instance. The dedup write throttles `trimIdempotent` to at most once an
|
|
4153
4326
|
* hour off this field (in-memory, so a fresh instance just sweeps on its
|
|
@@ -4197,6 +4370,39 @@ declare abstract class ShardDO {
|
|
|
4197
4370
|
* memo simply forces one re-run and (at most) one redundant push.
|
|
4198
4371
|
*/
|
|
4199
4372
|
private readonly subMemos;
|
|
4373
|
+
/**
|
|
4374
|
+
* Per-socket poke baseline for shape subscriptions: maps each shape's
|
|
4375
|
+
* subscription id to the `__cdc_log` cursor it has been poked through.
|
|
4376
|
+
* `pokeShapeSubscribers` reads each op page since this cursor and advances
|
|
4377
|
+
* it to the flush watermark. In-memory only (like {@link ShardDO.subMemos});
|
|
4378
|
+
* a cold memo on a reconnected/hibernated socket re-seeds from the client's
|
|
4379
|
+
* `sinceCheckpoint`.
|
|
4380
|
+
*/
|
|
4381
|
+
private readonly shapeMemos;
|
|
4382
|
+
/**
|
|
4383
|
+
* Per-socket, per-**global**-shape membership snapshot: maps each global
|
|
4384
|
+
* shape's subscription id to a `key → projected-value JSON` map of the rows
|
|
4385
|
+
* last poked to that socket. A `.global()` (D1) table has no op-log to diff,
|
|
4386
|
+
* so {@link ShardDO.refreshGlobalShape} re-reads the full membership on each
|
|
4387
|
+
* alarm tick and diffs it against this snapshot to compute the poke. Parallel
|
|
4388
|
+
* to {@link ShardDO.shapeMemos} (the cursor baseline for poke-live shapes).
|
|
4389
|
+
*
|
|
4390
|
+
* This is a hot in-memory **cache** over the durable `__global_shape_snapshot`
|
|
4391
|
+
* table (keyed by the socket's `connectionId` + subId): a hibernation eviction
|
|
4392
|
+
* clears the WeakMap, so on the next alarm wake {@link ShardDO.readGlobalSnapshot}
|
|
4393
|
+
* misses and re-loads the baseline from SQLite — without it, the diff would run
|
|
4394
|
+
* against an empty baseline and a row deleted from D1 while the DO slept would
|
|
4395
|
+
* never be poked as a `delete`, lingering on the client as a phantom row.
|
|
4396
|
+
*/
|
|
4397
|
+
private readonly globalShapeSnapshots;
|
|
4398
|
+
/**
|
|
4399
|
+
* Whether a global-shape poll alarm is currently armed. Guards
|
|
4400
|
+
* {@link ShardDO.scheduleGlobalPoll} from re-arming on every seed; reset in
|
|
4401
|
+
* {@link ShardDO.alarm} before the poll so a still-subscribed shape re-arms.
|
|
4402
|
+
*/
|
|
4403
|
+
private globalPollScheduled;
|
|
4404
|
+
/** Monotonic per-DO poke id source; correlates a poke's `pokeStart`/`pokePart`/`pokeEnd` frames. */
|
|
4405
|
+
private pokeSequence;
|
|
4200
4406
|
/** Per-socket whisper-rate token bucket (see {@link ShardDO.WHISPER_RATE_BURST}). In-memory; resets on hibernation. */
|
|
4201
4407
|
private readonly whisperBuckets;
|
|
4202
4408
|
/**
|
|
@@ -4315,6 +4521,15 @@ declare abstract class ShardDO {
|
|
|
4315
4521
|
webSocketClose(ws: WebSocket, _code: number, _reason: string, _wasClean: boolean): Promise<void>;
|
|
4316
4522
|
/** Hibernation API: invoked on socket error. */
|
|
4317
4523
|
webSocketError(_ws: WebSocket, _error: unknown): void;
|
|
4524
|
+
/**
|
|
4525
|
+
* Durable Object alarm handler — the heartbeat for `.global()`-table shapes.
|
|
4526
|
+
* The runtime wakes this when the poll alarm armed by `scheduleGlobalPoll`
|
|
4527
|
+
* fires; it refreshes every subscribed global shape (diff-poke from the global
|
|
4528
|
+
* backend) and re-arms while any remain. With no global subscribers left, the
|
|
4529
|
+
* alarm is not re-armed and the DO goes idle. A base-only / global-free DO
|
|
4530
|
+
* never arms it, so this stays dormant there.
|
|
4531
|
+
*/
|
|
4532
|
+
alarm(): Promise<void>;
|
|
4318
4533
|
/** Subclasses implement function dispatch. */
|
|
4319
4534
|
abstract handleRpc(functionPath: string, args: Record<string, unknown>): Promise<unknown>;
|
|
4320
4535
|
/**
|
|
@@ -4752,16 +4967,105 @@ declare abstract class ShardDO {
|
|
|
4752
4967
|
* unless the request carried an `x-lunora-mutation-id` header (queries and
|
|
4753
4968
|
* legacy clients leave `currentRequestMutationId` undefined).
|
|
4754
4969
|
*
|
|
4755
|
-
*
|
|
4756
|
-
*
|
|
4757
|
-
*
|
|
4758
|
-
*
|
|
4759
|
-
*
|
|
4760
|
-
*
|
|
4761
|
-
*
|
|
4970
|
+
* For a mutation this runs INSIDE the handler's transaction (via
|
|
4971
|
+
* {@link ShardDO.commitMutationBookkeeping}, which `handleRpc` invokes before
|
|
4972
|
+
* the transaction commits), so the dedup row is durable iff the writes are —
|
|
4973
|
+
* closing the crash window where the writes commit but the replay guard does
|
|
4974
|
+
* not. Actions/queries aren't transaction-wrapped, so they call this on the
|
|
4975
|
+
* live dispatch path right after the handler resolves, through the same
|
|
4976
|
+
* `this.sql` handle. `INSERT OR IGNORE` keeps a concurrent double-dispatch (or
|
|
4977
|
+
* the now-skipped post-dispatch call) of the same id idempotent. Also runs the
|
|
4978
|
+
* throttled dedup-table GC.
|
|
4762
4979
|
*/
|
|
4763
4980
|
protected persistIdempotentResult(result: unknown): void;
|
|
4764
4981
|
/**
|
|
4982
|
+
* Whether `functionPath` names a registered custom mutator (a `defineMutator`
|
|
4983
|
+
* declaration) rather than an ordinary `mutation`. The base class knows of no
|
|
4984
|
+
* mutators, so the default is `false`; the codegen-generated subclass
|
|
4985
|
+
* overrides this to consult its mutator registry. When `true` (and the push
|
|
4986
|
+
* carries a `clientId`/`clientSeq`), the dispatch path applies the
|
|
4987
|
+
* `__client_watermark` ordering semantics instead of the legacy idempotency
|
|
4988
|
+
* dedup.
|
|
4989
|
+
*/
|
|
4990
|
+
protected isCustomMutator(_functionPath: string): boolean;
|
|
4991
|
+
/**
|
|
4992
|
+
* Classify an in-flight custom-mutator push against the shard's stored
|
|
4993
|
+
* high-watermark for `currentRequestClientId`. The watermark is the highest
|
|
4994
|
+
* per-client sequence the DO has applied, so the push is exactly one of:
|
|
4995
|
+
*
|
|
4996
|
+
* - `"already"` — `seq <= watermark`: a replay of a confirmed (or in-flight,
|
|
4997
|
+
* now-resent) mutation. The handler must NOT re-run; the dispatch path returns
|
|
4998
|
+
* a benign ack so the client drops the pending overlay.
|
|
4999
|
+
* - `"next"` — `seq == watermark + 1`: the next mutation in order. Run the
|
|
5000
|
+
* authoritative `server` impl and advance the watermark in the same commit.
|
|
5001
|
+
* - `"gap"` — `seq > watermark + 1`: an out-of-order arrival (an earlier push
|
|
5002
|
+
* was lost). Halt: the client must resend from `watermark + 1`.
|
|
5003
|
+
*
|
|
5004
|
+
* Returns `undefined` when the push is not a watermarked custom mutator
|
|
5005
|
+
* (missing client id/seq, or a stub `sql` handle without the table) so the
|
|
5006
|
+
* caller falls through to the legacy idempotency path.
|
|
5007
|
+
*/
|
|
5008
|
+
protected classifyClientMutation(): ClientMutationClass | undefined;
|
|
5009
|
+
/**
|
|
5010
|
+
* Terminal response for a watermarked custom-mutator push that is NOT the
|
|
5011
|
+
* next-in-order mutation — an idempotent replay ack (`"already"`) or an
|
|
5012
|
+
* out-of-order halt (`"gap"`). Returns `undefined` for an ordinary mutation
|
|
5013
|
+
* or a `"next"` push so `fetch` proceeds to the authoritative handler. Records
|
|
5014
|
+
* the function call on the short-circuit paths so metrics stay attributed.
|
|
5015
|
+
*/
|
|
5016
|
+
protected rejectNonNextMutation(functionPath: string, mutatorClass: ClientMutationClass | undefined, dispatchStartedAt: number): Response | undefined;
|
|
5017
|
+
/**
|
|
5018
|
+
* Respond to a dispatch that hit the `(identity, mutationId)` idempotency
|
|
5019
|
+
* cache. Records the (zero-work) function call, then: for a `"next"` custom
|
|
5020
|
+
* mutator whose handler already committed but whose watermark advance was
|
|
5021
|
+
* lost to a crash in between, re-advance and echo `lastMutationId` exactly as
|
|
5022
|
+
* the post-commit path does (otherwise the cached branch returns a bare
|
|
5023
|
+
* result with a stale watermark and the client reports every later seq as a
|
|
5024
|
+
* gap forever); for everything else, return the bare cached `{ result }`.
|
|
5025
|
+
*/
|
|
5026
|
+
protected respondFromIdempotencyCache(functionPath: string, dispatchStartedAt: number, mutatorClass: ClientMutationClass | undefined, cachedValue: unknown): Response;
|
|
5027
|
+
/**
|
|
5028
|
+
* Build the success response for a dispatched RPC. A `"next"` custom-mutator
|
|
5029
|
+
* push echoes the applied `lastMutationId` so the client drops the pending
|
|
5030
|
+
* optimistic overlay as soon as the ack lands; ordinary calls return the bare
|
|
5031
|
+
* `{ result }` envelope unchanged.
|
|
5032
|
+
*/
|
|
5033
|
+
protected buildDispatchResponse(mutatorClass: ClientMutationClass | undefined, result: unknown): Response;
|
|
5034
|
+
/**
|
|
5035
|
+
* Commit a mutation's replay bookkeeping — the `(identity, mutationId)`
|
|
5036
|
+
* idempotency dedup row and, for a `"next"` custom-mutator push, the
|
|
5037
|
+
* `__client_watermark` advance — INSIDE the handler's transaction. Called by
|
|
5038
|
+
* the generated `handleRpc` mutation branch after the user handler resolves
|
|
5039
|
+
* but before the transaction commits, so the writes, the dedup row, and the
|
|
5040
|
+
* watermark land in one atomic commit: a crash can't leave the writes durable
|
|
5041
|
+
* without the replay guard (which a re-dispatch would otherwise re-run) nor
|
|
5042
|
+
* without the watermark. Sets {@link ShardDO.mutationBookkeepingCommitted} so
|
|
5043
|
+
* `fetch` skips the redundant post-dispatch persist.
|
|
5044
|
+
*/
|
|
5045
|
+
protected commitMutationBookkeeping(result: unknown): void;
|
|
5046
|
+
/**
|
|
5047
|
+
* Best-effort replay bookkeeping for the live dispatch path, run after
|
|
5048
|
+
* `handleRpc` returns. A generated mutation already committed it atomically
|
|
5049
|
+
* inside its transaction (via {@link ShardDO.commitMutationBookkeeping}, which
|
|
5050
|
+
* sets the flag), so this skips. Actions/queries aren't transaction-wrapped,
|
|
5051
|
+
* so they record their dedup row here (a no-op without an `x-lunora-mutation-id`),
|
|
5052
|
+
* and a `"next"` push advances its watermark (the gap self-heals on replay).
|
|
5053
|
+
*/
|
|
5054
|
+
protected recordPostDispatchBookkeeping(result: unknown, mutatorClass: ClientMutationClass | undefined): void;
|
|
5055
|
+
/**
|
|
5056
|
+
* Advance the stored high-watermark for the in-flight custom mutator to
|
|
5057
|
+
* `currentRequestClientSeq` through the same `this.sql` handle. On the
|
|
5058
|
+
* transactional path ({@link ShardDO.commitMutationBookkeeping}, `strict`) it
|
|
5059
|
+
* runs inside the handler's commit, so the watermark is durable iff the writes
|
|
5060
|
+
* are; a failure rethrows to roll the mutation back. On the best-effort
|
|
5061
|
+
* cache-hit recovery path (`strict` omitted) a missing table is swallowed —
|
|
5062
|
+
* the replay re-runs and re-advances (the read side treats a missing row as
|
|
5063
|
+
* watermark 0), so the gap self-heals.
|
|
5064
|
+
*/
|
|
5065
|
+
protected advanceClientMutationWatermark(options?: {
|
|
5066
|
+
strict?: boolean;
|
|
5067
|
+
}): void;
|
|
5068
|
+
/**
|
|
4765
5069
|
* Replay a batch of CDC changes into this shard (point-in-time recovery).
|
|
4766
5070
|
* Schema-aware — it builds a `createShardCtxDb` writer — so the base class
|
|
4767
5071
|
* can't implement it; the codegen-generated subclass overrides this to call
|
|
@@ -4780,6 +5084,17 @@ declare abstract class ShardDO {
|
|
|
4780
5084
|
protected subscribe(ws: WebSocket, subId: string, query: SubscriptionQuery): "ok" | "serialize_failed" | "too_many";
|
|
4781
5085
|
protected unsubscribe(ws: WebSocket, subId: string): void;
|
|
4782
5086
|
/**
|
|
5087
|
+
* Register a live shape subscription on a socket — the partial-replication
|
|
5088
|
+
* parallel to {@link ShardDO.subscribe}. Stores the descriptor in the
|
|
5089
|
+
* attachment's `shapes` registry (created lazily) so it survives
|
|
5090
|
+
* hibernation, sharing the per-socket cap with `subs`. Returns a status the
|
|
5091
|
+
* caller surfaces as a structured error frame; never throws (a thrown
|
|
5092
|
+
* `webSocketMessage` is a fatal-channel error under the hibernation API).
|
|
5093
|
+
*/
|
|
5094
|
+
protected shapeSubscribe(ws: WebSocket, subId: string, shape: ShapeSubscriptionQuery): "ok" | "serialize_failed" | "too_many";
|
|
5095
|
+
/** Remove a shape subscription and its poke baseline. Mirrors {@link ShardDO.unsubscribe}'s rollback-on-serialize-failure contract. */
|
|
5096
|
+
protected shapeUnsubscribe(ws: WebSocket, subId: string): void;
|
|
5097
|
+
/**
|
|
4783
5098
|
* Decide whether a single subscription is interested in a mutation
|
|
4784
5099
|
* delta. The default implementation checks the table name, then runs a
|
|
4785
5100
|
* shallow-equality predicate over `query.args` against `delta.row`. A
|
|
@@ -4817,6 +5132,40 @@ declare abstract class ShardDO {
|
|
|
4817
5132
|
*/
|
|
4818
5133
|
protected executeSubscription(_functionPath: string, _args: Record<string, unknown>, _identity?: SubscriptionIdentity): Promise<SubscriptionOutcome | null>;
|
|
4819
5134
|
/**
|
|
5135
|
+
* Resolve a named shape to its concrete query plan for `identity`. The base
|
|
5136
|
+
* class has no shape registry, so it returns `undefined` — partial
|
|
5137
|
+
* replication is disabled and a `shape_subscribe` is rejected. The
|
|
5138
|
+
* codegen-generated subclass overrides this to look the shape up in the
|
|
5139
|
+
* project's `defineShape` registry, evaluate its `where(ctx, args)` under the
|
|
5140
|
+
* subscriber's verified identity, and AND-compose it with the table's RLS
|
|
5141
|
+
* read base-where into {@link ResolvedShape.effectiveWhere}.
|
|
5142
|
+
*
|
|
5143
|
+
* `identity` is the socket's OWN verified identity (the same unforgeable
|
|
5144
|
+
* value `refreshSubscriptions` threads), passed by value so this never reads
|
|
5145
|
+
* the mutable per-request identity fields. Returning `undefined` is the
|
|
5146
|
+
* fail-closed signal — an unknown shape, or an RLS-required table with no
|
|
5147
|
+
* policy resolving for this identity, yields no subscription rather than
|
|
5148
|
+
* leaking rows.
|
|
5149
|
+
*/
|
|
5150
|
+
protected resolveShape(_name: string, _args: Record<string, unknown>, _identity?: SubscriptionIdentity): ResolvedShape | undefined;
|
|
5151
|
+
/**
|
|
5152
|
+
* Read the FULL current membership of a `.global()`-table shape from its D1
|
|
5153
|
+
* (or Hyperdrive) backend — the seed/poll source for the latency-tiered
|
|
5154
|
+
* global shape path. A `.global()` table lives in another store with no
|
|
5155
|
+
* per-DO op-log, so this is the only way to learn its rows from inside the
|
|
5156
|
+
* shard DO; {@link ShardDO.seedGlobalShape} calls it once on subscribe and
|
|
5157
|
+
* {@link ShardDO.refreshGlobalShape} on every alarm tick, diffing the result
|
|
5158
|
+
* against the per-socket snapshot to compute the poke.
|
|
5159
|
+
*
|
|
5160
|
+
* The base class has no global backend, so it returns `[]` (a base-only DO,
|
|
5161
|
+
* or a project with no global tables, never resolves a global shape). The
|
|
5162
|
+
* codegen subclass overrides it to drain `globalDb.findMany(table, { where:
|
|
5163
|
+
* effectiveWhere })` under the socket's verified `identity` — the same
|
|
5164
|
+
* unforgeable value `resolveShape` composed the RLS predicate with, so the
|
|
5165
|
+
* D1 read is identity-scoped exactly like the poke-live path.
|
|
5166
|
+
*/
|
|
5167
|
+
protected readGlobalShapeRows(_resolved: ResolvedShape, _identity?: SubscriptionIdentity): Promise<ShapeRow[]>;
|
|
5168
|
+
/**
|
|
4820
5169
|
* Look up a streaming-query function and return a thunk that produces the
|
|
4821
5170
|
* `AsyncIterable<unknown>` when handed an {@link AbortSignal}. The codegen
|
|
4822
5171
|
* subclass overrides this to dispatch via `LUNORA_FUNCTIONS`; the base
|
|
@@ -5408,8 +5757,8 @@ declare abstract class ShardDO {
|
|
|
5408
5757
|
* by the next loop iteration, so every committed write is observed by a
|
|
5409
5758
|
* refresh that runs after it — bursts simply share a pass. The post-write
|
|
5410
5759
|
* high-watermark and live-socket set are re-read inside each
|
|
5411
|
-
* `refreshSubscriptions` call, so a later batch
|
|
5412
|
-
* committed state.
|
|
5760
|
+
* `refreshSubscriptions` / `pokeShapeSubscribers` call, so a later batch
|
|
5761
|
+
* always reflects the latest committed state.
|
|
5413
5762
|
*/
|
|
5414
5763
|
private drainSubscriptionRefreshes;
|
|
5415
5764
|
/**
|
|
@@ -5485,6 +5834,182 @@ declare abstract class ShardDO {
|
|
|
5485
5834
|
*/
|
|
5486
5835
|
private seedSubscription;
|
|
5487
5836
|
/**
|
|
5837
|
+
* Drive the full `shape_subscribe` flow as one failure-aware unit: persist the
|
|
5838
|
+
* attachment, seed the shape, and ack ONLY once both succeed. A persist
|
|
5839
|
+
* rejection (`too_many`/`serialize_failed`) or a seed that can't resolve the
|
|
5840
|
+
* shape (unknown / RLS-denied / cross-shard-invalid) rolls the attachment back
|
|
5841
|
+
* and sends an `error` frame instead of acking — so a client is never left
|
|
5842
|
+
* acked but subscribed to a shape that will never deliver. Never throws (a
|
|
5843
|
+
* thrown `webSocketMessage` is fatal to the hibernating socket).
|
|
5844
|
+
*/
|
|
5845
|
+
private handleShapeSubscribe;
|
|
5846
|
+
/** Send a structured `error` frame for a failed `shape_subscribe`, swallowing a send on an already-closed socket. */
|
|
5847
|
+
private sendShapeSubscribeError;
|
|
5848
|
+
/**
|
|
5849
|
+
* Seed a freshly-registered shape subscription. Resolves the shape under the
|
|
5850
|
+
* socket's verified identity, then ships either:
|
|
5851
|
+
*
|
|
5852
|
+
* - a **catch-up** poke (the membership diff in `(sinceCheckpoint, cursor]`)
|
|
5853
|
+
* when the client supplied a still-current checkpoint within the CDC retention
|
|
5854
|
+
* window and on this epoch — the cheap reconnect path; or
|
|
5855
|
+
* - a **full** insert-poke of the shape's entire current membership — a
|
|
5856
|
+
* first-time subscribe, or a reconnect that fell outside retention / forked
|
|
5857
|
+
* epoch.
|
|
5858
|
+
*
|
|
5859
|
+
* Either way the per-socket shape memo advances to the flush watermark so
|
|
5860
|
+
* later `pokeShapeSubscribers` passes diff from the right point.
|
|
5861
|
+
*
|
|
5862
|
+
* Returns `"ok"` once the shape resolved and its seed poke was attempted, or a
|
|
5863
|
+
* `{ code, message }` failure when the shape can't be resolved — an unknown /
|
|
5864
|
+
* RLS-denied shape (a base class with no registry resolves nothing), or a
|
|
5865
|
+
* `resolveShape` that threw (e.g. a cross-shard-join guard). The caller rolls
|
|
5866
|
+
* back the persisted attachment and errors instead of acking, so a client is
|
|
5867
|
+
* never left subscribed to a shape that will never deliver.
|
|
5868
|
+
*/
|
|
5869
|
+
private seedShapeSubscription;
|
|
5870
|
+
/**
|
|
5871
|
+
* Seed a non-`.global()` (op-log-backed) shape: either a catch-up diff over
|
|
5872
|
+
* `(sinceSeq, cursor]` when the client supplied a still-current checkpoint on
|
|
5873
|
+
* this epoch within the CDC retention window, or a full membership insert-poke
|
|
5874
|
+
* otherwise. The memo advances to `cursor` only once the poke is delivered, so
|
|
5875
|
+
* a failed send re-diffs from the prior point rather than skipping rows. May
|
|
5876
|
+
* throw (a stub `sql` handle, a membership probe failure); the caller converts
|
|
5877
|
+
* it to a structured `shape_subscribe` error.
|
|
5878
|
+
*/
|
|
5879
|
+
private seedOpLogShape;
|
|
5880
|
+
/**
|
|
5881
|
+
* Fan the membership diff of every shape affected by this flush to its
|
|
5882
|
+
* subscribers — the partial-replication parallel to
|
|
5883
|
+
* {@link ShardDO.refreshSubscriptions}, called alongside it from
|
|
5884
|
+
* {@link ShardDO.flushChangedTables}. For each socket (bounded fan-out, same
|
|
5885
|
+
* concurrency + `awaitWsDrain` backpressure as the subscription path) it
|
|
5886
|
+
* resolves each shape under the socket's identity, diffs only the shapes
|
|
5887
|
+
* whose table changed in `(memoCursor, frameCursor]`, and emits one poke
|
|
5888
|
+
* carrying a part per changed shape. No-op when no socket holds a shape.
|
|
5889
|
+
*/
|
|
5890
|
+
private pokeShapeSubscribers;
|
|
5891
|
+
/**
|
|
5892
|
+
* Diff every op-log-backed shape a socket holds against this flush, splitting
|
|
5893
|
+
* the results into the poke parts to send and the per-shape memo advances. A
|
|
5894
|
+
* `.global()` shape (driven by the alarm poll loop, not this flush) and a shape
|
|
5895
|
+
* whose table didn't change are skipped; a shape whose resolve/diff throws is
|
|
5896
|
+
* logged and skipped with its memo unadvanced so a later flush retries. Empty
|
|
5897
|
+
* diffs advance unconditionally; part-bearing shapes advance only once the
|
|
5898
|
+
* caller confirms the poke was delivered.
|
|
5899
|
+
*/
|
|
5900
|
+
private collectShapePokeParts;
|
|
5901
|
+
/**
|
|
5902
|
+
* Build the row-ops for a shape over the op range `(sinceSeq, upTo]`. Reads
|
|
5903
|
+
* the changelog (drained across pages), collapses to the latest op per row,
|
|
5904
|
+
* then runs ONE membership probe ({@link selectShapeMemberIds}) over the
|
|
5905
|
+
* changed ids: a row still in the set → upsert with its post-image doc
|
|
5906
|
+
* (projected to the shape's columns); a row that left the set, or any delete,
|
|
5907
|
+
* → `delete(key)` (a delete carries no post-image, so membership is
|
|
5908
|
+
* unknowable from the op alone — the client no-ops an unknown key).
|
|
5909
|
+
*/
|
|
5910
|
+
private buildShapeDiff;
|
|
5911
|
+
/** Build the full insert-poke of a shape's current membership — the first-seed/full-reseed rowset. */
|
|
5912
|
+
private buildShapeSeed;
|
|
5913
|
+
/**
|
|
5914
|
+
* Seed a `.global()`-table shape: read its full membership from D1, ship it
|
|
5915
|
+
* as one insert-poke, record the membership snapshot the alarm poll loop will
|
|
5916
|
+
* diff against, and arm the poll alarm. A global shape has no op-log cursor,
|
|
5917
|
+
* so the poke is stamped at this DO's current cursor (informational only) and
|
|
5918
|
+
* carries no resume base — a reconnect always re-seeds full.
|
|
5919
|
+
*/
|
|
5920
|
+
private seedGlobalShape;
|
|
5921
|
+
/**
|
|
5922
|
+
* Re-read a global shape's membership from D1 and poke only the diff against
|
|
5923
|
+
* the socket's last snapshot: a new key → `insert`, a changed projected value
|
|
5924
|
+
* → `update`, a vanished key → `delete`. The snapshot advances to the fresh
|
|
5925
|
+
* membership even when the diff is empty, so the next tick compares from here.
|
|
5926
|
+
* No frame is sent when nothing changed (the common steady-state tick).
|
|
5927
|
+
*/
|
|
5928
|
+
private refreshGlobalShape;
|
|
5929
|
+
/**
|
|
5930
|
+
* Read a socket's global-shape baseline, preferring the hot in-memory cache
|
|
5931
|
+
* and falling back to the durable `__global_shape_snapshot` table on a miss (a
|
|
5932
|
+
* cold socket after a hibernation eviction). The loaded baseline repopulates
|
|
5933
|
+
* the cache so subsequent ticks in this wake hit memory. An empty
|
|
5934
|
+
* `connectionId` (a socket that never went through the lifecycle-aware upgrade,
|
|
5935
|
+
* e.g. a unit harness) skips the durable read and behaves as in-memory-only.
|
|
5936
|
+
*/
|
|
5937
|
+
private readGlobalSnapshot;
|
|
5938
|
+
/** Record a socket's latest global-shape membership snapshot in the in-memory cache (creating the per-socket map lazily). */
|
|
5939
|
+
private recordGlobalSnapshot;
|
|
5940
|
+
/**
|
|
5941
|
+
* Load a durable global-shape baseline from SQLite, or an empty map when none
|
|
5942
|
+
* is stored / the durable path is unavailable. A stub `sql` handle (unit
|
|
5943
|
+
* harness) or a missing table degrades to in-memory-only behavior rather than
|
|
5944
|
+
* failing the poll tick.
|
|
5945
|
+
*/
|
|
5946
|
+
private loadGlobalSnapshot;
|
|
5947
|
+
/**
|
|
5948
|
+
* Persist a socket's global-shape baseline to SQLite so the poll-loop diff
|
|
5949
|
+
* survives hibernation. A no-op for a connection-id-less socket or a stub
|
|
5950
|
+
* `sql` handle (the in-memory cache then carries the baseline for the DO's
|
|
5951
|
+
* lifetime, matching the pre-durable behavior).
|
|
5952
|
+
*/
|
|
5953
|
+
private saveGlobalSnapshot;
|
|
5954
|
+
/**
|
|
5955
|
+
* Arm the poll alarm for `.global()` shapes if one isn't already pending.
|
|
5956
|
+
* Idempotent — every global-shape seed calls it, but only the first arms the
|
|
5957
|
+
* alarm. Degrades to a no-op when the runtime exposes no `setAlarm` (the unit
|
|
5958
|
+
* harness): a global shape is then seed-only, which the poll-loop tests assert
|
|
5959
|
+
* by driving {@link ShardDO.alarm} directly.
|
|
5960
|
+
*/
|
|
5961
|
+
private scheduleGlobalPoll;
|
|
5962
|
+
/**
|
|
5963
|
+
* Record a contained shape-tier error (poll / poke / seed) into the DO's log
|
|
5964
|
+
* ring without aborting the rest of the pass. The shape pipeline is a
|
|
5965
|
+
* best-effort fan-out: one socket's read or one shape's resolve failing must
|
|
5966
|
+
* never take down the others — so callers swallow the throw and surface it
|
|
5967
|
+
* here for diagnosis. `context` is a synthetic `shape:phase:subId` path.
|
|
5968
|
+
*/
|
|
5969
|
+
private recordShapeError;
|
|
5970
|
+
/**
|
|
5971
|
+
* Guard a global shape's materialized membership against {@link
|
|
5972
|
+
* ShardDO.GLOBAL_SHAPE_MAX_ROWS}. Returns `true` when the row count is within
|
|
5973
|
+
* the cap; otherwise records a diagnosable error and returns `false` so the
|
|
5974
|
+
* caller fails the shape closed (no snapshot retained, no poke sent) rather
|
|
5975
|
+
* than risking a DO eviction on an unbounded global table. The transient read
|
|
5976
|
+
* buffer is bounded by the same gate — an over-cap membership is dropped, not
|
|
5977
|
+
* snapshotted per socket.
|
|
5978
|
+
*/
|
|
5979
|
+
private withinGlobalShapeBound;
|
|
5980
|
+
/**
|
|
5981
|
+
* Refresh every `.global()`-table shape held across all live sockets, one
|
|
5982
|
+
* diff-poke per (socket, shape). Returns the number of global shapes still
|
|
5983
|
+
* subscribed so {@link ShardDO.alarm} knows whether to re-arm. Expired sockets
|
|
5984
|
+
* are dropped in passing (mirrors {@link ShardDO.pokeShapeSubscribers}).
|
|
5985
|
+
*/
|
|
5986
|
+
private pollGlobalShapes;
|
|
5987
|
+
/**
|
|
5988
|
+
* Refresh one socket's `.global()`-table shapes, containing per-shape
|
|
5989
|
+
* failures so a single throw never aborts the poll tick (and with it the
|
|
5990
|
+
* re-arm). Returns the count of global shapes still subscribed on this socket
|
|
5991
|
+
* — a failed `resolveShape`/read keeps its shape counted so the alarm keeps
|
|
5992
|
+
* polling and retries next tick.
|
|
5993
|
+
*/
|
|
5994
|
+
private pollSocketGlobalShapes;
|
|
5995
|
+
/**
|
|
5996
|
+
* Send one poke (`pokeStart` → `pokePart` per shape → `pokeEnd`) to a socket.
|
|
5997
|
+
* All parts apply atomically at `pokeEnd`. Returns `true` when every frame was
|
|
5998
|
+
* handed to the socket, `false` when a send threw mid-poke (the socket closed)
|
|
5999
|
+
* — callers must NOT advance their shape baselines on a `false` so the client
|
|
6000
|
+
* re-receives the rows on its next flush/reconnect instead of losing them.
|
|
6001
|
+
*/
|
|
6002
|
+
private sendPoke;
|
|
6003
|
+
/**
|
|
6004
|
+
* The recipient client's `__client_watermark` for stamping a poke's
|
|
6005
|
+
* `lastMutationId`, or `undefined` when the socket announced no `clientId`
|
|
6006
|
+
* (a client that doesn't use custom mutators — nothing to drop an overlay
|
|
6007
|
+
* for). Read off the attachment so it survives hibernation.
|
|
6008
|
+
*/
|
|
6009
|
+
private socketClientWatermark;
|
|
6010
|
+
/** Record a shape's poke baseline cursor on a socket (creating the per-socket map lazily). */
|
|
6011
|
+
private recordShapeMemo;
|
|
6012
|
+
/**
|
|
5488
6013
|
* Record `outcome` as this socket's diff baseline for `subId` without
|
|
5489
6014
|
* sending a frame. Used by the resume fast-path, where the client keeps its
|
|
5490
6015
|
* cached value but the server still needs a baseline so the next
|
|
@@ -5799,4 +6324,4 @@ interface WhereSqlStrategy {
|
|
|
5799
6324
|
* `undefined` when the input imposes no constraint (empty `where`).
|
|
5800
6325
|
*/
|
|
5801
6326
|
declare const compileWhereSql: (where: WhereInput | undefined, strategy: WhereSqlStrategy) => SQL | undefined;
|
|
5802
|
-
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, AGGREGATE_SQL_FUNCTION, AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, type AdvisoriesResult, type AdvisoryFinding, type AggregateIndexDefinitionLike, type AggregateOp, type AggregateOptions, type AggregateResult, type AggregateTally, type ApplyOnDeleteOptions, type AuditEntry, type AuditLogResult, type AuthMetrics, type AuthMetricsBucket, type BroadcastDelta, CDC_LOG_TABLE, type CacheEntry, type CapturedMailRow, type CdcChange, type Clock, type ColumnMeta, type ColumnMetaLike, ConflictError, type CountArgs, CountRlsUnsupportedError, type CtxDbOptions, DATA_MIGRATION_STATE_TABLE, DEFAULT_MAX_RELATION_KEYS, type DataMigrationDocument, type DataMigrationLike, type DataMigrationTransform, type DatabaseWriterLike, type DependencyTracker, type DeployInfo, type ExportRow, type ExportShardAdminArgs, type ExportShardArgs, FLAGS_FUNCTION_PREFIX, FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_TABLE, type FacetColumnOptions, type FacetColumnResult, type FacetValue, type FieldOperators, type FlagEvaluation, type FlagsResult, type FunctionCallStat, type FunctionMetricBucket, type FunctionMetricIndexHit, type FunctionStatsResult, type GroupByEntry, type GroupByOptions, type HibernatableWebSocket, type IdGenerator, type ImportError, type ImportShardAdminArgs, type ImportShardArgs, type ImportShardResult, type IndexDefinitionLike, type IndexRangeBuilderLike, LogBuffer, type LogEntry, type LogEventInput, type LogLevel, type LogSink, MAIL_RETENTION, MAIL_TABLE, MAX_SQL_ROWS, MIN_ADMIN_TOKEN_LENGTH, MIN_AUTH_SECRET_LENGTH, type MaskColumnMetadata, type MaskPoliciesResult, type MigrationDirection, type MigrationRunResult, type MigrationStatus, type MigrationStatusRow, type MutationDelta, type NestedWith, NotFoundError, NotUniqueError, type OnDeleteActionLike, type OrderByInput, type OrderKey, type PaginationOptions, type PitrBookmarkResult, type PitrRestoreArgs, type PitrRestoreResult, type PitrStorage, type QueryArgs, type QueryPage, type QueueMetadata, type QueuesResult, RANK_TIEBREAK, RELATION_FUNCTION_PREFIX, RLS_UNWRAP_SYMBOL, ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, type RankDirection, type RankIndexDefinitionLike, type RankOptions, type RankPage, type RankPageOptions, type RankPageRow, type RankPageRowKey, type RankResult, type RankSortKeyLike, ReactiveCache, type ReactiveCacheOptions, type ReadHook, type ReadTablePageOptions, type RecordAuthEventInput, type RecordFunctionMetricInput, type RecordMailInput, type RelationDefinitionLike, type RenderedSql, type ResolveRelationPredicatesOptions, type ResolveWithOptions, type RestrictableQueryOptions, type RlsPoliciesResult, type RlsPolicyMetadata, RlsRequiredError, type RlsRoleMetadata, type RpcRequest, type RunDataMigrationOptions, type RunShardApplyCdcArgs, type RunShardApplyCdcResult, type RunShardBulkDeleteArgs, type RunShardBulkDeleteResult, type RunShardExportArgs, type RunShardImportArgs, type RunShardMigrationArgs, type RunShardRankBeforeArgs, type RunShardRankPageArgs, type RunShardWriteArgs, type RunShardWriteResult, type RunTriggersOptions, SCAN_DEP, SESSION_DO_TTL_DEFAULT, SHARD_REGISTRY_DO_NAME, type ScheduledFunctionDoc, type SchedulerLike, type SchemaLike, type SearchFilterBuilderLike, type SecurityAuditResult, type SecurityFinding, type SecurityFindingKind, type SecurityFindingLevel, type SelectMatchingIdsOptions, type ServerDefaultContextLike, SessionDO, type SessionRecord, type SettingEntry, type SettingKind, type SettingsResult, ShardDO, type ShardDOOptions, type ShardDOState, type ShardRankPageResult, ShardRegistryDO, type SocketAttachment, type SortDirection, type SqlConsoleResult, type SqlCursor, type SqlEngine, type SqlExec, type StorageRuleMetadata, type StorageRulesResult, type StudioFeaturesResult, type SubscriptionEnvelope, type SubscriptionOutcome, type SubscriptionQuery, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemReaderOptions, type SystemReaderSchedulerLike, type SystemReaderStorageLike, type SystemTableName, type TableColumnsResult, type TableDefinitionLike, type TableIndexInfo, type TableIndexesResult, type TableInfo, type TablePage, type TableReaderLike, type TablesColumnsResult, type TransactionSqlLike, type TriggerContextLike, type TriggerDefinitionLike, type TriggerEventLike, type TriggerOpLike, type TriggerTimingLike, type ValidatorLike, type WhereInput, type WhereSqlStrategy, type WithInput, type WorkflowMetadata, type WorkflowsResult, type WriteEvent, type WriteHook, aggregateSqlFunction, aggregateTableName, applyCdcChanges, applyOnDelete, applySelect, armRestore, assertFlatPredicate, assertReadonly, assertValidClientId, backfillAggregateIndexes, backfillRankIndexes, buildFtsMatch, buildSecurityAudit, buildSeekWhere, clearCapturedMail, coerceAggregateNumber, compileWhereSql, containsRelationPredicate, createDependencyTracker, createShardCtxDb, createSystemReader, decodeCursor, depKey, encodeAggregateKey, encodeCursor, encodePartitionKey, ensureAuthMetricsTables, ensureFunctionMetricsTables, ensureMailTable, exportShardRows, exportShardTable, facetColumn, foldAggregateTally, ftsTableName, guardWriter, hasTrigger, importShardRows, isRelationPredicate, listTables, matchesRankStaticWhere, matchesStaticWhere, mergeWhere, normalizeCountArgument, normalizeIdStructurally, normalizeOrderKeys, parseExportShardArgs, parseImportShardArgs, planAggregateLookup, rankTableName, reactiveCacheKey, readAggregateValue, readAuthMetrics, readBookmark, readCapturedMail, readCdcChanges, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetrics, readFunctionMetricsTotals, readMigrationStatus, readTablePage, recordAuthEvent, recordCapturedMail, recordFunctionMetric, renderSql, resolveRankPartition, resolveRelationPredicates, resolveWith, runDataMigration, runReadonlySql, runRowValidators, runShardMigrations, runTriggers, scoreDocument, selectExportTables, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy, selectMatchingIds, serveRelationFanout, softDeleteScope, sortColumnName, stableStringify, stringifySearchText, subscriptionListDeltas, throwingScheduler, tokenizeSearch, trimCdcChanges, validateImportRow };
|
|
6327
|
+
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, AGGREGATE_SQL_FUNCTION, AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, type AdvisoriesResult, type AdvisoryFinding, type AggregateIndexDefinitionLike, type AggregateOp, type AggregateOptions, type AggregateResult, type AggregateTally, type ApplyOnDeleteOptions, type AuditEntry, type AuditLogResult, type AuthMetrics, type AuthMetricsBucket, type BroadcastDelta, CDC_LOG_TABLE, type CacheEntry, type CapturedMailRow, type CdcChange, type Clock, type ColumnMeta, type ColumnMetaLike, ConflictError, type CountArgs, CountRlsUnsupportedError, type CtxDbOptions, DATA_MIGRATION_STATE_TABLE, DEFAULT_MAX_RELATION_KEYS, type DataMigrationDocument, type DataMigrationLike, type DataMigrationTransform, type DatabaseWriterLike, type DependencyTracker, type DeployInfo, type ExportRow, type ExportShardAdminArgs, type ExportShardArgs, FLAGS_FUNCTION_PREFIX, FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_TABLE, type FacetColumnOptions, type FacetColumnResult, type FacetValue, type FieldOperators, type FlagEvaluation, type FlagsResult, type FunctionCallStat, type FunctionMetricBucket, type FunctionMetricIndexHit, type FunctionStatsResult, type GroupByEntry, type GroupByOptions, type HibernatableWebSocket, type IdGenerator, type ImportError, type ImportShardAdminArgs, type ImportShardArgs, type ImportShardResult, type IndexDefinitionLike, type IndexRangeBuilderLike, LogBuffer, type LogEntry, type LogEventInput, type LogLevel, type LogSink, MAIL_RETENTION, MAIL_TABLE, MAX_SQL_ROWS, MIN_ADMIN_TOKEN_LENGTH, MIN_AUTH_SECRET_LENGTH, type MaskColumnMetadata, type MaskPoliciesResult, type MigrationDirection, type MigrationRunResult, type MigrationStatus, type MigrationStatusRow, type MutationDelta, type NestedWith, NotFoundError, NotUniqueError, type OnDeleteActionLike, type OrderByInput, type OrderKey, type PaginationOptions, type PitrBookmarkResult, type PitrRestoreArgs, type PitrRestoreResult, type PitrStorage, type QueryArgs, type QueryPage, type QueueMetadata, type QueuesResult, RANK_TIEBREAK, RELATION_FUNCTION_PREFIX, RLS_UNWRAP_SYMBOL, ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, type RankDirection, type RankIndexDefinitionLike, type RankOptions, type RankPage, type RankPageOptions, type RankPageRow, type RankPageRowKey, type RankResult, type RankSortKeyLike, ReactiveCache, type ReactiveCacheOptions, type ReadHook, type ReadTablePageOptions, type RecordAuthEventInput, type RecordFunctionMetricInput, type RecordMailInput, type RelationDefinitionLike, type RenderedSql, type ResolveRelationPredicatesOptions, type ResolveWithOptions, type RestrictableQueryOptions, type RlsPoliciesResult, type RlsPolicyMetadata, RlsRequiredError, type RlsRoleMetadata, type RpcRequest, type RunDataMigrationOptions, type RunShardApplyCdcArgs, type RunShardApplyCdcResult, type RunShardBulkDeleteArgs, type RunShardBulkDeleteResult, type RunShardExportArgs, type RunShardImportArgs, type RunShardMigrationArgs, type RunShardRankBeforeArgs, type RunShardRankPageArgs, type RunShardWriteArgs, type RunShardWriteResult, type RunTriggersOptions, SCAN_DEP, SESSION_DO_TTL_DEFAULT, SHARD_REGISTRY_DO_NAME, type ScheduledFunctionDoc, type SchedulerLike, type SchemaLike, type SearchFilterBuilderLike, type SecurityAuditResult, type SecurityFinding, type SecurityFindingKind, type SecurityFindingLevel, type SelectMatchingIdsOptions, type ServerDefaultContextLike, SessionDO, type SessionRecord, type SettingEntry, type SettingKind, type SettingsResult, type ShapeSubscriptionQuery, ShardDO, type ShardDOOptions, type ShardDOState, type ShardRankPageResult, ShardRegistryDO, type SocketAttachment, type SortDirection, type SqlConsoleResult, type SqlCursor, type SqlEngine, type SqlExec, type StorageRuleMetadata, type StorageRulesResult, type StudioFeaturesResult, type SubscriptionEnvelope, type SubscriptionOutcome, type SubscriptionQuery, type SystemDatabaseReader, type SystemDoc, type SystemQuery, type SystemReaderOptions, type SystemReaderSchedulerLike, type SystemReaderStorageLike, type SystemTableName, type TableColumnsResult, type TableDefinitionLike, type TableIndexInfo, type TableIndexesResult, type TableInfo, type TablePage, type TableReaderLike, type TablesColumnsResult, type TransactionSqlLike, type TriggerContextLike, type TriggerDefinitionLike, type TriggerEventLike, type TriggerOpLike, type TriggerTimingLike, type ValidatorLike, type WhereInput, type WhereSqlStrategy, type WithInput, type WorkflowMetadata, type WorkflowsResult, type WriteEvent, type WriteHook, aggregateSqlFunction, aggregateTableName, applyCdcChanges, applyOnDelete, applySelect, armRestore, assertFlatPredicate, assertReadonly, assertShapeShardable, assertValidClientId, backfillAggregateIndexes, backfillRankIndexes, buildFtsMatch, buildSecurityAudit, buildSeekWhere, clearCapturedMail, coerceAggregateNumber, compileWhereSql, containsRelationPredicate, createDependencyTracker, createShardCtxDb, createSystemReader, decodeCursor, depKey, encodeAggregateKey, encodeCursor, encodePartitionKey, ensureAuthMetricsTables, ensureFunctionMetricsTables, ensureMailTable, exportShardRows, exportShardTable, facetColumn, foldAggregateTally, ftsTableName, guardWriter, hasTrigger, importShardRows, isRelationPredicate, listTables, matchesRankStaticWhere, matchesStaticWhere, mergeWhere, normalizeCountArgument, normalizeIdStructurally, normalizeOrderKeys, parseExportShardArgs, parseImportShardArgs, planAggregateLookup, rankTableName, reactiveCacheKey, readAggregateValue, readAuthMetrics, readBookmark, readCapturedMail, readCdcChanges, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetrics, readFunctionMetricsTotals, readMigrationStatus, readTablePage, recordAuthEvent, recordCapturedMail, recordFunctionMetric, renderSql, resolveRankPartition, resolveRelationPredicates, resolveWith, runDataMigration, runReadonlySql, runRowValidators, runShardMigrations, runTriggers, scoreDocument, selectExportTables, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy, selectMatchingIds, serveRelationFanout, softDeleteScope, sortColumnName, stableStringify, stringifySearchText, subscriptionListDeltas, throwingScheduler, tokenizeSearch, trimCdcChanges, validateImportRow };
|