@fitzzero/quickdraw-core 5.1.1 → 5.1.2
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/README.md +533 -180
- package/dist/{admin-DKwkIh5i.d.ts → admin-DWWrT1h6.d.ts} +2 -2
- package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-D4bFKsrb.d.ts} +6 -4
- package/dist/{auth-BhWqdyb-.d.ts → auth-DXiSJZaf.d.ts} +42 -16
- package/dist/{caller-CXTFswBO.d.ts → caller-BT-Mv4bD.d.ts} +117 -22
- package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
- package/dist/chunk-4D2DOGAW.js.map +1 -0
- package/dist/chunk-5CGO426C.js +15 -0
- package/dist/chunk-5CGO426C.js.map +1 -0
- package/dist/{chunk-RZTP4IEW.js → chunk-6K5BY47X.js} +4594 -3481
- package/dist/chunk-6K5BY47X.js.map +1 -0
- package/dist/{chunk-VSQBHPWH.js → chunk-753VJIUP.js} +13 -15
- package/dist/chunk-753VJIUP.js.map +1 -0
- package/dist/{chunk-ZIVPHYRG.js → chunk-7QCUX4TK.js} +4 -4
- package/dist/chunk-7QCUX4TK.js.map +1 -0
- package/dist/chunk-AK23XSWD.js +16 -0
- package/dist/chunk-AK23XSWD.js.map +1 -0
- package/dist/{chunk-SHEGLZEP.js → chunk-AONAFOYU.js} +14 -5
- package/dist/{chunk-SHEGLZEP.js.map → chunk-AONAFOYU.js.map} +1 -1
- package/dist/chunk-DKE6QO26.js +136 -0
- package/dist/chunk-DKE6QO26.js.map +1 -0
- package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
- package/dist/chunk-DUBU3BB3.js.map +1 -0
- package/dist/{chunk-CDKG4TFA.js → chunk-GKH3LJ7N.js} +1 -1
- package/dist/chunk-GKH3LJ7N.js.map +1 -0
- package/dist/{chunk-OECZPRPW.js → chunk-GSIPUNJL.js} +49 -9
- package/dist/chunk-GSIPUNJL.js.map +1 -0
- package/dist/{chunk-DD4SKCNO.js → chunk-LCC7HNFP.js} +12 -1
- package/dist/chunk-LCC7HNFP.js.map +1 -0
- package/dist/{chunk-2PWMUVC7.js → chunk-MBH6IDSM.js} +480 -12
- package/dist/chunk-MBH6IDSM.js.map +1 -0
- package/dist/{chunk-QCHKWIRS.js → chunk-NMXYENH4.js} +10 -10
- package/dist/{chunk-QCHKWIRS.js.map → chunk-NMXYENH4.js.map} +1 -1
- package/dist/chunk-NO4M6PO5.js +101 -0
- package/dist/chunk-NO4M6PO5.js.map +1 -0
- package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
- package/dist/chunk-NW6U45HX.js.map +1 -0
- package/dist/{chunk-REX5YPHX.js → chunk-RJ5I2VO3.js} +74 -19
- package/dist/chunk-RJ5I2VO3.js.map +1 -0
- package/dist/{chunk-QEKVYG5F.js → chunk-RL4VKLBX.js} +1 -1
- package/dist/{chunk-QEKVYG5F.js.map → chunk-RL4VKLBX.js.map} +1 -1
- package/dist/chunk-XH2IZVLT.js +62 -0
- package/dist/chunk-XH2IZVLT.js.map +1 -0
- package/dist/{chunk-4DIQHASK.js → chunk-Z5ILULF2.js} +26 -7
- package/dist/chunk-Z5ILULF2.js.map +1 -0
- package/dist/cli/quickdraw-docs.js +5 -3
- package/dist/cli/quickdraw-docs.js.map +1 -1
- package/dist/client/index.d.ts +30 -18
- package/dist/client/index.js +8 -6
- package/dist/client/index.js.map +1 -1
- package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-hWcPUVS9.d.ts} +3 -3
- package/dist/{connection-Cr1BU07W.d.ts → connection-CgijdGpT.d.ts} +8 -4
- package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Cp-Wk500.d.ts} +36 -14
- package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-BB_PkqQ7.d.ts} +16 -10
- package/dist/{envelope-Cp3YcVxC.d.ts → envelope-DzWyIXjj.d.ts} +18 -4
- package/dist/{http-Djj2Inuu.d.ts → http-DotQ5bj8.d.ts} +68 -17
- package/dist/index.d.ts +7 -7
- package/dist/index.js +37 -13
- package/dist/index.js.map +1 -1
- package/dist/{infer-Teo1xpsd.d.ts → infer-BmoZsL9a.d.ts} +43 -10
- package/dist/logger-Yz93KzdV.d.ts +30 -0
- package/dist/{metrics-BdBu5o8G.d.ts → metrics-DW80Exve.d.ts} +2 -2
- package/dist/origins-kvpxnVcW.d.ts +8 -0
- package/dist/prisma/index.d.ts +5 -5
- package/dist/prisma/index.js +130 -67
- package/dist/prisma/index.js.map +1 -1
- package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
- package/dist/server/auth/index.d.ts +82 -33
- package/dist/server/auth/index.js +273 -268
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/express/index.d.ts +9 -2
- package/dist/server/express/index.js +1 -1
- package/dist/server/index.d.ts +147 -67
- package/dist/server/index.js +520 -381
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/index.d.ts +63 -17
- package/dist/server/mcp/index.js +256 -54
- package/dist/server/mcp/index.js.map +1 -1
- package/dist/server/otel.d.ts +3 -3
- package/dist/{sharing-DVa8W-yR.d.ts → sharing-UDLn1049.d.ts} +3 -3
- package/dist/testing/client.d.ts +14 -14
- package/dist/testing/client.js +9 -7
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts +12 -12
- package/dist/testing/index.js +21 -12
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock.d.ts +5 -5
- package/dist/testing/mock.js +8 -6
- package/dist/{types-Cu0vmx7c.d.ts → types-CYliTP65.d.ts} +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-2PWMUVC7.js.map +0 -1
- package/dist/chunk-4DIQHASK.js.map +0 -1
- package/dist/chunk-CDKG4TFA.js.map +0 -1
- package/dist/chunk-DD4SKCNO.js.map +0 -1
- package/dist/chunk-H23KEFBA.js.map +0 -1
- package/dist/chunk-OECZPRPW.js.map +0 -1
- package/dist/chunk-REX5YPHX.js.map +0 -1
- package/dist/chunk-RT6OILOI.js.map +0 -1
- package/dist/chunk-RZTP4IEW.js.map +0 -1
- package/dist/chunk-TBMKJ26R.js.map +0 -1
- package/dist/chunk-VSQBHPWH.js.map +0 -1
- package/dist/chunk-YSWH776Y.js +0 -13
- package/dist/chunk-YSWH776Y.js.map +0 -1
- package/dist/chunk-ZIVPHYRG.js.map +0 -1
- package/dist/logger-BY28acW-.d.ts +0 -16
- /package/dist/{rateLimit-ZMIZJUZF.js.map → rateLimit-5RKBFLUR.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/access/forms.ts","../src/server/access/policy.ts","../src/server/access/policies/anyOf.ts","../src/server/access/policies/members.ts","../src/server/collections/define.ts","../src/server/collections/buffer.ts","../src/server/collections/items.ts","../src/server/collections/cursor.ts","../src/server/collections/index.ts","../src/server/access/cache.ts","../src/server/access/tools.ts","../src/server/emit/pending.ts","../src/server/emit/subscriptions.ts","../src/server/realtime/validate.ts","../src/server/realtime/channels.ts","../src/server/cluster/acks.ts","../src/server/cluster/lastSeen.ts","../src/server/cluster/counter.ts","../src/server/cluster/revisions.ts","../src/server/cluster/deployment.ts","../src/server/realtime/presenceRequests.ts","../src/server/realtime/presence.ts","../src/server/realtime/seeds.ts","../src/server/emit/resolve.ts","../src/server/access/rowless.ts","../src/server/emit/affects.ts","../src/server/emit/changeLog.ts","../src/server/emit/hub.ts","../src/server/emit/versions.ts","../src/server/emit/subscribe.ts","../src/server/emit/race.ts","../src/server/realtime/streamIndex.ts","../src/server/emit/revocation.ts","../src/server/realtime/streamTargets.ts","../src/server/realtime/streamRevocation.ts","../src/server/realtime/streamSubscribe.ts","../src/server/access/basicEngine.ts","../src/server/access/policies/resolver.ts","../src/server/collections/scopes.ts","../src/server/collections/bind.ts","../src/server/emit/frames.ts","../src/server/collections/deltas.ts","../src/server/collections/moves.ts","../src/server/collections/access.ts","../src/server/collections/selfAccess.ts","../src/server/collections/unnamed.ts","../src/server/collections/send.ts","../src/server/collections/collectionSink.ts","../src/server/pipeline/concurrency.ts","../src/server/emit/lane.ts","../src/server/emit/answer.ts","../src/server/collections/requests.ts","../src/server/collections/snapshot.ts","../src/server/collections/subscribe.ts","../src/server/collections/extension.ts","../src/server/collections/selfRecheck.ts","../src/server/collections/revocation.ts","../src/server/collections/live.ts","../src/server/realtime/events.ts","../src/server/realtime/roomFrames.ts","../src/server/realtime/roomNames.ts","../src/server/realtime/leaving.ts","../src/server/realtime/rooms.ts","../src/server/realtime/streamSubscriptions.ts","../src/server/realtime/streamFeeds.ts","../src/server/realtime/streamPushes.ts","../src/server/realtime/streams.ts","../src/server/realtime/realtime.ts","../src/server/collections/changed.ts","../src/server/topicIndex.ts","../src/server/topicRevocation.ts","../src/server/topics.ts","../src/server/emit/entitySink.ts","../src/server/emit/extension.ts","../src/server/emit/live.ts","../src/server/access/api.ts","../src/server/access/bindings.ts","../src/server/access/changes.ts","../src/server/access/rowAccess.ts","../src/server/access/engine.ts","../src/server/access/resolverReads.ts","../src/server/pipeline/accessSettings.ts","../src/server/emit/tieredOutputs.ts","../src/server/realtime/channelWarnings.ts","../src/server/pipeline/definitionWarnings.ts","../src/server/uow/untracked.ts","../src/server/pipeline/tracking.ts","../src/server/pipeline/settings.ts","../src/server/access/claims.ts","../src/server/pipeline/run.ts","../src/server/pipeline/share.ts","../src/server/pipeline/replies.ts","../src/server/pipeline/execute.ts","../src/server/pipeline/notModified.ts","../src/server/pipeline/stages.ts","../src/server/pipeline/pipeline.ts","../src/server/registry.ts","../src/server/dispatcher.ts","../src/server/observability/stallWatchdog.ts","../src/server/transports/http.ts","../src/server/rateLimit.ts","../src/server/createServer.ts","../src/server/access/trackedModels.ts","../src/server/lifecycle.ts","../src/server/transports/socketServer.ts","../src/server/transports/legacy.ts","../src/server/transports/middleware.ts","../src/server/cluster/adapterClients.ts","../src/server/cluster/broadcasts.ts","../src/server/transports/pushes.ts","../src/server/transports/socketio.ts"],"sourcesContent":["// Run-time side of the access forms: the `custom(fn)` builder, the shape\n// check `defineService` runs on every method's form, and the row ids an\n// `entry` or `scope` form refers to.\n\nimport { isAccessLevel } from \"../../contract/access\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { AccessForm, CustomAccess, EntryAccess, ScopeAccess } from \"./types\";\n\n/**\n * A custom access check: the call passes when `check(ctx, input)` resolves\n * `true`. The caller must be authenticated first, so `ctx.principal` is\n * never `null` in `check`. A service-wide `Admin` grant passes without\n * running it (unless the service sets `adminBypass: false`). A method with\n * custom access cannot `share: \"all\"`, because its result may depend on who\n * asks.\n *\n * It replaces the row check: on a service with an access policy,\n * `defineService` refuses it on a method whose input has `id` unless the\n * method says `rowless: true`. A check on the caller's claims is the\n * method's `claims`, beside an `entry` form: no grant skips that.\n *\n * @example\n * access: custom((ctx, input) => ctx.principal.userId === input.ownerId),\n */\nexport function custom<Input, Ctx>(\n check: (ctx: Ctx, input: Input) => boolean | PromiseLike<boolean>,\n): CustomAccess<Input, Ctx> {\n if (typeof check !== \"function\") {\n throw new TypeError(\"custom(check): check must be a function\");\n }\n return Object.freeze({ kind: \"custom\", check });\n}\n\ntype UnknownForm = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is UnknownForm {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** True when `form` is a `custom(fn)` form. */\nexport function isCustomAccess(form: AccessForm): form is CustomAccess {\n return typeof form === \"object\" && form.kind === \"custom\";\n}\n\nfunction isIdSelector(value: unknown): boolean {\n return (typeof value === \"string\" && value.length > 0) || typeof value === \"function\";\n}\n\nconst OBJECT_FORM_KEYS = new Set([\"service\", \"entry\", \"scope\", \"of\", \"id\"]);\n\nfunction objectFormProblem(form: UnknownForm): string | undefined {\n const unknownKey = Object.keys(form).find((key) => !OBJECT_FORM_KEYS.has(key));\n if (unknownKey !== undefined) {\n return `has an unknown key \"${unknownKey}\"`;\n }\n const levels = [\"service\", \"entry\", \"scope\"].filter((key) => form[key] !== undefined);\n if (levels.length === 0 || !levels.every((key) => isAccessLevel(form[key]))) {\n return \"needs service, entry or scope set to an access level\";\n }\n if (form.scope !== undefined) {\n const valid = levels.length === 1 && isRecord(form.of) && isIdSelector(form.id);\n return valid ? undefined : \"a scope form is { scope, of: contract, id } and nothing else\";\n }\n if (form.of !== undefined || (form.id !== undefined && !isIdSelector(form.id))) {\n return \"id must be an input key or a function, and of belongs to scope forms\";\n }\n return form.entry === undefined && form.id !== undefined\n ? \"id belongs to entry and scope forms\"\n : undefined;\n}\n\n/**\n * Why `form` is not an access form, or `undefined` when it is one. Run by\n * `defineService` so a JavaScript caller or a cast fails at definition time\n * rather than on the first call.\n */\nexport function accessFormProblem(form: unknown): string | undefined {\n if (form === \"public\" || form === \"authenticated\") {\n return undefined;\n }\n if (!isRecord(form)) {\n return 'must be \"public\", \"authenticated\", { service }, { entry }, { scope, of, id } or custom(fn)';\n }\n if (form.kind === \"custom\") {\n return typeof form.check === \"function\" ? undefined : \"custom access needs a check function\";\n }\n return objectFormProblem(form);\n}\n\nfunction idsFrom(value: unknown): readonly string[] | undefined {\n if (typeof value === \"string\" && value.length > 0) {\n return [value];\n }\n const isIdList =\n Array.isArray(value) &&\n value.length > 0 &&\n value.every((id) => typeof id === \"string\" && id.length > 0);\n return isIdList ? (value as readonly string[]) : undefined;\n}\n\n/**\n * The row ids an `entry` or `scope` form refers to, read from the parsed\n * input: `id` names an input key or is a function of the input, and an\n * `entry` form without `id` reads `input.id`. A missing or empty id is a\n * `FORBIDDEN` call: a failed lookup denies.\n */\nexport function accessIds(form: EntryAccess | ScopeAccess, input: unknown): readonly string[] {\n const { id } = form;\n let value: unknown;\n if (typeof id === \"function\") {\n value = (id as (input: unknown) => unknown)(input);\n } else if (isRecord(input)) {\n value = input[id ?? \"id\"];\n }\n const ids = idsFrom(value);\n if (ids === undefined) {\n throw new QuickdrawError(\"FORBIDDEN\", \"Insufficient permissions\");\n }\n return ids;\n}\n","// Access policies (RFC 0003 section 4.2): how a principal's level on a row of\n// a service is found. A service declares one with `defineService(contract,\n// { model, access })`, and every surface (method calls, list filters, and\n// later subscriptions and collections) asks it the same two questions:\n//\n// - `levelsFor(principal, ids)`: the principal's level on each row, in one\n// batched lookup. A row that is not found, a malformed column or an\n// unknown level gives `null`: no access.\n// - `accessWhere(principal, level)`: a filter matching exactly the rows on\n// which the principal has at least `level`, or `\"none\"`.\n//\n// The builders (`owner`, `jsonAcl`, `members`, `inherit`, `anyOf`,\n// `resolver`, `everyone`) live in `policies/`. A policy reads the database only through\n// the `PolicyTools` it is given, which batch, memoize per request and, when\n// the dispatcher enables it, cache across requests; `reads` tells the engine\n// which columns and models a policy depends on, so tracked writes to them\n// evict the cache (`changes.ts`). It replaces 4.1's `checkAccess`,\n// `checkEntryACL` and `checkBatchSubscriptionAccess`\n// (4.1 `src/server/BaseService.ts:292-306, 513-547`).\n//\n// The framework never imports generated Prisma types. A policy's type\n// carries the column names it reads, and `defineService` checks them against\n// the app's database client structurally, through each model delegate's\n// `fields` (`ModelColumn`); with a client that has no such members any name\n// passes.\n\nimport type { AccessLevel } from \"../../contract/access\";\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { StorageAdapter, StorageRow, StorageWhere } from \"../storage\";\nimport type { Principal } from \"../types\";\n\n/** A principal's level on one row: an access level, or `null` for none. */\nexport type RowLevel = AccessLevel | null;\n\n/** Levels by row id. An id missing from the map has no level. */\nexport type RowLevels = ReadonlyMap<string, RowLevel>;\n\n/** A storage filter matching the rows a principal may see, or `\"none\"` when no row matches. */\nexport type AccessFilter = StorageWhere | \"none\";\n\n/** A membership table a `members` policy reads: one row per user and entry. */\nexport interface MembershipRead {\n /** The membership model, named as the client names it: `\"projectMember\"`. */\n readonly model: string;\n /** The column holding the id of the row the membership is on: `\"projectId\"`. */\n readonly entry: string;\n /** The column holding the member's user id: `\"userId\"`. */\n readonly user: string;\n /** The column holding the member's role. */\n readonly level: string;\n /** Maps stored roles to access levels; without it a role must be a level name. */\n readonly levels: Readonly<Record<string, AccessLevel>> | undefined;\n}\n\n/** A parent row a policy takes its level from: `inherit({ from, via })`. */\nexport interface ParentLink {\n /** The parent service's contract. */\n readonly from: AnyContract;\n /** The column of the service's model holding the parent row's id. */\n readonly via: string;\n}\n\n/**\n * What a policy reads, so the engine can register interest in those columns\n * with the storage adapter (tracked writes then carry their `before` and\n * `after` values) and evict cached lookups when they are written.\n */\nexport interface PolicyReads {\n /** Columns of the service's own model. */\n readonly columns: readonly string[];\n /** Membership tables. */\n readonly memberships: readonly MembershipRead[];\n /** The services whose policies this one asks (`inherit`). */\n readonly inherits: readonly AnyContract[];\n /**\n * The parent rows a level comes from (`inherit`), with the column naming\n * each: the rows a live subscription's access is anchored on besides its\n * own (RFC 0003 section 4.4).\n */\n readonly parents?: readonly ParentLink[];\n /** Whether the policy reads the database through the storage adapter. */\n readonly storage: boolean;\n}\n\n/** What a policy reads the database with: batched, memoized per request, and cached when enabled. */\nexport interface PolicyTools {\n /** The dispatcher's storage adapter. */\n readonly storage: StorageAdapter;\n /** The database model of the service the policy guards, named as the client names it. */\n readonly model: string;\n /**\n * The service's rows `ids`, with the columns its policy reads (`reads.columns`),\n * in one query for every id not read yet in this request. `null` for a row\n * that does not exist.\n */\n rows(ids: readonly string[]): Promise<ReadonlyMap<string, StorageRow | null>>;\n /** The level each of `userId`'s memberships in `read` gives on the rows `ids`, in one query. */\n memberships(read: MembershipRead, userId: string, ids: readonly string[]): Promise<RowLevels>;\n /** The principal's level on rows of another service, from that service's policy. */\n levelsOf(contract: AnyContract, principal: Principal, ids: readonly string[]): Promise<RowLevels>;\n /** Another service's filter for the principal and `level`, from that service's policy. */\n whereOf(contract: AnyContract, principal: Principal, level: AccessLevel): Promise<AccessFilter>;\n /** The ids of the rows of another service the principal has at least `level` on. */\n idsWhere(\n contract: AnyContract,\n principal: Principal,\n level: AccessLevel,\n ): Promise<readonly string[]>;\n}\n\n/** The other models a policy reads, and their columns: `{ model: \"projectMember\", columns: \"projectId\" | \"userId\" | \"role\" }`. */\nexport interface ForeignColumns {\n readonly model: string;\n readonly columns: string;\n}\n\n/** The builder a policy came from. */\nexport type PolicyKind =\n | \"owner\"\n | \"jsonAcl\"\n | \"members\"\n | \"inherit\"\n | \"anyOf\"\n | \"resolver\"\n | \"everyone\";\n\n/**\n * A service's access policy, from one of the builders. `Columns` names the\n * columns of the service's own model it reads and `Foreign` the other models\n * and columns; `defineService` checks both against the app's database client.\n */\nexport interface AccessPolicy<\n Columns extends string = string,\n Foreign extends ForeignColumns = ForeignColumns,\n> {\n readonly kind: PolicyKind;\n /** The columns and models the policy depends on. */\n readonly reads: PolicyReads;\n /** The principal's level on each of `ids`, from one batched lookup. */\n levelsFor(principal: Principal, ids: readonly string[], tools: PolicyTools): Promise<RowLevels>;\n /** A filter matching exactly the rows on which the principal has at least `level`. */\n accessWhere(principal: Principal, level: AccessLevel, tools: PolicyTools): Promise<AccessFilter>;\n /** Type-only: the columns of the service's model this policy reads. Never set. */\n readonly \"~columns\"?: Columns;\n /** Type-only: the other models and columns this policy reads. Never set. */\n readonly \"~foreign\"?: Foreign;\n}\n\n/** Any access policy. */\nexport type AnyAccessPolicy = AccessPolicy<string, ForeignColumns>;\n\n/** The own-model columns an access policy type reads. */\nexport type PolicyColumns<P> =\n P extends AccessPolicy<infer Columns, ForeignColumns> ? Columns : never;\n\n/** The other models and columns an access policy type reads. */\nexport type PolicyForeign<P> = P extends AccessPolicy<string, infer Foreign> ? Foreign : never;\n\n// ---------------------------------------------------------------------------\n// The app's models, read structurally from its database client: a model\n// delegate (`db.project`) lists its scalar fields in `fields`, as Prisma's\n// generated client does. Nothing here names a Prisma type.\n// ---------------------------------------------------------------------------\n\ninterface ModelDelegateLike {\n readonly fields: object;\n findMany(...args: never[]): unknown;\n}\n\ntype DelegateNames<Db> = {\n [Name in keyof Db]-?: Db[Name] extends ModelDelegateLike ? Name : never;\n}[keyof Db] &\n string;\n\n/** The model names of the app's database client, or any string when the client lists none. */\nexport type ModelName<Db> = [DelegateNames<Db>] extends [never] ? string : DelegateNames<Db>;\n\ntype FieldsOf<Db, Model> = Model extends keyof Db\n ? Db[Model] extends { readonly fields: infer Fields }\n ? Fields\n : never\n : never;\n\n/** The columns of `Model` in the app's database client, or any string when the client does not list them. */\nexport type ModelColumn<Db, Model extends string> = [FieldsOf<Db, Model>] extends [never]\n ? string\n : keyof FieldsOf<Db, Model> & string;\n\n/** Every model of the app's database client with its columns: what a policy may read besides its own model. */\nexport type ForeignColumnsOf<Db> = [DelegateNames<Db>] extends [never]\n ? ForeignColumns\n : {\n [Name in DelegateNames<Db>]: {\n readonly model: Name;\n readonly columns: ModelColumn<Db, Name>;\n };\n }[DelegateNames<Db>];\n\n/** The access policies a service of `Model` may declare, given the app's database client. */\nexport type PolicyFor<Db, Model> = Model extends string\n ? AccessPolicy<ModelColumn<Db, Model>, ForeignColumnsOf<Db>>\n : never;\n\n// ---------------------------------------------------------------------------\n// Run time: the builders brand what they return, so `defineService` can tell\n// a policy from a look-alike object.\n// ---------------------------------------------------------------------------\n\nconst POLICIES = new WeakSet<object>();\n\n/** What a builder provides; `definePolicy` freezes and brands it. */\nexport type PolicySpec = Omit<AnyAccessPolicy, \"~columns\" | \"~foreign\"> & Record<string, unknown>;\n\n/** Freezes and brands a policy made by one of the builders. */\nexport function definePolicy<P extends AnyAccessPolicy>(spec: PolicySpec): P {\n const policy = Object.freeze({ ...spec, reads: Object.freeze(spec.reads) });\n POLICIES.add(policy);\n return policy as unknown as P;\n}\n\n/** True when `value` is a policy from one of the builders (`owner`, `members`, ...). */\nexport function isAccessPolicy(value: unknown): value is AnyAccessPolicy {\n return typeof value === \"object\" && value !== null && POLICIES.has(value);\n}\n\n/** Throws a `TypeError` unless `value` is a non-empty string: a column or model name. */\nexport function checkName(builder: string, option: string, value: unknown): string {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new TypeError(\n `${builder}: ${option} must be a ${option === \"model\" ? \"model\" : \"column\"} name`,\n );\n }\n return value;\n}\n\n/** A map holding the level `levelOf(id)` gives each of `ids`. */\nexport function levelsById(\n ids: readonly string[],\n levelOf: (id: string) => RowLevel,\n): Map<string, RowLevel> {\n return new Map(ids.map((id) => [id, levelOf(id)]));\n}\n\n/** `{ id: { in: ids } }`, or `\"none\"` for no ids. */\nexport function idFilter(ids: readonly string[]): AccessFilter {\n return ids.length === 0 ? \"none\" : { id: { in: [...new Set(ids)] } };\n}\n\n/** The id list of a filter `idFilter` made, or `undefined` for any other filter. */\nexport function idsOfFilter(filter: StorageWhere): readonly string[] | undefined {\n const keys = Object.keys(filter);\n const { id } = filter;\n if (keys.length !== 1 || typeof id !== \"object\" || id === null) {\n return undefined;\n }\n const list: unknown = (id as Readonly<Record<string, unknown>>).in;\n const onlyIn = Object.keys(id).length === 1;\n return onlyIn && Array.isArray(list) && list.every((item) => typeof item === \"string\")\n ? (list as readonly string[])\n : undefined;\n}\n","// `anyOf(...policies)` (RFC 0003 section 4.2): the highest level any of the\n// policies grants. Policies that read the service's own rows share one read\n// of them (`PolicyTools.rows`), so `anyOf(owner(\"ownerId\"), jsonAcl(\"acl\"))`\n// costs one query.\n\nimport { maxLevel } from \"../levels\";\nimport {\n definePolicy,\n isAccessPolicy,\n type AccessFilter,\n type AccessPolicy,\n type AnyAccessPolicy,\n type MembershipRead,\n type PolicyColumns,\n type PolicyForeign,\n type PolicyReads,\n type RowLevel,\n} from \"../policy\";\nimport type { StorageWhere } from \"../../storage\";\n\nfunction unionReads(policies: readonly AnyAccessPolicy[]): PolicyReads {\n const memberships = new Set<MembershipRead>();\n for (const policy of policies) {\n for (const read of policy.reads.memberships) {\n memberships.add(read);\n }\n }\n return {\n columns: [...new Set(policies.flatMap((policy) => policy.reads.columns))],\n memberships: [...memberships],\n inherits: [...new Set(policies.flatMap((policy) => policy.reads.inherits))],\n parents: policies.flatMap((policy) => policy.reads.parents ?? []),\n storage: policies.some((policy) => policy.reads.storage),\n };\n}\n\nconst MEMBERS = new WeakMap<object, readonly AnyAccessPolicy[]>();\n\n/**\n * The policies an `anyOf` policy combines, or `undefined` for any other\n * policy: the sharing kit finds the `jsonAcl` or `members` policy among them.\n */\nexport function anyOfPolicies(policy: AnyAccessPolicy): readonly AnyAccessPolicy[] | undefined {\n return MEMBERS.get(policy);\n}\n\n/**\n * The highest level any of `policies` grants on each row. List filters match\n * a row any of them lets through.\n *\n * @example\n * access: anyOf(owner(\"ownerId\"), members({ model: \"projectMember\", entry: \"projectId\", user: \"userId\", level: \"role\" })),\n */\nexport function anyOf<const P extends readonly AnyAccessPolicy[]>(\n ...policies: P\n): AccessPolicy<PolicyColumns<P[number]>, PolicyForeign<P[number]>> {\n if (policies.length === 0 || !policies.every(isAccessPolicy)) {\n throw new TypeError(\"anyOf(...policies): pass one or more access policies\");\n }\n const all: readonly AnyAccessPolicy[] = Object.freeze([...policies]);\n const combined = definePolicy<AccessPolicy<PolicyColumns<P[number]>, PolicyForeign<P[number]>>>({\n kind: \"anyOf\",\n policies: all,\n reads: unionReads(all),\n async levelsFor(principal, ids, tools) {\n const each = await Promise.all(all.map((policy) => policy.levelsFor(principal, ids, tools)));\n const levels = new Map<string, RowLevel>();\n for (const id of ids) {\n levels.set(\n id,\n each.reduce<RowLevel>((level, granted) => maxLevel(level, granted.get(id)), null),\n );\n }\n return levels;\n },\n async accessWhere(principal, level, tools) {\n const filters = await Promise.all(\n all.map((policy) => policy.accessWhere(principal, level, tools)),\n );\n const matching = filters.filter((filter): filter is StorageWhere => filter !== \"none\");\n // A policy that lets every row through (`everyone`, a resolver's `{}`) makes the whole\n // filter `{}`: Prisma reads an empty object inside `OR` as matching nothing.\n if (matching.some((filter) => Object.keys(filter).length === 0)) {\n return {};\n }\n if (matching.length <= 1) {\n return matching[0] ?? (\"none\" satisfies AccessFilter);\n }\n return { OR: matching };\n },\n });\n MEMBERS.set(combined, all);\n return combined;\n}\n","// `members({ model, entry, user, level, levels? })` (RFC 0003 section 4.2):\n// the level comes from a membership table, one row per user and entry\n// (`projectMember { id, projectId, userId, role }`, the pair unique by\n// `@@unique([projectId, userId])`). The table needs an `id` column: the\n// write tracker keys rows by it, so a table keyed by a composite `@@id` is\n// never tracked and a removed member is never revoked (`createServer` names\n// such a table at start: `../trackedModels.ts`).\n\nimport { isAccessLevel, type AccessLevel } from \"../../../contract/access\";\nimport { levelsAtLeast } from \"../levels\";\nimport {\n checkName,\n definePolicy,\n idFilter,\n type AccessPolicy,\n type AnyAccessPolicy,\n type MembershipRead,\n} from \"../policy\";\n\n/**\n * The membership table a policy `members` made reads, or `undefined` for\n * any other policy: what the sharing kit reads and writes.\n */\nexport function membershipOf(policy: AnyAccessPolicy): MembershipRead | undefined {\n return policy.kind === \"members\" ? policy.reads.memberships[0] : undefined;\n}\n\n/** Options of {@link members}. */\nexport interface MembersOptions<\n Model extends string = string,\n Entry extends string = string,\n User extends string = string,\n Level extends string = string,\n> {\n /**\n * The membership model, named as the client names it: `\"projectMember\"`.\n * It needs an `id` column (keep the pair unique with `@@unique`, never a\n * composite `@@id`), or its writes are not tracked and never revoke.\n */\n readonly model: Model;\n /** The column holding the id of the row the membership is on: `\"projectId\"`. */\n readonly entry: Entry;\n /** The column holding the member's user id: `\"userId\"`. */\n readonly user: User;\n /** The column holding the member's role. */\n readonly level: Level;\n /**\n * Maps stored roles to access levels: `{ owner: \"Admin\", editor: \"Moderate\", viewer: \"Read\" }`.\n * Without it a stored role must be a level name. A role that maps to no\n * level grants nothing. Roles that map to one level are peers: with\n * `{ owner: \"Admin\", admin: \"Admin\" }` the sharing kit lets an `admin`\n * demote or remove the `owner`. To make an owner untouchable, give the\n * row an owner column (`anyOf(owner(\"ownerId\"), members(...))`, or\n * `jsonAcl(..., { owner })`).\n */\n readonly levels?: Readonly<Record<string, AccessLevel>>;\n}\n\nfunction checkLevels(\n owner: string,\n levels: unknown,\n): Readonly<Record<string, AccessLevel>> | undefined {\n if (levels === undefined) {\n return undefined;\n }\n const valid =\n typeof levels === \"object\" &&\n levels !== null &&\n !Array.isArray(levels) &&\n Object.values(levels).every(isAccessLevel);\n if (!valid) {\n throw new TypeError(\n `${owner}: levels must map stored roles to access levels, as in { editor: \"Moderate\" }`,\n );\n }\n return Object.freeze({ ...(levels as Record<string, AccessLevel>) });\n}\n\n/**\n * A membership table's options, `{ model, entry, user, level, levels? }`,\n * checked and frozen. A `TypeError` names `owner(option)` for an option of\n * the wrong kind. `members` takes one table, and a resolver's `reads` a list\n * of them.\n */\nexport function membershipRead(options: object, owner: (option: string) => string): MembershipRead {\n const { model, entry, user, level, levels } = options as Readonly<Record<string, unknown>>;\n return Object.freeze({\n model: checkName(owner(\"model\"), \"model\", model),\n entry: checkName(owner(\"entry\"), \"entry\", entry),\n user: checkName(owner(\"user\"), \"user\", user),\n level: checkName(owner(\"level\"), \"level\", level),\n levels: checkLevels(owner(\"levels\"), levels),\n });\n}\n\n/**\n * The stored roles that give at least `level`: the level names from `level`\n * up without a `levels` map, else the roles the map gives such a level. A\n * `via` collection over the item service's own membership table counts only\n * the links holding one (`collections/define.ts`).\n */\nexport function rolesAtLeast(read: MembershipRead, level: AccessLevel): string[] {\n const enough = new Set<string>(levelsAtLeast(level));\n if (read.levels === undefined) {\n return [...enough];\n }\n return Object.entries(read.levels)\n .filter(([, mapped]) => enough.has(mapped))\n .map(([role]) => role);\n}\n\n/**\n * The level comes from the principal's row in a membership table: one query\n * per lookup, filtered by the entry ids and the user id. Several rows for one\n * user and entry give the highest level among them. The table needs an `id`\n * column, or no write to it is tracked and a removed member keeps what they\n * subscribed to; `createServer` names such a table at start.\n *\n * @example\n * access: members({ model: \"projectMember\", entry: \"projectId\", user: \"userId\", level: \"role\" }),\n */\nexport function members<\n const Model extends string,\n const Entry extends string,\n const User extends string,\n const Level extends string,\n>(\n options: MembersOptions<Model, Entry, User, Level>,\n): AccessPolicy<never, { readonly model: Model; readonly columns: Entry | User | Level }> {\n if (typeof options !== \"object\" || options === null) {\n throw new TypeError(\"members(options): options must be { model, entry, user, level }\");\n }\n const read = membershipRead(options, (option) => `members({ ${option} })`);\n return definePolicy({\n kind: \"members\",\n membership: read,\n reads: { columns: [], memberships: [read], inherits: [], storage: true },\n levelsFor: (principal, ids, tools) => tools.memberships(read, principal.userId, ids),\n async accessWhere(principal, level, tools) {\n const roles = rolesAtLeast(read, level);\n if (roles.length === 0) {\n return \"none\";\n }\n const rows = await tools.storage.findMany(read.model, {\n where: { [read.user]: principal.userId, [read.level]: { in: roles } },\n select: { [read.entry]: true },\n });\n const entries = rows.map((row) => row[read.entry]);\n return idFilter(entries.filter((entry): entry is string => typeof entry === \"string\"));\n },\n });\n}\n","// Collections as a service defines them (RFC 0003 section 7.1). The contract\n// declares what a collection is: its scope column or junction, its item\n// projection, its membership filter, its order, its page sizes and its index.\n// The service adds what a contract cannot carry, because access policies live\n// on the server: the contract whose rows the scope values are ids of\n// (`anchor`), or `scopeAccess: \"self\"` for a scope whose value is the\n// subscriber's own user id; and the `bulkThreshold` past which one flush's\n// changes to a scope go out as a single `reset`. Every collection of the\n// contract needs one or the other, so a scope nobody could authorize fails\n// when the service is defined rather than when a client subscribes. A\n// `\"self\"` scope is stripped at `Read` and may not declare a higher\n// `access`, since no level is checked to subscribe to it; on a service with\n// a policy its items are the rows the policy gives its user at least `Read`\n// on (`selfAccess.ts`). The\n// index fields are checked here too, against the item projection only the\n// service compiles: a contract cannot see a schema's keys. No order column\n// may sit above the collection's `access` in the contract's `fields`, since\n// cursors carry order columns' values.\n//\n// 4.1 defined a collection with functions (`resolveScopeId`,\n// `checkScopeAccess`, `snapshot`, `toItem`;\n// 4.1 `src/server/collections.ts:36-72`), so the framework could not know\n// which writes move a row and read the whole row before every update.\n\nimport type { AccessLevel } from \"../../contract/access\";\nimport {\n DEFAULT_COLLECTION_LIMIT,\n DEFAULT_COLLECTION_MAX_LIMIT,\n type CollectionDef,\n type CollectionWhere,\n type OrderBy,\n} from \"../../contract/collections\";\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport { meetsLevel } from \"../access/levels\";\nimport { anyOfPolicies } from \"../access/policies/anyOf\";\nimport { membershipOf, rolesAtLeast } from \"../access/policies/members\";\nimport type { AnyAccessPolicy, MembershipRead } from \"../access/policy\";\nimport type { Projection } from \"../emit/projection\";\nimport { modelKey } from \"../storage\";\n\ntype Fail = (message: string) => never;\n\ntype UnknownRecord = Readonly<Record<string, unknown>>;\n\n/** How many changed rows of one scope a flush sends as deltas; past it, one `reset` instead. */\nexport const DEFAULT_BULK_THRESHOLD = 200;\n\n/** Where a collection's scope value comes from: a column of the row, or a junction table. */\nexport type CollectionScope =\n | { readonly kind: \"column\"; readonly column: string }\n | {\n readonly kind: \"via\";\n /** The junction model, as the client names it. */\n readonly model: string;\n /** The junction column holding the row's id. */\n readonly entry: string;\n /** The junction column holding the scope value. */\n readonly scope: string;\n /** A junction write sends its entry again to every scope that still holds it (`via`'s `refreshEntry`). */\n readonly refreshEntry: boolean;\n /**\n * The junction is the item service's `members` table: only links whose\n * role gives at least the collection's `access` count, by one rule per\n * role column the policy's `members` reads of the table use (a link\n * any rule counts counts), and a write of a role column can move the\n * link in or out.\n */\n readonly levels?: readonly LinkLevel[];\n };\n\n/** One role rule of a `via` scope over the item service's `members` table. */\nexport interface LinkLevel {\n /** The junction's role column. */\n readonly column: string;\n /** The stored roles that give at least the collection's `access`; none: no link counts by this column. */\n readonly roles: readonly string[];\n}\n\n/** A `via` scope, compiled. */\nexport type ViaCollectionScope = Extract<CollectionScope, { readonly kind: \"via\" }>;\n\n/**\n * The filter of a `via` scope's junction rows that count as links: `where`,\n * and over the item service's `members` table a role one of the scope's\n * rules counts.\n */\nexport function linkWhere(via: ViaCollectionScope, where: UnknownRecord): UnknownRecord {\n const rules = (via.levels ?? []).map((rule) => ({ [rule.column]: { in: [...rule.roles] } }));\n if (rules.length === 0) {\n return where;\n }\n return rules.length === 1 ? { ...where, ...rules[0] } : { AND: [where, { OR: rules }] };\n}\n\n/**\n * Whether junction row values make a link under the scope's role rules:\n * always without any; `undefined` when no rule counts them and the values\n * lack a role a rule reads.\n */\nexport function linkQualifies(\n via: ViaCollectionScope,\n values: UnknownRecord | undefined,\n): boolean | undefined {\n if (via.levels === undefined) {\n return true;\n }\n let unknown = false;\n for (const rule of via.levels) {\n const role = values?.[rule.column];\n if (typeof role === \"string\" && rule.roles.includes(role)) {\n return true;\n }\n unknown ||= role === undefined;\n }\n return unknown ? undefined : false;\n}\n\n/** One collection of a service: its contract declaration and the service's option, checked. */\nexport interface ServiceCollection {\n readonly name: string;\n readonly scope: CollectionScope;\n /** The item projection, compiled with the service's `project` option. */\n readonly item: Projection;\n /** The membership filter; empty when the collection declares none. */\n readonly where: CollectionWhere;\n readonly order: OrderBy;\n /** The page size of a snapshot that asks for none. */\n readonly limit: number;\n /** The largest page a snapshot may ask for. */\n readonly maxLimit: number;\n /** The level a subscriber needs on the scope's anchor row. */\n readonly access: AccessLevel;\n /** The contract of the rows scope values are ids of; `undefined` for a `\"self\"` scope. */\n readonly anchor: AnyContract | undefined;\n /** More changed rows than this for one scope in one flush go out as one `reset`. */\n readonly bulkThreshold: number;\n /**\n * The item fields every member's index row holds (RFC 0003 section 7.4),\n * in the order the contract declares them; `undefined` without an index.\n */\n readonly index: readonly string[] | undefined;\n}\n\nconst OPTION_KEYS: ReadonlySet<string> = new Set([\"anchor\", \"scopeAccess\", \"bulkThreshold\"]);\n\nfunction isRecord(value: unknown): value is UnknownRecord {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isContract(value: unknown): value is AnyContract {\n return (\n isRecord(value) &&\n typeof value.name === \"string\" &&\n value.name.length > 0 &&\n Object.isFrozen(value)\n );\n}\n\ninterface CheckedOption {\n readonly anchor: AnyContract | undefined;\n readonly bulkThreshold: number;\n}\n\n/** One entry of the service's `collections` option, checked. */\nfunction checkOption(owner: string, option: unknown, fail: Fail): CheckedOption {\n if (!isRecord(option)) {\n fail(`${owner} must be { anchor: contract } or { scopeAccess: \"self\" }`);\n }\n const unknownKey = Object.keys(option).find((key) => !OPTION_KEYS.has(key));\n if (unknownKey !== undefined) {\n fail(\n `${owner} has an unknown option \"${unknownKey}\"; the options are anchor, scopeAccess and bulkThreshold`,\n );\n }\n const { anchor, scopeAccess, bulkThreshold = DEFAULT_BULK_THRESHOLD } = option;\n if ((anchor === undefined) === (scopeAccess === undefined)) {\n fail(\n `${owner} needs exactly one of anchor (the contract whose rows its scope values are ids of) and scopeAccess: \"self\"`,\n );\n }\n if (anchor !== undefined && !isContract(anchor)) {\n fail(`${owner}: anchor must be a contract from defineContract`);\n }\n if (scopeAccess !== undefined && scopeAccess !== \"self\") {\n fail(\n `${owner}: scopeAccess must be \"self\", for a scope whose value is the subscriber's user id`,\n );\n }\n if (\n typeof bulkThreshold !== \"number\" ||\n !Number.isSafeInteger(bulkThreshold) ||\n bulkThreshold < 1\n ) {\n fail(`${owner}: bulkThreshold must be a positive whole number`);\n }\n return { anchor: anchor as AnyContract | undefined, bulkThreshold };\n}\n\n/**\n * The collection's index fields, checked against its item (RFC 0003 sections\n * 2 and 7.4): each is a key of the item projection other than `id`, named\n * once, and one the collection's items carry, so not reserved by the\n * contract's `fields` for a level above the collection's `access`. An index\n * row holds what its item holds, nothing more. Every `order` column but `id`\n * is an index field, so a client can keep the index in order as deltas\n * arrive. `views` read index rows, so a collection with views needs an index.\n */\nfunction checkIndex(\n name: string,\n def: CollectionDef,\n item: Projection,\n access: AccessLevel,\n fail: Fail,\n): readonly string[] | undefined {\n const { index, views } = def;\n if (index === undefined) {\n if (views !== undefined) {\n fail(`collection \"${name}\" declares views but no index; views read index rows`);\n }\n return undefined;\n }\n if (!Array.isArray(index) || !index.every((field) => typeof field === \"string\")) {\n fail(`collection \"${name}\": index must be a list of item field names`);\n }\n const owner = `collection \"${name}\": index field`;\n const hidden = item.tiers.hidden(access);\n for (const [position, field] of index.entries()) {\n if (field === \"id\") {\n fail(`${owner} \"id\" is not needed; every index row starts with the member's id`);\n }\n if (!item.keys.includes(field)) {\n fail(\n `${owner} \"${field}\" is not a key of its item \"${item.name}\"; index fields are item fields`,\n );\n }\n if (hidden.has(field)) {\n fail(\n `${owner} \"${field}\" is reserved by the contract's fields for a level above the collection's access (${access}), so its items never carry it`,\n );\n }\n if (index.indexOf(field) !== position) {\n fail(`${owner} \"${field}\" is named twice`);\n }\n }\n checkIndexOrder(name, def.order, index, fail);\n return Object.freeze([...index]);\n}\n\n/**\n * No `order` column may be reserved by the contract's `fields` for a level\n * above the collection's `access`, index or not: a page's cursor carries\n * the last row's value of every order column, and the page's order tells\n * how the rows' values compare, so either would hand a subscriber the field.\n */\nfunction checkOrderTiers(\n name: string,\n order: OrderBy,\n fields: Readonly<Record<string, AccessLevel>>,\n access: AccessLevel,\n fail: Fail,\n): void {\n for (const [column] of order) {\n const required = Object.hasOwn(fields, column) ? fields[column] : undefined;\n if (required !== undefined && !meetsLevel(access, required)) {\n fail(\n `collection \"${name}\": order column \"${column}\" is reserved by the contract's fields for ${required}, above the collection's access (${access}); a page's cursor and order would tell its subscribers what it holds`,\n );\n }\n }\n}\n\n/** Every order column but `id` must be an index field: a client keeps the index in order by them. */\nfunction checkIndexOrder(name: string, order: OrderBy, index: readonly string[], fail: Fail): void {\n const missing = order.map(([column]) => column).find((c) => c !== \"id\" && !index.includes(c));\n if (missing !== undefined) {\n fail(\n `collection \"${name}\": order column \"${missing}\" is not an index field; a client keeps the index in order by it`,\n );\n }\n}\n\n/**\n * The level a collection's subscribers need on its anchor row, which its\n * items are also stripped at: its `access`, `Read` by default. A `\"self\"`\n * scope is authorized by the subscriber's own user id, never by a level, so\n * its items are stripped at `Read` and it may not declare more: a higher\n * `access` would hand every subscriber that level's fields of the rows in\n * their own scope. On a service with a policy its items are the rows the\n * policy gives its user at least `Read` on (`selfAccess.ts`).\n */\nfunction accessOf(\n name: string,\n def: CollectionDef,\n anchor: AnyContract | undefined,\n fail: Fail,\n): AccessLevel {\n if (anchor !== undefined) {\n return def.access ?? \"Read\";\n }\n if (def.access !== undefined && meetsLevel(def.access, \"Moderate\")) {\n fail(\n `collection \"${name}\" has scopeAccess \"self\", which is authorized by the subscriber's user id and not by a level, so its access may not be above Read (it declares ${def.access})`,\n );\n }\n return \"Read\";\n}\n\n/**\n * The `members` reads of `policy`, alone or inside `anyOf` at any depth,\n * over the junction `via` names: the same model, the policy's `entry` the\n * via's `entry`, and its `user` the via's `scope`. A `resolver`'s\n * memberships do not count.\n */\nfunction membersReadsOf(\n policy: AnyAccessPolicy | undefined,\n via: { readonly model: string; readonly entry: string; readonly scope: string },\n): MembershipRead[] {\n if (policy === undefined) {\n return [];\n }\n const read = membershipOf(policy);\n const same =\n read !== undefined &&\n modelKey(read.model) === modelKey(via.model) &&\n read.entry === via.entry &&\n read.user === via.scope;\n return [\n ...(same ? [read] : []),\n ...(anyOfPolicies(policy) ?? []).flatMap((member) => membersReadsOf(member, via)),\n ];\n}\n\n/** The role rules of `reads` at `access`: one per role column, with the roles any read counts. */\nfunction linkLevels(\n reads: readonly MembershipRead[],\n access: AccessLevel,\n): readonly LinkLevel[] | undefined {\n if (reads.length === 0) {\n return undefined;\n }\n const roles = new Map<string, Set<string>>();\n for (const read of reads) {\n roles.set(\n read.level,\n new Set([...(roles.get(read.level) ?? []), ...rolesAtLeast(read, access)]),\n );\n }\n return Object.freeze(\n [...roles].map(([column, counted]) =>\n Object.freeze({ column, roles: Object.freeze([...counted]) }),\n ),\n );\n}\n\nfunction scopeOf(\n def: CollectionDef,\n policy: AnyAccessPolicy | undefined,\n access: AccessLevel,\n): CollectionScope {\n const { scope } = def;\n if (typeof scope === \"string\") {\n return Object.freeze({ kind: \"column\", column: scope });\n }\n const levels = linkLevels(membersReadsOf(policy, scope), access);\n return Object.freeze({\n kind: \"via\",\n model: scope.model,\n entry: scope.entry,\n scope: scope.scope,\n refreshEntry: scope.refreshEntry === true,\n ...(levels === undefined ? {} : { levels }),\n });\n}\n\nfunction compileOne(\n [name, def]: readonly [string, CollectionDef],\n contract: Pick<AnyContract, \"fields\">,\n projections: ReadonlyMap<string, Projection>,\n [option, policy]: readonly [unknown, AnyAccessPolicy | undefined],\n fail: Fail,\n): ServiceCollection {\n if (option === undefined) {\n fail(\n `collection \"${name}\" needs its scope's access: collections: { ${name}: { anchor: contract } }, or { scopeAccess: \"self\" } for a scope that is the subscriber's user id`,\n );\n }\n const { anchor, bulkThreshold } = checkOption(`collections.${name}`, option, fail);\n const item = projections.get(def.item);\n if (item === undefined) {\n fail(`collection \"${name}\": item \"${def.item}\" is not a projection of the contract`);\n }\n const access = accessOf(name, def, anchor, fail);\n checkOrderTiers(name, def.order, contract.fields, access, fail);\n return Object.freeze({\n name,\n scope: scopeOf(def, policy, access),\n item,\n where: Object.freeze({ ...def.where }),\n order: def.order,\n limit: def.limit ?? DEFAULT_COLLECTION_LIMIT,\n maxLimit: def.maxLimit ?? DEFAULT_COLLECTION_MAX_LIMIT,\n access,\n anchor,\n bulkThreshold,\n index: checkIndex(name, def, item, access, fail),\n });\n}\n\n/**\n * Compiles the contract's collections with the service's `collections`\n * option. Fails, through `fail`, for a collection without an entry, an entry\n * naming no collection, a malformed entry, and collections on a service\n * without a model.\n */\nexport function compileCollections(\n contract: AnyContract,\n projections: ReadonlyMap<string, Projection>,\n model: string | undefined,\n option: unknown,\n fail: Fail,\n policy?: AnyAccessPolicy,\n): ReadonlyMap<string, ServiceCollection> {\n if (option !== undefined && !isRecord(option)) {\n fail(\n 'collections must map each collection of the contract to { anchor } or { scopeAccess: \"self\" }',\n );\n }\n const options = option ?? {};\n const unknownName = Object.keys(options).find(\n (name) => !Object.hasOwn(contract.collections, name),\n );\n if (unknownName !== undefined) {\n fail(`collections names \"${unknownName}\", which is not a collection of the contract`);\n }\n const declared = Object.entries(contract.collections);\n if (declared.length > 0 && model === undefined) {\n fail(\"collections need model: their items are rows of the service's model\");\n }\n const compiled = new Map<string, ServiceCollection>();\n for (const [name, def] of declared) {\n compiled.set(\n name,\n compileOne([name, def], contract, projections, [options[name], policy], fail),\n );\n }\n return compiled;\n}\n","// The recent deltas of each collection scope (RFC 0003 section 7.3): a client\n// that reconnects sends the revision it holds the scope at (`since`), and\n// while this process still holds every change made since then it gets those\n// deltas instead of the scope again. Bounded per scope at 500 deltas or 5\n// minutes, and per process; 4.1 had no resume at all.\n//\n// Each scope has a floor: the oldest revision a client may hold and still be\n// answered from here. Whatever this process cannot replay raises it:\n//\n// - a frame dropped for age or size: the floor rises to its revision;\n// - a flush that changed the scope without building its deltas (nobody here\n// subscribed to it): to that revision;\n// - a frame that removes a row nobody could place (a touch with `removed`,\n// a `via` entry deleted without its links read), which every subscribed\n// scope gets and none keeps: to its revision (`send.ts`), and past every\n// revision taken so far for every scope of the collection, subscribed\n// or not, on every node (`skipAll`, `unnamed.ts`);\n// - a `reset`: past its revision, since a client must load the scope again;\n// - a frame recorded after a newer one (flushes can finish out of order):\n// past the newest, since a client holding the newer revision may not have\n// received the older frame;\n// - the process starting, and the state of an idle scope being forgotten,\n// which raises the floor every scope without state starts from. A scope\n// with subscribers here is pinned and never forgotten, so a client that\n// checks an unchanged scope now and then keeps resuming it;\n// - a flush that changed a collection nobody here subscribes to, in scopes\n// it would have had to read to name: past every revision taken so far, for\n// every scope of that collection (`skipAll`).\n//\n// Deltas of one frame share its revision, and frames are kept in the order\n// they went out, so a resume replays them in that order and never sorts.\n\nimport type { CollectionDelta, Revision } from \"../../protocol/envelope\";\nimport { currentRev, nextRev } from \"../rev\";\n\n/** Deltas kept per scope. */\nexport const RESUME_MAX_DELTAS = 500;\n\n/** How long a delta is kept, in milliseconds. */\nexport const RESUME_MAX_AGE_MS = 300_000;\n\n/** Scopes without subscribers whose state is kept; past it the least recently changed is forgotten. */\nexport const RESUME_MAX_SCOPES = 10_000;\n\n/** Options of {@link createDeltaBuffer}; the defaults are the RFC's bounds. */\nexport interface DeltaBufferOptions {\n readonly maxDeltas?: number;\n readonly maxAgeMs?: number;\n readonly maxScopes?: number;\n /** The clock, in milliseconds. Default `Date.now`. */\n readonly now?: () => number;\n}\n\ninterface Frame {\n readonly rev: Revision;\n readonly at: number;\n readonly deltas: readonly CollectionDelta[];\n}\n\ninterface ScopeLog {\n frames: Frame[];\n /** How many deltas `frames` hold. */\n size: number;\n /** The oldest revision a client may hold and resume from. */\n floor: Revision;\n /** The newest revision of a change to the scope this process saw. */\n newest: Revision;\n /** When the scope last changed, or lost its last subscriber. */\n at: number;\n}\n\n/** What a covered resume replays: the deltas since the client's revision, and the revision after them. */\nexport interface Replay {\n readonly rev: Revision;\n readonly deltas: readonly CollectionDelta[];\n}\n\n/**\n * The recent deltas of every scope, keyed by the scope's room name. A scope's\n * collection (its group, `service\\0collection`) may have a floor of its own.\n */\nexport interface DeltaBuffer {\n /** Keeps a frame this process sent to the scope. */\n record(key: string, rev: Revision, deltas: readonly CollectionDelta[]): void;\n /** A flush at `rev` changed the scope, and its deltas were not built: no resume from before it. */\n skip(key: string, rev: Revision): void;\n /** A flush changed scopes of the group it did not name: no resume of any from before now. */\n skipAll(group: string): void;\n /** The scope was reset (or closed) at `rev`: no resume from before it. */\n reset(key: string, rev: Revision): void;\n /**\n * The deltas after `since`, in the order they went out, when every change\n * since then is still held; `undefined` when the client must load the scope.\n */\n since(key: string, since: Revision, group?: string): Replay | undefined;\n /** The oldest revision a client may hold and still resume the scope from. */\n floor(key: string, group?: string): Revision;\n /** The revision of the scope's last change this process saw, or the floor when it knows of none. */\n lastChange(key: string, group?: string): Revision;\n /** The scope has a subscriber here: keep its state. */\n pin(key: string): void;\n /** The scope's last subscriber here left: its state may be forgotten once idle. */\n unpin(key: string): void;\n}\n\ninterface Logs {\n /** Scopes without subscribers here, least recently changed first. */\n readonly idle: Map<string, ScopeLog>;\n readonly pinned: Map<string, ScopeLog>;\n /** The floor of every scope of a group, past a change no scope of it named. */\n readonly groups: Map<string, Revision>;\n /** The floor of a scope without state. */\n base: Revision;\n}\n\nfunction logOf(logs: Logs, key: string): ScopeLog | undefined {\n return logs.pinned.get(key) ?? logs.idle.get(key);\n}\n\n/** Drops the oldest frames while the scope holds too many deltas or old ones. */\nfunction expire(log: ScopeLog, at: number, maxDeltas: number, maxAgeMs: number): void {\n for (let first = log.frames[0]; first !== undefined; first = log.frames[0]) {\n if (log.size <= maxDeltas && first.at >= at - maxAgeMs) {\n return;\n }\n log.frames.shift();\n log.size -= first.deltas.length;\n log.floor = Math.max(log.floor, first.rev);\n }\n}\n\n/** Forgets idle scopes changed too long ago, and the least recently changed past the cap. */\nfunction forget(logs: Logs, at: number, maxScopes: number, maxAgeMs: number): void {\n for (const [key, log] of logs.idle) {\n if (logs.idle.size <= maxScopes && log.at >= at - maxAgeMs) {\n return;\n }\n logs.idle.delete(key);\n logs.base = Math.max(logs.base, log.floor, log.newest);\n }\n}\n\n/** The scope's log, made when missing; an idle one moves to the most recently changed end. */\nfunction changed(logs: Logs, key: string, rev: Revision, at: number): ScopeLog {\n const pinned = logs.pinned.get(key);\n const log = pinned ??\n logs.idle.get(key) ?? { frames: [], size: 0, floor: logs.base, newest: logs.base, at };\n if (pinned === undefined) {\n logs.idle.delete(key);\n logs.idle.set(key, log);\n }\n if (rev < log.newest) {\n log.floor = Math.max(log.floor, log.newest + 1);\n }\n log.newest = Math.max(log.newest, rev);\n log.at = at;\n return log;\n}\n\n/** Creates the delta buffer of one dispatcher. */\nexport function createDeltaBuffer(options: DeltaBufferOptions = {}): DeltaBuffer {\n const maxDeltas = options.maxDeltas ?? RESUME_MAX_DELTAS;\n const maxAgeMs = options.maxAgeMs ?? RESUME_MAX_AGE_MS;\n const maxScopes = options.maxScopes ?? RESUME_MAX_SCOPES;\n const now = options.now ?? Date.now;\n const logs: Logs = { idle: new Map(), pinned: new Map(), groups: new Map(), base: nextRev() };\n const groupFloor = (group: string | undefined): Revision =>\n group === undefined ? 0 : (logs.groups.get(group) ?? 0);\n const floor = (key: string, group?: string): Revision =>\n Math.max(logOf(logs, key)?.floor ?? logs.base, groupFloor(group));\n return Object.freeze({\n record(key: string, rev: Revision, deltas: readonly CollectionDelta[]): void {\n const at = now();\n const log = changed(logs, key, rev, at);\n log.frames.push({ rev, at, deltas: [...deltas] });\n log.size += deltas.length;\n expire(log, at, maxDeltas, maxAgeMs);\n forget(logs, at, maxScopes, maxAgeMs);\n },\n skip(key: string, rev: Revision): void {\n const at = now();\n const log = changed(logs, key, rev, at);\n log.floor = Math.max(log.floor, rev);\n forget(logs, at, maxScopes, maxAgeMs);\n },\n skipAll(group: string): void {\n // Every revision a client may hold was taken by now: none of them is covered.\n logs.groups.set(group, Math.max(groupFloor(group), currentRev() + 1));\n },\n reset(key: string, rev: Revision): void {\n const at = now();\n const log = changed(logs, key, rev, at);\n log.floor = Math.max(log.floor, rev + 1);\n log.frames = [];\n log.size = 0;\n forget(logs, at, maxScopes, maxAgeMs);\n },\n since(key: string, since: Revision, group?: string): Replay | undefined {\n const log = logOf(logs, key);\n if (log !== undefined) {\n expire(log, now(), maxDeltas, maxAgeMs);\n }\n if (since < floor(key, group)) {\n return undefined;\n }\n const frames = (log?.frames ?? []).filter((frame) => frame.rev > since);\n return {\n rev: Math.max(since, log?.newest ?? since),\n deltas: frames.flatMap((frame) => frame.deltas),\n };\n },\n floor,\n lastChange: (key: string, group?: string) =>\n Math.max(logOf(logs, key)?.newest ?? logs.base, groupFloor(group) - 1),\n pin(key: string): void {\n if (logs.pinned.has(key)) {\n return;\n }\n const log = logs.idle.get(key) ?? {\n frames: [],\n size: 0,\n floor: logs.base,\n newest: logs.base,\n at: now(),\n };\n logs.idle.delete(key);\n logs.pinned.set(key, log);\n },\n unpin(key: string): void {\n const log = logs.pinned.get(key);\n if (log === undefined) {\n return;\n }\n const at = now();\n logs.pinned.delete(key);\n log.at = at;\n logs.idle.set(key, log);\n forget(logs, at, maxScopes, maxAgeMs);\n },\n });\n}\n","// Collection items and membership (RFC 0003 sections 7.1 and 7.2). An item is\n// the row in the collection's item projection, the same for everyone in the\n// scope: collections have no per-subscriber field tiers, so a field the\n// contract's `fields` reserves for a level above the collection's `access` is\n// left out of every item and patch. Membership is the declared scope plus the\n// equality filter `where`, read from a row's values.\n//\n// `qd:col:items` (section 7.4) loads items by id: a client holding a scope's\n// index asks for the members it shows. The read applies the scope and\n// `where`, and in a self scope on a service with a policy the policy's\n// filter for the subscriber (`selfAccess.ts`), so an id that is not a member\n// the subscriber may read is simply absent from the answer.\n\nimport type { Revision } from \"../../protocol/envelope\";\nimport type { AccessFilter } from \"../access/policy\";\nimport { pickKeys, projectRow } from \"../emit/projection\";\nimport { strip } from \"../emit/tiers\";\nimport type { StorageAdapter, StorageRow, StorageWhere } from \"../storage\";\nimport type { BoundCollection } from \"./bind\";\nimport { linkWhere, type ServiceCollection } from \"./define\";\n\n/** The most ids one `qd:col:items` may name. */\nexport const MAX_ITEM_IDS = 200;\n\ntype Values = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is Values {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** The keys of the item projection a subscriber at the collection's `access` level does not receive. */\nfunction hiddenOf(collection: ServiceCollection): ReadonlySet<string> {\n return collection.item.tiers.hidden(collection.access);\n}\n\n/** One row as a collection item. */\nexport function itemOf(collection: ServiceCollection, row: StorageRow): unknown {\n const item = projectRow(collection.item, row);\n return isRecord(item) ? strip(item, hiddenOf(collection)) : item;\n}\n\n/** The fields of a `patched` delta: the patched item keys the row has, without hidden ones. */\nexport function patchOf(\n collection: ServiceCollection,\n row: StorageRow,\n fields: readonly string[],\n): Record<string, unknown> {\n const hidden = hiddenOf(collection);\n return pickKeys(\n row,\n fields.filter((field) => !hidden.has(field)),\n );\n}\n\n/** The columns besides `id` that decide membership of a column-scoped collection: its scope column and `where`. */\nexport function membershipColumns(collection: ServiceCollection): readonly string[] {\n const where = Object.keys(collection.where);\n return collection.scope.kind === \"column\" ? [collection.scope.column, ...where] : where;\n}\n\n/** True when `values` match the collection's `where`. */\nexport function matchesWhere(collection: ServiceCollection, values: Values): boolean {\n return Object.entries(collection.where).every(\n ([column, expected]) => values[column] === expected,\n );\n}\n\n/**\n * The scope `values` put a row in, for a column-scoped collection: its scope\n * value when `where` matches, `null` when the row is in no scope, and\n * `undefined` when `values` lack a column that decides it.\n */\nexport function scopeIn(\n collection: ServiceCollection,\n values: Values | undefined,\n): string | null | undefined {\n if (values === undefined || collection.scope.kind !== \"column\") {\n return undefined;\n }\n if (membershipColumns(collection).some((column) => !Object.hasOwn(values, column))) {\n return undefined;\n }\n const scope = values[collection.scope.column];\n const valid = typeof scope === \"string\" && scope.length > 0;\n return valid && matchesWhere(collection, values) ? scope : null;\n}\n\n/** What a read for items selects: the item's select, plus `extra` columns (order or membership). */\nexport function selectWith(\n base: Readonly<Record<string, unknown>>,\n extra: readonly string[],\n): Readonly<Record<string, unknown>> {\n const select: Record<string, unknown> = { ...base, id: true };\n for (const column of extra) {\n if (select[column] === undefined) {\n select[column] = true;\n }\n }\n return select;\n}\n\n/**\n * A scope's members filter with an access filter ANDed in; `undefined` when\n * there are no members or no member is readable (`\"none\"`). An empty filter\n * (`{}`, every row) adds nothing.\n */\nexport function readableMembers(\n members: StorageWhere | undefined,\n filter: AccessFilter | undefined,\n): StorageWhere | undefined {\n if (members === undefined || filter === \"none\") {\n return undefined;\n }\n return filter === undefined || Object.keys(filter).length === 0\n ? members\n : { AND: [members, filter] };\n}\n\n/**\n * The filter matching the members of `scope` among `ids`: its scope column,\n * or the ids among them its `via` junction links to it, and `where`.\n * `undefined` when none can be a member.\n */\nasync function membersAmong(\n storage: StorageAdapter,\n collection: BoundCollection,\n scope: string,\n ids: readonly string[],\n): Promise<StorageWhere | undefined> {\n const { where } = collection;\n const filtered = (filter: StorageWhere): StorageWhere =>\n Object.keys(where).length === 0 ? filter : { AND: [filter, where] };\n if (collection.scope.kind === \"column\") {\n return filtered({ [collection.scope.column]: scope, id: { in: [...ids] } });\n }\n const { model, entry, scope: column } = collection.scope;\n const links = await storage.findMany(model, {\n where: linkWhere(collection.scope, { [column]: scope, [entry]: { in: [...ids] } }),\n select: { [entry]: true },\n });\n const linked = links.map((link) => link[entry]).filter((id) => typeof id === \"string\");\n return linked.length === 0 ? undefined : filtered({ id: { in: [...new Set(linked)] } });\n}\n\n/**\n * The items of the members of `scope` among `ids`, in the order of `ids`,\n * each once, and the revision they were read at (`rev`, claimed before the\n * first read): one read for a column scope, two for a `via` scope (its\n * links among `ids`, then the rows). An id that is not a member is left out,\n * and so is a row `filter` does not match (`\"none\"`: every row).\n */\nexport async function readItemsById(\n storage: StorageAdapter,\n collection: BoundCollection,\n scope: string,\n ids: readonly string[],\n rev: Revision,\n filter?: AccessFilter,\n): Promise<{ readonly rev: Revision; readonly items: unknown[] }> {\n const wanted = [...new Set(ids)];\n const members = readableMembers(\n wanted.length === 0 || filter === \"none\"\n ? undefined\n : await membersAmong(storage, collection, scope, wanted),\n filter,\n );\n if (members === undefined) {\n return { rev, items: [] };\n }\n const rows = await storage.findMany(collection.model, {\n where: members,\n select: collection.item.select,\n });\n const found = new Map(rows.flatMap((row) => (typeof row.id === \"string\" ? [[row.id, row]] : [])));\n const items = wanted.flatMap((id) => {\n const row = found.get(id);\n return row === undefined ? [] : [itemOf(collection, row)];\n });\n return { rev, items };\n}\n","// Keyset cursors over a collection's `order` (RFC 0003 section 7.3). A\n// cursor holds the last row's value of each order column, `id` last, as\n// base64url JSON; the next page is the rows after those values in `order`.\n// Unlike an offset, it stays on its row when rows are inserted or removed\n// before it. 4.1 left paging to each collection's own `snapshot` function\n// (4.1 `src/server/collections.ts:51-55`), which in practice used offsets.\n//\n// Nulls sort last in ascending order and first in descending order (as\n// PostgreSQL does by default); a nullable column is ordered that way\n// explicitly, so the database's own default does not matter. Prisma refuses\n// a null filter or null ordering on a required column, so which columns may\n// be null comes from the storage adapter (`StorageAdapter.nullable`).\n//\n// order [ordinal asc, id asc], cursor (3, \"t9\"):\n// ordinal > 3 OR ordinal IS NULL (when nullable) OR (ordinal = 3 AND id > \"t9\")\n\nimport type { OrderBy, SortDirection } from \"../../contract/collections\";\nimport type { StorageRow, StorageWhere } from \"../storage\";\nimport { unreadable } from \"../transports/ack\";\n\n/** A cursor's values: the value of each order column of the row it follows, `id` last. */\nexport type CursorValues = readonly unknown[];\n\nconst DATE = \"$date\";\nconst BIGINT = \"$bigint\";\n\nconst INVALID = \"cursor is not a cursor of this collection\";\n\nfunction isTagged(value: unknown, tag: string): value is Readonly<Record<string, string>> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.keys(value).length === 1 &&\n typeof (value as Readonly<Record<string, unknown>>)[tag] === \"string\"\n );\n}\n\n/** A column value as JSON can carry it: dates and big integers tagged. */\nfunction pack(value: unknown): unknown {\n if (value instanceof Date) {\n return { [DATE]: value.toISOString() };\n }\n if (typeof value === \"bigint\") {\n return { [BIGINT]: value.toString() };\n }\n return value ?? null;\n}\n\n/** A packed value back, or `undefined` for one no cursor holds. */\nfunction unpack(value: unknown): unknown {\n if (isTagged(value, DATE)) {\n const date = new Date(value[DATE] ?? \"\");\n return Number.isNaN(date.getTime()) ? undefined : date;\n }\n if (isTagged(value, BIGINT)) {\n const digits = value[BIGINT] ?? \"\";\n return /^-?\\d+$/.test(digits) ? BigInt(digits) : undefined;\n }\n const plain = value === null || [\"string\", \"number\", \"boolean\"].includes(typeof value);\n return plain ? value : undefined;\n}\n\n/** The cursor that follows `row`: its value of each order column. */\nexport function encodeCursor(order: OrderBy, row: StorageRow): string {\n const values = order.map(([column]) => pack(row[column]));\n return Buffer.from(JSON.stringify(values), \"utf8\").toString(\"base64url\");\n}\n\n/** The values a cursor holds, or a `VALIDATION` error for a string that is not a cursor of `order`. */\nexport function decodeCursor(order: OrderBy, cursor: string): CursorValues {\n let parsed: unknown;\n try {\n parsed = JSON.parse(Buffer.from(cursor, \"base64url\").toString(\"utf8\"));\n } catch {\n throw unreadable(INVALID, [\"cursor\"]);\n }\n if (!Array.isArray(parsed) || parsed.length !== order.length) {\n throw unreadable(INVALID, [\"cursor\"]);\n }\n const values = parsed.map(unpack);\n const id = values.at(-1);\n if (values.includes(undefined) || typeof id !== \"string\" || id.length === 0) {\n throw unreadable(INVALID, [\"cursor\"]);\n }\n return values;\n}\n\n/** Prisma's `orderBy` for `order`: nulls last ascending and first descending, where a column may hold them. */\nexport function orderByOf(\n order: OrderBy,\n nullable: ReadonlySet<string>,\n): Readonly<Record<string, unknown>>[] {\n return order.map(([column, direction]) => ({\n [column]: nullable.has(column)\n ? { sort: direction, nulls: direction === \"asc\" ? \"last\" : \"first\" }\n : direction,\n }));\n}\n\n/** The rows strictly after `value` in one column, or `undefined` when none can be. */\nfunction beyond(\n column: string,\n direction: SortDirection,\n value: unknown,\n nullable: boolean,\n): StorageWhere | undefined {\n if (direction === \"desc\") {\n return value === null ? { [column]: { not: null } } : { [column]: { lt: value } };\n }\n if (value === null) {\n return undefined;\n }\n const greater = { [column]: { gt: value } };\n return nullable ? { OR: [greater, { [column]: null }] } : greater;\n}\n\n/**\n * The filter matching the rows after `values` in `order`: for each column, the\n * rows equal on every column before it and after it on that one.\n */\nexport function afterCursor(\n order: OrderBy,\n values: CursorValues,\n nullable: ReadonlySet<string>,\n): StorageWhere {\n const branches: StorageWhere[] = [];\n const equal: StorageWhere[] = [];\n for (const [index, [column, direction]] of order.entries()) {\n const value = values[index] ?? null;\n const after = beyond(column, direction, value, nullable.has(column) || value === null);\n if (after !== undefined) {\n branches.push(equal.length === 0 ? after : { AND: [...equal, after] });\n }\n equal.push({ [column]: value });\n }\n return branches.length === 1 ? (branches[0] ?? {}) : { OR: branches };\n}\n","// The collection index (RFC 0003 section 7.4): one small row per member of a\n// scope, `[id, rev, ...index fields]` in `order`, sent whole with the first\n// page of the scope. A client then knows the scope's membership and order at\n// once, filters it by views without asking the server, and loads full items\n// by window, by id (`qd:col:items`) or all at once. 4.1 had nothing like it:\n// a board loaded page after page, and mirrored the server's filters to know\n// what it held.\n//\n// Deltas keep the index live, from the same flush batch as the items: an\n// `added` delta carries its member's index row, built from the very item it\n// sends (`deltas.ts`), and `patched` and `updated` deltas carry every changed\n// index field, since index fields are item fields the items carry\n// (`define.ts`). So an index row and its item never disagree.\n//\n// An index row's `rev` is the time in the service's `versionColumn` when it\n// declares one, else the revision the snapshot (or the flush, for an `added`\n// delta) was read at. Index fields are read with the item's own select for\n// them (the item's whole select when it has a `map`) and projected and\n// stripped as items are.\n//\n// A snapshot's index is one more statement, run beside the page and the\n// count. It holds at most {@link INDEX_MAX_ROWS} rows: a larger scope gets\n// `indexTruncated: true` instead, and is loaded by pages.\n\nimport type { Revision, WireIndexRow } from \"../../protocol/envelope\";\nimport { versionTime } from \"../rev\";\nimport type { StorageAdapter, StorageRow, StorageWhere } from \"../storage\";\nimport type { BoundCollection } from \"./bind\";\nimport { orderByOf } from \"./cursor\";\nimport { itemOf, selectWith } from \"./items\";\n\n/** The most members a scope's index holds; a larger scope's first page says `indexTruncated`. */\nexport const INDEX_MAX_ROWS = 50_000;\n\n/** What a first page carries besides its items: the scope's index, or that it was too large for one. */\nexport type IndexPart =\n | { readonly index: readonly WireIndexRow[] }\n | { readonly indexTruncated: true };\n\ntype Values = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is Values {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * The columns a read of an indexed collection's rows adds to the item's\n * select, so the index rows built from them carry their version: the\n * service's `versionColumn`, or none.\n */\nexport function indexColumns(collection: BoundCollection): readonly string[] {\n const { versionColumn } = collection.service;\n return collection.index === undefined || versionColumn === undefined ? [] : [versionColumn];\n}\n\n/** What an index read selects: `id` and the item's select for each index field, or its whole select when it maps. */\nfunction indexSelect(collection: BoundCollection, fields: readonly string[]): Values {\n const { item } = collection;\n const select =\n item.map === undefined\n ? Object.fromEntries(\n fields.flatMap((field) =>\n item.select[field] === undefined ? [] : [[field, item.select[field]]],\n ),\n )\n : item.select;\n return selectWith(select, indexColumns(collection));\n}\n\n/**\n * The index row of a member, from the item it is sent as (`item`, built from\n * `row`) and `rev`, the revision `row` was read at: its version column's time\n * instead, when the service declares one. A field the item lacks is `null`.\n */\nexport function indexRowFrom(\n collection: BoundCollection,\n item: unknown,\n row: StorageRow,\n rev: Revision,\n): WireIndexRow {\n const values = isRecord(item) ? item : {};\n const { versionColumn } = collection.service;\n const version = versionColumn === undefined ? undefined : versionTime(row[versionColumn]);\n const id = typeof row.id === \"string\" ? row.id : \"\";\n return [id, version ?? rev, ...(collection.index ?? []).map((field) => values[field] ?? null)];\n}\n\n/**\n * Reads the index of the scope `members` matches, in `order` (`nullable`\n * holds the order columns that may hold null), at revision `rev`: one\n * statement. More than `max` members give `indexTruncated` instead.\n */\nexport async function readIndex(\n storage: StorageAdapter,\n collection: BoundCollection,\n members: StorageWhere,\n nullable: ReadonlySet<string>,\n rev: Revision,\n max = INDEX_MAX_ROWS,\n): Promise<IndexPart> {\n const fields = collection.index ?? [];\n const rows = await storage.findMany(collection.model, {\n where: members,\n select: indexSelect(collection, fields),\n orderBy: orderByOf(collection.order, nullable),\n take: max + 1,\n });\n if (rows.length > max) {\n return { indexTruncated: true };\n }\n return {\n index: rows.flatMap((row) =>\n typeof row.id === \"string\"\n ? [indexRowFrom(collection, itemOf(collection, row), row, rev)]\n : [],\n ),\n };\n}\n","// Memoized and cached policy lookups (RFC 0003 section 4.2): \"results are\n// memoized per request; an optional `cacheMs` keeps them across requests;\n// tracked writes to the membership model, the access column or the owner\n// column evict the affected entries\".\n//\n// Values are kept per namespace (one per service's rows, one per membership\n// table a service's policy reads, one per service's levels), per scope (the\n// user id for per-user values, `\"\"` for a row's columns) and per row id.\n//\n// - The request memo holds promises, so two lookups of one row in a request,\n// even concurrent ones, share one query. It lives for one engine call: an\n// authorization, or one `levelsFor` / `accessWhere` of the dispatcher.\n// - The cross-request cache holds settled values until `cacheMs` passes or a\n// tracked write evicts them (`changes.ts`). Only the database reads are\n// kept (row columns and membership levels), never a level computed from\n// them, so a change to a parent row needs no cascade: the child's level is\n// recomputed from the parent's freshly read values.\n// - A lookup is kept across requests only when no eviction of its namespace\n// happened while it ran (the namespace's generation is unchanged), and\n// only when it did not read inside a transaction, whose uncommitted rows\n// may yet roll back. A deny is kept like a grant, under the same eviction.\n// - A lookup inside a transaction does not read the cache either: a check\n// made there (a sharing change's re-check of its caller) must see the\n// rows as the transaction does, not a value kept before it began (the 5.1\n// audit's SHARE-4).\n\n/** A namespace of cached values; compared by identity. */\nexport interface Namespace {\n /** For debugging: what the namespace holds. */\n readonly label: string;\n}\n\n/** Creates a namespace. */\nexport function namespace(label: string): Namespace {\n return Object.freeze({ label });\n}\n\ntype Scoped<V> = Map<string, Map<string, V>>;\n\nfunction getIn<V>(\n store: Map<Namespace, Scoped<V>>,\n ns: Namespace,\n scope: string,\n id: string,\n): V | undefined {\n return store.get(ns)?.get(scope)?.get(id);\n}\n\nfunction setIn<V>(\n store: Map<Namespace, Scoped<V>>,\n ns: Namespace,\n scope: string,\n id: string,\n value: V,\n): boolean {\n let scopes = store.get(ns);\n if (scopes === undefined) {\n scopes = new Map();\n store.set(ns, scopes);\n }\n let ids = scopes.get(scope);\n if (ids === undefined) {\n ids = new Map();\n scopes.set(scope, ids);\n }\n const added = !ids.has(id);\n ids.set(id, value);\n return added;\n}\n\n/** One engine call's memo: lookups in flight or settled, by namespace, scope and id. */\nexport interface RequestMemo {\n get(ns: Namespace, scope: string, id: string): Promise<unknown> | undefined;\n set(ns: Namespace, scope: string, id: string, value: Promise<unknown>): void;\n}\n\n/** Creates the memo of one engine call. */\nexport function createRequestMemo(): RequestMemo {\n const store = new Map<Namespace, Scoped<Promise<unknown>>>();\n return {\n get: (ns, scope, id) => getIn(store, ns, scope, id),\n set(ns, scope, id, value) {\n setIn(store, ns, scope, id, value);\n },\n };\n}\n\ninterface Entry {\n readonly value: unknown;\n readonly expiresAt: number;\n}\n\n/** Options of {@link createAccessCache}. */\nexport interface AccessCacheOptions {\n /** How long a value is kept, in milliseconds. */\n readonly ttlMs: number;\n /** At most this many values are kept; past it, expired ones are dropped, then all. Default 100,000. */\n readonly maxEntries?: number;\n /** The clock. Default `Date.now`. */\n readonly now?: () => number;\n}\n\n/** The cross-request cache of policy lookups. */\nexport interface AccessCache {\n /** The value kept for the row, or `undefined` when none is (a kept value may be `null`). */\n get(ns: Namespace, scope: string, id: string): { readonly value: unknown } | undefined;\n set(ns: Namespace, scope: string, id: string, value: unknown): void;\n /**\n * Drops kept values: one (`scope` and `id`), the row's in every scope\n * (`id` only), a scope's (`scope` only: a user's levels), or the whole\n * namespace (neither). Every eviction moves the namespace to its next\n * generation.\n */\n evict(ns: Namespace, scope?: string, id?: string): void;\n /** Changes on every eviction in `ns`; a lookup that saw it change while running is not kept. */\n generation(ns: Namespace): number;\n /** How many values are kept. */\n readonly size: number;\n}\n\nconst DEFAULT_MAX_ENTRIES = 100_000;\n\n/** Drops one scope's values, or every scope's without `scope`; returns how many values went. */\nfunction dropScopes(scopes: Scoped<Entry>, scope: string | undefined): number {\n const names = scope === undefined ? [...scopes.keys()] : [scope];\n let dropped = 0;\n for (const name of names) {\n dropped += scopes.get(name)?.size ?? 0;\n scopes.delete(name);\n }\n return dropped;\n}\n\n/** Creates the cross-request cache. */\nexport function createAccessCache(options: AccessCacheOptions): AccessCache {\n const { ttlMs } = options;\n const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;\n const now = options.now ?? Date.now;\n const store = new Map<Namespace, Scoped<Entry>>();\n const generations = new Map<Namespace, number>();\n let size = 0;\n\n const bump = (ns: Namespace): void => {\n generations.set(ns, (generations.get(ns) ?? 0) + 1);\n };\n const sweep = (): void => {\n const time = now();\n for (const scopes of store.values()) {\n for (const ids of scopes.values()) {\n for (const [id, entry] of ids) {\n if (entry.expiresAt <= time) {\n ids.delete(id);\n size -= 1;\n }\n }\n }\n }\n };\n const evictRow = (scopes: Scoped<Entry>, scope: string | undefined, id: string): void => {\n const targets = scope === undefined ? [...scopes.values()] : [scopes.get(scope)];\n for (const ids of targets) {\n if (ids?.delete(id) === true) {\n size -= 1;\n }\n }\n };\n\n return {\n get(ns, scope, id) {\n const entry = getIn(store, ns, scope, id);\n if (entry === undefined) {\n return undefined;\n }\n if (entry.expiresAt <= now()) {\n store.get(ns)?.get(scope)?.delete(id);\n size -= 1;\n return undefined;\n }\n return { value: entry.value };\n },\n set(ns, scope, id, value) {\n if (size >= maxEntries) {\n sweep();\n }\n if (size >= maxEntries) {\n store.clear();\n size = 0;\n }\n if (setIn(store, ns, scope, id, { value, expiresAt: now() + ttlMs })) {\n size += 1;\n }\n },\n evict(ns, scope, id) {\n bump(ns);\n const scopes = store.get(ns);\n if (scopes === undefined) {\n return;\n }\n if (id !== undefined) {\n evictRow(scopes, scope, id);\n return;\n }\n size -= dropScopes(scopes, scope);\n if (scopes.size === 0) {\n store.delete(ns);\n }\n },\n generation: (ns) => generations.get(ns) ?? 0,\n get size() {\n return size;\n },\n };\n}\n\n/** Where a lookup reads through: the call's memo, and the cache when one is on. */\nexport interface LookupScope {\n readonly memo: RequestMemo;\n readonly cache: AccessCache | undefined;\n /** Whether a lookup starting now may read or keep the cross-request cache (it is not inside a transaction). */\n keepable(): boolean;\n}\n\n/**\n * The values of `ids` in `ns` and `scope`: from the memo, then the cache, and\n * the rest from one call of `load`. An id `load` does not return is `null`.\n * Rejects when `load` does; the memo then holds the failure for the rest of\n * the call, and nothing is cached.\n */\nexport async function lookup<V>(\n where: LookupScope,\n ns: Namespace,\n scope: string,\n ids: readonly string[],\n load: (missing: readonly string[]) => Promise<ReadonlyMap<string, V>>,\n): Promise<Map<string, V | null>> {\n const pending = new Map<string, Promise<V | null>>();\n const missing: string[] = [];\n const kept = where.cache !== undefined && where.keepable() ? where.cache : undefined;\n for (const id of new Set(ids)) {\n const memoized = where.memo.get(ns, scope, id) as Promise<V | null> | undefined;\n const cached = memoized === undefined ? kept?.get(ns, scope, id) : undefined;\n if (memoized !== undefined) {\n pending.set(id, memoized);\n } else if (cached === undefined) {\n missing.push(id);\n } else {\n const value = Promise.resolve(cached.value as V | null);\n where.memo.set(ns, scope, id, value);\n pending.set(id, value);\n }\n }\n if (missing.length > 0) {\n const generation = kept?.generation(ns);\n const batch = load(missing).then((loaded) => {\n if (kept !== undefined && kept.generation(ns) === generation) {\n for (const id of missing) {\n kept.set(ns, scope, id, loaded.get(id) ?? null);\n }\n }\n return loaded;\n });\n for (const id of missing) {\n const value = batch.then((loaded) => loaded.get(id) ?? null);\n where.memo.set(ns, scope, id, value);\n pending.set(id, value);\n }\n }\n const settled = await Promise.all(\n [...pending].map(async ([id, value]) => [id, await value] as const),\n );\n return new Map(settled);\n}\n","// One engine call's policy evaluation: the `PolicyTools` a policy reads the\n// database with, and the levels and filters of the bound policies. Every\n// lookup goes through the call's memo, and the database reads through the\n// cross-request cache when it is on (`cache.ts`): the service's rows, read\n// once with every column its policy uses, and each membership table's levels\n// per user.\n\nimport { isAccessLevel, type AccessLevel } from \"../../contract/access\";\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { StorageAdapter, StorageRow } from \"../storage\";\nimport type { Principal } from \"../types\";\nimport type { Binding } from \"./bindings\";\nimport {\n createRequestMemo,\n lookup,\n namespace,\n type AccessCache,\n type LookupScope,\n type Namespace,\n} from \"./cache\";\nimport { maxLevel } from \"./levels\";\nimport {\n idsOfFilter,\n type AccessFilter,\n type MembershipRead,\n type PolicyTools,\n type RowLevel,\n type RowLevels,\n} from \"./policy\";\n\n/** What every call of one dispatcher's engine shares. */\nexport interface EngineState {\n /** The bound policies, by service name. */\n readonly bindings: ReadonlyMap<string, Binding>;\n readonly storage: StorageAdapter | undefined;\n /** The cross-request cache, when `cacheMs` turned it on. */\n readonly cache: AccessCache | undefined;\n}\n\n/** One engine call: its lookups share a memo. */\nexport interface PolicyCall {\n /** The policy's level on each of `ids`: no service grants. */\n levels(binding: Binding, principal: Principal, ids: readonly string[]): Promise<RowLevels>;\n /** The policy's filter for `level`: no service grants. */\n where(binding: Binding, principal: Principal, level: AccessLevel): Promise<AccessFilter>;\n /**\n * The rows each of `ids`'s level is derived from, as `anchorKey`s: the row\n * itself, then its `inherit` parents up the chain. After `levels` in the\n * same call, the parents' ids come from the rows it already read.\n */\n anchors(binding: Binding, ids: readonly string[]): Promise<Map<string, string[]>>;\n}\n\n/** The key of the anchor `id` of `service`: a row a level is derived from. */\nexport function anchorKey(service: string, id: string): string {\n return `${service}\\u0000${id}`;\n}\n\n/** What one call's tools share. */\ninterface CallScope {\n readonly state: EngineState;\n readonly storage: StorageAdapter;\n /** Memo, then cache: for reads with eviction rules. */\n readonly cached: LookupScope;\n /** Memo only: for everything else. */\n readonly memoOnly: LookupScope;\n readonly undeclared: Map<MembershipRead, Namespace>;\n readonly tools: Map<Binding, PolicyTools>;\n readonly call: PolicyCall;\n}\n\nfunction storageMissing(): never {\n throw new QuickdrawError(\n \"INTERNAL\",\n \"An access policy read the database, but the dispatcher has no storage adapter: pass db as trackPrisma(prisma), or pass storage\",\n );\n}\n\n/** Stands in for a storage adapter the dispatcher does not have: any use fails with `INTERNAL`. */\nconst NO_STORAGE = new Proxy(Object.freeze({}) as StorageAdapter, {\n get: (_target, key) => (key === \"then\" ? undefined : storageMissing()),\n});\n\nfunction roleLevel(read: MembershipRead, role: unknown): RowLevel {\n if (read.levels === undefined) {\n return isAccessLevel(role) ? role : null;\n }\n return typeof role === \"string\" && Object.hasOwn(read.levels, role)\n ? (read.levels[role] ?? null)\n : null;\n}\n\nasync function readRows(\n storage: StorageAdapter,\n binding: Binding,\n ids: readonly string[],\n): Promise<Map<string, StorageRow>> {\n const select = Object.fromEntries([\"id\", ...binding.columns].map((column) => [column, true]));\n const rows = await storage.findMany(binding.model, { where: { id: { in: [...ids] } }, select });\n const byId = new Map<string, StorageRow>();\n for (const row of rows) {\n if (typeof row.id === \"string\") {\n byId.set(row.id, row);\n }\n }\n return byId;\n}\n\nasync function readMemberships(\n storage: StorageAdapter,\n read: MembershipRead,\n userId: string,\n ids: readonly string[],\n): Promise<Map<string, RowLevel>> {\n const rows = await storage.findMany(read.model, {\n where: { [read.entry]: { in: [...ids] }, [read.user]: userId },\n select: { [read.entry]: true, [read.level]: true },\n });\n const levels = new Map<string, RowLevel>();\n for (const row of rows) {\n const entry = row[read.entry];\n if (typeof entry === \"string\") {\n levels.set(entry, maxLevel(levels.get(entry), roleLevel(read, row[read.level])));\n }\n }\n return levels;\n}\n\nfunction bindingOf(state: EngineState, contract: AnyContract): Binding {\n const binding = state.bindings.get(contract.name);\n if (binding === undefined) {\n throw new QuickdrawError(\n \"INTERNAL\",\n `An access policy asked about ${contract.name}, which this dispatcher serves without an access policy`,\n );\n }\n return binding;\n}\n\n/** True when two membership reads name the same table and columns, and map roles alike. */\nfunction sameRead(a: MembershipRead, b: MembershipRead): boolean {\n const columns = ([\"model\", \"entry\", \"user\", \"level\"] as const).every((key) => a[key] === b[key]);\n if (!columns || a.levels === undefined || b.levels === undefined) {\n return columns && a.levels === b.levels;\n }\n const mapped = b.levels;\n const roles = Object.entries(a.levels);\n return (\n roles.length === Object.keys(mapped).length &&\n roles.every(([role, level]) => Object.hasOwn(mapped, role) && mapped[role] === level)\n );\n}\n\n/**\n * Memo and cache for a membership table the policy declared, which a\n * resolver names with a copy of what its `reads` declared; memo only for one\n * it did not declare (a tracked write to it evicts nothing).\n */\nfunction membershipScope(\n scope: CallScope,\n binding: Binding,\n read: MembershipRead,\n): [LookupScope, Namespace] {\n const declared =\n binding.memberships.get(read) ??\n [...binding.memberships].find(([known]) => sameRead(known, read))?.[1];\n if (declared !== undefined) {\n return [scope.cached, declared];\n }\n let ns = scope.undeclared.get(read);\n if (ns === undefined) {\n ns = namespace(`${read.model} (undeclared)`);\n scope.undeclared.set(read, ns);\n }\n return [scope.memoOnly, ns];\n}\n\nasync function idsWhere(\n scope: CallScope,\n contract: AnyContract,\n principal: Principal,\n level: AccessLevel,\n): Promise<readonly string[]> {\n const target = bindingOf(scope.state, contract);\n const filter = await scope.call.where(target, principal, level);\n if (filter === \"none\") {\n return [];\n }\n const listed = idsOfFilter(filter);\n if (listed !== undefined) {\n return listed;\n }\n const rows = await scope.storage.findMany(target.model, { where: filter, select: { id: true } });\n return rows.map((row) => row.id).filter((id): id is string => typeof id === \"string\");\n}\n\n/** The tools `binding`'s policy gets in this call. */\nfunction toolsFor(scope: CallScope, binding: Binding): PolicyTools {\n const made = scope.tools.get(binding);\n if (made !== undefined) {\n return made;\n }\n const { storage, state, call } = scope;\n const tools: PolicyTools = {\n storage,\n model: binding.model,\n rows: (ids) =>\n lookup(scope.cached, binding.rows, \"\", ids, (missing) => readRows(storage, binding, missing)),\n memberships(read, userId, ids) {\n const [where, ns] = membershipScope(scope, binding, read);\n return lookup(where, ns, userId, ids, (missing) =>\n readMemberships(storage, read, userId, missing),\n );\n },\n levelsOf: (contract, principal, ids) => call.levels(bindingOf(state, contract), principal, ids),\n whereOf: (contract, principal, level) =>\n call.where(bindingOf(state, contract), principal, level),\n idsWhere: (contract, principal, level) => idsWhere(scope, contract, principal, level),\n };\n scope.tools.set(binding, tools);\n return tools;\n}\n\n/** `PolicyCall.anchors`: each row, then the anchors of its `inherit` parents. */\nasync function anchorsOf(\n scope: CallScope,\n binding: Binding,\n ids: readonly string[],\n): Promise<Map<string, string[]>> {\n const anchors = new Map(ids.map((id) => [id, [anchorKey(binding.service.name, id)]]));\n for (const link of binding.policy.reads.parents ?? []) {\n const rows = await toolsFor(scope, binding).rows(ids);\n const parentOf = new Map<string, string>();\n for (const id of ids) {\n const parent = rows.get(id)?.[link.via];\n if (typeof parent === \"string\" && parent.length > 0) {\n parentOf.set(id, parent);\n }\n }\n const parents = await anchorsOf(scope, bindingOf(scope.state, link.from), [\n ...new Set(parentOf.values()),\n ]);\n for (const [id, parent] of parentOf) {\n anchors.get(id)?.push(...(parents.get(parent) ?? []));\n }\n }\n return anchors;\n}\n\n/** `where`, computing each service's filter for a principal and a level once. */\nfunction memoized(where: PolicyCall[\"where\"]): PolicyCall[\"where\"] {\n const made = new Map<string, Promise<AccessFilter>>();\n const principals = new Map<Principal, number>();\n return (binding, principal, level) => {\n let index = principals.get(principal);\n if (index === undefined) {\n index = principals.size;\n principals.set(principal, index);\n }\n const key = `${binding.service.name}\\u0000${String(index)}\\u0000${level}`;\n let filter = made.get(key);\n if (filter === undefined) {\n filter = where(binding, principal, level);\n made.set(key, filter);\n }\n return filter;\n };\n}\n\n/** Starts one engine call over `state`: its lookups share one memo. */\nexport function startCall(state: EngineState): PolicyCall {\n const memo = createRequestMemo();\n const memoOnly: LookupScope = { memo, cache: undefined, keepable: () => false };\n const scope: CallScope = {\n state,\n storage: state.storage ?? NO_STORAGE,\n cached: {\n memo,\n cache: state.cache,\n keepable: () => state.storage?.inTransaction?.() === false,\n },\n memoOnly,\n undeclared: new Map(),\n tools: new Map(),\n call: {\n levels: (binding, principal, ids) =>\n lookup(memoOnly, binding.levels, principal.userId, ids, (missing) =>\n binding.policy.levelsFor(principal, missing, toolsFor(scope, binding)),\n ),\n // Once per service, principal and level: `inherit` asks its parent's filter, then its ids.\n where: memoized((binding, principal, level) =>\n binding.policy.accessWhere(principal, level, toolsFor(scope, binding)),\n ),\n anchors: (binding, ids) => anchorsOf(scope, binding, ids),\n },\n };\n return scope.call;\n}\n","// The subscribes and watches a socket has in flight (RFC 0003 sections 6, 7.3\n// and 11.3), and how often its client unsubscribed from each while one ran.\n// A subscribe reads before it joins, so an unsubscribe that arrives while it\n// runs must stop its join: the subscribe notes the count when it begins and\n// joins only if the count did not move. The count matters only while a\n// subscribe of the key is in flight, so nothing is kept for any other key:\n// a client unsubscribing from keys it never subscribed to costs no memory.\n\nimport type { QuickdrawServerSocket } from \"../transports/types\";\n\ninterface Pending {\n /** Subscribes of the key in flight. */\n running: number;\n /** Unsubscribes from the key since the first of them began. */\n unsubscribes: number;\n}\n\n/** In-flight subscribes per socket and key: a row (`anchorKey`), a scope's room or a topic's room. */\nexport class PendingKeys {\n readonly #sockets = new WeakMap<QuickdrawServerSocket, Map<string, Pending>>();\n\n /** A subscribe of `keys` begins; returns how often each was unsubscribed from so far. */\n begin(socket: QuickdrawServerSocket, keys: Iterable<string>): Map<string, number> {\n const pending = this.#sockets.get(socket) ?? new Map<string, Pending>();\n this.#sockets.set(socket, pending);\n const counts = new Map<string, number>();\n for (const key of new Set(keys)) {\n const entry = pending.get(key) ?? { running: 0, unsubscribes: 0 };\n entry.running += 1;\n pending.set(key, entry);\n counts.set(key, entry.unsubscribes);\n }\n return counts;\n }\n\n /** The subscribe of `keys` that `begin` started has ended. */\n end(socket: QuickdrawServerSocket, keys: Iterable<string>): void {\n const pending = this.#sockets.get(socket);\n if (pending === undefined) {\n return;\n }\n for (const key of new Set(keys)) {\n const entry = pending.get(key);\n if (entry === undefined) {\n continue;\n }\n entry.running -= 1;\n if (entry.running === 0) {\n pending.delete(key);\n }\n }\n if (pending.size === 0) {\n this.#sockets.delete(socket);\n }\n }\n\n /** The client unsubscribed from `key`: counted only while a subscribe of it is in flight. */\n unsubscribed(socket: QuickdrawServerSocket, key: string): void {\n const entry = this.#sockets.get(socket)?.get(key);\n if (entry !== undefined) {\n entry.unsubscribes += 1;\n }\n }\n\n /** How often the client unsubscribed from `key` while a subscribe of it was in flight. */\n count(socket: QuickdrawServerSocket, key: string): number {\n return this.#sockets.get(socket)?.get(key)?.unsubscribes ?? 0;\n }\n\n /** How many keys the socket has a subscribe in flight for. */\n size(socket: QuickdrawServerSocket): number {\n return this.#sockets.get(socket)?.size ?? 0;\n }\n}\n","// The live entity subscriptions of this process's sockets (RFC 0003 sections\n// 4.4 and 6). Each socket keeps its own on `socket.data.entities`: the level\n// it joined the row's tier room at, and the rows that level is derived from\n// (its anchors). The index here finds the sockets an access change can\n// concern by anchor, so revocation re-resolves only theirs. Rooms stay the\n// source of truth for who receives frames: nothing here is read to emit, and\n// 4.1's per-entity `subscribers` map (4.1 `src/server/BaseService.ts:86-89`)\n// is not kept.\n//\n// Services and ids come from client frames, so the records are kept in\n// objects without a prototype and read only through their own keys: a frame\n// naming `__proto__` or `constructor` finds nothing (`ownRecord`).\n\nimport type { AccessLevel } from \"../../contract/access\";\nimport { entityRoom } from \"../../contract/names\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { MAX_ENTITY_IDS_PER_SOCKET } from \"../../protocol/version\";\nimport type { AccessChange } from \"../access/changes\";\nimport { anchorKey } from \"../access/tools\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { PendingKeys } from \"./pending\";\n\n/**\n * `records[key]` when `records` holds `key` itself, never through its\n * prototype: client frames name the keys of per-socket records, and a key\n * like `__proto__`, `constructor` or `toString` must find nothing.\n */\nexport function ownRecord<T>(\n records: Readonly<Record<string, T>> | undefined,\n key: string,\n): T | undefined {\n return records !== undefined && Object.hasOwn(records, key) ? records[key] : undefined;\n}\n\n/** An empty record map without a prototype, so no key a client names is found on it. */\nexport function emptyRecords<T>(): Record<string, T> {\n return Object.create(null) as Record<string, T>;\n}\n\n/** One live subscription, as `socket.data.entities[service][id]` records it. */\nexport interface EntitySubscription {\n /** The level the socket holds on the row: it is in the row's room for this level. */\n readonly level: AccessLevel;\n /** The rows the level is derived from (`anchorKey`s): the row, then its `inherit` parents. */\n readonly anchors: readonly string[];\n}\n\n/**\n * `socket.data.entities`: a socket's subscriptions, by service, then row id.\n * Plain data, in objects without a prototype; read it with `ownRecord`.\n */\nexport type EntitySubscriptions = Record<string, Record<string, EntitySubscription>>;\n\n/** One subscription of a socket, with the row it is on. */\nexport interface SubscriptionEntry {\n readonly service: string;\n readonly id: string;\n readonly subscription: EntitySubscription;\n}\n\n/** How many of a socket's records each socket has under one key of an index. */\nexport type Counts = Map<QuickdrawServerSocket, number>;\n\n/** The service an `anchorKey` names. */\nexport function serviceOf(anchor: string): string {\n return anchor.slice(0, anchor.indexOf(\"\\u0000\"));\n}\n\n/** Counts one more (`1`) or one fewer (`-1`) record of the socket under `key`; drops what reaches zero. */\nexport function count(\n index: Map<string, Counts>,\n key: string,\n socket: QuickdrawServerSocket,\n by: 1 | -1,\n): void {\n const counts = index.get(key) ?? new Map<QuickdrawServerSocket, number>();\n const next = (counts.get(socket) ?? 0) + by;\n if (next > 0) {\n counts.set(socket, next);\n index.set(key, counts);\n return;\n }\n counts.delete(socket);\n if (counts.size === 0) {\n index.delete(key);\n }\n}\n\n/** Why a socket at `MAX_ENTITY_IDS_PER_SOCKET` rows is refused one more (`CONFLICT`). */\nexport const TOO_MANY_ROWS = `A socket may subscribe to at most ${MAX_ENTITY_IDS_PER_SOCKET} rows; unsubscribe from some first`;\n\n/** This process's entity subscriptions, indexed by anchor. */\nexport class SubscriptionIndex {\n /** Moves on every access change this process handles; a subscribe that saw it move checks again. */\n accessChanges = 0;\n readonly #byAnchor = new Map<string, Counts>();\n readonly #byService = new Map<string, Counts>();\n /** Per socket, how many rows it holds subscriptions to. */\n readonly #held = new WeakMap<QuickdrawServerSocket, number>();\n /** The rows each socket has a `qd:sub` batch in flight for, by `anchorKey`. */\n readonly pending = new PendingKeys();\n\n #index(socket: QuickdrawServerSocket, anchors: readonly string[], by: 1 | -1): void {\n for (const anchor of anchors) {\n count(this.#byAnchor, anchor, socket, by);\n count(this.#byService, serviceOf(anchor), socket, by);\n }\n }\n\n /** The socket's subscription to a row, or `undefined`. */\n get(socket: QuickdrawServerSocket, service: string, id: string): EntitySubscription | undefined {\n return ownRecord(ownRecord(socket.data.entities, service), id);\n }\n\n /** Every subscription of the socket. */\n *entries(socket: QuickdrawServerSocket): Generator<SubscriptionEntry> {\n for (const [service, rows] of Object.entries(socket.data.entities ?? {})) {\n for (const [id, subscription] of Object.entries(rows)) {\n yield { service, id, subscription };\n }\n }\n }\n\n /** How many rows the socket holds subscriptions to. */\n held(socket: QuickdrawServerSocket): number {\n return this.#held.get(socket) ?? 0;\n }\n\n /**\n * `CONFLICT` when holding the rows of `ids` the socket does not hold yet\n * would take it past `MAX_ENTITY_IDS_PER_SOCKET` (the 5.1 audit's\n * COLL-4): a row held already never counts again.\n */\n checkRoom(socket: QuickdrawServerSocket, service: string, ids: readonly string[]): void {\n const fresh = new Set(ids.filter((id) => this.get(socket, service, id) === undefined));\n if (this.held(socket) + fresh.size > MAX_ENTITY_IDS_PER_SOCKET) {\n throw new QuickdrawError(\"CONFLICT\", TOO_MANY_ROWS);\n }\n }\n\n /** True when the socket may hold the row: it holds it already, or fewer rows than the cap. */\n hasRoom(socket: QuickdrawServerSocket, service: string, id: string): boolean {\n return (\n this.get(socket, service, id) !== undefined || this.held(socket) < MAX_ENTITY_IDS_PER_SOCKET\n );\n }\n\n /** Records a subscription and puts the socket in the row's room for its level, replacing any earlier one. */\n set(\n socket: QuickdrawServerSocket,\n service: string,\n id: string,\n subscription: EntitySubscription,\n ): void {\n const previous = this.get(socket, service, id);\n if (previous === undefined) {\n this.#held.set(socket, this.held(socket) + 1);\n } else {\n this.#index(socket, previous.anchors, -1);\n if (previous.level !== subscription.level) {\n void socket.leave(entityRoom(service, id, previous.level));\n }\n }\n const services = (socket.data.entities ??= emptyRecords());\n const rows = ownRecord(services, service) ?? emptyRecords<EntitySubscription>();\n services[service] = rows;\n rows[id] = subscription;\n this.#index(socket, subscription.anchors, 1);\n void socket.join(entityRoom(service, id, subscription.level));\n }\n\n /** Ends a subscription: the socket leaves the row's room. Returns what it was. */\n delete(\n socket: QuickdrawServerSocket,\n service: string,\n id: string,\n ): EntitySubscription | undefined {\n const previous = this.get(socket, service, id);\n if (previous === undefined) {\n return undefined;\n }\n this.#held.set(socket, this.held(socket) - 1);\n this.#index(socket, previous.anchors, -1);\n void socket.leave(entityRoom(service, id, previous.level));\n const rows = ownRecord(socket.data.entities, service);\n if (rows !== undefined) {\n delete rows[id];\n }\n return previous;\n }\n\n /** A `qd:sub` batch of these rows begins; returns how often each was unsubscribed from so far. */\n begin(\n socket: QuickdrawServerSocket,\n service: string,\n ids: readonly string[],\n ): Map<string, number> {\n const counts = this.pending.begin(\n socket,\n ids.map((id) => anchorKey(service, id)),\n );\n return new Map(ids.map((id) => [id, counts.get(anchorKey(service, id)) ?? 0]));\n }\n\n /** The batch `begin` started has ended. */\n end(socket: QuickdrawServerSocket, service: string, ids: readonly string[]): void {\n this.pending.end(\n socket,\n ids.map((id) => anchorKey(service, id)),\n );\n }\n\n /** A client unsubscribed: forget its subscription, and stop one still being made from joining. */\n unsubscribe(socket: QuickdrawServerSocket, service: string, id: string): void {\n this.pending.unsubscribed(socket, anchorKey(service, id));\n this.delete(socket, service, id);\n }\n\n /** How often the client unsubscribed from the row while a batch of it ran; a batch joins only if that did not move. */\n unsubscribes(socket: QuickdrawServerSocket, service: string, id: string): number {\n return this.pending.count(socket, anchorKey(service, id));\n }\n\n /** A socket disconnected: Socket.IO has emptied its rooms; drop it from the index. */\n drop(socket: QuickdrawServerSocket): void {\n for (const { subscription } of this.entries(socket)) {\n this.#index(socket, subscription.anchors, -1);\n }\n socket.data.entities = emptyRecords();\n this.#held.delete(socket);\n }\n\n /**\n * The subscriptions an access change can concern: those anchored on the\n * changed row (any row of the service when `id` is absent), of the changed\n * user's sockets (every user's when `userId` is absent).\n */\n matching(change: AccessChange): Map<QuickdrawServerSocket, SubscriptionEntry[]> {\n const key = change.id === undefined ? undefined : anchorKey(change.service, change.id);\n const sockets =\n key === undefined ? this.#byService.get(change.service) : this.#byAnchor.get(key);\n const found = new Map<QuickdrawServerSocket, SubscriptionEntry[]>();\n for (const socket of sockets?.keys() ?? []) {\n if (change.userId !== undefined && socket.data.principal?.userId !== change.userId) {\n continue;\n }\n const entries = [...this.entries(socket)].filter(({ subscription }) =>\n subscription.anchors.some((anchor) =>\n key === undefined ? serviceOf(anchor) === change.service : anchor === key,\n ),\n );\n if (entries.length > 0) {\n found.set(socket, entries);\n }\n }\n return found;\n }\n}\n","// Synchronous schema checks for the realtime paths (RFC 0003 section 12.5):\n// a channel message, a pushed stream item and an emitted event are checked\n// where they happen, with no promise per message. A Standard Schema may\n// validate asynchronously (an async refinement); such a schema cannot be\n// used on these paths, and `validateNow` says so instead of awaiting it.\n\nimport type { StandardSchemaV1, ValidationIssue } from \"../../contract/standardSchema\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { toWireIssues } from \"../pipeline/validation\";\n\n/** What a synchronous check found: the parsed value, the issues, or that the schema is asynchronous. */\nexport type SyncValidation =\n | { readonly value: unknown; readonly issues?: undefined }\n | { readonly issues: readonly ValidationIssue[] }\n | \"async\";\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n (typeof value === \"object\" || typeof value === \"function\") &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/** Validates `value` against `schema` without awaiting: `\"async\"` when the schema answers with a promise. */\nexport function validateNow(schema: StandardSchemaV1, value: unknown): SyncValidation {\n const result = schema[\"~standard\"].validate(value);\n if (isThenable(result)) {\n // Not awaited: keep a rejection from going unhandled.\n Promise.resolve(result).catch(() => undefined);\n return \"async\";\n }\n return result.issues === undefined ? { value: result.value } : { issues: result.issues };\n}\n\n/**\n * Whether a stream's items are checked: always, unless it declared\n * `validate: \"development\"` and the dispatcher does not check outputs\n * (`outputValidation`, off in production).\n */\nexport function checksItems(\n stream: { readonly validate: \"always\" | \"development\" },\n outputValidation: boolean,\n): boolean {\n return stream.validate === \"always\" || outputValidation;\n}\n\n/**\n * Checks what the server is about to send (a stream item, an event payload)\n * against its schema and returns the validated value, which is what goes\n * out: streams and events have no projections, so the schema is what keeps\n * the app's other keys off the wire (a Zod object strips them). A mismatch\n * is the app's bug, so it throws `INTERNAL` with the issues (logged, never\n * sent), and nothing is sent.\n */\nexport function checkOutgoing(schema: StandardSchemaV1, value: unknown, label: string): unknown {\n const result = validateNow(schema, value);\n if (result === \"async\") {\n throw new TypeError(\n `${label}: its schema validates asynchronously; streams and events are checked synchronously, so use a synchronous schema`,\n );\n }\n if (result.issues !== undefined) {\n throw new QuickdrawError(\"INTERNAL\", `${label} does not match its contract schema`, {\n issues: toWireIssues(result.issues),\n });\n }\n return result.value;\n}\n","// Channels (RFC 0003 section 12.5): fire-and-forget client-to-server input\n// such as cursors or typing, on one `qd:ch` listener per v5 socket. A message\n// is one array argument, `[service, channel, payload]`, sent volatile and\n// never acknowledged. Ported from 4.1's `registerChannelListener`\n// (4.1 `src/server/ServiceRegistry.ts:209-266`) and `checkChannelAccess`\n// (4.1 `src/server/BaseService.ts:956-983`).\n//\n// This is the hot path: no acknowledgement, no logging and no asynchronous\n// work per message. In order: a malformed frame or an unknown service or\n// channel is dropped; the socket's token bucket for that service and channel\n// (refilled at `ratePerSecond`, holding at most `burst`) drops a message over\n// the rate; an anonymous socket's message is dropped, and so is one from a\n// principal of a kind the service does not admit (`../access/kinds.ts`, a\n// set made when the service was defined); the payload is checked against\n// the channel's schema, synchronously, and dropped when it fails; the access\n// check runs in memory (the service-wide grant a `{ service }` access names,\n// then the contract's `requires`: the socket must already hold the entity or\n// collection subscription the payload names, or be in the app room the\n// requirement names (or in one whose name starts with its `prefix`), joined\n// by a call over this very socket); then the handler runs with the parsed\n// payload, and the room that matched as `ctx.room`. 4.1's `requireRoom`\n// skipped its check when it named no room; every form here drops the message\n// instead. A socket whose dropped messages within 10 s exceed 100 times the\n// channel's rate is disconnected: sustained flooding, not a burst. The rate\n// limiter never counts `qd:ch` (`transports/middleware.ts`).\n//\n// A handler's throw or rejection is logged and does not stop the channel:\n// at error, or at debug for a `QuickdrawError` the client caused (any code\n// but `INTERNAL` and `TIMEOUT`), as the pipeline logs calls. A schema that\n// validates asynchronously cannot be used here: its messages are dropped,\n// with one warning per channel.\n\nimport { CLIENT_EVENTS, collectionRoom } from \"../../contract/names\";\nimport { meetsLevel, serviceGrant } from \"../access/levels\";\nimport type { Hub } from \"../emit/hub\";\nimport { ownRecord } from \"../emit/subscriptions\";\nimport { describeError, failureLevel } from \"../pipeline/metrics\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport type { Principal } from \"../types\";\nimport type { Rooms } from \"./rooms\";\nimport type { ChannelContext, Presence, ServiceChannel } from \"./types\";\nimport { validateNow } from \"./validate\";\n\n/** How long the abuse guard counts a socket's messages dropped for one channel's rate before it starts over. */\nexport const CHANNEL_ABUSE_WINDOW_MS = 10_000;\n\n/** A socket is disconnected once its drops within the window exceed this many times the channel's rate. */\nexport const CHANNEL_ABUSE_MULTIPLIER = 100;\n\n/** One socket's token bucket for one channel, and its abuse window. */\ninterface Bucket {\n tokens: number;\n refilledAt: number;\n windowStart: number;\n dropped: number;\n}\n\n/** What one socket's channel messages share. */\ninterface SocketChannels {\n readonly socket: QuickdrawServerSocket;\n /** Bounded by the channels the services declare: unknown names never get one. */\n readonly buckets: Map<ServiceChannel, Bucket>;\n /** The handlers' context, made again when the socket's principal (new grants) or the matched room changes. */\n ctx: ChannelContext | undefined;\n}\n\n/** What every socket's channel messages share. */\nexport interface ChannelDeps {\n readonly hub: Hub;\n readonly rooms: Rooms;\n readonly presence: Presence;\n /** Channels already warned about for an asynchronous schema. */\n readonly warned: WeakSet<ServiceChannel>;\n}\n\n/** Takes one token, refilling first; false when the bucket is empty. */\nfunction take(bucket: Bucket, channel: ServiceChannel, now: number): boolean {\n const refill = ((now - bucket.refilledAt) / 1000) * channel.ratePerSecond;\n bucket.tokens = Math.min(channel.burst, bucket.tokens + refill);\n bucket.refilledAt = now;\n if (bucket.tokens < 1) {\n return false;\n }\n bucket.tokens -= 1;\n return true;\n}\n\n/** Counts a drop; true once the window's drops pass the abuse threshold. */\nfunction abusive(bucket: Bucket, channel: ServiceChannel, now: number): boolean {\n if (now - bucket.windowStart > CHANNEL_ABUSE_WINDOW_MS) {\n bucket.windowStart = now;\n bucket.dropped = 0;\n }\n bucket.dropped += 1;\n return bucket.dropped > channel.ratePerSecond * CHANNEL_ABUSE_MULTIPLIER;\n}\n\nfunction bucketOf(state: SocketChannels, channel: ServiceChannel, now: number): Bucket {\n let bucket = state.buckets.get(channel);\n if (bucket === undefined) {\n bucket = { tokens: channel.burst, refilledAt: now, windowStart: now, dropped: 0 };\n state.buckets.set(channel, bucket);\n }\n return bucket;\n}\n\n/** The parsed payload, or `undefined` when the message is dropped. */\nfunction parse(\n deps: ChannelDeps,\n channel: ServiceChannel,\n payload: unknown,\n): { readonly value: unknown } | undefined {\n const result = validateNow(channel.payload, payload);\n if (result === \"async\") {\n if (!deps.warned.has(channel)) {\n deps.warned.add(channel);\n deps.hub.logger.warn(\n `Channel ${channel.service}.${channel.name} has a payload schema that validates asynchronously; its messages are dropped, since channels validate synchronously`,\n { category: \"quickdraw.channel\" },\n );\n }\n return undefined;\n }\n return result.issues === undefined ? { value: result.value } : undefined;\n}\n\n/**\n * Whether the socket holds what `requires` names for `key`: the entity\n * subscription, the collection scope subscription, or the app room (one a\n * call over this socket joined with `ctx.rooms.join`). All three are the\n * socket's own records, kept on the node it is connected to, so the check\n * holds behind a cluster adapter without asking another node.\n */\nfunction holds(\n requires: NonNullable<ServiceChannel[\"requires\"]>,\n socket: QuickdrawServerSocket,\n service: string,\n key: string,\n): boolean {\n switch (requires.kind) {\n case \"entity\":\n return ownRecord(ownRecord(socket.data.entities, service), key) !== undefined;\n case \"collection\":\n return (\n ownRecord(socket.data.collections, collectionRoom(service, requires.collection, key)) !==\n undefined\n );\n default:\n return ownRecord(socket.data.appRooms, key) !== undefined;\n }\n}\n\n/**\n * The first app room the socket joined whose name starts with `prefix`\n * (the room it joined earliest, when there are several), or `undefined`.\n * `appRooms` has no prototype, so `for...in` sees its own rooms only.\n */\nfunction roomWithPrefix(socket: QuickdrawServerSocket, prefix: string): string | undefined {\n const joined = socket.data.appRooms;\n for (const room in joined) {\n if (room.startsWith(prefix)) {\n return room;\n }\n }\n return undefined;\n}\n\n/**\n * The in-memory access check: the service grant `access` names, then the\n * contract's `requires`. `false` when the message is dropped; else the app\n * room a room requirement matched, which the handler gets as `ctx.room`\n * (`undefined` for the other forms, and for a channel that requires none).\n */\nfunction allowed(\n channel: ServiceChannel,\n socket: QuickdrawServerSocket,\n principal: Principal,\n value: unknown,\n): string | undefined | false {\n const { access, requires } = channel;\n if (\n access !== \"authenticated\" &&\n !meetsLevel(serviceGrant(principal, channel.service), access.service)\n ) {\n return false;\n }\n if (requires === undefined) {\n return undefined;\n }\n if (requires.kind === \"roomPrefix\") {\n return roomWithPrefix(socket, requires.prefix) ?? false;\n }\n const key = requires.select(value);\n if (key === undefined || !holds(requires, socket, channel.service, key)) {\n return false;\n }\n return requires.kind === \"room\" ? key : undefined;\n}\n\n/** The handlers' context for the socket's principal and the room a message matched: made again only when either changes. */\nfunction contextOf(\n deps: ChannelDeps,\n state: SocketChannels,\n principal: Principal,\n room: string | undefined,\n): ChannelContext {\n if (state.ctx?.principal !== principal || state.ctx.room !== room) {\n state.ctx = Object.freeze({\n principal,\n socketId: state.socket.id,\n room,\n log: deps.hub.logger,\n rooms: deps.rooms.of(state.socket),\n presence: deps.presence,\n });\n }\n return state.ctx;\n}\n\n/** Logs a handler's failure: at debug when the client caused it, as the pipeline logs calls (RFC 0003 section 9). */\nfunction failed(\n deps: ChannelDeps,\n channel: ServiceChannel,\n ctx: ChannelContext,\n error: unknown,\n): void {\n const level = failureLevel(error);\n deps.hub.logger[level](`The handler of channel ${channel.service}.${channel.name} failed`, {\n category: \"quickdraw.channel\",\n userId: ctx.principal.userId,\n socketId: ctx.socketId,\n error: describeError(error),\n });\n}\n\nfunction run(\n deps: ChannelDeps,\n channel: ServiceChannel,\n value: unknown,\n ctx: ChannelContext,\n): void {\n try {\n const result: unknown = channel.handler(value, ctx);\n if (typeof result === \"object\" && result !== null && \"then\" in result) {\n Promise.resolve(result).catch((error: unknown) => {\n failed(deps, channel, ctx, error);\n });\n }\n } catch (error) {\n failed(deps, channel, ctx, error);\n }\n}\n\nfunction flooded(\n deps: ChannelDeps,\n state: SocketChannels,\n channel: ServiceChannel,\n bucket: Bucket,\n): void {\n deps.hub.logger.warn(\n `Disconnecting socket ${state.socket.id} for sustained flooding of channel ${channel.service}.${channel.name}`,\n {\n category: \"quickdraw.channel\",\n userId: state.socket.data.principal?.userId,\n dropped: bucket.dropped,\n },\n );\n state.socket.disconnect(true);\n}\n\n/** One `qd:ch` message, through every check to the handler. */\nfunction receive(deps: ChannelDeps, state: SocketChannels, frame: unknown): void {\n if (!Array.isArray(frame)) {\n return;\n }\n const [service, name, payload] = frame as readonly unknown[];\n const channel =\n typeof service === \"string\" && typeof name === \"string\"\n ? deps.hub.registry.services.get(service)?.channels.get(name)\n : undefined;\n if (channel === undefined) {\n return;\n }\n const now = Date.now();\n const bucket = bucketOf(state, channel, now);\n if (!take(bucket, channel, now)) {\n if (abusive(bucket, channel, now)) {\n flooded(deps, state, channel, bucket);\n }\n return;\n }\n const { principal } = state.socket.data;\n // Of a kind the service does not admit (`../access/kinds.ts`); no list\n // holds \"\", so a principal without a kind is dropped too.\n if (principal === null || channel.kinds?.has(principal.kind ?? \"\") === false) {\n return;\n }\n const parsed = parse(deps, channel, payload);\n if (parsed === undefined) {\n return;\n }\n const room = allowed(channel, state.socket, principal, parsed.value);\n if (room !== false) {\n run(deps, channel, parsed.value, contextOf(deps, state, principal, room));\n }\n}\n\n/** The socket extension that serves `qd:ch` for one dispatcher's channels. */\nexport function channelMessages(deps: ChannelDeps): (socket: QuickdrawServerSocket) => void {\n return (socket) => {\n const state: SocketChannels = { socket, buckets: new Map(), ctx: undefined };\n socket.on(CLIENT_EVENTS.channel, (frame: unknown) => {\n try {\n receive(deps, state, frame);\n } catch (error) {\n // A schema or selector that throws must not end the process: Socket.IO runs listeners from nextTick.\n deps.hub.logger.error(\"A channel message failed\", {\n category: \"quickdraw.channel\",\n socketId: socket.id,\n error: describeError(error),\n });\n }\n });\n };\n}\n","// Waiting on the rest of a cluster, bounded (pack H's multi-node proof): a\n// command to the cluster's Valkey (the revision counter, last-seen times),\n// and a server-to-server event that is answered. A node that broadcasts an\n// access change or a user's reloaded grants waits until every other node has\n// applied it, so the flush that caused it sends its frames only once no node\n// still holds what it revoked. Socket.IO hands the listener the\n// acknowledgement as the event's last argument when the sender asked for\n// answers (`serverSideEmitWithAck`).\n\n/** How long a node waits on the rest of the cluster by default: `cluster.timeoutMs`. */\nexport const DEFAULT_CLUSTER_TIMEOUT_MS = 1000;\n\nclass Timeout extends Error {\n constructor(ms: number) {\n super(`no answer within ${ms} ms`);\n }\n}\n\n/** `promise`, or a rejection once `ms` passed. */\nexport async function within<T>(promise: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(new Timeout(ms));\n }, ms);\n timer.unref?.();\n });\n try {\n return await Promise.race([promise, timeout]);\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** The acknowledgement a server-to-server event came with (its last argument), or one that does nothing. */\nexport function answerOf<T = boolean>(rest: readonly unknown[]): (value: T) => void {\n const last = rest.at(-1);\n return typeof last === \"function\" ? (last as (value: T) => void) : () => undefined;\n}\n","// Users' last-seen times across a cluster (RFC 0003 section 12.5, and the gap\n// section 17 recorded for pack E): `presence.lastSeen(userId)` is now while\n// any node holds a socket of the user, else the last time a node saw the\n// user's last socket there disconnect. Each process keeps its own (bounded,\n// `PresenceRecords`); behind a cluster's Valkey a node also writes it to\n// `{keyPrefix}:seen:{userId}`, kept for `LAST_SEEN_TTL_MS` and never moved\n// back, and an answer takes the later of the two. When Valkey does not\n// answer, a node answers from its own records.\n\nimport type { Hub } from \"../emit/hub\";\nimport { DEFAULT_CLUSTER_TIMEOUT_MS, within } from \"./acks\";\n\n/** How long a user's last-seen time is kept in the cluster's Valkey: 30 days. */\nexport const LAST_SEEN_TTL_MS = 30 * 24 * 60 * 60 * 1000;\n\n/** Writes the time unless a later one is there; keeps it `ARGV[2]` ms. */\nconst LAST_SEEN_SCRIPT = [\n \"local kept = tonumber(redis.call('GET', KEYS[1]) or '0')\",\n \"if tonumber(ARGV[1]) > kept then\",\n \" redis.call('SET', KEYS[1], ARGV[1], 'PX', ARGV[2])\",\n \"end\",\n \"return 1\",\n].join(\"\\n\");\n\nfunction keyOf(prefix: string, userId: string): string {\n return `${prefix}:seen:${userId}`;\n}\n\n/** Records in the cluster's Valkey that `userId`'s last socket on this node disconnected `at`. */\nexport function recordLastSeen(hub: Hub, userId: string, at: number): void {\n const target = hub.revisions.counterClient();\n if (target === undefined || target.client.isReady === false) {\n return;\n }\n const key = keyOf(target.keyPrefix, userId);\n const args = [\"EVAL\", LAST_SEEN_SCRIPT, \"1\", key, String(at), String(LAST_SEEN_TTL_MS)];\n target.client.sendCommand(args).catch((error: unknown) => {\n hub.logger.debug(\"Recording a user's last-seen time in the cluster failed\", {\n category: \"quickdraw.presence\",\n userId,\n error: error instanceof Error ? error.message : String(error),\n });\n });\n}\n\n/** The last time any node of the cluster saw `userId` leave, or `undefined` (one server, none kept, no answer). */\nexport async function readLastSeen(hub: Hub, userId: string): Promise<number | undefined> {\n const target = hub.revisions.counterClient();\n if (target === undefined || target.client.isReady === false) {\n return undefined;\n }\n const timeoutMs = hub.cluster?.timeoutMs ?? DEFAULT_CLUSTER_TIMEOUT_MS;\n try {\n const reply = await within(\n target.client.sendCommand([\"GET\", keyOf(target.keyPrefix, userId)]),\n timeoutMs,\n );\n const value = typeof reply === \"string\" ? Number(reply) : Number.NaN;\n return Number.isSafeInteger(value) ? value : undefined;\n } catch {\n return undefined;\n }\n}\n","// The shared revision counter of a cluster (pack H, child 2): one key in the\n// Valkey (or Redis) behind the Socket.IO adapter, which every node takes its\n// flush revisions from, so revisions from different nodes are one total\n// order instead of clocks that agree only within their skew.\n//\n// The counter keeps to the clock revisions are read against: a script makes\n// it `max(last + 1, the server's time in microseconds, the caller's floor +\n// 1)` in one round trip. In microseconds it moves past the clock only above\n// a million flushes a second across the cluster, so revisions a client\n// holds and the `versionColumn` times \"not modified\" compares them with\n// stay comparable (`../rev.ts`), and a node never gets a revision below one\n// it issued. Reading it (`current`) is one GET; a key Valkey does not have\n// is unknown, never 0.\n//\n// The key has no TTL and must survive Valkey restarts and failovers\n// (persistence or replication). When it is lost anyway, the script starts\n// it again at the server's clock, above the node's floor: since the counter\n// kept to the clock, that is above every revision issued before, unless the\n// clock stepped back. A node that sees the key gone after it had seen it\n// logs a warning.\n//\n// Valkey may stop answering. A command that fails, or does not answer within\n// `timeoutMs`, makes the counter answer `undefined` (the caller falls back to\n// its own clock) and logs one error. While it is degraded no call sends a\n// command or waits: a call made once `RETRY_MS` passed (with the client\n// connected) starts one probe in the background (a GET), and the probe that\n// answers ends the outage, logging that the counter is back.\n\nimport { createHash } from \"node:crypto\";\nimport type { Logger } from \"../../contract/logger\";\nimport type { Revision } from \"../../protocol/envelope\";\nimport { describeError } from \"../pipeline/metrics\";\nimport { DEFAULT_CLUSTER_TIMEOUT_MS, within } from \"./acks\";\n\n/**\n * A Valkey or Redis client the cluster helpers send commands through: a\n * node-redis client (`redis` 4 to 6) as it is, or an ioredis one through\n * {@link clusterClientOf}.\n */\nexport interface ClusterClient {\n /** Sends one command, `[\"GET\", key]`, and resolves with its reply. */\n sendCommand(args: string[]): Promise<unknown>;\n /** False while the client is not connected; commands sent then would wait in its queue. */\n readonly isReady?: boolean;\n}\n\n/**\n * The counter script: the next revision, above the caller's floor and never\n * below the server's clock in microseconds, and whether the key was there\n * (`[revision, 1 | 0]`).\n */\nexport const REVISION_SCRIPT = [\n \"if redis.replicate_commands then redis.replicate_commands() end\",\n \"local time = redis.call('TIME')\",\n \"local now = tonumber(time[1]) * 1000000 + tonumber(time[2])\",\n \"local held = redis.call('GET', KEYS[1])\",\n \"local last = tonumber(held or '0')\",\n \"local floor = tonumber(ARGV[1]) or 0\",\n \"local rev = math.max(last + 1, now, floor + 1)\",\n \"return { redis.call('INCRBY', KEYS[1], rev - last), held and 1 or 0 }\",\n].join(\"\\n\");\n\nconst REVISION_SCRIPT_SHA = createHash(\"sha1\").update(REVISION_SCRIPT).digest(\"hex\");\n\n/** How long a degraded counter waits before it probes Valkey again. */\nexport const RETRY_MS = 1000;\n\n/** A cluster's shared revision counter, as one node sees it. */\nexport interface SharedCounter {\n /**\n * A new revision: the counter, moved past `floor` (the last revision this\n * node issued) and the server's clock. `undefined` when Valkey did not\n * answer: the node then uses its own clock.\n */\n next(floor: Revision): Promise<Revision | undefined>;\n /**\n * The counter's last revision; `null` when Valkey does not have the key\n * (no flush took one since the key was made or lost: unknown), and\n * `undefined` when Valkey did not answer.\n */\n current(): Promise<Revision | null | undefined>;\n /** True while Valkey is not answering. */\n degraded(): boolean;\n}\n\n/** Options of {@link createSharedCounter}. */\nexport interface SharedCounterOptions {\n readonly client: ClusterClient;\n readonly key: string;\n readonly logger: Logger;\n readonly timeoutMs?: number;\n /** The clock retries are timed with; tests pass their own. */\n readonly now?: () => number;\n}\n\n/** A reply that should be a whole number of microseconds, read. */\nfunction revisionIn(reply: unknown): Revision {\n const value = typeof reply === \"string\" ? Number(reply) : reply;\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n throw new TypeError(`the counter answered ${String(reply)}, not a revision`);\n }\n return value;\n}\n\n/** The script's reply, read: the revision, and whether the key was there. */\nfunction scriptReply(reply: unknown): { readonly rev: Revision; readonly held: boolean } {\n if (!Array.isArray(reply) || reply.length !== 2) {\n throw new TypeError(`the counter answered ${String(reply)}, not [revision, held]`);\n }\n return { rev: revisionIn(reply[0]), held: Number(reply[1]) === 1 };\n}\n\nfunction noScript(error: unknown): boolean {\n return error instanceof Error && error.message.startsWith(\"NOSCRIPT\");\n}\n\n/** A counter's outages: one error each, a probe in the background, one info at the end. */\ninterface Outages {\n /** True while Valkey is not answering. */\n readonly down: () => boolean;\n /** A command failed or did not answer: the counter is degraded (logged once). */\n failed(error: unknown): undefined;\n /** While degraded: one GET in the background once the retry delay passed; nothing waits on it. */\n probe(): void;\n}\n\nfunction createOutages(\n options: SharedCounterOptions,\n timeoutMs: number,\n now: () => number,\n): Outages {\n const { client, key, logger } = options;\n let down = false;\n let retryAt = 0;\n let probing = false;\n const recovered = (): void => {\n if (down) {\n down = false;\n logger.info(\"The shared revision counter answers again\", {\n category: \"quickdraw.cluster\",\n key,\n });\n }\n };\n return {\n down: () => down,\n failed(error: unknown): undefined {\n retryAt = now() + RETRY_MS;\n if (!down) {\n down = true;\n logger.error(\n \"The shared revision counter did not answer; this node takes revisions from its own clock until it does\",\n { category: \"quickdraw.cluster\", key, error: describeError(error) },\n );\n }\n return undefined;\n },\n probe(): void {\n if (probing || now() < retryAt || client.isReady === false) {\n return;\n }\n probing = true;\n retryAt = now() + RETRY_MS;\n void within(\n Promise.resolve().then(() => client.sendCommand([\"GET\", key])),\n timeoutMs,\n )\n .then(recovered, () => {\n retryAt = now() + RETRY_MS;\n })\n .finally(() => {\n probing = false;\n });\n },\n };\n}\n\n/** Creates the counter at `key`, sending its commands through `client`. */\nexport function createSharedCounter(options: SharedCounterOptions): SharedCounter {\n const { client, key, logger } = options;\n const timeoutMs = options.timeoutMs ?? DEFAULT_CLUSTER_TIMEOUT_MS;\n const outages = createOutages(options, timeoutMs, options.now ?? Date.now);\n /** This node saw the key: a script that finds it missing means it was lost. */\n let seen = false;\n\n const send = async (args: string[]): Promise<unknown> => {\n if (outages.down()) {\n outages.probe();\n return undefined;\n }\n if (client.isReady === false) {\n return outages.failed(new Error(\"the client is not connected\"));\n }\n try {\n return await within(\n Promise.resolve().then(() => client.sendCommand(args)),\n timeoutMs,\n );\n } catch (error) {\n if (noScript(error)) {\n throw error;\n }\n return outages.failed(error);\n }\n };\n\n /** A revision from the script's reply, saying when the key it saw was lost. */\n const revisionOf = (reply: unknown): Revision | undefined => {\n try {\n const { rev, held } = scriptReply(reply);\n if (!held && seen) {\n logger.warn(\n \"The revision counter key was lost; configure persistence or replication for it\",\n { category: \"quickdraw.cluster\", key, rev },\n );\n }\n seen = true;\n return rev;\n } catch (error) {\n return outages.failed(error);\n }\n };\n\n return Object.freeze({\n async next(floor: Revision): Promise<Revision | undefined> {\n const floorArg = String(Math.max(0, Math.floor(floor)));\n let reply: unknown;\n try {\n reply = await send([\"EVALSHA\", REVISION_SCRIPT_SHA, \"1\", key, floorArg]);\n } catch {\n // The script is not cached on this server yet (or any more): send it whole.\n reply = await send([\"EVAL\", REVISION_SCRIPT, \"1\", key, floorArg]);\n }\n return reply === undefined ? undefined : revisionOf(reply);\n },\n async current(): Promise<Revision | null | undefined> {\n const reply = await send([\"GET\", key]);\n if (reply === undefined || reply === null) {\n return reply;\n }\n try {\n const rev = revisionIn(reply);\n seen = true;\n return rev;\n } catch (error) {\n return outages.failed(error);\n }\n },\n degraded: () => outages.down(),\n });\n}\n\n/**\n * The client `value` stands for, or `undefined`: a node-redis client (it has\n * `sendCommand(args)` and `isReady`), or an ioredis one (`call` and\n * `status`), wrapped to look the same.\n */\nexport function clusterClientOf(value: unknown): ClusterClient | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n const candidate = value as {\n readonly call?: unknown;\n readonly status?: unknown;\n readonly sendCommand?: unknown;\n };\n if (typeof candidate.call === \"function\" && typeof candidate.status === \"string\") {\n const call = candidate.call as (command: string, ...args: string[]) => Promise<unknown>;\n return {\n sendCommand: ([command = \"\", ...args]) => call.call(value, command, ...args),\n get isReady() {\n return (value as { readonly status: unknown }).status === \"ready\";\n },\n };\n }\n if (typeof candidate.sendCommand === \"function\") {\n return value as ClusterClient;\n }\n return undefined;\n}\n","// The revisions of one dispatcher's live data (RFC 0003 section 5.3, step 2,\n// and pack H's shared flush order). On one server they are the process's\n// clock (`../rev.ts`), as they always were. Behind a cluster adapter whose\n// Valkey (or Redis) client the server can reach (the Socket.IO Redis\n// adapter's publishing client, or `cluster.client`), they come from the\n// cluster's shared counter (`counter.ts`) instead:\n//\n// - a flush asks the counter for its revision the moment it is handed to\n// the dispatcher's sinks, one round trip, and its sinks run once it\n// answered, still in arrival order (`../uow/flush.ts`), so a payload is\n// never older than its revision claims and frames leave each process in\n// revision order; across nodes, revisions are one total order;\n// - a read that claims a revision (a subscription's rows, a page, a search,\n// a row sent again after a level change) reads the counter first: the\n// last revision any node took, so a write with a revision up to it\n// committed before the read, and any later one gets a greater one. The\n// process's own last revision would not do: a quiet node's is old, and a\n// client holding a newer frame from another node would keep its stale row;\n// - when Valkey does not answer, the node falls back to its own clock (one\n// error logged per outage), still never below a revision it issued, and\n// reads claim its clock too (`max(now, the last revision this process\n// took, the last it issued)`): comparisons with other nodes' hold within\n// the skew between this node's clock and Valkey's (the counter keeps to\n// Valkey's clock) until the counter answers again. A key Valkey does not\n// have (none taken since it was made or lost) is read the same way, never\n// as 0.\n\nimport type { Logger } from \"../../contract/logger\";\nimport type { Revision } from \"../../protocol/envelope\";\nimport { clockRev, currentRev, nextRev, observeRev } from \"../rev\";\nimport type { QuickdrawIo } from \"../transports/types\";\nimport {\n clusterClientOf,\n createSharedCounter,\n type ClusterClient,\n type SharedCounter,\n} from \"./counter\";\n\nexport type { ClusterBroadcasts } from \"./broadcasts\";\nexport type { ClusterClient } from \"./counter\";\n\n/** An ioredis client, as the cluster helpers use one. */\nexport interface IoRedisLike {\n call(command: string, ...args: string[]): Promise<unknown>;\n readonly status: string;\n}\n\n/** `createServer`'s `cluster` option: where a cluster's shared state lives, behind a cluster adapter. */\nexport interface ClusterOptions {\n /**\n * The Valkey or Redis client of the shared revision counter and of the\n * users' last-seen times: a node-redis or ioredis client. Default: the\n * publishing client of the Socket.IO Redis adapter (`setupRedisAdapter`,\n * or `createAdapter(pub, sub)` in `socket.adapter`). Without one, behind\n * another adapter, revisions stay per process.\n */\n readonly client?: ClusterClient | IoRedisLike;\n /**\n * The prefix of the cluster's keys (`{keyPrefix}:rev`,\n * `{keyPrefix}:seen:{userId}`), and the deployment: every server-to-server\n * event carries it, and a node ignores another deployment's events. It is\n * `setupRedisAdapter`'s default key too. Each deployment that shares a\n * Valkey needs its own. Default `\"quickdraw\"`; a non-empty string.\n */\n readonly keyPrefix?: string;\n /**\n * How long a counter command may take before the node takes its revision\n * from its own clock, in milliseconds. Default 1,000.\n */\n readonly timeoutMs?: number;\n}\n\n/** What the revisions read of the hub they belong to. */\nexport interface RevisionHub {\n readonly io: QuickdrawIo | undefined;\n readonly probe: { local(): boolean };\n readonly logger: Logger;\n cluster: ClusterOptions | undefined;\n}\n\n/** The revisions of one dispatcher. */\nexport interface Revisions {\n /**\n * Called when a flush is handed to the sinks: `undefined` when revisions\n * are the process's (the flush keeps the one it took), else a function to\n * call when the flush's turn comes, which resolves with its revision.\n */\n forFlush(): (() => Promise<Revision>) | undefined;\n /**\n * The revision a read made from now on is no older than: at once on one\n * server; behind a counter its last revision, or the clock's when it does\n * not answer or has no key. Never 0.\n */\n claim(): Revision | Promise<Revision>;\n /** Behind a counter, the counter's revision when it moved past `rev`; `undefined` otherwise. */\n movedPast(rev: Revision): Promise<Revision | undefined>;\n /** True when revisions come from the cluster's counter: the process's change log sees only its own flushes. */\n shared(): boolean;\n /** The counter, when there is one: a user's last-seen time lives beside it. */\n counterClient(): { readonly client: ClusterClient; readonly keyPrefix: string } | undefined;\n}\n\n/** The default prefix of a cluster's keys. */\nexport const DEFAULT_KEY_PREFIX = \"quickdraw\";\n\n/** A cluster client found for the hub: as given, and as the helpers use it. */\ninterface Found {\n readonly raw: object;\n readonly client: ClusterClient;\n readonly keyPrefix: string;\n}\n\n/** Creates the revisions of the hub. */\nexport function createRevisions(hub: RevisionHub): Revisions {\n const found = new WeakMap<object, Found>();\n const counters = new WeakMap<object, SharedCounter>();\n /** The highest revision this dispatcher gave a flush: the floor of its next one. */\n let issued = 0;\n\n /** The cluster's client: `cluster.client`, or the Redis adapter's publishing client. */\n const target = (): Found | undefined => {\n if (hub.probe.local()) {\n return undefined;\n }\n const adapter = hub.io?.sockets.adapter as { readonly pubClient?: unknown } | undefined;\n const raw: unknown = hub.cluster?.client ?? adapter?.pubClient;\n if (typeof raw !== \"object\" || raw === null) {\n return undefined;\n }\n let entry = found.get(raw);\n const client = entry === undefined ? clusterClientOf(raw) : entry.client;\n if (entry === undefined && client !== undefined) {\n entry = { raw, client, keyPrefix: hub.cluster?.keyPrefix ?? DEFAULT_KEY_PREFIX };\n found.set(raw, entry);\n }\n return entry;\n };\n\n const counterOf = (): SharedCounter | undefined => {\n const entry = target();\n if (entry === undefined) {\n return undefined;\n }\n let counter = counters.get(entry.raw);\n if (counter === undefined) {\n counter = createSharedCounter({\n client: entry.client,\n key: `${entry.keyPrefix}:rev`,\n logger: hub.logger,\n timeoutMs: hub.cluster?.timeoutMs,\n });\n counters.set(entry.raw, counter);\n }\n return counter;\n };\n\n /** The flush's revision: the counter's answer, or the clock's; above every one issued before. */\n const assign = (answer: Revision | undefined): Revision => {\n const rev = Math.max(answer ?? nextRev(), issued + 1);\n issued = rev;\n observeRev(rev);\n return rev;\n };\n\n /** The revision a read claims: the counter's, or without one (no answer, no key) the clock's. */\n const fresh = (value: Revision | null | undefined): Revision => {\n const rev = Math.max(value ?? Math.max(clockRev(), currentRev()), issued);\n observeRev(rev);\n return rev;\n };\n\n return Object.freeze({\n forFlush() {\n const counter = counterOf();\n if (counter === undefined) {\n return undefined;\n }\n // Asked now, in arrival order: one connection answers in order.\n const answer = counter.next(issued);\n return async () => assign(await answer);\n },\n claim() {\n const counter = counterOf();\n return counter === undefined ? currentRev() : counter.current().then(fresh);\n },\n async movedPast(rev: Revision) {\n // No answer: nothing reaches this node from the others either. No key: no node took a\n // revision since it was made or lost.\n const value = await counterOf()?.current();\n return typeof value === \"number\" && value > rev ? fresh(value) : undefined;\n },\n shared: () => counterOf() !== undefined,\n counterClient: () => {\n const entry = target();\n return entry === undefined ? undefined : { client: entry.client, keyPrefix: entry.keyPrefix };\n },\n });\n}\n","// Deployments sharing one Valkey (the 5.1 audit's RT-2). Valkey pub/sub is\n// global across databases, so two deployments on one Valkey (staging and\n// production, say) whose adapters share channels hear each other's\n// server-to-server events, and up to 5.1.0 each node applied whatever\n// arrived: another deployment's reloaded grants (an escalation until the\n// socket reconnects), its disconnects, stream items, room removals, access\n// changes and unnamed removals.\n//\n// A deployment is its `cluster.keyPrefix` (default \"quickdraw\"), which also\n// prefixes the cluster's Valkey keys and is `setupRedisAdapter`'s default\n// key. The socket server registers it for its `io`; senders tag each\n// `quickdraw:*` payload with it (`tagged`, `emitToNodes`); listeners go\n// through `onNodeEvent`, which applies an event of its own deployment only:\n//\n// - an untagged event comes from a node of an earlier quickdraw version\n// (during a rolling deploy, or of another deployment that shares the\n// Valkey and was not upgraded yet, which a node cannot tell apart): it is\n// applied, with one warning per server;\n// - a foreign one is not applied, with one error per server; an event that\n// asks for an answer is still answered (`true`, or `null` for presence),\n// so the other deployment's wait ends and it does not go degraded.\n//\n// The probe (`broadcasts.ts`) is tagged too, but every node answers it\n// whatever its tag: it carries nothing and only says \"I am up\". Tags do not\n// separate what the adapter itself carries: room broadcasts and `qd:rotate`\n// on a shared adapter key still reach the other deployment's sockets, and a\n// node of an earlier version applies anything. One Valkey, or a distinct\n// keyPrefix and adapter key, per deployment.\n\nimport type { Logger } from \"../../contract/logger\";\nimport type { QuickdrawIo } from \"../transports/types\";\nimport { answerOf } from \"./acks\";\nimport { DEFAULT_KEY_PREFIX } from \"./revisions\";\n\n/** The key of the deployment in a server-to-server event's payload. */\nexport const DEPLOYMENT_KEY = \"deployment\";\n\nconst DEPLOYMENTS = new WeakMap<object, string>();\n\n/** What a server logged once about events from other nodes. */\ninterface Logged {\n untagged: boolean;\n foreign: boolean;\n}\n\nconst LOGGED = new WeakMap<object, Logged>();\n\n/** Registers `prefix` as the deployment of the server `io`. */\nexport function registerDeployment(io: object, prefix: string): void {\n DEPLOYMENTS.set(io, prefix);\n}\n\n/**\n * Registers the deployment `cluster.keyPrefix` names (default \"quickdraw\")\n * for the server `io`; a `TypeError` for a prefix that is not a non-empty\n * string.\n */\nexport function registerClusterDeployment(\n io: object,\n cluster: { readonly keyPrefix?: unknown } | undefined,\n): void {\n registerDeployment(io, checkKeyPrefix(cluster));\n}\n\n/**\n * The deployment `cluster` names: its `keyPrefix`, \"quickdraw\" when it has\n * none. Throws for one that is not a non-empty string (`null` included);\n * `createServer` checks it before anything starts.\n */\nexport function checkKeyPrefix(cluster: { readonly keyPrefix?: unknown } | undefined): string {\n const prefix = cluster?.keyPrefix === undefined ? DEFAULT_KEY_PREFIX : cluster.keyPrefix;\n if (typeof prefix !== \"string\" || prefix === \"\") {\n throw new TypeError(\"createServer: cluster.keyPrefix must be a non-empty string\");\n }\n return prefix;\n}\n\n/** The deployment of the server `io`: its `cluster.keyPrefix`, \"quickdraw\" by default. */\nexport function deploymentOf(io: object): string {\n return DEPLOYMENTS.get(io) ?? DEFAULT_KEY_PREFIX;\n}\n\n/** `payload`, tagged with the deployment of the server `io`. */\nexport function tagged<T extends object>(\n io: object,\n payload: T,\n): T & { readonly deployment: string } {\n return { ...payload, [DEPLOYMENT_KEY]: deploymentOf(io) };\n}\n\n/** Sends `event` to the other nodes, unanswered, tagged with this server's deployment. */\nexport function emitToNodes(io: QuickdrawIo, event: string, payload: object): void {\n io.serverSideEmit(event, tagged(io, payload));\n}\n\nfunction loggedOf(io: object): Logged {\n let logged = LOGGED.get(io);\n if (logged === undefined) {\n logged = { untagged: false, foreign: false };\n LOGGED.set(io, logged);\n }\n return logged;\n}\n\n/**\n * Listens for `event` from the other nodes of the server `io`, and runs\n * `handler` with its payload and its answer (which does nothing for an event\n * sent unanswered) for an event of this deployment, or one without a\n * deployment (a node of an earlier version: warned once). An event of\n * another deployment is answered `foreign` and not handled (logged once).\n */\nexport function onNodeEvent(\n io: QuickdrawIo,\n logger: Logger,\n event: string,\n handler: (payload: unknown, answer: (value: unknown) => void) => void,\n foreign: unknown = true,\n): void {\n io.on(event, (payload: unknown, ...rest: unknown[]) => {\n const answer = answerOf<unknown>(rest);\n const tag: unknown =\n typeof payload === \"object\" && payload !== null\n ? (payload as Readonly<Record<string, unknown>>)[DEPLOYMENT_KEY]\n : undefined;\n const logged = loggedOf(io);\n if (tag === undefined) {\n if (!logged.untagged) {\n logged.untagged = true;\n logger.warn(\n `A node sent ${event} without its deployment: a node of an earlier quickdraw version, during a rolling deploy or of another deployment that shares this Valkey and still runs one. Its events are applied, so upgrade every deployment that shares the Valkey; none arrives once every node runs this version`,\n { category: \"quickdraw.cluster\", event },\n );\n }\n handler(payload, answer);\n return;\n }\n if (tag !== deploymentOf(io)) {\n if (!logged.foreign) {\n logged.foreign = true;\n logger.error(\n `A node of another deployment (cluster.keyPrefix \"${String(tag)}\") shares this node's Valkey channels: its ${event} and every later event of it are ignored, but its room broadcasts still reach this node's sockets. Give each deployment its own Valkey, or its own cluster.keyPrefix and adapter key (docs/deploying.md)`,\n { category: \"quickdraw.cluster\", event, deployment: tag },\n );\n }\n answer(foreign);\n return;\n }\n handler(payload, answer);\n });\n}\n","// Presence across a cluster (the 5.1 audit's RT-5). Asking every node with\n// `io.in(room).fetchSockets()` made each node serialize every socket in the\n// room (its handshake headers and cookies, auth and token, rooms and data:\n// about 15.6 KB a socket, 100 KB for a bloated one) on every join and every\n// user's last leave, and every node parse every answer. Here a node asks the\n// others with an answered event, `quickdraw:presence`, carrying `{ room }`\n// (answered with the user ids of that node's app-room records) or\n// `{ userId }` (answered with whether that node has a socket of the user),\n// tagged with its deployment: only ids or a boolean cross Valkey, and a node\n// of another deployment answers `null`, which counts for nothing.\n//\n// Requests are coalesced per room and per user: one in flight, and one\n// trailing request every caller that arrives meanwhile shares, sent once the\n// one in flight settles, so no caller gets an answer read before it asked.\n//\n// A node of an earlier version does not know the event and never answers.\n// A request nobody answered within `cluster.timeoutMs` falls back to the old\n// read of every node's sockets for the next 30 s (warned for the first\n// window of an episode, at most once every 10 minutes), so a rolling deploy\n// costs one timeout per window, never a failure. That read counts what it\n// always counted: a socket a raw `socket.join` put in the room, and on an\n// adapter key another deployment shares, that deployment's sockets.\n\nimport { userRoom } from \"../../contract/names\";\nimport { DEFAULT_CLUSTER_TIMEOUT_MS, within } from \"../cluster/acks\";\nimport { onNodeEvent, tagged } from \"../cluster/deployment\";\nimport type { Hub } from \"../emit/hub\";\nimport type { PresenceRecords } from \"./presence\";\n\n/** The server-to-server event one node asks the others for a room's users or a user's sockets on. */\nexport const PRESENCE_EVENT = \"quickdraw:presence\";\n\n/** How long a node reads every node's sockets after a presence request went unanswered. */\nexport const PRESENCE_FALLBACK_MS = 30_000;\n\n/** How long after one fallback warning a window opens without another. */\nexport const PRESENCE_WARN_EVERY_MS = 10 * 60_000;\n\n/** A node's presence requests to the other nodes of its cluster, and its answers to theirs. */\nexport interface PresenceRequests {\n /** The users the other nodes have in app room `room`, as their records hold them. */\n users(room: string): Promise<string[]>;\n /** True when another node has a socket of `userId`. */\n online(userId: string): Promise<boolean>;\n /** Answers the other nodes' presence requests, on the server the hub was given. */\n listen(): void;\n}\n\n/** One key's requests: the one in flight, and the trailing one callers share meanwhile. */\ninterface Slot<T> {\n readonly running: Promise<T>;\n queued: Promise<T> | undefined;\n}\n\n/** A request coalesced by key: the one in flight, or else one trailing request shared by every caller meanwhile. */\ntype Coalesced = <T>(key: string, ask: () => Promise<T>) => Promise<T>;\n\n/**\n * Coalesces requests per key: with none in flight a request is sent at\n * once; with one in flight, every caller that arrives meanwhile shares one\n * trailing request, sent once the one in flight settles.\n */\nfunction coalescer(): Coalesced {\n const slots = new Map<string, Slot<unknown>>();\n const start = <T>(key: string, ask: () => Promise<T>): Promise<T> => {\n const running = ask();\n const slot: Slot<T> = { running, queued: undefined };\n slots.set(key, slot as Slot<unknown>);\n const settle = (): void => {\n if (slots.get(key) === slot && slot.queued === undefined) {\n slots.delete(key);\n }\n };\n running.then(settle, settle);\n return running;\n };\n return <T>(key: string, ask: () => Promise<T>): Promise<T> => {\n const slot = slots.get(key) as Slot<T> | undefined;\n if (slot === undefined) {\n return start(key, ask);\n }\n slot.queued ??= slot.running.then(\n () => start(key, ask),\n () => start(key, ask),\n );\n return slot.queued;\n };\n}\n\n/** The ids among a node's answers to a room request; `null` (another deployment) and anything else count for nothing. */\nfunction idsOf(answers: unknown): string[] {\n const ids = new Set<string>();\n for (const answer of Array.isArray(answers) ? (answers as unknown[]) : []) {\n for (const id of Array.isArray(answer) ? (answer as unknown[]) : []) {\n if (typeof id === \"string\" && id !== \"\") {\n ids.add(id);\n }\n }\n }\n return [...ids];\n}\n\n/** The users of the other nodes' sockets in `room`, from every node's sockets (the fallback). */\nasync function readUsers(hub: Hub, room: string): Promise<string[]> {\n const { io } = hub;\n if (io === undefined) {\n return [];\n }\n const sockets = await io.in(room).fetchSockets();\n const ids = new Set<string>();\n for (const socket of sockets) {\n const userId = socket.data.principal?.userId;\n if (!io.sockets.sockets.has(socket.id) && typeof userId === \"string\" && userId !== \"\") {\n ids.add(userId);\n }\n }\n return [...ids];\n}\n\n/** Whether another node has a socket of `userId`, from every node's sockets (the fallback). */\nasync function readOnline(hub: Hub, userId: string): Promise<boolean> {\n const { io } = hub;\n if (io === undefined) {\n return false;\n }\n const sockets = await io.in(userRoom(userId)).fetchSockets();\n return sockets.some((socket) => !io.sockets.sockets.has(socket.id));\n}\n\n/** Answers the other nodes' presence requests, from this node's app-room records and its sockets. */\nfunction answerRequests(hub: Hub, records: PresenceRecords): void {\n const { io } = hub;\n if (io === undefined) {\n return;\n }\n onNodeEvent(\n io,\n hub.logger,\n PRESENCE_EVENT,\n (payload, answer) => {\n const { room, userId } = (payload ?? {}) as Readonly<Record<string, unknown>>;\n if (typeof room === \"string\") {\n answer(records.users(room) ?? []);\n } else if (typeof userId === \"string\") {\n answer((io.sockets.adapter.rooms.get(userRoom(userId))?.size ?? 0) > 0);\n } else {\n answer(null);\n }\n },\n null,\n );\n}\n\n/** Creates the presence requests of the dispatcher whose hub this is; `now` is the clock the fallback window reads. */\nexport function createPresenceRequests(\n hub: Hub,\n records: PresenceRecords,\n now: () => number = Date.now,\n): PresenceRequests {\n const coalesced = coalescer();\n let fallbackUntil = 0;\n let warnedAt: number | undefined;\n\n /** Opens a fallback window; warns for the first of an episode, at most once every 10 minutes. */\n const fallBack = (): void => {\n const at = now();\n fallbackUntil = at + PRESENCE_FALLBACK_MS;\n if (warnedAt === undefined || at - warnedAt >= PRESENCE_WARN_EVERY_MS) {\n warnedAt = at;\n hub.logger.warn(\n \"A node did not answer a presence request within cluster.timeoutMs (a node of an earlier quickdraw version during a rolling deploy, a node that stopped answering, or an adapter that does not answer server-side events): presence reads every node's sockets (fetchSockets) for the next 30 s\",\n { category: \"quickdraw.presence\" },\n );\n }\n };\n\n /** Asks the other nodes, or reads their sockets during a fallback window or once nobody answered. */\n const ask = async <T>(\n payload: object,\n answered: (answers: unknown) => T,\n read: () => Promise<T>,\n ) => {\n const { io } = hub;\n if (io === undefined || now() < fallbackUntil) {\n return await read();\n }\n const timeoutMs = hub.cluster?.timeoutMs ?? DEFAULT_CLUSTER_TIMEOUT_MS;\n try {\n const answers: unknown = await within(\n io.serverSideEmitWithAck(PRESENCE_EVENT, tagged(io, payload)),\n timeoutMs,\n );\n return answered(answers);\n } catch {\n fallBack();\n return await read();\n }\n };\n\n return Object.freeze({\n users: (room: string) =>\n coalesced(`r\\u0000${room}`, () => ask({ room }, idsOf, () => readUsers(hub, room))),\n online: (userId: string) =>\n coalesced(`u\\u0000${userId}`, () =>\n ask(\n { userId },\n (answers) => Array.isArray(answers) && answers.includes(true),\n () => readOnline(hub, userId),\n ),\n ),\n listen: () => {\n answerRequests(hub, records);\n },\n });\n}\n","// Presence (RFC 0003 section 12.5): who is online, when they were last seen,\n// and who is in a room. 4.1 apps read `io.sockets` themselves for this.\n//\n// This process keeps, for every app room a method joined with\n// `ctx.rooms.join`, how many sockets of each user are in it (so a join and a\n// leave know at once whether they change who is there), and the time each\n// user's last socket disconnected. Both are bounded: a socket is in at most\n// `MAX_APP_ROOMS` app rooms, and the last-seen times are kept for the\n// `PRESENCE_MAX_LAST_SEEN` users seen last. Both live in `Map`s, so a user id\n// or room named `__proto__` is an ordinary key.\n//\n// `count` and `users` answer for app rooms only: a framework room (`qd:`,\n// `user:`) or a name with the shape of a socket id is `VALIDATION`, as for\n// `ctx.rooms.join`, and on this process they answer from the records of the\n// rooms `ctx.rooms.join` joined, never from the adapter's rooms, which hold\n// every socket's own room and any room a raw `socket.join` made (the 5.1\n// audit's RT-I1).\n//\n// The answers come from this process's rooms while the server runs the\n// in-memory adapter it was created with. Behind a cluster adapter (Redis)\n// other nodes' sockets are not visible here, so `isOnline`, `count` and\n// `users` ask the other nodes with an answered request that carries user\n// ids alone (`presenceRequests.ts`; the 5.1 audit's RT-5), and `lastSeen`\n// also reads the last disconnect any node recorded in the cluster's Valkey\n// (`../cluster/lastSeen.ts`).\n\nimport { RESERVED_ROOM_PREFIXES, socketIdShaped, userRoom } from \"../../contract/names\";\nimport { readLastSeen, recordLastSeen } from \"../cluster/lastSeen\";\nimport type { Hub } from \"../emit/hub\";\nimport { unreadable } from \"../transports/ack\";\nimport { createPresenceRequests, type PresenceRequests } from \"./presenceRequests\";\nimport type { Presence } from \"./types\";\n\n/** How many users' last-seen times one process keeps; the least recently seen go first. */\nexport const PRESENCE_MAX_LAST_SEEN = 100_000;\n\n/** The most app rooms (`ctx.rooms.join`) one socket may be in at once. */\nexport const MAX_APP_ROOMS = 100;\n\n/** This process's app-room occupancy by user, and its users' last-seen times. */\nexport class PresenceRecords {\n /** Per app room, how many sockets of each user are in it. */\n readonly #rooms = new Map<string, Map<string, number>>();\n /** When each user's last socket disconnected, oldest first. */\n readonly #lastSeen = new Map<string, number>();\n\n /** A socket of `userId` entered `room`; true when it is the user's first socket there. */\n entered(room: string, userId: string): boolean {\n const users = this.#rooms.get(room) ?? new Map<string, number>();\n this.#rooms.set(room, users);\n const sockets = (users.get(userId) ?? 0) + 1;\n users.set(userId, sockets);\n return sockets === 1;\n }\n\n /** A socket of `userId` left `room`; true when it was the user's last socket there. */\n exited(room: string, userId: string): boolean {\n const users = this.#rooms.get(room);\n const sockets = users?.get(userId);\n if (users === undefined || sockets === undefined) {\n return false;\n }\n if (sockets > 1) {\n users.set(userId, sockets - 1);\n return false;\n }\n users.delete(userId);\n if (users.size === 0) {\n this.#rooms.delete(room);\n }\n return true;\n }\n\n /** The users with a socket of this process in app room `room`, or `undefined` for a room no user joined here. */\n users(room: string): string[] | undefined {\n const users = this.#rooms.get(room);\n return users === undefined ? undefined : [...users.keys()];\n }\n\n /** The user's last socket disconnected at `at`. */\n seen(userId: string, at: number): void {\n this.#lastSeen.delete(userId);\n this.#lastSeen.set(userId, at);\n if (this.#lastSeen.size > PRESENCE_MAX_LAST_SEEN) {\n const oldest = this.#lastSeen.keys().next();\n if (oldest.done !== true) {\n this.#lastSeen.delete(oldest.value);\n }\n }\n }\n\n /** When the user's last socket here disconnected, or `undefined`. */\n lastSeen(userId: string): number | undefined {\n return this.#lastSeen.get(userId);\n }\n}\n\n/** The presence of one dispatcher: its hub, this process's records, and its requests to the other nodes. */\nexport interface PresenceState {\n readonly hub: Hub;\n readonly records: PresenceRecords;\n readonly requests: PresenceRequests;\n}\n\n/** Creates the presence state of the dispatcher whose hub this is. */\nexport function createPresenceState(hub: Hub): PresenceState {\n const records = new PresenceRecords();\n return { hub, records, requests: createPresenceRequests(hub, records) };\n}\n\n/**\n * The user's last socket on this process disconnected at `at`: kept here,\n * and behind a cluster's Valkey for every node (`../cluster/lastSeen.ts`).\n */\nexport function markSeen(hub: Hub, records: PresenceRecords, userId: string, at: number): void {\n records.seen(userId, at);\n recordLastSeen(hub, userId, at);\n}\n\n/** The users of this process's sockets in `room`, from the records of the rooms `ctx.rooms.join` joined. */\nfunction localUsers(records: PresenceRecords, room: string): string[] {\n return records.users(room) ?? [];\n}\n\n/**\n * The users with a socket in `room` on any node: behind a cluster adapter,\n * what the other nodes answer (`presenceRequests.ts`). This node's own are\n * read once the other nodes answered, not when they were asked: a socket\n * that joined here meanwhile sent its `joined` to the room already, and a\n * list that left it out would undo it.\n */\nexport async function usersInRoom(state: PresenceState, room: string): Promise<string[]> {\n const { hub, records } = state;\n if (hub.io === undefined) {\n return [];\n }\n if (hub.probe.local()) {\n return localUsers(records, room);\n }\n const remote = await state.requests.users(room);\n return [...new Set([...remote, ...localUsers(records, room)])];\n}\n\n/** True while some socket of `userId` is in `room`, on any node. */\nexport async function inRoom(state: PresenceState, room: string, userId: string): Promise<boolean> {\n return (await usersInRoom(state, room)).includes(userId);\n}\n\nfunction checkName(member: string, value: unknown): asserts value is string {\n if (typeof value !== \"string\" || value === \"\") {\n throw new TypeError(`presence.${member}: pass a non-empty string`);\n }\n}\n\n/**\n * Throws `VALIDATION` for a framework room (`qd:` entity, collection, topic\n * and stream rooms, `user:` rooms) or a name with the shape of a socket id,\n * as `ctx.rooms.join` does: who sits in one would tell who is subscribed to\n * a row, which sockets a user has, or whose socket an id is. Presence\n * answers for app rooms only.\n */\nfunction checkRoom(member: string, room: unknown): asserts room is string {\n checkName(member, room);\n if (RESERVED_ROOM_PREFIXES.some((prefix) => room.startsWith(prefix))) {\n throw unreadable(\n `presence.${member}: room \"${room}\" is reserved; presence answers for app rooms, not for rooms starting with ${RESERVED_ROOM_PREFIXES.join(\" or \")}`,\n );\n }\n if (socketIdShaped(room)) {\n throw unreadable(\n `presence.${member}: room \"${room}\" has the shape of a Socket.IO socket id (20 letters, digits, \"_\" or \"-\"); presence answers for app rooms, and every socket is alone in the room of its id`,\n );\n }\n}\n\n/** The presence API of one dispatcher, answered from its server's sockets (none before a server attaches). */\nexport function createPresence(state: PresenceState): Presence {\n const { hub, records } = state;\n const isOnline = async (userId: string): Promise<boolean> => {\n checkName(\"isOnline\", userId);\n const { io } = hub;\n if (io === undefined) {\n return false;\n }\n // A socket of the user here answers at once; behind a cluster adapter, else the other nodes do.\n const here = (io.sockets.adapter.rooms.get(userRoom(userId))?.size ?? 0) > 0;\n return here || hub.probe.local() ? here : await state.requests.online(userId);\n };\n const users = async (room: string): Promise<string[]> => {\n checkRoom(\"users\", room);\n return await usersInRoom(state, room);\n };\n return Object.freeze({\n isOnline,\n async lastSeen(userId: string): Promise<number | null> {\n checkName(\"lastSeen\", userId);\n if (await isOnline(userId)) {\n return Date.now();\n }\n const seen = Math.max(records.lastSeen(userId) ?? 0, (await readLastSeen(hub, userId)) ?? 0);\n return seen > 0 ? seen : null;\n },\n async count(room: string): Promise<number> {\n checkRoom(\"count\", room);\n return (await usersInRoom(state, room)).length;\n },\n users,\n });\n}\n","// The seeds of streams (RFC 0003 section 12.5): the latest `seed` items of\n// each scope of each stream, kept in memory on this process so a new\n// subscriber starts with recent history. A restart empties them, and each\n// node of a cluster keeps its own from the pushes it received since it\n// started (every node receives every push of a stream that keeps a seed:\n// `streams.ts`), so a node that started after the pushes has none of them.\n// A stream whose service computes its seed (`streams: { <name>: { seed } }`)\n// keeps nothing here: each subscribe asks the app for the current state, on\n// whichever node it arrives. Durable history is the app's: store the rows\n// and expose a collection.\n//\n// Bounded twice: a scope keeps at most its stream's `seed` items (at most\n// 1,000), and a stream keeps at most `STREAM_MAX_SCOPES` scopes, dropping the\n// one pushed to least recently. Scopes are `Map` keys, so a scope named\n// `__proto__` is an ordinary one.\n\nimport type { ServiceStream, StreamSeedContext } from \"./types\";\nimport { checkOutgoing, checksItems } from \"./validate\";\n\n/** The most scopes one stream keeps a seed for; the scope pushed to least recently goes first. */\nexport const STREAM_MAX_SCOPES = 10_000;\n\n/**\n * The seed `stream`'s service computes for one subscriber (`streams: {\n * <name>: { seed } }`), each item checked against the stream's schema, and\n * the checked items are what is sent, as `push` sends (unchecked as `push`\n * leaves them, for a stream that validates in development only). The function is\n * called before this awaits anything: in the caller's tick, the one it\n * joined the socket to the feed in. A function that returns something other\n * than an array, or an item that does not fit, throws for `INTERNAL`.\n */\nexport async function computeSeed(\n service: string,\n stream: ServiceStream,\n scope: string | undefined,\n ctx: StreamSeedContext,\n outputValidation: boolean,\n): Promise<unknown[]> {\n const compute = stream.computeSeed;\n const items: unknown = await compute?.(scope, ctx);\n const label = `The seed of ${service}.${stream.name}`;\n if (!Array.isArray(items)) {\n throw new TypeError(`${label}: its seed function must return an array of items`);\n }\n if (!checksItems(stream, outputValidation)) {\n return items as unknown[];\n }\n return items.map((item: unknown, index) =>\n checkOutgoing(stream.item, item, `Item ${String(index)} of ${label}`),\n );\n}\n\n/** The key of a global stream's one feed among a stream's scopes. */\nconst GLOBAL_FEED = \"\";\n\n/** The key of one stream among a dispatcher's streams. */\nexport function streamKey(service: string, stream: string): string {\n return `${service}\\u0000${stream}`;\n}\n\n/** The seeds of one dispatcher's streams. */\nexport class StreamSeeds {\n /** Per stream (`service\\0stream`), each scope's latest items, the scope pushed to last at the end. */\n readonly #streams = new Map<string, Map<string, unknown[]>>();\n\n /** Keeps `item` as the newest of a scope's seed of at most `size` items. */\n push(stream: string, scope: string | undefined, item: unknown, size: number): void {\n if (size <= 0) {\n return;\n }\n const scopes = this.#streams.get(stream) ?? new Map<string, unknown[]>();\n this.#streams.set(stream, scopes);\n const key = scope ?? GLOBAL_FEED;\n const items = scopes.get(key) ?? [];\n // Moved to the end: the scope pushed to last.\n scopes.delete(key);\n scopes.set(key, items);\n items.push(item);\n if (items.length > size) {\n items.splice(0, items.length - size);\n }\n if (scopes.size > STREAM_MAX_SCOPES) {\n const oldest = scopes.keys().next();\n if (oldest.done !== true) {\n scopes.delete(oldest.value);\n }\n }\n }\n\n /** A scope's seed, oldest first: a copy. */\n seed(stream: string, scope: string | undefined): unknown[] {\n return [...(this.#streams.get(stream)?.get(scope ?? GLOBAL_FEED) ?? [])];\n }\n\n /** How many scopes of a stream have a seed. */\n scopes(stream: string): number {\n return this.#streams.get(stream)?.size ?? 0;\n }\n}\n","// A subscriber's level on rows, and what it is derived from (RFC 0003\n// sections 4.3 and 4.4): the service's policy through the dispatcher's\n// engine, counted as `dispatcher.access.levelsFor` counts it, with the rows\n// each level is anchored on. A service without a policy has no row levels:\n// only a service-wide `Admin` grant (with `adminBypass`) reaches its rows.\n\nimport type { AccessLevel } from \"../../contract/access\";\nimport type { ResolvedAccess } from \"../access/api\";\nimport { meetsLevel, serviceGrant } from \"../access/levels\";\nimport { anchorKey } from \"../access/tools\";\nimport type { AnyService } from \"../service\";\nimport type { Principal } from \"../types\";\nimport type { Hub } from \"./hub\";\nimport { SUBSCRIBE_LEVEL } from \"./tiers\";\n\n/** The principal's levels on `ids` of `service` and their anchors, in one engine call. */\nexport async function resolveAccess(\n hub: Hub,\n service: AnyService,\n principal: Principal,\n ids: readonly string[],\n): Promise<ResolvedAccess> {\n if (service.access !== undefined && service.model !== undefined) {\n return await hub.policies.resolve(service.name, principal, ids);\n }\n const bypass = service.adminBypass && serviceGrant(principal, service.name) === \"Admin\";\n return {\n levels: new Map(ids.map((id) => [id, bypass ? \"Admin\" : null])),\n anchors: new Map(ids.map((id) => [id, [anchorKey(service.name, id)]])),\n };\n}\n\n/** The level a subscription to the row holds, or `undefined` when the level is too low to subscribe. */\nexport function subscriberLevel(access: ResolvedAccess, id: string): AccessLevel | undefined {\n const level = access.levels.get(id) ?? null;\n return level !== null && meetsLevel(level, SUBSCRIBE_LEVEL) ? level : undefined;\n}\n\n/** The anchors of the row's level; the row itself when the engine named none. */\nexport function anchorsOf(access: ResolvedAccess, service: string, id: string): readonly string[] {\n return access.anchors.get(id) ?? [anchorKey(service, id)];\n}\n","// The rowless check, run by `defineService`. On a service with an access\n// policy (RFC 0003 section 4.2), a method whose input has `id` reads or\n// writes the row that id names. A form that asks the policy nothing about\n// that row hands it to anyone the form admits, whoever's row it is: 4.x's \"a\n// Read method with no row id is open to every signed-in user\", in 5.0's\n// spelling. Such a method is refused when it is defined, naming the ways\n// out: a form that asks the policy about the row id names (`{ entry: L }`,\n// or `{ service: L, entry: L }` to keep the grant), or `rowless: true` on the\n// method, which says every caller the form admits may reach any row on\n// purpose (public profiles, lookups by an id that tells nothing, a create\n// whose `id` the client made).\n//\n// The forms refused:\n//\n// - the forms that check the caller's level on no row: `\"public\"`,\n// `\"authenticated\"`, `{ service: L }` with `L` below `Admin`;\n// - `custom(fn)`, which asks the policy nothing: a claim check written as one\n// let any token holding the claim reach every tenant's rows, and a\n// service-wide `Admin` grant skips it (the 5.1 audit's ACCESS-1 and\n// ACCESS-4; a claim check is the method's `claims`, beside an `entry`\n// form, `claims.ts`);\n// - `{ scope, of, id }`, which checks a row of another service, and `{\n// entry, id }` naming another key, which checks another row (ACCESS-5).\n//\n// The kit handlers that check the row whatever their form\n// (`checksRowsItself`) stay exempt.\n//\n// The input's keys come from its Standard JSON Schema (`inputKeys`): the\n// top-level keys of every object the input may be, so `id` in any branch of a\n// union counts, with values JSON Schema cannot write (a `Date`, a `Set`, a\n// `bigint`, a custom type) read as any value. Not checked: an input without\n// JSON Schema (a Zod 3 schema), which cannot say whether it holds an `id`; an\n// input that is no object (a bare string that is the id itself, an array, a\n// record); a row named another way (`ids`, `taskId`, a nested `where.id`)\n// under a form that checks the row id names; and an `entry` form whose `id`\n// is a function, which names its row in code.\n\nimport { inputKeys } from \"../emit/projection\";\nimport { isKitHandler, isRowChecked, type ServiceMethod } from \"../service\";\nimport { isCustomAccess } from \"./forms\";\nimport type { AccessForm, EntryAccess, ScopeAccess } from \"./types\";\n\n/**\n * What a form checks of the row `input.id` names: `\"checked\"` when the\n * policy decides on it (an `entry` form on `id`, or a function naming the\n * row in code, a `scope` form on the service's own rows by `id`, and a\n * service-wide `Admin` grant), `\"none\"` when the form\n * checks the caller's level on no row, `\"custom\"` for `custom(fn)`, and\n * `\"other\"` when it checks another row (a `scope` form, an `entry` form on\n * another key).\n */\nexport type Reach = \"checked\" | \"none\" | \"custom\" | \"other\";\n\n/** What `form`, on service `service`, checks of the row `input.id` names ({@link Reach}). */\nexport function reachOf(form: AccessForm, service: string): Reach {\n if (form === \"public\" || form === \"authenticated\") {\n return \"none\";\n }\n if (isCustomAccess(form)) {\n return \"custom\";\n }\n if (form.scope !== undefined) {\n // A scope form on the service's own rows by `id` asks its own policy about that row.\n return form.of.name === service && form.id === \"id\" ? \"checked\" : \"other\";\n }\n if (form.entry !== undefined) {\n return typeof form.id === \"string\" && form.id !== \"id\" ? \"other\" : \"checked\";\n }\n return form.service === \"Admin\" ? \"checked\" : \"none\";\n}\n\n/** A form that checks no row as code, and who it lets reach every row, for the message. */\nfunction described(form: AccessForm): { readonly code: string; readonly who: string } {\n if (form === \"public\") {\n return { code: '\"public\"', who: \"anyone, signed in or not,\" };\n }\n if (form === \"authenticated\") {\n return { code: '\"authenticated\"', who: \"every signed-in user\" };\n }\n const level = typeof form === \"object\" && !isCustomAccess(form) ? form.service : undefined;\n return {\n code: `{ service: \"${String(level)}\" }`,\n who: `everyone with a service-wide ${String(level)} grant`,\n };\n}\n\n/** The form to suggest instead: the policy's check at the method's level, keeping a named grant. */\nfunction suggestion(method: ServiceMethod): string {\n const { access } = method;\n if (typeof access === \"object\" && !isCustomAccess(access) && access.service !== undefined) {\n return `{ service: \"${access.service}\", entry: \"${access.service}\" }`;\n }\n return `{ entry: \"${method.kind === \"query\" ? \"Read\" : \"Moderate\"}\" }`;\n}\n\n/** How an `id` selector is written in a message: the key, quoted, or a function's placeholder. */\nfunction selector(id: unknown): string {\n return typeof id === \"string\" ? `\"${id}\"` : \"(input) => ...\";\n}\n\n/**\n * The message for a form that checks another row than the one `id` names:\n * a `scope` form, or an `entry` form on another key.\n */\nfunction otherRow(form: EntryAccess<unknown> | ScopeAccess<unknown>, optOut: string): string {\n if (form.scope !== undefined) {\n const { scope, of } = form as ScopeAccess<unknown>;\n const id: unknown = form.id;\n const shown = `{ scope: \"${scope}\", of: ${of.name}, id: ${selector(id)} }`;\n if (id === \"id\") {\n return (\n `${shown} checks the ${of.name} row id names, not a row of this service: ` +\n \"if id names a row of this service, that lets everyone it admits reach any row by its id. \" +\n `Give it { entry: \"${scope}\" } so the policy decides on the row id names, or, if id names a ${of.name} row as the form says, or a row the method creates, or every caller its access admits may reach any row, ${optOut}`\n );\n }\n return (\n `${shown} checks a row of ${of.name}, not the row id names: ` +\n \"on a service with an access policy, that lets everyone it admits reach any row by its id. \" +\n `Give it { entry: \"${scope}\" } so the policy decides on the row id names, or, if id names a row the method creates (an id the client made) or every caller its access admits may reach any row, ${optOut}`\n );\n }\n const { entry, service, id } = form as EntryAccess<unknown>;\n const grant = service === undefined ? \"\" : `service: \"${service}\", `;\n return (\n `{ ${grant}entry: \"${entry}\", id: ${selector(id)} } checks the row ${String(id)} names, not the row id names: ` +\n \"on a service with an access policy, that lets everyone it admits reach any row by its id. \" +\n `Give it { ${grant}entry: \"${entry}\" } so the policy decides on the row id names, or, if every caller its access admits may reach any row, ${optOut}`\n );\n}\n\n/**\n * Why `method`, on a service with an access policy, must not be defined as\n * it is: its input has `id`, its form asks the policy nothing about the row\n * that id names, and it did not say `rowless: true`. `undefined` when it\n * may.\n */\nexport function rowlessProblem(method: ServiceMethod, service: string): string | undefined {\n const { access, handler } = method;\n const reach = reachOf(access, service);\n if (method.rowless || reach === \"checked\" || isRowChecked(handler)) {\n return undefined;\n }\n if (inputKeys(method.input)?.includes(\"id\") !== true) {\n return undefined;\n }\n const optOut = isKitHandler(handler)\n ? `name it in the kit's rowless option (rowless: [\"${method.name}\"])`\n : \"set rowless: true on the method\";\n const start = `method \"${method.name}\" takes a row id (its input has id), but its access `;\n if (reach === \"custom\") {\n return (\n `${start}custom(check) asks the policy nothing about that row: ` +\n \"on a service with an access policy, a check that passes lets the caller reach any row by its id, and a service-wide Admin grant skips the check. \" +\n `Give it ${suggestion(method)} so the policy decides, with claims: (claims, input) => ... beside it for a check on the caller's claims, ` +\n `or, if every caller the check admits may reach any row, ${optOut}`\n );\n }\n if (reach === \"other\") {\n return `${start}${otherRow(access as EntryAccess<unknown> | ScopeAccess<unknown>, optOut)}`;\n }\n const form = described(access);\n return (\n `${start}${form.code} checks no row: ` +\n `on a service with an access policy, that lets ${form.who} reach any row by its id. ` +\n `Give it ${suggestion(method)} so the policy decides, or, if every caller its access admits may reach any row, ${optOut}`\n );\n}\n","// Which rows a flush touched, per service (RFC 0003 section 5.3, steps 1 and\n// 3). A write to a model touches its row in every service declaring that\n// model; then each service's `affects` adds the rows its written rows point\n// at, one hop and without duplicates: a task written with `affects: [{\n// service: task, id: \"parentTaskId\" }]` touches its parent task as well, which\n// is then sent whole. 4.1 left this to lifecycle hooks and hand-written emits\n// (4.1 `src/server/BaseService.ts:741-827`).\n\nimport type { Registry } from \"../registry\";\nimport type { AffectsLink, AnyService } from \"../service\";\nimport { modelKey, type StorageAdapter } from \"../storage\";\nimport { ANY_FIELD, type WriteRecord } from \"../uow/types\";\n\n/** What a flush did to one row of one service. */\nexport interface Touch {\n readonly op: WriteRecord[\"op\"];\n /** The fields written; `[ANY_FIELD]` when they are unknown, as for a touch or an affected row. */\n readonly fields: readonly string[];\n}\n\n/** The rows a flush touched, by service, then by row id. */\nexport type TouchedRows = ReadonlyMap<AnyService, ReadonlyMap<string, Touch>>;\n\n/** How writes find services: by model, and through each `affects` link. */\nexport interface Routes {\n /** The services declaring each model, by the client's model name. */\n readonly byModel: ReadonlyMap<string, readonly AnyService[]>;\n /** The service each `affects` link points at. */\n readonly targets: ReadonlyMap<AffectsLink, AnyService>;\n}\n\nfunction fail(message: string): never {\n throw new TypeError(`createDispatcher: ${message}`);\n}\n\nfunction targetOf(registry: Registry, service: AnyService, link: AffectsLink): AnyService {\n const target = registry.services.get(link.service.name);\n if (target === undefined) {\n fail(`${service.name} affects ${link.service.name}, which this dispatcher does not serve`);\n }\n if (target.model === undefined || target.contract.entity === undefined) {\n fail(\n `${service.name} affects ${target.name}, which has no model and entity, so it has no rows to send again`,\n );\n }\n return target;\n}\n\n/**\n * The routes of `registry`'s services. Registers each `affects` link's\n * columns with the storage adapter, so writes report them. Throws a\n * `TypeError` for a link to a service this dispatcher cannot send rows of.\n */\nexport function routesOf(registry: Registry, storage: StorageAdapter | undefined): Routes {\n const byModel = new Map<string, AnyService[]>();\n const targets = new Map<AffectsLink, AnyService>();\n for (const service of registry.services.values()) {\n if (service.model === undefined) {\n continue;\n }\n const key = modelKey(service.model);\n byModel.set(key, [...(byModel.get(key) ?? []), service]);\n for (const link of service.affects) {\n targets.set(link, targetOf(registry, service, link));\n storage?.registerInterest(key, link.columns);\n }\n }\n return { byModel, targets };\n}\n\ntype Touched = Map<AnyService, Map<string, Touch>>;\n\nfunction rowsOf(touched: Touched, service: AnyService): Map<string, Touch> {\n let rows = touched.get(service);\n if (rows === undefined) {\n rows = new Map();\n touched.set(service, rows);\n }\n return rows;\n}\n\n/** The ids a written row points at through `link`: before and after the write. */\nfunction linkedIds(link: AffectsLink, write: WriteRecord): Set<string> {\n const ids = new Set<string>();\n for (const values of [write.before, write.after]) {\n for (const id of values === undefined ? [] : link.ids(values)) {\n ids.add(id);\n }\n }\n return ids;\n}\n\n/** Marks the rows `write` affects through `service`'s links: sent whole, unless the flush deleted them. */\nfunction affect(touched: Touched, routes: Routes, service: AnyService, write: WriteRecord): void {\n for (const link of service.affects) {\n const target = routes.targets.get(link);\n const ids = linkedIds(link, write);\n if (target === undefined || ids.size === 0) {\n continue;\n }\n const rows = rowsOf(touched, target);\n for (const id of ids) {\n const touch = rows.get(id);\n if (touch?.op !== \"delete\") {\n rows.set(id, { op: touch?.op ?? \"update\", fields: [ANY_FIELD] });\n }\n }\n }\n}\n\n/** The rows `writes` touched per service, `affects` expanded one hop. */\nexport function touchedRows(writes: readonly WriteRecord[], routes: Routes): TouchedRows {\n const touched: Touched = new Map();\n for (const write of writes) {\n for (const service of routes.byModel.get(modelKey(write.model)) ?? []) {\n rowsOf(touched, service).set(write.id, { op: write.op, fields: write.fields });\n }\n }\n for (const write of writes) {\n for (const service of routes.byModel.get(modelKey(write.model)) ?? []) {\n affect(touched, routes, service, write);\n }\n }\n return touched;\n}\n","// The in-process change log (RFC 0003 section 6): the revision of the last\n// flush that touched each row, since the process started. It answers \"not\n// modified\" for services without a `versionColumn`: a caller holding a row\n// at revision `v` gets \"not modified\" when no flush since `v` touched it.\n//\n// It is bounded: past `maxEntries` rows the least recently changed one is\n// dropped, and the log then knows only that the dropped row did not change\n// after the newest revision it has dropped (its floor). It starts with a\n// floor of the revision current when it was made, so a revision from before\n// the process started is never answered \"not modified\".\n//\n// It sees the writes this process flushes and nothing else: not raw SQL\n// without `ctx.touch`, not database cascades, not other processes. A\n// deployment of several processes behind a load balancer stops it answering\n// (`changeLog: false`) or gives its services a `versionColumn`; behind a\n// Socket.IO cluster adapter it never answers. It is kept either way:\n// subscriptions also use it to tell a deleted row from a forbidden one, and\n// to catch a flush that raced a subscribe.\n\nimport type { Revision } from \"../../protocol/envelope\";\nimport { nextRev } from \"../rev\";\n\n/** The change log's options: `false` turns it off. */\nexport interface ChangeLogOptions {\n /** How many rows it keeps. Default 100,000. */\n readonly maxEntries?: number;\n}\n\ninterface Entry {\n readonly rev: Revision;\n /** The row's last recorded write deleted it. */\n readonly removed: boolean;\n}\n\n/** The last flush revision per row. */\nexport interface ChangeLog {\n /** Records that the flush at `rev` wrote the row; `removed` when that write deleted it. */\n record(service: string, id: string, rev: Revision, removed: boolean): void;\n /** The revision of the row's last recorded change, or the floor when none is kept. */\n lastChange(service: string, id: string): Revision;\n /** True when the row's last recorded change deleted it. */\n removed(service: string, id: string): boolean;\n /** True when no flush this process saw since `rev` touched the row. */\n unchangedSince(service: string, id: string, rev: Revision): boolean;\n}\n\nconst DEFAULT_MAX_ENTRIES = 100_000;\n\nfunction keyOf(service: string, id: string): string {\n return `${service}\\u0000${id}`;\n}\n\n/** Creates a change log, starting at the revision current now. */\nexport function createChangeLog(options: ChangeLogOptions = {}): ChangeLog {\n const max = options.maxEntries ?? DEFAULT_MAX_ENTRIES;\n if (!Number.isSafeInteger(max) || max < 1) {\n throw new TypeError(\"createDispatcher: changeLog.maxEntries must be a positive whole number\");\n }\n const entries = new Map<string, Entry>();\n let floor = nextRev();\n const lastChange = (service: string, id: string): Revision =>\n entries.get(keyOf(service, id))?.rev ?? floor;\n return Object.freeze({\n record(service: string, id: string, rev: Revision, removed: boolean): void {\n const key = keyOf(service, id);\n const kept = entries.get(key);\n // Flushes can finish out of order; the newest revision wins.\n const entry = kept !== undefined && kept.rev > rev ? kept : { rev, removed };\n entries.delete(key);\n entries.set(key, entry);\n const first = entries.size > max ? entries.entries().next() : undefined;\n if (first !== undefined && first.done !== true) {\n const [oldest, dropped] = first.value;\n entries.delete(oldest);\n floor = Math.max(floor, dropped.rev);\n }\n },\n lastChange,\n removed: (service: string, id: string) => entries.get(keyOf(service, id))?.removed === true,\n unchangedSince: (service: string, id: string, rev: Revision) => lastChange(service, id) <= rev,\n });\n}\n","// What the live-data modules of one dispatcher share (RFC 0003 sections 4.4,\n// 5.3 and 6): the services and how writes reach them, the storage adapter\n// rows are read through, the policies levels come from, the change log, the\n// index of this process's subscriptions, and, once a server attaches it, the\n// Socket.IO server frames go out on.\n\nimport type { Logger } from \"../../contract/logger\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { AccessEngine, PolicyEngine } from \"../access/api\";\nimport {\n createRevisions,\n type ClusterBroadcasts,\n type ClusterOptions,\n type Revisions,\n} from \"../cluster/revisions\";\nimport type { Registry } from \"../registry\";\nimport type { StorageAdapter } from \"../storage\";\nimport type { QuickdrawIo } from \"../transports/types\";\nimport { routesOf, type Routes } from \"./affects\";\nimport { createChangeLog, type ChangeLog, type ChangeLogOptions } from \"./changeLog\";\nimport { SubscriptionIndex } from \"./subscriptions\";\n\n/** Whether every subscriber of this server is a socket of this process. */\nexport interface AdapterProbe {\n /**\n * True while the server's Socket.IO adapter is the in-memory one it was\n * created with. Behind a cluster adapter (Redis) rooms on other nodes are\n * not visible here, so room occupancy cannot skip a read, and access\n * changes are broadcast to the other nodes.\n */\n local(): boolean;\n}\n\n/** Options of {@link createHub}. */\nexport interface HubOptions {\n readonly registry: Registry;\n readonly storage: StorageAdapter | undefined;\n readonly policies: PolicyEngine;\n /** The dispatcher's access engine, which decides who may subscribe to a stream. */\n readonly access: AccessEngine;\n readonly logger: Logger;\n /** The change log's options, or `false` for none. */\n readonly changeLog: ChangeLogOptions | false | undefined;\n /**\n * The dispatcher's `outputValidation` (on unless `NODE_ENV` is\n * `\"production\"`): whether a stream declared `validate: \"development\"`\n * checks what is pushed to it.\n */\n readonly outputValidation?: boolean;\n}\n\n/** The live-data state of one dispatcher. */\nexport interface Hub {\n readonly registry: Registry;\n readonly storage: StorageAdapter | undefined;\n readonly policies: PolicyEngine;\n /** The dispatcher's access engine (RFC 0003 section 4.1): stream subscribers are authorized through it. */\n readonly access: AccessEngine;\n readonly logger: Logger;\n /** Whether a stream declared `validate: \"development\"` checks its items: the dispatcher's `outputValidation`. */\n readonly outputValidation: boolean;\n readonly routes: Routes;\n /**\n * The rows recent flushes touched. Always kept: subscriptions use it to\n * tell a deleted row from a forbidden one and to catch a flush racing a\n * subscribe. It answers \"not modified\" only when `answers` is on.\n */\n readonly changeLog: ChangeLog;\n /** Whether the change log answers \"not modified\" (the dispatcher's `changeLog` is not `false`). */\n readonly answers: boolean;\n readonly subscriptions: SubscriptionIndex;\n /** The Socket.IO server, once `createServer` attached one. */\n io: QuickdrawIo | undefined;\n probe: AdapterProbe;\n /** `createServer`'s `cluster` option: where the cluster's shared state lives, behind a cluster adapter. */\n cluster: ClusterOptions | undefined;\n /** The server's answered broadcasts to the other nodes, once `createServer` attached them. */\n broadcasts: ClusterBroadcasts | undefined;\n /**\n * The revisions flushes take and reads claim: the process's clock, or\n * behind a cluster adapter the cluster's shared counter (`cluster/revisions.ts`).\n */\n readonly revisions: Revisions;\n /**\n * Work started for a socket's event that may still send frames once it\n * settles (a room's presence read from every node): a server's `close()`\n * waits for it, so nothing is sent through an adapter the app is about to\n * close.\n */\n readonly inFlight: Set<Promise<unknown>>;\n}\n\nconst ALWAYS_LOCAL: AdapterProbe = Object.freeze({ local: () => true });\n\n/** Creates the live-data state of a dispatcher. Throws a `TypeError` for an `affects` it cannot follow. */\nexport function createHub(options: HubOptions): Hub {\n const hub: Omit<Hub, \"revisions\"> = {\n registry: options.registry,\n storage: options.storage,\n policies: options.policies,\n access: options.access,\n logger: options.logger,\n outputValidation: options.outputValidation ?? process.env.NODE_ENV !== \"production\",\n routes: routesOf(options.registry, options.storage),\n changeLog: createChangeLog(options.changeLog === false ? undefined : options.changeLog),\n answers: options.changeLog !== false,\n subscriptions: new SubscriptionIndex(),\n io: undefined,\n probe: ALWAYS_LOCAL,\n cluster: undefined,\n broadcasts: undefined,\n inFlight: new Set(),\n };\n return Object.assign(hub, { revisions: createRevisions(hub) });\n}\n\n/** Keeps `work` in the hub's work in flight until it settles. */\nexport function track(hub: Pick<Hub, \"inFlight\">, work: Promise<unknown>): void {\n hub.inFlight.add(work);\n const done = (): void => {\n hub.inFlight.delete(work);\n };\n work.then(done, done);\n}\n\n/** Resolves once the hub's work in flight, and any it started meanwhile, has settled. */\nexport async function drain(hub: Pick<Hub, \"inFlight\">): Promise<void> {\n while (hub.inFlight.size > 0) {\n await Promise.allSettled([...hub.inFlight]);\n }\n}\n\n/**\n * The change log, when it may answer \"not modified\": it is on, and, since it\n * sees only this process's writes, the server is not behind a cluster adapter.\n */\nexport function usableChangeLog(hub: Hub): ChangeLog | undefined {\n return hub.answers && hub.probe.local() ? hub.changeLog : undefined;\n}\n\n/** A service the registry holds. */\nexport type RegisteredService =\n Registry[\"services\"] extends ReadonlyMap<string, infer S> ? S : never;\n\n/** A service whose rows can be subscribed to and sent: it has an entity and a model. */\nexport interface LiveService {\n readonly service: RegisteredService;\n readonly model: string;\n}\n\n/** The service `name` names, if its rows can be sent; `NOT_FOUND` otherwise. */\nexport function liveService(hub: Hub, name: string): LiveService {\n const service = hub.registry.services.get(name);\n if (service === undefined) {\n throw new QuickdrawError(\"NOT_FOUND\", `Unknown service \"${name}\"`);\n }\n if (service.model === undefined || service.contract.entity === undefined) {\n throw new QuickdrawError(\n \"NOT_FOUND\",\n `${name} has no entity rows to subscribe to: it declares no model or its contract no entity`,\n );\n }\n return { service, model: service.model };\n}\n","// Row versions for \"not modified\" answers (RFC 0003 sections 6 and 9, step 5).\n// A row's version is the time in its service's `versionColumn` when the\n// service declares one (read in one narrow query), or else the revision of\n// the last flush the in-process change log saw touch it. The version is taken\n// before the row itself is read, so an answer is never older than the version\n// it claims.\n//\n// - A call to a query whose output is one projection row (`\"entity\"`,\n// `nullable(\"card\")`) and whose input has an `id` gets that row's version,\n// when the row it returns is that row: a caller that sends it back as `v`\n// gets `{ ok: true, nm: true, v }` while the row is unchanged. A query\n// keyed by another id (the latest task of project `id`) returns some other\n// row, whose changes that version does not follow, and gets none. This is\n// the dispatcher's default `versions`.\n// - It answers only for a row the method's access form checked (an `entry`\n// form on `id`, a `scope` form on the service's own rows by `id`,\n// `{ service: \"Admin\" }`), for a caller the service's `Admin` bypass\n// passes, and for a `rowless` method whose form checks no row (`\"public\"`,\n// `\"authenticated\"`, `{ service: L }`): it says any caller it admits may\n// read any row. A version is a one-bit oracle: \"not modified\" before the\n// handler runs told a caller a scope form let in (or a custom form, or an\n// `entry` form on another key) that a row it may not read exists, and\n// that it had not changed (the 5.1 audit's ACCESS-6). Any other query\n// always runs its handler, `rowless` or not: such a form narrows in its\n// handler.\n// - `qd:sub` answers \"not modified\" for an id whose held revision is no\n// older than the row's version.\n\nimport type { Revision } from \"../../protocol/envelope\";\nimport { isCustomAccess } from \"../access/forms\";\nimport { serviceGrant } from \"../access/levels\";\nimport { reachOf } from \"../access/rowless\";\nimport type { VersionRequest, VersionSource } from \"../pipeline/notModified\";\nimport type { AnyService } from \"../service\";\nimport { versionTime } from \"../rev\";\nimport { usableChangeLog, type Hub } from \"./hub\";\n\n/** The versions of some rows of a service. */\nexport interface RowVersions {\n /** Each row's version; a row without one is absent. */\n readonly versions: ReadonlyMap<string, number>;\n /** Rows the version column's read found missing; empty when nothing was read. */\n readonly missing: ReadonlySet<string>;\n}\n\nconst NONE: RowVersions = Object.freeze({\n versions: new Map<string, number>(),\n missing: new Set<string>(),\n});\n\n/**\n * The versions of `ids` of `service`: from its `versionColumn` in one query,\n * or from the change log (behind a cluster adapter it has none), or none.\n */\nexport async function rowVersions(\n hub: Hub,\n service: AnyService,\n ids: readonly string[],\n): Promise<RowVersions> {\n const { model, versionColumn } = service;\n if (ids.length === 0 || model === undefined) {\n return NONE;\n }\n if (versionColumn === undefined) {\n const log = usableChangeLog(hub);\n return log === undefined\n ? NONE\n : {\n versions: new Map(ids.map((id) => [id, log.lastChange(service.name, id)])),\n missing: new Set(),\n };\n }\n const rows =\n (await hub.storage?.findMany(model, {\n where: { id: { in: [...ids] } },\n select: { id: true, [versionColumn]: true },\n })) ?? [];\n const versions = new Map<string, number>();\n for (const row of rows) {\n const time = versionTime(row[versionColumn]);\n if (typeof row.id === \"string\" && time !== undefined) {\n versions.set(row.id, time);\n }\n }\n const found = new Set(rows.map((row) => row.id));\n return { versions, missing: new Set(ids.filter((id) => !found.has(id))) };\n}\n\n/** The ids whose held revision is no older than their row's version: \"not modified\". */\nexport function unchangedRows(\n versions: RowVersions,\n held: ReadonlyMap<string, Revision>,\n): Set<string> {\n const unchanged = new Set<string>();\n for (const [id, rev] of held) {\n const version = versions.versions.get(id);\n if (version !== undefined && version <= rev) {\n unchanged.add(id);\n }\n }\n return unchanged;\n}\n\nfunction inputId(input: unknown): string | undefined {\n if (typeof input !== \"object\" || input === null) {\n return undefined;\n }\n const { id } = input as { readonly id?: unknown };\n return typeof id === \"string\" && id.length > 0 ? id : undefined;\n}\n\n/**\n * True when the method's access form checked the caller's level on the row\n * its input's `id` names (`reachOf`: an `entry` form on `id`, a `scope` form\n * on the service's own rows by `id`, `{ service: \"Admin\" }`; not an `id`\n * function, which names its row in code), when the caller's service-wide\n * `Admin` grant passes the service's bypass, or when the method is\n * `rowless` under a form that checks no row. A scope form on another\n * service, a custom form or an `entry` form on another key checked\n * something else, `rowless` or not.\n */\nfunction checkedRow({ service, method, ctx }: VersionRequest): boolean {\n const { principal } = ctx;\n if (\n principal !== null &&\n service.adminBypass &&\n serviceGrant(principal, service.name) === \"Admin\"\n ) {\n return true;\n }\n const form = method.access;\n const reach = reachOf(form, service.name);\n if (reach === \"none\") {\n return method.rowless;\n }\n const inCode = typeof form === \"object\" && !isCustomAccess(form) && typeof form.id === \"function\";\n return reach === \"checked\" && !inCode;\n}\n\n/**\n * The dispatcher's default `versions`: the version of the row a query\n * returns, for a query whose output is one projection row and whose input\n * has an `id`, when the method's form checked that row (`checkedRow`),\n * attached only when the row returned is row `id`. Any other query has\n * none, and always runs.\n */\nexport function createVersionSource(hub: Hub): VersionSource {\n return Object.freeze({\n async versionOf(request) {\n const { service, method, input } = request;\n const id = inputId(input);\n if (\n id === undefined ||\n method.projection === undefined ||\n method.projection.kind === \"list\" ||\n !checkedRow(request)\n ) {\n return undefined;\n }\n const { versions } = await rowVersions(hub, service, [id]);\n return versions.get(id);\n },\n describes({ input }, result) {\n const id = inputId(input);\n const returned =\n typeof result === \"object\" && result !== null\n ? (result as { readonly id?: unknown }).id\n : undefined;\n return id !== undefined && returned === id;\n },\n } satisfies VersionSource);\n}\n","// One `qd:sub` batch (RFC 0003 sections 4.3 and 6). It replaces 4.1's\n// `subscribe` and `batchSubscribe` (4.1 `src/server/BaseService.ts:176-283`),\n// which joined a row's rooms before reading the row (`:204-213`, `:252-264`),\n// so a socket could sit in the room of a row that did not exist. Here a batch\n// goes, in this order:\n//\n// 1. authorize every id in one engine call, which also gives the rows each\n// level is anchored on; an id below `Read` is `FORBIDDEN` and never read;\n// 2. take the revision before any row is read: the last one taken, so reads\n// do not push revisions ahead of the clock (`currentRev`); behind a\n// cluster's counter, the counter's last one (`cluster/revisions.ts`);\n// 3. find which held rows are unchanged (\"not modified\"): one narrow read of\n// the service's `versionColumn`, or the change log;\n// 4. read the other allowed rows in one `findMany` with the entity\n// projection's select;\n// 5. put the socket in the room of each row found, for its level, and record\n// the subscription and its anchors on `socket.data`. A socket holds at\n// most `MAX_ENTITY_IDS_PER_SOCKET` rows (the 5.1 audit's COLL-4): a batch\n// whose new rows would pass it is refused whole, `CONFLICT`, before step\n// 1, and a row batches running at once left no room for is answered\n// `CONFLICT` here; a row held already never counts again;\n// 6. settle the races: an access change while the batch ran (or a replaced\n// principal: new grants) re-resolves the joined rows with the socket's\n// principal as it is then, never the one the batch began with (the 5.1\n// audit's LIVE-1: a demoted Admin joined the Admin room and kept it), so\n// a lowered grant denies and a raised one answers at its level; another\n// identity, or none, denies every row. A flush that touched a joined row\n// after the revision (its frame may have gone out before the join)\n// re-reads that row (behind a cluster's counter, any flush on any node:\n// every joined row). Then, while access keeps changing, the joined rows\n// are resolved again, at most `MAX_RECHECKS` times; a row whose anchors\n// were still moving is denied. A subscription the batch recorded and\n// someone else ended meanwhile (revocation, a disconnect) is `FORBIDDEN`;\n// one someone else replaced (a newer resolution) is answered at that\n// one's level;\n// 7. answer each id: its row stripped for its level, \"not modified\", or why\n// not.\n//\n// Revocation finds a socket through the anchors its subscriptions record, so\n// an access change made after a row was joined with its current anchors\n// reaches the batch's subscription by itself; the rechecks cover changes\n// made before that, on anchors the batch had not recorded yet.\n\nimport type { EntityResult, Revision } from \"../../protocol/envelope\";\nimport { currentRev } from \"../rev\";\nimport type { StorageRow } from \"../storage\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport type { Hub, LiveService } from \"./hub\";\nimport { projectRow } from \"./projection\";\nimport { anchorsOf, resolveAccess, subscriberLevel } from \"./resolve\";\nimport { TOO_MANY_ROWS, type EntitySubscription } from \"./subscriptions\";\nimport { strip } from \"./tiers\";\nimport { rowVersions, unchangedRows } from \"./versions\";\n\n/** How often a subscribe resolves access again after its reads, while access keeps changing. */\nexport const MAX_RECHECKS = 3;\n\n/** A `qd:sub` frame, read. */\nexport interface SubscribeRequest {\n readonly s: string;\n /** The ids, in request order; an id may repeat. */\n readonly ids: readonly string[];\n /** The revision the client holds, for each id it sent one for. */\n readonly held: ReadonlyMap<string, Revision>;\n}\n\n/** One answered id: its level, the row read (none for \"not modified\"), and the revision. */\ninterface Answer {\n readonly level: EntitySubscription[\"level\"];\n readonly row: StorageRow | undefined;\n readonly rev: Revision;\n}\n\ninterface Batch {\n readonly hub: Hub;\n readonly socket: QuickdrawServerSocket;\n readonly target: LiveService;\n /** The principal the batch began with: step 1 resolves with it. */\n readonly principal: NonNullable<QuickdrawServerSocket[\"data\"][\"principal\"]>;\n /** The access changes the process had seen when the batch last resolved access. */\n checkedAt: number;\n /** The socket's principal when the batch last resolved access. */\n resolvedWith: QuickdrawServerSocket[\"data\"][\"principal\"];\n /** Per id, how often the socket had unsubscribed from it when the batch began. */\n readonly unsubscribes: ReadonlyMap<string, number>;\n readonly denied: Set<string>;\n /** Answered rows the socket could not hold: past `MAX_ENTITY_IDS_PER_SOCKET` (`CONFLICT`). */\n readonly refused: Set<string>;\n readonly answers: Map<string, Answer>;\n /** The subscription the batch recorded for each row it joined, while the batch manages it. */\n readonly joined: Map<string, EntitySubscription>;\n /** The joined rows whose level or anchors the last recheck changed. */\n moving: ReadonlySet<string>;\n}\n\nconst FORBIDDEN: EntityResult = Object.freeze({\n ok: false,\n e: Object.freeze({ code: \"FORBIDDEN\", message: \"Insufficient permissions\" }),\n});\n\nconst NOT_FOUND: EntityResult = Object.freeze({\n ok: false,\n e: Object.freeze({ code: \"NOT_FOUND\", message: \"No such row\" }),\n});\n\nconst CONFLICT: EntityResult = Object.freeze({\n ok: false,\n e: Object.freeze({ code: \"CONFLICT\", message: TOO_MANY_ROWS }),\n});\n\n/** The rows `ids`, read in one query with the entity projection's select. */\nasync function readRows(\n hub: Hub,\n target: LiveService,\n ids: readonly string[],\n): Promise<Map<string, StorageRow>> {\n const projection = target.service.projections.get(\"entity\");\n if (ids.length === 0 || projection === undefined || hub.storage === undefined) {\n return new Map();\n }\n const rows = await hub.storage.findMany(target.model, {\n where: { id: { in: [...ids] } },\n select: projection.select,\n });\n return new Map(rows.flatMap((row) => (typeof row.id === \"string\" ? [[row.id, row]] : [])));\n}\n\n/** True while the socket's subscription to the row is still the one the batch recorded. */\nfunction isOwn(batch: Batch, id: string): boolean {\n const own = batch.joined.get(id);\n const current = batch.hub.subscriptions.get(batch.socket, batch.target.service.name, id);\n return own !== undefined && current === own;\n}\n\n/**\n * True while the batch may put the socket in the row's room: the socket is\n * still connected (a socket indexed after its disconnect would stay in the\n * index forever), and the client has not unsubscribed from the row since the\n * batch began.\n */\nfunction joinable(batch: Batch, id: string): boolean {\n const { hub, socket, target } = batch;\n const unsubscribes = hub.subscriptions.unsubscribes(socket, target.service.name, id);\n return socket.connected && unsubscribes === batch.unsubscribes.get(id);\n}\n\n/** Step 5: joins the room of each answered row the socket may still join (`joinable`). */\nfunction join(batch: Batch, anchors: (id: string) => readonly string[]): void {\n const { hub, socket, target } = batch;\n const service = target.service.name;\n for (const [id, answer] of batch.answers) {\n if (!joinable(batch, id)) {\n continue;\n }\n if (!hub.subscriptions.hasRoom(socket, service, id)) {\n // Batches running at once filled the socket meanwhile.\n batch.answers.delete(id);\n batch.refused.add(id);\n continue;\n }\n const subscription: EntitySubscription = { level: answer.level, anchors: anchors(id) };\n hub.subscriptions.set(socket, service, id, subscription);\n batch.joined.set(id, subscription);\n }\n}\n\n/** Gives up a joined row the socket may no longer join; the answer stands, as for a row never joined. */\nfunction abandon(batch: Batch, id: string): void {\n if (isOwn(batch, id)) {\n batch.hub.subscriptions.delete(batch.socket, batch.target.service.name, id);\n }\n batch.joined.delete(id);\n}\n\n/** Ends a subscription the batch made, and answers the id with `result`; another's is left alone. */\nfunction retract(batch: Batch, id: string, result: \"denied\" | \"missing\"): void {\n if (isOwn(batch, id)) {\n batch.hub.subscriptions.delete(batch.socket, batch.target.service.name, id);\n }\n batch.joined.delete(id);\n batch.answers.delete(id);\n if (result === \"denied\") {\n batch.denied.add(id);\n }\n}\n\n/**\n * A joined row whose subscription is no longer the batch's. Ended by\n * someone else (revocation, a disconnect): `FORBIDDEN`, unless the client\n * unsubscribed, which leaves the answer as it was. Replaced by a newer\n * resolution (revocation's, or another batch's): answered at its level.\n */\nfunction release(batch: Batch, id: string): void {\n const { hub, socket, target } = batch;\n const service = target.service.name;\n const current = hub.subscriptions.get(socket, service, id);\n const answer = batch.answers.get(id);\n batch.joined.delete(id);\n if (current !== undefined) {\n if (answer !== undefined) {\n batch.answers.set(id, { ...answer, level: current.level });\n }\n return;\n }\n if (hub.subscriptions.unsubscribes(socket, service, id) === batch.unsubscribes.get(id)) {\n batch.answers.delete(id);\n batch.denied.add(id);\n }\n}\n\n/** Releases every joined row whose subscription someone else ended or replaced. */\nfunction releaseTaken(batch: Batch): void {\n for (const id of [...batch.joined.keys()]) {\n if (!isOwn(batch, id)) {\n release(batch, id);\n }\n }\n}\n\nfunction sameSubscription(a: EntitySubscription | undefined, b: EntitySubscription): boolean {\n return (\n a !== undefined &&\n a.level === b.level &&\n a.anchors.length === b.anchors.length &&\n a.anchors.every((anchor, index) => anchor === b.anchors[index])\n );\n}\n\n/** True when access changed, or the socket's principal was replaced, since the batch last resolved it. */\nfunction accessMoved(batch: Batch): boolean {\n return (\n batch.hub.subscriptions.accessChanges !== batch.checkedAt ||\n batch.socket.data.principal !== batch.resolvedWith\n );\n}\n\n/**\n * Step 6: access changed since the batch last resolved it, so the joined\n * rows are resolved again, with the socket's principal as it is now: the\n * same user's current grants, and nothing for another identity or none.\n */\nasync function recheckAccess(batch: Batch): Promise<void> {\n const { hub, target, principal, socket } = batch;\n if (!accessMoved(batch)) {\n return;\n }\n batch.checkedAt = hub.subscriptions.accessChanges;\n const now = socket.data.principal;\n batch.resolvedWith = now;\n batch.moving = new Set();\n if (batch.joined.size === 0) {\n return;\n }\n const service = target.service.name;\n const ids = [...batch.joined.keys()];\n const access =\n now !== null && now.userId === principal.userId\n ? await resolveAccess(hub, target.service, now, ids)\n : undefined;\n const moving = new Set<string>();\n for (const id of ids) {\n if (!isOwn(batch, id)) {\n release(batch, id);\n continue;\n }\n // The guards `join` applies, since this may join the row's room again.\n if (!joinable(batch, id)) {\n abandon(batch, id);\n continue;\n }\n const level = access === undefined ? undefined : subscriberLevel(access, id);\n const answer = batch.answers.get(id);\n if (access === undefined || level === undefined || answer === undefined) {\n retract(batch, id, \"denied\");\n continue;\n }\n const subscription: EntitySubscription = { level, anchors: anchorsOf(access, service, id) };\n if (!sameSubscription(batch.joined.get(id), subscription)) {\n moving.add(id);\n hub.subscriptions.set(socket, service, id, subscription);\n batch.joined.set(id, subscription);\n batch.answers.set(id, { ...answer, level });\n }\n }\n batch.moving = moving;\n}\n\n/**\n * The joined rows a flush may have touched after the revision, and the\n * revision to read them again at. This process's change log names them; it\n * sees only this process's flushes, so behind a cluster's counter every\n * joined row is read again once any node took a revision after `rev`.\n */\nasync function touchedSince(\n batch: Batch,\n rev: Revision,\n): Promise<{ readonly stale: string[]; readonly fresh: Revision }> {\n const { hub, target } = batch;\n const joined = [...batch.joined.keys()];\n if (hub.revisions.shared()) {\n const moved = await hub.revisions.movedPast(rev);\n return { stale: moved === undefined ? [] : joined, fresh: moved ?? rev };\n }\n const service = target.service.name;\n const stale = joined.filter((id) => hub.changeLog.lastChange(service, id) > rev);\n return { stale, fresh: stale.length === 0 ? rev : currentRev() };\n}\n\n/** Step 6: rows a flush touched after the revision are read again, at the newer one. */\nasync function rereadTouched(batch: Batch, rev: Revision): Promise<void> {\n const { hub, target } = batch;\n const { stale, fresh } = await touchedSince(batch, rev);\n if (stale.length === 0) {\n return;\n }\n const rows = await readRows(hub, target, stale);\n for (const id of stale) {\n const row = rows.get(id);\n const answer = batch.answers.get(id);\n if (row === undefined || answer === undefined) {\n retract(batch, id, \"missing\");\n continue;\n }\n batch.answers.set(id, { level: answer.level, row, rev: fresh });\n }\n}\n\n/** Step 6. */\nasync function settleRaces(batch: Batch, rev: Revision): Promise<void> {\n await recheckAccess(batch);\n await rereadTouched(batch, rev);\n for (let round = 0; round < MAX_RECHECKS && accessMoved(batch); round += 1) {\n await recheckAccess(batch);\n }\n if (accessMoved(batch)) {\n // Access changed during the last check too: a row it gave new anchors may have missed a change on them.\n for (const id of batch.moving) {\n if (batch.joined.has(id)) {\n retract(batch, id, \"denied\");\n }\n }\n }\n releaseTaken(batch);\n}\n\n/** Steps 1 to 5. */\nasync function answerBatch(batch: Batch, held: ReadonlyMap<string, Revision>): Promise<Revision> {\n const { hub, target, principal } = batch;\n const service = target.service.name;\n const ids = [...batch.unsubscribes.keys()];\n const access = await resolveAccess(hub, target.service, principal, ids);\n const allowed = new Set(ids.filter((id) => subscriberLevel(access, id) !== undefined));\n for (const id of ids) {\n if (!allowed.has(id)) {\n batch.denied.add(id);\n }\n }\n const claimed = hub.revisions.claim();\n const rev = typeof claimed === \"number\" ? claimed : await claimed;\n const heldAllowed = new Map([...held].filter(([id]) => allowed.has(id)));\n const versions = await rowVersions(hub, target.service, [...heldAllowed.keys()]);\n const unchanged = unchangedRows(versions, heldAllowed);\n const toRead = [...allowed].filter((id) => !unchanged.has(id) && !versions.missing.has(id));\n const rows = await readRows(hub, target, toRead);\n for (const id of allowed) {\n const level = subscriberLevel(access, id);\n const row = rows.get(id);\n if (level !== undefined && (row !== undefined || unchanged.has(id))) {\n batch.answers.set(id, { level, row, rev });\n }\n }\n join(batch, (id) => anchorsOf(access, service, id));\n return rev;\n}\n\nfunction resultOf(batch: Batch, id: string): EntityResult {\n if (batch.denied.has(id)) {\n return FORBIDDEN;\n }\n if (batch.refused.has(id)) {\n return CONFLICT;\n }\n const found = batch.answers.get(id);\n if (found === undefined) {\n return NOT_FOUND;\n }\n if (found.row === undefined) {\n return { ok: true, nm: true, rev: found.rev };\n }\n const projection = batch.target.service.projections.get(\"entity\");\n const data = projection === undefined ? found.row : projectRow(projection, found.row);\n const hidden = projection?.tiers.hidden(found.level);\n const isRow = typeof data === \"object\" && data !== null && hidden !== undefined;\n return {\n ok: true,\n d: isRow ? strip(data as Readonly<Record<string, unknown>>, hidden) : data,\n rev: found.rev,\n };\n}\n\n/**\n * Answers one `qd:sub` batch of a socket with a principal, one result per\n * requested id in request order. Rejects when a lookup or read fails; the\n * subscriptions the batch made are then ended.\n */\nexport async function subscribe(\n hub: Hub,\n socket: QuickdrawServerSocket,\n target: LiveService,\n request: SubscribeRequest,\n): Promise<EntityResult[]> {\n const { principal } = socket.data;\n if (principal === null) {\n throw new TypeError(\"subscribe: the socket has no principal\");\n }\n const service = target.service.name;\n // At most MAX_ENTITY_IDS_PER_SOCKET rows a socket: the whole batch is refused before any read.\n hub.subscriptions.checkRoom(socket, service, request.ids);\n const batch: Batch = {\n hub,\n socket,\n target,\n principal,\n checkedAt: hub.subscriptions.accessChanges,\n resolvedWith: principal,\n unsubscribes: hub.subscriptions.begin(socket, service, request.ids),\n denied: new Set(),\n refused: new Set(),\n answers: new Map(),\n joined: new Map(),\n moving: new Set(),\n };\n try {\n const rev = await answerBatch(batch, request.held);\n await settleRaces(batch, rev);\n } catch (error) {\n for (const id of [...batch.joined.keys()]) {\n retract(batch, id, \"missing\");\n }\n throw error;\n } finally {\n hub.subscriptions.end(socket, service, request.ids);\n }\n return request.ids.map((id) => resultOf(batch, id));\n}\n","// Settling a subscribe against the access changes made while it was being\n// authorized (RFC 0003 section 4.3; the 5.1 audit's LIVE-2 and RT-1). A\n// subscribe authorizes, then records itself; an access change flushed in\n// between re-checks only what was recorded, so it misses this one, and the\n// socket would keep a room it lost. So a subscribe notes the process's\n// access changes and the socket's principal before it authorizes\n// (`raceStart`), and once recorded, while either moved, authorizes again\n// with the socket's principal as it is then, at most `MAX_RECHECKS` more\n// times (`settleJoin`):\n//\n// - another identity, or none, is denied without a lookup; the same user\n// with replaced grants is authorized with the grants the socket holds now;\n// - denied, the record ends, and the subscribe is answered `FORBIDDEN`;\n// - a record revocation ended meanwhile is `FORBIDDEN` too, unless the\n// client unsubscribed or the socket went; one revocation authorized again\n// meanwhile (with other anchors) is adopted, and settled in turn;\n// - allowed with other anchors, the record is replaced, so revocation finds\n// it by them; while access still moved after the last check, a record\n// whose anchors that check moved is denied: it may have missed a change on\n// them.\n//\n// Change topic watches (`../topicRevocation.ts`) and stream feeds\n// (`../realtime/streamSubscribe.ts`) settle here, recorded so revocation\n// finds them, but out of their room until they settled: nothing reaches a\n// socket that is then refused. Entity batches and collection scopes settle\n// by the same rules in their own modules (`subscribe.ts`,\n// `../collections/subscribe.ts`), in their room already: they need it to\n// catch every change after the snapshot they read.\n\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { MAX_RECHECKS } from \"./subscribe\";\n\n/** What a subscribe noted before it authorized: the access changes the process had seen, and the socket's principal. */\nexport interface RaceStart {\n readonly checkedAt: number;\n readonly principal: QuickdrawServerSocket[\"data\"][\"principal\"];\n}\n\n/** A hub's count of the access changes it handled (`subscriptions.ts`). */\ninterface AccessChanges {\n readonly subscriptions: { readonly accessChanges: number };\n}\n\n/** Notes what a subscribe settles against: call it before it authorizes. */\nexport function raceStart(hub: AccessChanges, socket: QuickdrawServerSocket): RaceStart {\n return { checkedAt: hub.subscriptions.accessChanges, principal: socket.data.principal };\n}\n\n/** True when access changed, or the socket's principal was replaced, since `start`. */\nexport function raceMoved(\n hub: AccessChanges,\n socket: QuickdrawServerSocket,\n start: RaceStart,\n): boolean {\n return (\n hub.subscriptions.accessChanges !== start.checkedAt || socket.data.principal !== start.principal\n );\n}\n\n/** A subscribe's record in its index, as `settleJoin` reads and changes it. */\nexport interface JoinedRecord<R extends { readonly anchors?: readonly string[] }> {\n /** The socket's record of the subscribe's room now. */\n readonly current: () => R | undefined;\n /** True when the client unsubscribed since the subscribe began, or the socket went. */\n readonly withdrawn: () => boolean;\n /**\n * Authorizes `record` again with the socket's principal as it is now: its\n * anchors, or `undefined` when denied (a lookup that failed included).\n */\n readonly authorize: (record: R) => Promise<readonly string[] | undefined>;\n /** Records `record` again with `anchors`; returns what it recorded. */\n readonly reanchor: (record: R, anchors: readonly string[]) => R;\n /** Ends the subscribe's record: the socket leaves the room, if it was in it. */\n readonly leave: () => void;\n}\n\nfunction forbidden(): QuickdrawError {\n return new QuickdrawError(\"FORBIDDEN\", \"Insufficient permissions\");\n}\n\nfunction sameAnchors(a: readonly string[] = [], b: readonly string[] = []): boolean {\n return a.length === b.length && a.every((anchor, index) => anchor === b[index]);\n}\n\n/**\n * Settles a subscribe recorded as `own` (the module header). Resolves with\n * the record the socket holds once access stood still, `own` or a newer\n * one, or `undefined` when the client unsubscribed or the socket went.\n * Throws `FORBIDDEN`, the record ended, when the subscribe lost access or\n * revocation ended its record.\n */\nexport async function settleJoin<R extends { readonly anchors?: readonly string[] }>(\n hub: AccessChanges,\n socket: QuickdrawServerSocket,\n start: RaceStart,\n own: R,\n joined: JoinedRecord<R>,\n): Promise<R | undefined> {\n const userId = start.principal?.userId ?? null;\n let checked = start;\n let record = own;\n let moving = false;\n for (let round = 0; round < MAX_RECHECKS && raceMoved(hub, socket, checked); round += 1) {\n checked = raceStart(hub, socket);\n const same = (checked.principal?.userId ?? null) === userId;\n const anchors = same ? await joined.authorize(record) : undefined;\n const current = joined.current();\n if (current === undefined) {\n // The client or the socket ended it, which stands; else revocation did: a denial.\n if (joined.withdrawn()) {\n return undefined;\n }\n throw forbidden();\n }\n if (anchors === undefined) {\n joined.leave();\n throw forbidden();\n }\n if (current === record) {\n moving = !sameAnchors(record.anchors, anchors);\n record = moving ? joined.reanchor(record, anchors) : record;\n } else {\n // Revocation authorized it again meanwhile: settle what it recorded.\n record = current;\n moving = true;\n }\n }\n if (moving && raceMoved(hub, socket, checked)) {\n // Access changed during the last check too, and it moved the anchors: they may have missed it.\n joined.leave();\n throw forbidden();\n }\n return record;\n}\n\n/**\n * Puts a settled subscribe in its room with `enter`, which returns the\n * record the socket holds there: that record, or `undefined` when the\n * client unsubscribed or the socket went meanwhile. Throws `FORBIDDEN` when\n * revocation ended the record after the subscribe settled.\n */\nexport function enterSettled<R>(\n enter: () => R | undefined,\n withdrawn: () => boolean,\n): R | undefined {\n const entered = enter();\n if (entered === undefined && !withdrawn()) {\n throw forbidden();\n }\n return entered;\n}\n","// The stream feeds this process's sockets subscribe to (RFC 0003 sections\n// 4.4 and 12.5), beside the collection scopes of `collections/scopes.ts`. Each\n// socket keeps its own on `socket.data.streams`, by room: the feed, and the\n// rows its access is derived from (its anchors). The index finds the\n// subscriptions an access change can concern by anchor, so revocation\n// (`streamRevocation.ts`) authorizes only those again. Rooms stay the source\n// of truth for who receives `qd:stream` frames: a subscribe still settling\n// its races is recorded but out of the room (`hold`, then `join`).\n\nimport { streamRoom } from \"../../contract/names\";\nimport type { AccessChange } from \"../access/changes\";\nimport { anchorKey } from \"../access/tools\";\nimport { count, emptyRecords, ownRecord, serviceOf, type Counts } from \"../emit/subscriptions\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport type { StreamSubscription } from \"./types\";\n\n/** The room of a stream subscription. */\nexport function streamRoomOf(subscription: StreamSubscription): string {\n return streamRoom(subscription.s, subscription.stream, subscription.scope);\n}\n\n/** The record of a subscription to `target`'s feed, with the rows its access is derived from. */\nexport function subscriptionOf(\n target: {\n readonly service: { readonly name: string };\n readonly stream: { readonly name: string };\n readonly scope: string | undefined;\n },\n anchors: readonly string[],\n): StreamSubscription {\n const { service, stream, scope } = target;\n return scope === undefined\n ? { s: service.name, stream: stream.name, anchors }\n : { s: service.name, stream: stream.name, scope, anchors };\n}\n\n/** This process's stream subscriptions, indexed by anchor. */\nexport class StreamIndex {\n readonly #byAnchor = new Map<string, Counts>();\n readonly #byService = new Map<string, Counts>();\n /** Per socket, the rooms of subscriptions recorded by `hold` and not joined yet. */\n readonly #held = new WeakMap<QuickdrawServerSocket, Set<string>>();\n\n #index(socket: QuickdrawServerSocket, subscription: StreamSubscription, by: 1 | -1): void {\n for (const anchor of subscription.anchors) {\n count(this.#byAnchor, anchor, socket, by);\n count(this.#byService, serviceOf(anchor), socket, by);\n }\n }\n\n /** The socket's subscription to a feed, by room, or `undefined`. */\n get(socket: QuickdrawServerSocket, room: string): StreamSubscription | undefined {\n return ownRecord(socket.data.streams, room);\n }\n\n /** Every stream subscription of the socket. */\n entries(socket: QuickdrawServerSocket): StreamSubscription[] {\n return Object.values(socket.data.streams ?? {});\n }\n\n /** How many feeds the socket subscribes to. */\n size(socket: QuickdrawServerSocket): number {\n return Object.keys(socket.data.streams ?? {}).length;\n }\n\n #record(socket: QuickdrawServerSocket, room: string, subscription: StreamSubscription): void {\n const previous = this.get(socket, room);\n socket.data.streams ??= emptyRecords();\n socket.data.streams[room] = subscription;\n this.#index(socket, subscription, 1);\n if (previous !== undefined) {\n this.#index(socket, previous, -1);\n }\n }\n\n /**\n * Records a subscription and puts the socket in the feed's room, replacing\n * any earlier one; one `hold` recorded stays out of the room until `join`.\n */\n set(socket: QuickdrawServerSocket, subscription: StreamSubscription): void {\n const room = streamRoomOf(subscription);\n this.#record(socket, room, subscription);\n if (this.#held.get(socket)?.has(room) !== true) {\n void socket.join(room);\n }\n }\n\n /**\n * Records a subscription still settling its races, replacing any earlier\n * one: revocation finds it, but the socket is not put in the feed's room\n * (it stays there if an earlier subscription put it there) until `join`.\n */\n hold(socket: QuickdrawServerSocket, subscription: StreamSubscription): void {\n const room = streamRoomOf(subscription);\n this.#record(socket, room, subscription);\n const held = this.#held.get(socket) ?? new Set<string>();\n held.add(room);\n this.#held.set(socket, held);\n }\n\n /**\n * Puts the socket in the room of a subscription `hold` recorded: what it\n * holds there, or `undefined` when nothing (an unsubscribe, a revocation\n * or a disconnect ended it), and the socket stays out.\n */\n join(socket: QuickdrawServerSocket, room: string): StreamSubscription | undefined {\n this.#held.get(socket)?.delete(room);\n const subscription = this.get(socket, room);\n if (subscription !== undefined) {\n void socket.join(room);\n }\n return subscription;\n }\n\n /** Ends a subscription: the socket leaves the feed's room. Returns what it was. */\n delete(socket: QuickdrawServerSocket, room: string): StreamSubscription | undefined {\n const previous = this.get(socket, room);\n if (previous !== undefined && socket.data.streams !== undefined) {\n delete socket.data.streams[room];\n this.#index(socket, previous, -1);\n }\n this.#held.get(socket)?.delete(room);\n void socket.leave(room);\n return previous;\n }\n\n /** A socket disconnected: Socket.IO has emptied its rooms; drop it from the index. */\n drop(socket: QuickdrawServerSocket): void {\n for (const subscription of this.entries(socket)) {\n this.#index(socket, subscription, -1);\n }\n socket.data.streams = emptyRecords();\n this.#held.delete(socket);\n }\n\n /**\n * The subscriptions an access change can concern: those anchored on the\n * changed row (any row of the service when `id` is absent), of the changed\n * user's sockets (every user's when `userId` is absent).\n */\n matching(change: AccessChange): Map<QuickdrawServerSocket, StreamSubscription[]> {\n const key = change.id === undefined ? undefined : anchorKey(change.service, change.id);\n const sockets =\n key === undefined ? this.#byService.get(change.service) : this.#byAnchor.get(key);\n const found = new Map<QuickdrawServerSocket, StreamSubscription[]>();\n for (const socket of sockets?.keys() ?? []) {\n if (change.userId !== undefined && socket.data.principal?.userId !== change.userId) {\n continue;\n }\n const entries = this.entries(socket).filter(({ anchors }) =>\n anchors.some((anchor) =>\n key === undefined ? serviceOf(anchor) === change.service : anchor === key,\n ),\n );\n if (entries.length > 0) {\n found.set(socket, entries);\n }\n }\n return found;\n }\n}\n","// Revocation (RFC 0003 section 4.4). Each live subscription records the rows\n// its level is derived from: its anchors. When a flush may have changed\n// someone's level on an anchor (`dispatcher.access.onAccessChanged`), the\n// subscriptions anchored there are resolved again, for the user the change\n// names or for everyone:\n//\n// - below `Read` now: the socket leaves the row's room and gets\n// `qd:revoked { kind: \"entity\", reason: \"access\", s, id }`; a row this\n// process's flush deleted is left alone, since its own removal frame (`r`)\n// goes out next. Its subscribers stay in its room, and a create of that id\n// (reported as an access change too) resolves them again before the new\n// row's first frame;\n// - another level: the socket moves to that level's room, and gets the row\n// again (`u`) when the two levels see different fields;\n// - a lookup that fails denies, as everywhere else.\n//\n// In 4.1 a subscriber's tier was fixed when it subscribed and an access\n// change took effect on re-subscribe (4.1 `src/server/BaseService.ts:171-175`).\n// The access sink runs before the entity sink, so a socket a flush revokes\n// never gets that flush's frames.\n//\n// Several nodes behind a cluster adapter each index their own sockets: a\n// node broadcasts every access change it flushes (`serverSideEmit`), and each\n// node re-resolves its own sockets. A changed `serviceAccess`\n// (`server.access.refresh`) re-resolves the user's subscriptions the same way.\n// Collection scopes, change topic watches and stream feeds are authorized\n// again alongside, through the hooks they give (`collections/revocation.ts`,\n// `topicRevocation.ts`, `realtime/streamRevocation.ts`). The access sink\n// waits for every socket's re-resolution, a failed one included\n// (`settleAll`), before the flush moves on to its frames: one socket's\n// failure must not let a demoted socket receive them (the 5.1 audit's\n// DATA-I1).\n\nimport { SERVER_EVENTS, userRoom } from \"../../contract/names\";\nimport type { AccessChange } from \"../access/changes\";\nimport { onNodeEvent } from \"../cluster/deployment\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport type { Hub } from \"./hub\";\nimport { projectRow } from \"./projection\";\nimport { anchorsOf, resolveAccess, subscriberLevel } from \"./resolve\";\nimport type { SubscriptionEntry } from \"./subscriptions\";\nimport { strip } from \"./tiers\";\n\n/** The server-to-server event an access change is broadcast on behind a cluster adapter. */\nexport const ACCESS_CHANGED_EVENT = \"quickdraw:access-changed\";\n\ntype Entries = readonly SubscriptionEntry[];\n\n/** Sends rows whose subscriber moved to a level that sees other fields again, whole, at a new revision. */\nasync function resend(\n hub: Hub,\n socket: QuickdrawServerSocket,\n service: string,\n ids: readonly string[],\n): Promise<void> {\n const target = hub.registry.services.get(service);\n const projection = target?.projections.get(\"entity\");\n if (ids.length === 0 || target?.model === undefined || projection === undefined) {\n return;\n }\n // Claimed before the read: behind a cluster's counter, no older than any frame the client holds.\n const rev = await hub.revisions.claim();\n const rows =\n (await hub.storage?.findMany(target.model, {\n where: { id: { in: [...ids] } },\n select: projection.select,\n })) ?? [];\n for (const row of rows) {\n const id = typeof row.id === \"string\" ? row.id : \"\";\n const subscription = hub.subscriptions.get(socket, service, id);\n const data = projectRow(projection, row);\n if (subscription !== undefined && typeof data === \"object\" && data !== null) {\n const hidden = projection.tiers.hidden(subscription.level);\n const d = strip(data as Readonly<Record<string, unknown>>, hidden);\n socket.emit(SERVER_EVENTS.entity, { t: \"u\", s: service, id, rev, d });\n }\n }\n}\n\n/**\n * Ends a subscription the principal may no longer read, unless the row is\n * deleted as far as this process's change log knows: the intake sink records\n * each flush before access is resolved, so a row created again counts as\n * existing. For a change another node broadcast, the log is trusted only\n * when the broadcast carried its row's state (`trustLog`), which was\n * recorded first: otherwise this process's log may be behind that node's\n * writes, and the change is never skipped.\n */\nfunction revoke(\n hub: Hub,\n socket: QuickdrawServerSocket,\n entry: { readonly service: string; readonly id: string },\n trustLog: boolean,\n): void {\n const { service, id } = entry;\n if (trustLog && hub.changeLog.removed(service, id)) {\n return;\n }\n if (hub.subscriptions.delete(socket, service, id) !== undefined) {\n socket.emit(SERVER_EVENTS.revoked, { kind: \"entity\", reason: \"access\", s: service, id });\n }\n}\n\n/** True when two levels see different fields of the service's entity. */\nfunction seesOther(hub: Hub, service: string, a: string, b: string): boolean {\n const tiers = hub.registry.services.get(service)?.projections.get(\"entity\")?.tiers;\n if (tiers === undefined || a === b) {\n return false;\n }\n const group = (level: string) =>\n tiers.groups.findIndex((tier) => tier.levels.some((l) => l === level));\n return group(a) !== group(b);\n}\n\n/** The levels of `entries` resolved again, or `undefined` when there is no principal or the lookup failed. */\nasync function resolveAgain(\n hub: Hub,\n socket: QuickdrawServerSocket,\n service: string,\n entries: Entries,\n) {\n const { principal } = socket.data;\n const target = hub.registry.services.get(service);\n if (principal === null || target === undefined) {\n return undefined;\n }\n const ids = entries.map((entry) => entry.id);\n try {\n return await resolveAccess(hub, target, principal, ids);\n } catch (error) {\n hub.logger.error(\n \"Resolving subscribers' access again failed; their subscriptions are revoked\",\n {\n category: \"quickdraw.access\",\n service,\n error: describeError(error),\n },\n );\n return undefined;\n }\n}\n\n/** Resolves one socket's subscriptions to one service again, and applies the new levels. */\nasync function reresolve(\n hub: Hub,\n socket: QuickdrawServerSocket,\n service: string,\n entries: Entries,\n trustLog: boolean,\n): Promise<void> {\n const access = await resolveAgain(hub, socket, service, entries);\n const moved: string[] = [];\n for (const { id, subscription } of entries) {\n // Unsubscribed, subscribed again or resolved again meanwhile: that is newer than this.\n if (!socket.connected || hub.subscriptions.get(socket, service, id) !== subscription) {\n continue;\n }\n const level = access === undefined ? undefined : subscriberLevel(access, id);\n if (access === undefined || level === undefined) {\n revoke(hub, socket, { service, id }, trustLog);\n continue;\n }\n hub.subscriptions.set(socket, service, id, { level, anchors: anchorsOf(access, service, id) });\n if (seesOther(hub, service, level, subscription.level)) {\n moved.push(id);\n }\n }\n await resend(hub, socket, service, moved);\n}\n\n/**\n * Resolves the given subscriptions again, one engine call per socket and\n * service. `trustLog` unless the change came from another node without its\n * row's state.\n */\nasync function reresolveAll(\n hub: Hub,\n found: ReadonlyMap<QuickdrawServerSocket, Entries>,\n trustLog: boolean,\n): Promise<void> {\n const work: Promise<void>[] = [];\n for (const [socket, entries] of found) {\n const byService = new Map<string, SubscriptionEntry[]>();\n for (const entry of entries) {\n byService.set(entry.service, [...(byService.get(entry.service) ?? []), entry]);\n }\n for (const [service, own] of byService) {\n work.push(reresolve(hub, socket, service, own, trustLog));\n }\n }\n await settleAll(work);\n}\n\n/**\n * Waits for every piece of `work` to settle, then rejects with the first\n * failure, if any: unlike `Promise.all`, it never moves on while some of the\n * work still runs.\n */\nexport async function settleAll(work: Iterable<unknown>): Promise<void> {\n const results = await Promise.allSettled(work);\n const failed = results.find(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (failed !== undefined) {\n throw failed.reason instanceof Error\n ? failed.reason\n : new Error(\"A re-resolution failed\", { cause: failed.reason });\n }\n}\n\n/**\n * An access change as it travels between nodes: with its row's state as the\n * flushing node's change log has it (the revision of its last write, and\n * whether that write deleted it), which the receiving node records in its\n * own log before resolving anything.\n */\nexport interface BroadcastChange extends AccessChange {\n readonly rev?: number;\n readonly removed?: boolean;\n}\n\n/** `change` with its row's state from this process's change log, for the other nodes. */\nfunction withRowState(hub: Hub, change: AccessChange): BroadcastChange {\n const { service, id } = change;\n if (id === undefined) {\n return change;\n }\n return {\n ...change,\n rev: hub.changeLog.lastChange(service, id),\n removed: hub.changeLog.removed(service, id),\n };\n}\n\n/**\n * Broadcasts a change this process flushed and waits until every other node\n * has re-resolved what it concerns (each answers once it is done), at most\n * `cluster.timeoutMs`: the access sinks run before the frame sinks, so a\n * flush that revokes a subscription on another node sends that flush's\n * frames only once the subscription is gone there too. The wait holds this\n * node's later flushes too, so it is skipped while Valkey is not connected,\n * and after a node failed to answer in time until every node answers a\n * probe again (`../cluster/broadcasts.ts`): the frames then go out at once,\n * and a slower node may still hold a socket the change revoked.\n */\nasync function broadcastChange(hub: Hub, change: BroadcastChange): Promise<void> {\n await hub.broadcasts?.broadcast(ACCESS_CHANGED_EVENT, change);\n}\n\n/** What the subscriptions of a dispatcher do when access changes. */\nexport interface Revocation {\n /**\n * Re-resolves the subscriptions `change` concerns on this process. A change\n * this process flushed (`remote` false) is also broadcast to the other\n * nodes, behind a cluster adapter, with its row's state, and resolves once\n * they re-resolved theirs too (`broadcastChange`).\n */\n changed(change: BroadcastChange, remote: boolean): Promise<void>;\n /** Re-resolves every subscription of `userId`'s sockets on this process: their grants changed. */\n regranted(userId: string): Promise<void>;\n}\n\n/** More subscriptions an access change re-resolves: the collection scopes, the change topics, the stream feeds. */\nexport interface RevocationHook {\n /** Re-resolves the subscriptions `change` concerns on this process. */\n changed(change: AccessChange): Promise<void>;\n /**\n * Re-resolves every subscription of these sockets, whose user's grants\n * changed: `userId`'s, whose sockets on this process they are (none when\n * the user has none here).\n */\n regranted(sockets: readonly QuickdrawServerSocket[], userId: string): Promise<void>;\n}\n\n/**\n * The revocation of one dispatcher's subscriptions; `hooks` re-resolve the\n * collection scopes and the change topics alongside.\n */\nexport function createRevocation(hub: Hub, hooks: readonly RevocationHook[] = []): Revocation {\n return Object.freeze({\n async changed(change: BroadcastChange, remote: boolean): Promise<void> {\n hub.subscriptions.accessChanges += 1;\n const others =\n !remote && hub.io !== undefined && !hub.probe.local()\n ? broadcastChange(hub, withRowState(hub, change))\n : undefined;\n const trustLog = !remote || change.removed !== undefined;\n await settleAll([\n others,\n reresolveAll(hub, hub.subscriptions.matching(change), trustLog),\n ...hooks.map(async (hook) => await hook.changed(change)),\n ]);\n },\n async regranted(userId: string): Promise<void> {\n hub.subscriptions.accessChanges += 1;\n const { io } = hub;\n const found = new Map<QuickdrawServerSocket, Entries>();\n for (const socketId of io?.sockets.adapter.rooms.get(userRoom(userId)) ?? []) {\n const socket = io?.sockets.sockets.get(socketId);\n if (socket?.data.principal?.userId === userId) {\n found.set(socket, [...hub.subscriptions.entries(socket)]);\n }\n }\n const sockets = [...found.keys()];\n await settleAll([\n reresolveAll(hub, found, true),\n ...hooks.map(async (hook) => await hook.regranted(sockets, userId)),\n ]);\n },\n });\n}\n\n/** The row state a broadcast change carries, `{ rev, removed }`, when both are well formed. */\nfunction rowStateOf(value: Readonly<Record<string, unknown>>): Partial<BroadcastChange> {\n const { rev, removed } = value;\n return Number.isSafeInteger(rev) && typeof removed === \"boolean\"\n ? { rev: rev as number, removed }\n : {};\n}\n\n/**\n * The access change another node broadcast, `{ service, id?, userId? }` with\n * its row's state when it names a row, or `undefined` for anything else.\n */\nfunction readChange(value: unknown): BroadcastChange | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n const fields = value as Readonly<Record<string, unknown>>;\n const { service, id, userId } = fields;\n if (typeof service !== \"string\" || service.length === 0) {\n return undefined;\n }\n const named = typeof id === \"string\" && id.length > 0;\n return {\n service,\n ...(named ? { id, ...rowStateOf(fields) } : {}),\n ...(typeof userId === \"string\" && userId.length > 0 ? { userId } : {}),\n };\n}\n\n/** Records the row state a broadcast change carries in this process's change log. */\nfunction recordRowState(hub: Hub, change: BroadcastChange): void {\n if (change.id !== undefined && change.rev !== undefined && change.removed !== undefined) {\n hub.changeLog.record(change.service, change.id, change.rev, change.removed);\n }\n}\n\n/**\n * Listens for the access changes other nodes broadcast, on the server the\n * hub was given: each records its row's state in this process's change log,\n * has `forget` evict what it names from the access cache (that node's write\n * changed it), is resolved again, and is answered once it is (the flushing\n * node waits for every node's answer before it sends the flush's frames).\n */\nexport function listenForChanges(\n hub: Hub,\n revocation: Revocation,\n forget: (change: AccessChange) => void,\n): void {\n if (hub.io === undefined) {\n return;\n }\n // Another deployment's change is answered and never applied (`../cluster/deployment.ts`).\n onNodeEvent(hub.io, hub.logger, ACCESS_CHANGED_EVENT, (broadcast, answer) => {\n const change = readChange(broadcast);\n if (change === undefined) {\n answer(false);\n return;\n }\n recordRowState(hub, change);\n forget(change);\n revocation.changed(change, true).then(\n () => {\n answer(true);\n },\n (error: unknown) => {\n answer(false);\n hub.logger.error(\"Revoking for an access change another node broadcast failed\", {\n category: \"quickdraw.access\",\n service: change.service,\n error: describeError(error),\n });\n },\n );\n });\n}\n","// Which stream feed a `qd:stream:sub` or `qd:stream:unsub` frame names, and\n// whether the socket may subscribe to it (RFC 0003 sections 8.2 and 12.5).\n//\n// A frame is `{ s, stream, scope? }`: `VALIDATION` when it is malformed or\n// its scope does not fit the stream (a scoped stream needs a scope of 1 to\n// 256 characters, a global stream takes none), `NOT_FOUND` for an unknown\n// service or stream. A subscriber is authorized with the stream's access\n// form through the dispatcher's access engine, as a method call with input\n// `{ scope }` would be: the scope is the row an `entry` or `scope` form\n// checks. `access: { room }` asks no engine: the subscribing socket must be\n// in that app room (a method joined it), signed in or not. A stream whose\n// contract declares no access is closed: `FORBIDDEN` for everyone. Before\n// any of it, a principal of a kind the service does not admit is `FORBIDDEN`\n// (`../access/kinds.ts`), whatever the form.\n\nimport { streamRoom } from \"../../contract/names\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { MAX_SCOPE_LENGTH } from \"../../protocol/version\";\nimport { checkKind } from \"../access/kinds\";\nimport { anchorKey } from \"../access/tools\";\nimport { createContext, NEVER_ABORTED } from \"../context\";\nimport type { Hub, RegisteredService } from \"../emit/hub\";\nimport { unreadable } from \"../transports/ack\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport type { ServiceStream, StreamRoomAccess } from \"./types\";\n\n/** One feed of a served stream: one scope of a scoped stream, or a global stream. */\nexport interface StreamTarget {\n readonly service: RegisteredService;\n readonly stream: ServiceStream;\n /** The scope of a scoped stream; `undefined` for a global stream. */\n readonly scope: string | undefined;\n /** The feed's room: `streamRoom(service, stream, scope)`. */\n readonly room: string;\n}\n\nfunction isName(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\n/** Why `scope` cannot name a feed of `stream`, or `undefined` when it can. */\nexport function scopeProblem(stream: ServiceStream, scope: unknown): string | undefined {\n if (!stream.scoped) {\n return scope === undefined ? undefined : `${stream.name} is a global stream: it takes no scope`;\n }\n return isName(scope) && scope.length <= MAX_SCOPE_LENGTH\n ? undefined\n : `${stream.name} is scoped: its scope is a string of 1 to ${MAX_SCOPE_LENGTH} characters`;\n}\n\n/**\n * The feed a `qd:stream:sub` or `qd:stream:unsub` frame names. Throws\n * `VALIDATION` for a malformed frame or a scope that does not fit, and\n * `NOT_FOUND` for an unknown service or stream (also one named `__proto__`:\n * services and streams are `Map`s).\n */\nexport function streamTarget(hub: Hub, value: unknown, event: string): StreamTarget {\n const frame =\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Readonly<Record<string, unknown>>)\n : {};\n if (!isName(frame.s) || !isName(frame.stream)) {\n throw unreadable(\n `A ${event} frame needs { s, stream, scope? } with s and stream non-empty strings`,\n );\n }\n const service = hub.registry.services.get(frame.s);\n if (service === undefined) {\n throw new QuickdrawError(\"NOT_FOUND\", `Unknown service \"${frame.s}\"`);\n }\n const stream = service.streams.get(frame.stream);\n if (stream === undefined) {\n throw new QuickdrawError(\"NOT_FOUND\", `${frame.s} has no stream \"${frame.stream}\"`);\n }\n const problem = scopeProblem(stream, frame.scope);\n if (problem !== undefined) {\n throw unreadable(problem, [\"scope\"]);\n }\n const scope = frame.scope as string | undefined;\n return { service, stream, scope, room: streamRoom(service.name, stream.name, scope) };\n}\n\n/**\n * Whether `socket` is in the app room a stream's `access: { room }` names for\n * `scope`: one its own calls joined (`socket.data.appRooms`, which has no\n * prototype), the named one or any with the prefix (global streams only:\n * `defineContract` refuses both on a scoped stream), or the one computed\n * from the scope.\n */\nexport function inStreamRoom(\n socket: QuickdrawServerSocket,\n access: StreamRoomAccess,\n scope: string | undefined,\n): boolean {\n const joined = socket.data.appRooms;\n if (access.kind === \"prefix\") {\n for (const room in joined) {\n if (room.startsWith(access.prefix)) {\n return true;\n }\n }\n return false;\n }\n const room = access.kind === \"name\" ? access.room : access.select(scope);\n return room !== undefined && joined !== undefined && Object.hasOwn(joined, room);\n}\n\n/**\n * Authorizes a subscriber of `target`: rejects with `FORBIDDEN` for a\n * principal of a kind the service does not admit, for a closed stream, or\n * for a socket outside the app room `access: { room }` names, and otherwise\n * as the access engine decides the stream's form (`UNAUTHENTICATED` for an\n * anonymous socket unless the form is `\"public\"`).\n */\nexport async function authorizeStream(\n hub: Hub,\n socket: QuickdrawServerSocket,\n target: StreamTarget,\n): Promise<void> {\n checkKind(target.service.kinds, socket.data.principal, target.service.name);\n const { room } = target.stream;\n if (room !== undefined) {\n if (!inStreamRoom(socket, room, target.scope)) {\n throw new QuickdrawError(\n \"FORBIDDEN\",\n `${target.service.name}.${target.stream.name} is open to the sockets in its app room: join the room first`,\n );\n }\n return;\n }\n const form = target.stream.access;\n if (form === undefined) {\n throw new QuickdrawError(\n \"FORBIDDEN\",\n `${target.service.name}.${target.stream.name} is closed: its contract declares no access`,\n );\n }\n const { principal } = socket.data;\n const ctx = createContext({\n principal,\n signal: NEVER_ABORTED,\n log: hub.logger,\n requestId: crypto.randomUUID(),\n transport: \"socket\",\n });\n const input = { scope: target.scope };\n await hub.access.authorize(form, {\n service: target.service,\n method: target.stream.name,\n principal,\n input,\n ctx,\n });\n}\n\n/**\n * The rows a subscriber's access to `target` is derived from (its anchors,\n * `anchorKey`s), for revocation: under an `entry` form, the feed's row of\n * the stream's service and its `inherit` parents; under a `scope` form, the\n * row of `of` the scope names and its parents. None for `\"public\"`,\n * `\"authenticated\"` or `{ service }`, which no row decides (a changed grant\n * authorizes every feed of the user again). Call it once the subscriber is\n * authorized; a lookup that fails rejects.\n */\nexport async function streamAnchors(\n hub: Hub,\n socket: QuickdrawServerSocket,\n target: StreamTarget,\n): Promise<readonly string[]> {\n const form = target.stream.access;\n const { principal } = socket.data;\n const { scope } = target;\n if (principal === null || scope === undefined || typeof form !== \"object\" || \"kind\" in form) {\n return [];\n }\n if (form.entry !== undefined && target.service.access !== undefined) {\n const resolved = await hub.policies.resolve(target.service.name, principal, [scope]);\n return resolved.anchors.get(scope) ?? [anchorKey(target.service.name, scope)];\n }\n if (form.scope !== undefined) {\n const resolved = await hub.policies.resolve(form.of.name, principal, [scope], {\n grants: false,\n });\n return resolved.anchors.get(scope) ?? [anchorKey(form.of.name, scope)];\n }\n return [];\n}\n\n/** An unsubscribe needs a principal, unless the stream is public or open to an app room's sockets. */\nexport function checkUnsubscriber(socket: QuickdrawServerSocket, target: StreamTarget): void {\n const { access, room } = target.stream;\n if (socket.data.principal === null && access !== \"public\" && room === undefined) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n}\n","// Revoking stream subscriptions (RFC 0003 sections 4.4 and 12.5), beside the\n// entity, collection and topic revocations (`emit/revocation.ts`, which calls\n// this on every access change it handles). Each feed's subscription records\n// the rows its access is derived from (its anchors, `streamIndex.ts`); when a\n// flush may have changed someone's level on one, the feeds anchored there are\n// authorized again through the access engine, as a subscribe is\n// (`streamTargets.ts`), for the user the change names or for everyone. A\n// changed `serviceAccess` (`server.access.refresh`, or another node's\n// `quickdraw:grants`) authorizes every feed of the user's sockets again, so\n// a `{ service }` stream is checked against the new grants.\n//\n// - no longer allowed: the socket leaves the feed's room and gets\n// `qd:revoked { kind: \"stream\", reason: \"access\", s, stream, scope? }`, and\n// no item pushed after that reaches it;\n// - still allowed: the subscription keeps its room, with its anchors read\n// again;\n// - a lookup that fails denies, as everywhere else.\n//\n// A feed open to an app room's sockets (`access: { room }`) is checked again\n// when its socket leaves an app room, by its own leave or a removal: one it\n// no longer meets is revoked the same way, at once. A subscribe an access\n// change overlapped is authorized again the same way once it joined\n// (`anchorsNow`, from `streamSubscribe.ts`).\n\nimport { SERVER_EVENTS } from \"../../contract/names\";\nimport type { RevokedFrame } from \"../../protocol/envelope\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { Hub } from \"../emit/hub\";\nimport { settleAll, type RevocationHook } from \"../emit/revocation\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { streamRoomOf, subscriptionOf, type StreamIndex } from \"./streamIndex\";\nimport { authorizeStream, inStreamRoom, streamAnchors, streamTarget } from \"./streamTargets\";\nimport type { StreamSubscription } from \"./types\";\n\ntype Found = Iterable<readonly [QuickdrawServerSocket, readonly StreamSubscription[]]>;\n\n/** The anchors the subscription may keep, or `undefined` when it may no longer read the feed. */\nexport async function anchorsNow(\n hub: Hub,\n socket: QuickdrawServerSocket,\n subscription: StreamSubscription,\n): Promise<readonly string[] | undefined> {\n try {\n const target = streamTarget(hub, subscription, SERVER_EVENTS.revoked);\n await authorizeStream(hub, socket, target);\n return await streamAnchors(hub, socket, target);\n } catch (error) {\n if (!(error instanceof QuickdrawError) || error.code === \"INTERNAL\") {\n hub.logger.error(\n \"Authorizing a stream subscriber again failed; the subscription is revoked\",\n {\n category: \"quickdraw.access\",\n service: subscription.s,\n stream: subscription.stream,\n error: describeError(error),\n },\n );\n }\n return undefined;\n }\n}\n\n/** Authorizes one subscription again, and applies the answer. */\nasync function reauthorize(\n hub: Hub,\n index: StreamIndex,\n socket: QuickdrawServerSocket,\n subscription: StreamSubscription,\n): Promise<void> {\n const anchors = await anchorsNow(hub, socket, subscription);\n const room = streamRoomOf(subscription);\n // Unsubscribed, subscribed again or authorized again meanwhile: that is newer than this.\n if (!socket.connected || index.get(socket, room) !== subscription) {\n return;\n }\n if (anchors !== undefined) {\n const target = streamTarget(hub, subscription, SERVER_EVENTS.revoked);\n index.set(socket, subscriptionOf(target, anchors));\n return;\n }\n revoke(index, socket, subscription);\n}\n\n/** Takes the socket out of a feed it may no longer read, and tells it: `qd:revoked`. */\nfunction revoke(\n index: StreamIndex,\n socket: QuickdrawServerSocket,\n subscription: StreamSubscription,\n): void {\n index.delete(socket, streamRoomOf(subscription));\n const { s, stream, scope } = subscription;\n const frame: RevokedFrame =\n scope === undefined\n ? { kind: \"stream\", reason: \"access\", s, stream }\n : { kind: \"stream\", reason: \"access\", s, stream, scope };\n socket.emit(SERVER_EVENTS.revoked, frame);\n}\n\n/**\n * The socket left an app room (its own leave, or taken out): each feed it\n * holds whose `access: { room }` it no longer meets is revoked at once, so\n * nothing pushed after the leave reaches it.\n */\nexport function revokeOutsideRooms(\n hub: Hub,\n index: StreamIndex,\n socket: QuickdrawServerSocket,\n): void {\n for (const subscription of index.entries(socket)) {\n const service = hub.registry.services.get(subscription.s);\n const room = service?.streams.get(subscription.stream)?.room;\n if (room !== undefined && !inStreamRoom(socket, room, subscription.scope)) {\n revoke(index, socket, subscription);\n }\n }\n}\n\n/** Authorizes the given subscriptions again, all at once. */\nasync function reauthorizeAll(hub: Hub, index: StreamIndex, found: Found): Promise<void> {\n const work: Promise<void>[] = [];\n for (const [socket, subscriptions] of found) {\n for (const subscription of subscriptions) {\n work.push(reauthorize(hub, index, socket, subscription));\n }\n }\n await settleAll(work);\n}\n\n/** The stream half of a dispatcher's revocation. */\nexport function createStreamRevocation(hub: Hub, index: StreamIndex): RevocationHook {\n return Object.freeze({\n changed: async (change) => await reauthorizeAll(hub, index, index.matching(change)),\n regranted: async (sockets) =>\n await reauthorizeAll(\n hub,\n index,\n sockets.map((socket) => [socket, index.entries(socket)] as const),\n ),\n } satisfies RevocationHook);\n}\n","// One `qd:stream:sub` (RFC 0003 sections 8.2 and 12.5): authorize the\n// subscriber (`streamTargets.ts`), record the subscription, settle the races\n// with access changes, then join the feed's room and read the seed in one\n// tick, so every item pushed after the seed reaches the socket as a\n// `qd:stream` frame (possibly before the acknowledgement), and none arrives\n// both ways.\n//\n// - A subscribe no access change overlapped joins in the tick it is\n// recorded.\n// - One an access change overlapped (or whose socket's principal was\n// replaced meanwhile) is authorized again first, with the socket's\n// principal as it is then (`../emit/race.ts`): recorded, so revocation\n// finds it, but out of the room, so nothing pushed meanwhile reaches it.\n// One that lost access is answered `FORBIDDEN` (the 5.1 audit's RT-1: a\n// member removed while subscribing kept the feed, seed and all).\n// - A stream whose service computes its seed (`streams: { <name>: { seed }\n// }`) calls that function instead of reading the kept items, at that same\n// point, under the subscriber's principal: one that returns at once keeps\n// the same guarantee; one that returns a promise may also see items pushed\n// while it runs, which then arrive both ways. What it returns is checked\n// against the item schema, and what it throws (or a mismatch) answers the\n// subscribe and takes the socket out of the feed.\n// - An unsubscribe that arrives while a subscribe of the same feed is being\n// authorized stops it from joining. A subscribe that did not join is\n// answered `{ ok: true, seed: [] }`: nobody reads that seed.\n//\n// A socket holds at most `MAX_STREAMS_PER_SOCKET` feeds (`CONFLICT` past\n// that), recorded on `socket.data.streams` with the rows their access is\n// derived from (`streamIndex.ts`), so an access change revokes them\n// (`streamRevocation.ts`).\n\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { Hub } from \"../emit/hub\";\nimport type { PendingKeys } from \"../emit/pending\";\nimport { enterSettled, raceMoved, raceStart, settleJoin, type RaceStart } from \"../emit/race\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { computeSeed, streamKey, type StreamSeeds } from \"./seeds\";\nimport { subscriptionOf, type StreamIndex } from \"./streamIndex\";\nimport { anchorsNow } from \"./streamRevocation\";\nimport { authorizeStream, streamAnchors, type StreamTarget } from \"./streamTargets\";\nimport type { StreamSubscription } from \"./types\";\n\n/** The acknowledgement of `qd:stream:sub` (`StreamSubscribeReply` in `envelope.ts`). */\nexport interface SeedReply {\n readonly ok: true;\n readonly seed: readonly unknown[];\n}\n\n/** The most stream feeds one socket may subscribe to at once. */\nexport const MAX_STREAMS_PER_SOCKET = 500;\n\n/** What the stream listeners of one dispatcher share. */\nexport interface StreamState {\n readonly hub: Hub;\n readonly seeds: StreamSeeds;\n readonly index: StreamIndex;\n /** The feeds each socket has a `qd:stream:sub` in flight for, by room. */\n readonly pending: PendingKeys;\n}\n\n/** A subscribe recorded: its record, what it settles against, and the unsubscribes when it began. */\ninterface Held {\n readonly own: StreamSubscription;\n readonly start: RaceStart;\n readonly unsubscribes: number;\n}\n\n/**\n * Records the subscription with `anchors`, out of the feed's room, unless an\n * unsubscribe or a disconnect overtook the subscribe: the record. `CONFLICT`\n * past the socket's feeds.\n */\nfunction holdFeed(\n state: StreamState,\n socket: QuickdrawServerSocket,\n target: StreamTarget,\n [anchors, unsubscribes]: readonly [readonly string[], number],\n): StreamSubscription | undefined {\n const known = state.index.get(socket, target.room) !== undefined;\n if (!known && state.index.size(socket) >= MAX_STREAMS_PER_SOCKET) {\n throw new QuickdrawError(\n \"CONFLICT\",\n `A socket may subscribe to at most ${MAX_STREAMS_PER_SOCKET} stream feeds; unsubscribe from one first`,\n );\n }\n if (withdrawn(state, socket, target, unsubscribes)) {\n return undefined;\n }\n const own = subscriptionOf(target, anchors);\n state.index.hold(socket, own);\n return own;\n}\n\n/** True when the client unsubscribed from the feed since the subscribe began, or the socket went. */\nfunction withdrawn(\n state: StreamState,\n socket: QuickdrawServerSocket,\n target: StreamTarget,\n unsubscribes: number,\n): boolean {\n return !socket.connected || state.pending.count(socket, target.room) !== unsubscribes;\n}\n\n/** Settles a recorded subscribe against the access changes made since it began (`../emit/race.ts`). */\nasync function settleFeed(\n state: StreamState,\n socket: QuickdrawServerSocket,\n target: StreamTarget,\n held: Held,\n): Promise<StreamSubscription | undefined> {\n const { hub, index } = state;\n return await settleJoin(hub, socket, held.start, held.own, {\n current: () => index.get(socket, target.room),\n withdrawn: () => withdrawn(state, socket, target, held.unsubscribes),\n authorize: async (subscription) => await anchorsNow(hub, socket, subscription),\n reanchor: (_subscription, anchors) => {\n const next = subscriptionOf(target, anchors);\n index.set(socket, next);\n return next;\n },\n leave: () => {\n index.delete(socket, target.room);\n },\n });\n}\n\n/**\n * The seed of a feed the socket holds as `held`: the kept items, or what\n * the service computes, called in this tick. A computed seed that fails\n * takes the socket out of the feed.\n */\nasync function seedOf(\n state: StreamState,\n socket: QuickdrawServerSocket,\n target: StreamTarget,\n held: StreamSubscription,\n): Promise<SeedReply> {\n if (target.stream.computeSeed === undefined) {\n const key = streamKey(target.service.name, target.stream.name);\n return { ok: true, seed: state.seeds.seed(key, target.scope) };\n }\n try {\n const ctx = Object.freeze({\n principal: socket.data.principal ?? null,\n socketId: socket.id,\n log: state.hub.logger,\n });\n return {\n ok: true,\n seed: await computeSeed(\n target.service.name,\n target.stream,\n target.scope,\n ctx,\n state.hub.outputValidation,\n ),\n };\n } catch (error) {\n // The subscriber is answered the failure, so it hears none of the items that follow.\n if (state.index.get(socket, target.room) === held) {\n state.index.delete(socket, target.room);\n }\n throw error;\n }\n}\n\n/**\n * Answers one `qd:stream:sub` of `target` (the module header). Rejects with\n * the authorization's refusal, `FORBIDDEN` for one that lost access while\n * it was answered, `CONFLICT` past the socket's feeds, or what a computed\n * seed throws.\n */\nexport async function subscribeFeed(\n state: StreamState,\n socket: QuickdrawServerSocket,\n target: StreamTarget,\n): Promise<SeedReply> {\n const { room } = target;\n const unsubscribes = state.pending.begin(socket, [room]).get(room) ?? 0;\n const start = raceStart(state.hub, socket);\n let held: StreamSubscription | undefined;\n try {\n await authorizeStream(state.hub, socket, target);\n const anchors = await streamAnchors(state.hub, socket, target);\n held = holdFeed(state, socket, target, [anchors, unsubscribes]);\n if (held !== undefined && raceMoved(state.hub, socket, start)) {\n held = await settleFeed(state, socket, target, { own: held, start, unsubscribes });\n }\n if (held !== undefined) {\n held = enterSettled(\n () => state.index.join(socket, room),\n () => withdrawn(state, socket, target, unsubscribes),\n );\n }\n } finally {\n state.pending.end(socket, [room]);\n }\n // The tick the socket joined the feed's room.\n return held === undefined ? { ok: true, seed: [] } : await seedOf(state, socket, target, held);\n}\n","// The default `AccessEngine`. It decides the forms that need no row lookup\n// (`\"public\"`, `\"authenticated\"`, `{ service }`, `custom(fn)`) and hands the\n// row-level forms (`entry`, `scope`) to a `RowAccess`, which the access\n// policies card provides. Without one, a row-level form fails with\n// `INTERNAL`: a configuration mistake, never a silent pass.\n\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { AnyContext } from \"../context\";\nimport type { MaybePromise } from \"../types\";\nimport { isCustomAccess } from \"./forms\";\nimport { meetsLevel, serviceGrant } from \"./levels\";\nimport type { AccessEngine, AccessForm, AccessRequest, RowAccess } from \"./types\";\n\n/** Options of {@link createBasicAccessEngine}. */\nexport interface BasicAccessEngineOptions {\n /**\n * Decides `entry` and `scope` forms. Without it they fail with `INTERNAL`,\n * naming the service, because no access policy is configured.\n */\n readonly rows?: RowAccess;\n}\n\nfunction forbidden(): QuickdrawError {\n return new QuickdrawError(\"FORBIDDEN\", \"Insufficient permissions\");\n}\n\nconst NO_ROW_POLICY: RowAccess = {\n allows(form, request) {\n const kind = form.scope === undefined ? \"entry\" : \"scope\";\n throw new QuickdrawError(\n \"INTERNAL\",\n `${request.service.name}.${request.method} uses ${kind} access, but no access policy is configured for ${request.service.name}`,\n );\n },\n};\n\nasync function decide(form: AccessForm, request: AccessRequest, rows: RowAccess): Promise<void> {\n if (form === \"public\") {\n return;\n }\n const { principal, service } = request;\n if (principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n const grant = serviceGrant(principal, service.name);\n if (form === \"authenticated\" || (service.adminBypass && grant === \"Admin\")) {\n return;\n }\n if (isCustomAccess(form)) {\n // The check was typed for this method's input and context, which are\n // what the dispatcher passes.\n const check = form.check as (ctx: AnyContext, input: unknown) => MaybePromise<boolean>;\n if ((await check(request.ctx, request.input)) === true) {\n return;\n }\n throw forbidden();\n }\n if (form.service !== undefined && meetsLevel(grant, form.service)) {\n return;\n }\n if (\n (form.entry !== undefined || form.scope !== undefined) &&\n (await rows.allows(form, request)) === true\n ) {\n return;\n }\n throw forbidden();\n}\n\n/**\n * The default access engine:\n *\n * - `\"public\"` always passes.\n * - Every other form needs a principal; without one the call fails with\n * `UNAUTHENTICATED`.\n * - A service-wide `Admin` grant passes every check on its service, unless\n * the service sets `adminBypass: false`.\n * - `\"authenticated\"` passes for any principal.\n * - `custom(fn)` passes when `fn(ctx, input)` resolves `true`.\n * - `{ service: L }` passes when the principal's grant on the service is at\n * least `L`. A lower grant counts only where `service` is named, so a\n * `Read` grant does not read every row.\n * - `{ entry }` and `{ scope }` ask `options.rows`; `{ service, entry }`\n * passes on either.\n *\n * Anything else fails with `FORBIDDEN`.\n */\nexport function createBasicAccessEngine(options: BasicAccessEngineOptions = {}): AccessEngine {\n const rows = options.rows ?? NO_ROW_POLICY;\n return Object.freeze({\n authorize: (form: AccessForm, request: AccessRequest) => decide(form, request, rows),\n });\n}\n","// `resolver({ levelsFor, where?, reads? })` (RFC 0003 section 4.2): a policy\n// written in app code, for access rules the other builders cannot state.\n//\n// `reads` (finding R1.1 of the 5.0.0 review) says what its levels depend on,\n// in the terms the other builders use (`PolicyReads`): columns of the\n// service's own model, as `owner` and `jsonAcl` read theirs, and membership\n// tables, as `members` reads its table. The engine then treats them as it\n// treats theirs: tracked writes to them evict cached lookups and report the\n// access changes that re-check live rows, collection scopes and change\n// topics (`../changes.ts`). Without `reads` nothing a write does re-checks a\n// resolver, so a user removed from a table it reads keeps the rows it let\n// them subscribe to; `reads: \"none\"` says its levels depend on nothing a\n// tracked write changes (only the principal's grants, say), and a resolver\n// with neither raises the `resolver-without-reads` development warning\n// (`../resolverReads.ts`).\n\nimport { isAccessLevel, type AccessLevel } from \"../../../contract/access\";\nimport type { MaybePromise, Principal } from \"../../types\";\nimport {\n definePolicy,\n levelsById,\n type AccessFilter,\n type AccessPolicy,\n type AnyAccessPolicy,\n type MembershipRead,\n type PolicyReads,\n type PolicyTools,\n type RowLevel,\n} from \"../policy\";\nimport { membershipRead, type MembersOptions } from \"./members\";\n\n/** A membership table a resolver's levels depend on: `{ model, entry, user, level, levels? }`, as `members` takes it. */\nexport type ResolverMembership = MembersOptions;\n\n/** What a resolver's levels depend on: `resolver({ reads })`. Name at least one column or table. */\nexport interface ResolverReads<\n Column extends string = string,\n Membership extends ResolverMembership = ResolverMembership,\n> {\n /**\n * Columns of the service's own model. A tracked write that sets one (or\n * creates or deletes a row) re-checks that row, for every user. `tools.rows`\n * reads them.\n */\n readonly columns?: readonly Column[];\n /**\n * Membership tables, one row per user and row of this service: `entry`\n * holds the id of this service's row, as for `members`. A tracked write to\n * one re-checks that user on that row.\n */\n readonly memberships?: readonly Membership[];\n}\n\n/** Options of {@link resolver}. */\nexport interface ResolverOptions<\n P extends Principal = Principal,\n Column extends string = string,\n Membership extends ResolverMembership = ResolverMembership,\n> {\n /**\n * The principal's level on each of `ids`, as a map or a record by id. An id\n * left out, or given anything but an access level, has no level. Read\n * everything for one call in one query: `ids` holds every row the call asks\n * about. Results are memoized for the request, never kept across requests.\n */\n readonly levelsFor: (\n principal: P,\n ids: readonly string[],\n tools: PolicyTools,\n ) => MaybePromise<ReadonlyMap<string, unknown> | Readonly<Record<string, unknown>>>;\n /**\n * A filter matching exactly the rows on which the principal has at least\n * `level`, or `\"none\"`. Without it, list filters through this policy match\n * no row, and the read/write kit's `reorder` moves none below a\n * service-wide grant.\n */\n readonly where?: (\n principal: P,\n level: AccessLevel,\n tools: PolicyTools,\n ) => MaybePromise<AccessFilter>;\n /**\n * What the levels depend on, so tracked writes re-check what they\n * decided: live rows, collection scopes and change topics.\n * `{ columns, memberships }` names the service's columns and the membership\n * tables `levelsFor` and `where` read; `\"none\"` says nothing a tracked\n * write changes can change a level (the levels come from the principal's\n * grants alone, say). Without it nothing a write does re-checks this\n * policy, and the server says so in development (`resolver-without-reads`).\n */\n readonly reads?: ResolverReads<Column, Membership> | \"none\";\n}\n\n/** The other models and columns the membership tables `M` read: what `defineService` checks. */\nexport type MembershipColumns<M> = M extends {\n readonly model: infer Model extends string;\n readonly entry: infer Entry extends string;\n readonly user: infer User extends string;\n readonly level: infer Level extends string;\n}\n ? { readonly model: Model; readonly columns: Entry | User | Level }\n : never;\n\nconst UNDECLARED = new WeakSet<object>();\n\n/** True for a policy `resolver` made without `reads`: nothing a tracked write does re-checks it. */\nexport function declaresNoReads(policy: AnyAccessPolicy): boolean {\n return UNDECLARED.has(policy);\n}\n\n/** What a resolver with `reads: \"none\"`, or none at all, declares. */\nfunction noReads(): PolicyReads {\n return { columns: [], memberships: [], inherits: [], storage: false };\n}\n\nconst READ_KEYS: readonly string[] = [\"columns\", \"memberships\"];\n\nfunction readsProblem(message: string): never {\n throw new TypeError(`resolver({ reads }): ${message}`);\n}\n\nfunction checkColumns(columns: unknown): readonly string[] {\n if (columns === undefined) {\n return [];\n }\n const valid =\n Array.isArray(columns) &&\n columns.every((column) => typeof column === \"string\" && column.length > 0);\n return valid\n ? Object.freeze([...new Set(columns as string[])])\n : readsProblem(\"columns must be a list of column names\");\n}\n\nfunction checkMemberships(memberships: unknown): readonly MembershipRead[] {\n if (memberships === undefined) {\n return [];\n }\n const valid =\n Array.isArray(memberships) &&\n memberships.every((each) => typeof each === \"object\" && each !== null && !Array.isArray(each));\n if (!valid) {\n readsProblem(\"memberships must be a list of { model, entry, user, level, levels? }\");\n }\n return Object.freeze(\n (memberships as object[]).map((each) =>\n membershipRead(each, () => \"resolver({ reads: { memberships } })\"),\n ),\n );\n}\n\n/**\n * The policy reads `reads` declares, or `undefined` when it declares none.\n * Declared columns and tables make the policy one that reads the database\n * (`storage`): `createDispatcher` then refuses to serve it without a storage\n * adapter, which is where the tables and columns are registered so tracked\n * writes carry their values (`../bindings.ts`; a deleted membership row\n * still says whose it was), and where `tools.rows` reads the columns.\n */\nfunction checkReads(reads: unknown): PolicyReads | undefined {\n if (reads === undefined) {\n return undefined;\n }\n if (reads === \"none\") {\n return noReads();\n }\n if (typeof reads !== \"object\" || reads === null || Array.isArray(reads)) {\n readsProblem('reads must be { columns?, memberships? } or \"none\"');\n }\n const given = reads as Readonly<Record<string, unknown>>;\n const unknownKey = Object.keys(given).find((key) => !READ_KEYS.includes(key));\n if (unknownKey !== undefined) {\n readsProblem(`reads has an unknown key \"${unknownKey}\"; the keys are columns and memberships`);\n }\n const columns = checkColumns(given.columns);\n const memberships = checkMemberships(given.memberships);\n if (columns.length === 0 && memberships.length === 0) {\n readsProblem('name a column or a membership table, or pass \"none\"');\n }\n return { columns, memberships, inherits: [], storage: true };\n}\n\nfunction levelIn(\n levels: ReadonlyMap<string, unknown> | Readonly<Record<string, unknown>>,\n id: string,\n): RowLevel {\n let level: unknown;\n if (levels instanceof Map) {\n level = levels.get(id);\n } else if (Object.hasOwn(levels, id)) {\n level = (levels as Readonly<Record<string, unknown>>)[id];\n }\n return isAccessLevel(level) ? level : null;\n}\n\n/**\n * A policy written in app code: `levelsFor` answers the level per row and\n * `where` the list filter. A resolver's own results are memoized for the\n * request and never cached across requests; what it reads through `tools`\n * is: `tools.rows(ids)` reads `id` and the declared columns in one query,\n * and `tools.memberships(table, userId, ids)` a member's levels, both kept\n * with `cacheMs` and evicted by tracked writes when `reads` declares them.\n *\n * `reads` declares what the levels depend on, so a tracked write to it\n * re-checks the live rows, collection scopes and change topics the policy\n * authorized, as for the other builders: a user removed from a membership\n * table stops receiving the rows it gave them. `defineService` checks the\n * declared columns and tables against the app's database client.\n *\n * @example\n * access: resolver({\n * levelsFor: (principal, ids, tools) => levelsFromMyTables(principal.userId, ids, tools),\n * where: (principal) => ({ visibility: \"public\" }),\n * reads: {\n * columns: [\"visibility\"],\n * memberships: [{ model: \"teamMember\", entry: \"projectId\", user: \"userId\", level: \"role\" }],\n * },\n * }),\n */\nexport function resolver<\n P extends Principal = Principal,\n const Column extends string = never,\n const Membership extends ResolverMembership = never,\n>(\n options: ResolverOptions<P, Column, Membership>,\n): AccessPolicy<Column, MembershipColumns<Membership>> {\n const valid =\n typeof options === \"object\" &&\n options !== null &&\n typeof options.levelsFor === \"function\" &&\n (options.where === undefined || typeof options.where === \"function\");\n if (!valid) {\n throw new TypeError(\n \"resolver({ levelsFor, where?, reads? }): levelsFor and where must be functions\",\n );\n }\n const { levelsFor, where } = options;\n const reads = checkReads(options.reads);\n const policy = definePolicy<AccessPolicy<Column, MembershipColumns<Membership>>>({\n kind: \"resolver\",\n reads: reads ?? noReads(),\n async levelsFor(principal, ids, tools) {\n const levels = await levelsFor(principal as P, ids, tools);\n if (typeof levels !== \"object\" || levels === null) {\n return levelsById(ids, () => null);\n }\n return levelsById(ids, (id) => levelIn(levels, id));\n },\n async accessWhere(principal, level, tools) {\n if (where === undefined) {\n return \"none\";\n }\n const filter: unknown = await where(principal as P, level, tools);\n const isFilter = typeof filter === \"object\" && filter !== null && !Array.isArray(filter);\n return isFilter ? (filter as AccessFilter) : \"none\";\n },\n });\n if (reads === undefined) {\n UNDECLARED.add(policy);\n }\n return policy;\n}\n","// The live collection subscriptions of this process's sockets (RFC 0003\n// sections 4.4 and 7), beside the entity subscriptions of\n// `emit/subscriptions.ts`. Each socket keeps its own on\n// `socket.data.collections`, by room: the scope, and the rows its access is\n// derived from (its anchors). The index finds the sockets an access change\n// can concern by anchor, and the scopes of a collection that have\n// subscribers here. Rooms stay the source of truth for who receives frames.\n// 4.1 kept nothing (4.1 `src/server/collections.ts:141-187`), so it could\n// not revoke a scope a user lost access to.\n\nimport { collectionRoom } from \"../../contract/names\";\nimport type { AccessChange } from \"../access/changes\";\nimport { anchorKey } from \"../access/tools\";\nimport { PendingKeys } from \"../emit/pending\";\nimport { emptyRecords, ownRecord } from \"../emit/subscriptions\";\nimport type { Revision } from \"../../protocol/envelope\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { MAX_SCOPES_PER_SOCKET } from \"../../protocol/version\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport type { PageRequest } from \"./snapshot\";\n\n/** A `qd:col:sub` frame, read. */\nexport interface ScopeRequest extends PageRequest {\n readonly s: string;\n readonly c: string;\n /** The revision the client holds the scope at. */\n readonly since?: Revision;\n}\n\n/** One live collection subscription, as `socket.data.collections[room]` records it. */\nexport interface ScopeSubscription {\n /** The service name. */\n readonly s: string;\n /** The collection name. */\n readonly c: string;\n readonly scope: string;\n /** The rows its access is derived from (`anchorKey`s): the anchor row, then its `inherit` parents. */\n readonly anchors: readonly string[];\n}\n\n/**\n * `socket.data.collections`: a socket's collection subscriptions, by room\n * name. Plain data, in an object without a prototype, read by own keys only.\n */\nexport type ScopeSubscriptions = Record<string, ScopeSubscription>;\n\n/** Told when a scope gains its first subscriber here, and loses its last. */\nexport interface ScopeListener {\n pin(room: string): void;\n unpin(room: string): void;\n}\n\ntype Counts = Map<QuickdrawServerSocket, number>;\n\nfunction serviceOf(anchor: string): string {\n return anchor.slice(0, anchor.indexOf(\"\\u0000\"));\n}\n\nfunction count(index: Map<string, Counts>, key: string, socket: QuickdrawServerSocket, by: 1 | -1) {\n const counts = index.get(key) ?? new Map<QuickdrawServerSocket, number>();\n const next = (counts.get(socket) ?? 0) + by;\n if (next > 0) {\n counts.set(socket, next);\n index.set(key, counts);\n return;\n }\n counts.delete(socket);\n if (counts.size === 0) {\n index.delete(key);\n }\n}\n\n/** The room of a subscription. */\nexport function roomOf(subscription: Pick<ScopeSubscription, \"s\" | \"c\" | \"scope\">): string {\n return collectionRoom(subscription.s, subscription.c, subscription.scope);\n}\n\n/** The key of one collection of one service, among all of a process's collections. */\nexport function groupOf(service: string, collection: string): string {\n return `${service}\\u0000${collection}`;\n}\n\n/** This process's collection subscriptions, indexed by anchor and by collection. */\nexport class ScopeIndex {\n readonly #byAnchor = new Map<string, Counts>();\n readonly #byService = new Map<string, Counts>();\n /** Per collection (`service\\0collection`), how many sockets here subscribe to each scope. */\n readonly #scopes = new Map<string, Map<string, number>>();\n /** Per socket, how many scopes it holds: counted, so checking the cap copies no keys. */\n readonly #sizes = new WeakMap<QuickdrawServerSocket, number>();\n /** The scopes each socket has a `qd:col:sub` in flight for, by room. */\n readonly #pending = new PendingKeys();\n readonly #listener: ScopeListener | undefined;\n\n constructor(listener?: ScopeListener) {\n this.#listener = listener;\n }\n\n #index(socket: QuickdrawServerSocket, subscription: ScopeSubscription, by: 1 | -1): void {\n for (const anchor of subscription.anchors) {\n count(this.#byAnchor, anchor, socket, by);\n count(this.#byService, serviceOf(anchor), socket, by);\n }\n const key = groupOf(subscription.s, subscription.c);\n const scopes = this.#scopes.get(key) ?? new Map<string, number>();\n const next = (scopes.get(subscription.scope) ?? 0) + by;\n if (next > 0) {\n scopes.set(subscription.scope, next);\n this.#scopes.set(key, scopes);\n } else {\n scopes.delete(subscription.scope);\n if (scopes.size === 0) {\n this.#scopes.delete(key);\n }\n }\n if (next === 1 && by === 1) {\n this.#listener?.pin(roomOf(subscription));\n } else if (next === 0) {\n this.#listener?.unpin(roomOf(subscription));\n }\n }\n\n /** The socket's subscription to a scope, by room, or `undefined`. */\n get(socket: QuickdrawServerSocket, room: string): ScopeSubscription | undefined {\n return ownRecord(socket.data.collections, room);\n }\n\n /** Every collection subscription of the socket. */\n entries(socket: QuickdrawServerSocket): ScopeSubscription[] {\n return Object.values(socket.data.collections ?? {});\n }\n\n /** How many scopes the socket holds. */\n size(socket: QuickdrawServerSocket): number {\n return this.#sizes.get(socket) ?? 0;\n }\n\n /**\n * `CONFLICT` when the socket holds `MAX_SCOPES_PER_SOCKET` scopes and\n * `room` is not one of them (the 5.1 audit's COLL-4): a scope held\n * already never counts again.\n */\n checkRoom(socket: QuickdrawServerSocket, room: string): void {\n if (this.get(socket, room) === undefined && this.size(socket) >= MAX_SCOPES_PER_SOCKET) {\n throw new QuickdrawError(\n \"CONFLICT\",\n `A socket may subscribe to at most ${MAX_SCOPES_PER_SOCKET} collection scopes; unsubscribe from one first`,\n );\n }\n }\n\n /** Records a subscription and puts the socket in the scope's room, replacing any earlier one. */\n set(socket: QuickdrawServerSocket, subscription: ScopeSubscription): void {\n const room = roomOf(subscription);\n const previous = this.get(socket, room);\n socket.data.collections ??= emptyRecords();\n socket.data.collections[room] = subscription;\n this.#index(socket, subscription, 1);\n if (previous === undefined) {\n this.#sizes.set(socket, this.size(socket) + 1);\n } else {\n this.#index(socket, previous, -1);\n }\n void socket.join(room);\n }\n\n /** Ends a subscription: the socket leaves the scope's room. Returns what it was. */\n delete(socket: QuickdrawServerSocket, room: string): ScopeSubscription | undefined {\n const previous = this.get(socket, room);\n if (previous === undefined) {\n return undefined;\n }\n const subscriptions = socket.data.collections;\n if (subscriptions !== undefined) {\n delete subscriptions[room];\n }\n this.#sizes.set(socket, this.size(socket) - 1);\n this.#index(socket, previous, -1);\n void socket.leave(room);\n return previous;\n }\n\n /** A `qd:col:sub` of the scope begins; returns how often it was unsubscribed from so far. */\n begin(socket: QuickdrawServerSocket, room: string): number {\n return this.#pending.begin(socket, [room]).get(room) ?? 0;\n }\n\n /** The subscribe `begin` started has ended. */\n end(socket: QuickdrawServerSocket, room: string): void {\n this.#pending.end(socket, [room]);\n }\n\n /** A client unsubscribed: forget its subscription, and stop one still being made from joining. */\n unsubscribe(socket: QuickdrawServerSocket, room: string): void {\n this.#pending.unsubscribed(socket, room);\n this.delete(socket, room);\n }\n\n /** How often the client unsubscribed from the scope while a subscribe of it ran; it joins only if that did not move. */\n unsubscribes(socket: QuickdrawServerSocket, room: string): number {\n return this.#pending.count(socket, room);\n }\n\n /** A socket disconnected: Socket.IO has emptied its rooms; drop it from the index. */\n drop(socket: QuickdrawServerSocket): void {\n for (const subscription of this.entries(socket)) {\n this.#index(socket, subscription, -1);\n }\n socket.data.collections = emptyRecords();\n this.#sizes.delete(socket);\n }\n\n /** The scopes of a collection that sockets of this process subscribe to. */\n scopes(service: string, collection: string): string[] {\n return [...(this.#scopes.get(groupOf(service, collection))?.keys() ?? [])];\n }\n\n /**\n * The subscriptions an access change can concern: those anchored on the\n * changed row (any row of the service when `id` is absent), of the changed\n * user's sockets (every user's when `userId` is absent).\n */\n matching(change: AccessChange): Map<QuickdrawServerSocket, ScopeSubscription[]> {\n const key = change.id === undefined ? undefined : anchorKey(change.service, change.id);\n const sockets =\n key === undefined ? this.#byService.get(change.service) : this.#byAnchor.get(key);\n const found = new Map<QuickdrawServerSocket, ScopeSubscription[]>();\n for (const socket of sockets?.keys() ?? []) {\n if (change.userId !== undefined && socket.data.principal?.userId !== change.userId) {\n continue;\n }\n const entries = this.entries(socket).filter(({ anchors }) =>\n anchors.some((anchor) =>\n key === undefined ? serviceOf(anchor) === change.service : anchor === key,\n ),\n );\n if (entries.length > 0) {\n found.set(socket, entries);\n }\n }\n return found;\n }\n}\n","// The collections of a dispatcher's services, bound to what serves them\n// (RFC 0003 sections 5.1 and 7.1): each anchor resolved to the served service\n// whose policy authorizes its scopes, and the columns that decide membership\n// registered with the storage adapter, so a write reports their values\n// (`before` and `after`) and a write that sets one reads the old value first.\n// Those are the scope column, the `where` columns, and a `via` junction's\n// entry and scope columns: every other write cannot move a row between\n// scopes, and costs no extra read. Order columns are not registered: no\n// collection change depends on their old values.\n\nimport type { Hub } from \"../emit/hub\";\nimport type { Registry } from \"../registry\";\nimport type { AnyService } from \"../service\";\nimport { modelKey, type StorageAdapter } from \"../storage\";\nimport type { WriteRecord } from \"../uow/types\";\nimport { createDeltaBuffer, type DeltaBuffer } from \"./buffer\";\nimport type { ServiceCollection } from \"./define\";\nimport type { FlushMoves } from \"./moves\";\nimport { ScopeIndex } from \"./scopes\";\n\n/** A collection of a served service, with its anchor's service. */\nexport interface BoundCollection extends ServiceCollection {\n /** The service the collection is a member of. */\n readonly service: AnyService;\n /** The service's model, as the client names it. */\n readonly model: string;\n /** The service whose policy authorizes the scopes; `undefined` for a `\"self\"` scope. */\n readonly anchorService: AnyService | undefined;\n}\n\n/** How writes find collections. */\nexport interface CollectionRoutes {\n /** The collections whose items are rows of each model. */\n readonly byModel: ReadonlyMap<string, readonly BoundCollection[]>;\n /** The `via` collections whose junction is each model. */\n readonly byJunction: ReadonlyMap<string, readonly BoundCollection[]>;\n /** The collections anchored on a service of each model: deleting such a row closes their scopes. */\n readonly byAnchorModel: ReadonlyMap<string, readonly BoundCollection[]>;\n /** The collection `name` of service `service`. */\n find(service: string, name: string): BoundCollection | undefined;\n}\n\n/** What a dispatcher keeps for its collections. */\nexport interface CollectionState {\n readonly routes: CollectionRoutes;\n readonly scopes: ScopeIndex;\n readonly buffer: DeltaBuffer;\n /** Each flush's moves, found once for the collection and topic sinks. */\n readonly moves: FlushMoves;\n}\n\n/** A dispatcher's live data with its collections: the same hub object, so the server it attaches is shared. */\nexport interface CollectionHub extends Hub {\n readonly collections: CollectionState;\n}\n\nfunction fail(message: string): never {\n throw new TypeError(`createDispatcher: ${message}`);\n}\n\nfunction anchorOf(\n registry: Registry,\n service: AnyService,\n collection: ServiceCollection,\n): AnyService | undefined {\n const { anchor } = collection;\n if (anchor === undefined) {\n return undefined;\n }\n const owner = `${service.name}.${collection.name}`;\n const target = registry.services.get(anchor.name);\n if (target === undefined) {\n fail(`${owner} is anchored on ${anchor.name}, which this dispatcher does not serve`);\n }\n if (target.model === undefined || target.access === undefined) {\n fail(\n `${owner} is anchored on ${target.name}, which declares no model and access policy to authorize its scopes with`,\n );\n }\n return target;\n}\n\nfunction add(\n index: Map<string, BoundCollection[]>,\n model: string,\n collection: BoundCollection,\n): void {\n index.set(model, [...(index.get(model) ?? []), collection]);\n}\n\n/**\n * Registers the columns that decide membership: the scope column or\n * junction, and the `where` columns; and a `via` collection's junction as\n * its entries' links, which a delete of an entry reads first\n * (`registerLinks`).\n */\nfunction registerInterest(storage: StorageAdapter | undefined, bound: BoundCollection): void {\n const { scope } = bound;\n const where = Object.keys(bound.where);\n if (scope.kind === \"column\") {\n storage?.registerInterest(bound.model, [scope.column, ...where]);\n return;\n }\n const roles = (scope.levels ?? []).map((rule) => rule.column);\n storage?.registerInterest(modelKey(scope.model), [scope.entry, scope.scope, ...roles]);\n storage?.registerLinks?.(bound.model, {\n model: modelKey(scope.model),\n entry: scope.entry,\n columns: [scope.scope, ...roles],\n });\n if (where.length > 0) {\n storage?.registerInterest(bound.model, where);\n }\n}\n\n/**\n * The routes of `registry`'s collections. Registers their membership columns\n * with the storage adapter. Throws a `TypeError` for an anchor this\n * dispatcher cannot authorize a scope through.\n */\nexport function bindCollections(\n registry: Registry,\n storage: StorageAdapter | undefined,\n): CollectionRoutes {\n const byModel = new Map<string, BoundCollection[]>();\n const byJunction = new Map<string, BoundCollection[]>();\n const byAnchorModel = new Map<string, BoundCollection[]>();\n const byName = new Map<string, BoundCollection>();\n for (const service of registry.services.values()) {\n for (const collection of service.collections.values()) {\n if (service.model === undefined) {\n continue;\n }\n const anchorService = anchorOf(registry, service, collection);\n const bound: BoundCollection = Object.freeze({\n ...collection,\n service,\n model: modelKey(service.model),\n anchorService,\n });\n byName.set(`${service.name}\\u0000${collection.name}`, bound);\n add(byModel, bound.model, bound);\n if (bound.scope.kind === \"via\") {\n add(byJunction, modelKey(bound.scope.model), bound);\n }\n if (anchorService?.model !== undefined) {\n add(byAnchorModel, modelKey(anchorService.model), bound);\n }\n registerInterest(storage, bound);\n }\n }\n return Object.freeze({\n byModel,\n byJunction,\n byAnchorModel,\n find: (service: string, name: string) => byName.get(`${service}\\u0000${name}`),\n });\n}\n\n/**\n * The scopes keyed by each row `writes` deleted that collections are\n * anchored on, with their collections: deleting a chat closes its messages'\n * scope (RFC 0003 section 7.2).\n */\nexport function anchoredScopes(\n routes: CollectionRoutes,\n writes: readonly WriteRecord[],\n): (readonly [BoundCollection, string])[] {\n const scopes: (readonly [BoundCollection, string])[] = [];\n for (const write of writes) {\n const anchored = routes.byAnchorModel.get(modelKey(write.model));\n if (write.op !== \"delete\" || anchored === undefined) {\n continue;\n }\n for (const collection of anchored) {\n scopes.push([collection, write.id]);\n }\n }\n return scopes;\n}\n\n/** The collection state of a dispatcher: its routes, its subscriptions and its resume buffer. */\nexport function createCollectionState(\n registry: Registry,\n storage: StorageAdapter | undefined,\n): CollectionState {\n const buffer = createDeltaBuffer();\n return {\n routes: bindCollections(registry, storage),\n scopes: new ScopeIndex(buffer),\n buffer,\n moves: new WeakMap(),\n };\n}\n","// Entity frames (RFC 0003 section 6), all on the event `qd:e`:\n//\n// | Write | Frame | Payload |\n// |--------------------------------------------------------|-------|---------------------|\n// | delete | `r` | none |\n// | create | `u` | the full projection |\n// | update of plain projection fields only (no `map`) | `p` | the changed fields |\n// | any other update: unknown fields (a touch, `affects`), | `u` | the full projection |\n// | a field outside the projection, a projection with `map`| | |\n//\n// A create is never a patch: a patch of a row the client never had could not\n// be applied. A patch also carries the service's `versionColumn` when the\n// projection has it, since tracked writes do not report `@updatedAt` columns.\n// Every frame of a flush carries the flush's revision.\n\nimport type { EntityFrame, Revision } from \"../../protocol/envelope\";\nimport type { StorageRow } from \"../storage\";\nimport { ANY_FIELD } from \"../uow/types\";\nimport type { Touch } from \"./affects\";\nimport { pickKeys, projectRow, type Projection } from \"./projection\";\n\n/** How a touched row goes out: whole, as a patch of `fields`, or as a removal. */\nexport type FrameKind =\n | { readonly t: \"u\" }\n | { readonly t: \"p\"; readonly fields: readonly string[] }\n | { readonly t: \"r\" };\n\nconst WHOLE: FrameKind = Object.freeze({ t: \"u\" });\n\nconst REMOVED: FrameKind = Object.freeze({ t: \"r\" });\n\n/** The frame a row's touch makes; see the table above. */\nexport function frameKind(\n projection: Projection,\n touch: Touch,\n versionColumn: string | undefined,\n): FrameKind {\n if (touch.op === \"delete\") {\n return REMOVED;\n }\n const { fields } = touch;\n const plain =\n touch.op === \"update\" &&\n projection.map === undefined &&\n fields.length > 0 &&\n !fields.includes(ANY_FIELD) &&\n fields.every((field) => projection.keys.includes(field));\n if (!plain) {\n return WHOLE;\n }\n const patched = new Set(fields);\n if (versionColumn !== undefined && projection.keys.includes(versionColumn)) {\n patched.add(versionColumn);\n }\n patched.delete(\"id\");\n return patched.size === 0 ? WHOLE : { t: \"p\", fields: [...patched] };\n}\n\n/**\n * What one read of a flush's rows selects: the projection's own select when\n * any row goes out whole, and only the patched fields when every row is a\n * patch, so a row is read no wider than what is sent.\n */\nexport function selectFor(\n projection: Projection,\n kinds: readonly FrameKind[],\n): Readonly<Record<string, unknown>> {\n if (kinds.some((kind) => kind.t === \"u\")) {\n return projection.select;\n }\n const select: Record<string, true> = { id: true };\n for (const kind of kinds) {\n if (kind.t === \"p\") {\n for (const field of kind.fields) {\n select[field] = true;\n }\n }\n }\n return select;\n}\n\n/** The frame of one row, before tiers are stripped: `row` is the row read, absent for a removal. */\nexport function buildFrame(\n service: string,\n id: string,\n kind: FrameKind,\n row: StorageRow | undefined,\n rev: Revision,\n projection: Projection,\n): EntityFrame | undefined {\n if (kind.t === \"r\") {\n return { t: \"r\", s: service, id, rev };\n }\n if (row === undefined) {\n return undefined;\n }\n if (kind.t === \"p\") {\n return { t: \"p\", s: service, id, rev, d: pickKeys(row, kind.fields) };\n }\n return { t: \"u\", s: service, id, rev, d: projectRow(projection, row) };\n}\n","// A flush's deltas per scope (RFC 0003 section 7.2): every move of the flush\n// that concerns a scope, in the order the rows were first written, batched\n// into the one frame the scope gets for the flush. More rows than the\n// collection's `bulkThreshold` for one scope make that frame a single\n// `reset`, read nothing, and let its clients load the scope again. 4.1 sent\n// one event per row per scope (4.1 `src/server/collections.ts:338-352`)\n// and left bulk writes to a hand-written `emitReset`.\n//\n// Items come from rows the moves already read, or from one read for the\n// rest, with the item's select (only the patched fields when every delta is\n// a patch). A row read as missing was deleted since: its own flush removes\n// it, so its `added` or `updated` is dropped here.\n//\n// In a collection that declares `index`, an `added` delta also carries its\n// member's index row, built from the item it sends (`index.ts`), with the\n// service's `versionColumn` read alongside the item for the row's `rev`.\n//\n// Behind a cluster adapter (`cluster`) a change that would be `patched` goes\n// out `updated`, with the whole item: frames from two nodes can reach a\n// client out of revision order, and a patch it dropped as older would lose\n// its fields. One that would be dropped as empty is still dropped.\n//\n// A delta is also decided by its row as read for the frame, not by the\n// write's own values alone. A flush takes its revision when it flushes,\n// after its handler settled and (behind a cluster) once the counter\n// answered, so a write that committed first can flush last: its rows may\n// have moved since. Behind a cluster adapter every delta is decided so: a\n// move out of a scope, or a delete, then carries a higher revision than a\n// later move back in, or a later create of its id, and a client would apply\n// it over them. The read is made after the flush took its revision, so it\n// sees every write whose flush took a lower one: a row in the scope at the\n// read goes out (`removed` becomes `updated`, or `added` for a row that left\n// scopes nobody could name), and one that is not there is `removed`. Every\n// frame a scope gets about a row is then right as of a read made after its\n// revision, and the newest one wins on the client. The rows of `removed`\n// deltas are read for it, with the membership columns.\n//\n// One server decides every delta of a column scope that is not a removal\n// the same way, by its row as read with the membership columns (the 5.1\n// audit's COLL-2: a flush that ran behind a slow handler tail, or waited in\n// a busy queue, sent a moved row's new values to the scope it left). It\n// keeps its cheaper rule for removals (no read): a write that commits first\n// and flushes last can still leave a client without a member there until\n// the row's next write.\n//\n// A self scope that follows its service's policy has its deltas checked\n// for its user before anything is read (`selfAccess.ts`): a row the user may\n// not read is a `denied` removal, whose row is never read, and which no\n// read-time decision turns back into an item.\n\nimport { collectionRoom } from \"../../contract/names\";\nimport type { CollectionDelta, Revision } from \"../../protocol/envelope\";\nimport { selectFor, type FrameKind } from \"../emit/frames\";\nimport type { StorageAdapter, StorageRow } from \"../storage\";\nimport type { BoundCollection } from \"./bind\";\nimport { indexColumns, indexRowFrom } from \"./index\";\nimport { itemOf, membershipColumns, patchOf, scopeIn, selectWith } from \"./items\";\nimport type { Moves } from \"./moves\";\n\n/** A delta whose item is not read yet. */\ntype Pending =\n | { readonly t: \"added\" | \"updated\"; readonly id: string }\n | {\n readonly t: \"removed\";\n readonly id: string;\n /** The row left scopes nobody could name: this scope may never have held it. */\n readonly unnamed?: true;\n /** Its scope's user may not read the row (`selfAccess.ts`): nothing turns it back into an item. */\n readonly denied?: true;\n }\n | { readonly t: \"patched\"; readonly id: string; readonly fields: readonly string[] };\n\n/** What one scope gets from one flush. */\nexport interface ScopePlan {\n readonly scope: string;\n readonly room: string;\n readonly deltas: Pending[];\n /** Too many rows changed, or junction rows went unseen: one `reset` instead. */\n reset: boolean;\n}\n\n/**\n * The plan of every scope the moves concern, in the order rows were first\n * written. `subscribed` are the collection's scopes with subscribers on this\n * process: a row that left scopes nobody can name is removed from them.\n */\nexport function planScopes(\n collection: BoundCollection,\n moves: Moves,\n subscribed: readonly string[],\n): ScopePlan[] {\n const plans = new Map<string, ScopePlan>();\n const planOf = (scope: string): ScopePlan => {\n let plan = plans.get(scope);\n if (plan === undefined) {\n const room = collectionRoom(collection.service.name, collection.name, scope);\n plan = { scope, room, deltas: [], reset: false };\n plans.set(scope, plan);\n }\n return plan;\n };\n for (const move of moves.moves) {\n const { id, kind } = move;\n for (const scope of move.left) {\n planOf(scope).deltas.push({ t: \"removed\", id });\n }\n for (const scope of move.entered) {\n planOf(scope).deltas.push({ t: \"added\", id });\n }\n for (const scope of move.stayed) {\n planOf(scope).deltas.push(\n kind.t === \"p\" ? { t: \"patched\", id, fields: kind.fields } : { t: \"updated\", id },\n );\n }\n const named = new Set([...move.left, ...move.entered, ...move.stayed]);\n for (const scope of move.unknownLeft ? subscribed : []) {\n if (!named.has(scope)) {\n planOf(scope).deltas.push({ t: \"removed\", id, unnamed: true });\n }\n }\n }\n for (const scope of moves.resetAll ? subscribed : []) {\n planOf(scope).reset = true;\n }\n for (const plan of plans.values()) {\n plan.reset ||= plan.deltas.length > collection.bulkThreshold;\n }\n return [...plans.values()];\n}\n\nconst WHOLE: FrameKind = Object.freeze({ t: \"u\" });\n\n/**\n * True when a delta needs no row read: its row was read already, or it is a\n * removal (behind a cluster adapter, a `denied` one only).\n */\nfunction readsNothing(\n delta: Pending,\n read: ReadonlyMap<string, StorageRow>,\n cluster: boolean,\n): boolean {\n return read.has(delta.id) || (delta.t === \"removed\" && (!cluster || delta.denied === true));\n}\n\n/**\n * The rows the plans' deltas take items from: those the moves read, and one\n * read for the others, with the membership columns of a column scope so its\n * deltas are decided at the read (`buildDeltas`). Behind a cluster adapter\n * (`cluster`) every change reads its whole item, and the rows of `removed`\n * deltas and of `also` are read too, with the membership columns.\n */\nexport async function readItems(\n storage: StorageAdapter,\n collection: BoundCollection,\n plans: readonly ScopePlan[],\n read: ReadonlyMap<string, StorageRow>,\n cluster = false,\n also: readonly string[] = [],\n): Promise<ReadonlyMap<string, StorageRow>> {\n const kinds = new Map<string, FrameKind>();\n for (const plan of plans.filter(({ reset }) => !reset)) {\n for (const delta of plan.deltas) {\n if (readsNothing(delta, read, cluster)) {\n continue;\n }\n const item = cluster || delta.t !== \"patched\" || kinds.get(delta.id)?.t === \"u\";\n kinds.set(delta.id, item ? WHOLE : { t: \"p\", fields: delta.fields });\n }\n }\n for (const id of cluster ? also : []) {\n if (!read.has(id)) {\n kinds.set(id, WHOLE);\n }\n }\n if (kinds.size === 0) {\n return read;\n }\n const select = selectFor(collection.item, [...kinds.values()]);\n const whole = [...kinds.values()].some((kind) => kind.t === \"u\");\n const decides = cluster || collection.scope.kind === \"column\";\n const columns = [\n ...(whole ? indexColumns(collection) : []),\n ...(decides ? membershipColumns(collection) : []),\n ];\n const rows = await storage.findMany(collection.model, {\n where: { id: { in: [...kinds.keys()] } },\n select: selectWith(select, columns),\n });\n const all = new Map(read);\n for (const row of rows) {\n if (typeof row.id === \"string\") {\n all.set(row.id, row);\n }\n }\n return all;\n}\n\n/** An `added` delta: the member's item, and in an indexed collection its index row, built from that item. */\nfunction added(collection: BoundCollection, row: StorageRow, rev: Revision): CollectionDelta {\n const item = itemOf(collection, row);\n return collection.index === undefined\n ? { t: \"added\", item }\n : { t: \"added\", item, index: indexRowFrom(collection, item, row, rev) };\n}\n\n/**\n * A pending delta of `scope` as the row read for the frame decides it\n * (`row` absent: the row is gone; `decidedByRow` says when it applies). In a column-scoped\n * collection a row not in the scope at the read is `removed`, and one in it\n * is not: a removal becomes `updated` (`added` for a row that left scopes\n * nobody could name, which this scope may never have held). A `via` scope's\n * links were already read at flush time (`moves.ts`), so there only a row\n * gone since is `removed`. A removal its scope's user may not read\n * (`denied`) stays a removal.\n */\nfunction decided(\n collection: BoundCollection,\n scope: string,\n pending: Pending,\n row: StorageRow | undefined,\n): Pending {\n if (pending.t === \"removed\" && pending.denied === true) {\n return pending;\n }\n if (collection.scope.kind !== \"column\") {\n return row === undefined && pending.t !== \"removed\"\n ? { t: \"removed\", id: pending.id }\n : pending;\n }\n if (row === undefined || scopeIn(collection, row) !== scope) {\n return pending.t === \"removed\" ? pending : { t: \"removed\", id: pending.id };\n }\n if (pending.t !== \"removed\") {\n return pending;\n }\n return { t: pending.unnamed === true ? \"added\" : \"updated\", id: pending.id };\n}\n\n/**\n * True when a pending delta is decided by its row as read (`decided`):\n * behind a cluster adapter every one; on one server one of a column scope\n * that is not a removal and whose row was read (a row read as missing keeps\n * its rule: it is dropped, and its own flush removes it).\n */\nfunction decidedByRow(\n collection: BoundCollection,\n pending: Pending,\n row: StorageRow | undefined,\n cluster: boolean,\n): boolean {\n return (\n cluster || (row !== undefined && pending.t !== \"removed\" && collection.scope.kind === \"column\")\n );\n}\n\n/**\n * The deltas of one scope's frame for the flush at `rev`, from its plan and\n * the rows read. A delta is decided by its row as read where\n * `decidedByRow` says so; behind a cluster adapter (`cluster`) one goes out\n * `updated`, whole, where a patch would go.\n */\nexport function buildDeltas(\n collection: BoundCollection,\n plan: ScopePlan,\n rows: ReadonlyMap<string, StorageRow>,\n rev: Revision,\n cluster = false,\n): CollectionDelta[] {\n if (plan.reset) {\n return [{ t: \"reset\" }];\n }\n const deltas: CollectionDelta[] = [];\n for (const pending of plan.deltas) {\n const row = rows.get(pending.id);\n const delta = decidedByRow(collection, pending, row, cluster)\n ? decided(collection, plan.scope, pending, row)\n : pending;\n if (delta.t === \"removed\") {\n deltas.push({ t: \"removed\", id: delta.id });\n continue;\n }\n if (row === undefined) {\n continue;\n }\n if (delta.t === \"patched\") {\n const d = patchOf(collection, row, delta.fields);\n if (Object.keys(d).length > 0) {\n deltas.push(\n cluster\n ? { t: \"updated\", item: itemOf(collection, row) }\n : { t: \"patched\", id: delta.id, d },\n );\n }\n continue;\n }\n deltas.push(\n delta.t === \"added\"\n ? added(collection, row, rev)\n : { t: \"updated\", item: itemOf(collection, row) },\n );\n }\n return deltas;\n}\n","// Which scopes a flush moved each row out of, into, or changed it in (RFC\n// 0003 section 7.2). Membership is declared, so it is read from the values a\n// write reports for the registered membership columns (`bind.ts`): a scope\n// before the write and a scope after it. The rules, ported from 4.1's\n// `notifyOne` (4.1 `src/server/collections.ts:220-270`), which compared\n// `resolveScopeId` before and after on full rows it read first:\n//\n// | Write | Before | After |\n// |--------------------------------|---------------------------|----------------|\n// | create | none | its values |\n// | create of a row the same unit | the deleted row's values | its values |\n// | deleted first (`before`) | (`before`) | |\n// | update | its old values (`before`, | its values |\n// | | over the new ones) | |\n// | delete | its old values | none |\n// | touch (`ctx.touch`) | unknown: none | read |\n// | touch merged with a tracked | the tracked write's old | its values, or |\n// | write that carried `before` | values (`before`) | read |\n// | an `affects` hop | the same as after | read |\n// | `via` junction create / delete | the entry's links without | its links now |\n// | | this flush's, with the | (read) |\n// | | ones it removed | |\n// | `via` entry created or touched | the same (its links | its links now |\n// | | before this flush) | (read) |\n// | `via` entry deleted, its links | the links its delete read | none |\n// | read first (`links`) | (those that counted) | |\n// | `via` junction row created | the deleted row's link, | its link, if |\n// | over one the unit deleted | if it counted | it counts |\n// | `via` junction role update | the old link, if its role | the new link, |\n// | (a `members` table) | counted | if it counts |\n// | `via` junction row written | its link read now, if it | its link read |\n// | without its values (a touch) | does not count now | now, if it |\n// | | (or the old values' link) | counts |\n//\n// A `via` scope over the item service's own `members` table counts only the\n// links whose role gives at least the collection's `access` (`define.ts`):\n// a junction row below it links nothing, and every link read asks for such\n// a role. A write of a role column that changes whether the row's link\n// counts is a move like one of the entry or scope columns; a change between\n// two roles that both count, or both do not, moves nothing and reads\n// nothing. The members policy registers the role as interest, so a write\n// carries the old role. A junction row written without the values that\n// place its link is read, role and all: below the rules, its link is\n// removed, unless its old values say it never counted (a `removed` of a row\n// a client never had changes nothing there).\n//\n// Left gives `removed`, entered `added` with the full item (never a patch: a\n// client cannot patch a row it never had), stayed `patched` or `updated` as\n// entity frames decide (`emit/frames.ts`); a row created again in the same\n// scope is `updated`, whole. A touched row's old scope is unknown, so it is\n// `added` to its scope now and its old scope is not told (a touch carries no\n// `before`), unless a tracked write merged with it says where it was: then\n// it moves, or stays `updated`, whole. A deleted `via` entry left the\n// scopes its delete read its links in (the tracked client reads them before\n// a delete of a via entry model: `registerLinks`), so only those are told\n// (the 5.1 audit's COLL-3: every subscribed scope learned the id of every\n// row deleted). A deleted row whose old scope the write does not carry (a\n// touch with `removed`, a `via` entry deleted without its links read) left\n// scopes nobody can name: every scope of the collection subscribed on this\n// process gets `removed`, which no resume buffer keeps (`send.ts`).\n//\n// A `via` entry's scopes before the flush are known whatever wrote the\n// entry: its links now, without the ones this flush's junction writes made,\n// with the ones they removed. So an entry created or touched (an `upsert`\n// that may have updated it is recorded as a create) is `added`, whole, to\n// every scope it is in now (a client upserts it where it already was, which\n// also covers links an untracked write made), and `removed` from the scopes\n// this flush's junction writes took it out of: a touch beside the removal of\n// a member's link no longer leaves the chat in that member's list.\n//\n// A `via` collection whose item reads the junction (`via`'s `refreshEntry`,\n// a member count) also sends every entry a junction write named again,\n// whole, to the scopes it stayed in: the count changed there too.\n//\n// Behind a cluster adapter (`current`) a write that committed first can\n// flush last (`deltas.ts`), so membership comes from what is read at flush\n// time: a column-scoped row's deltas are decided by its row read for the\n// frame (`deltas.ts`), and a `via` entry's links are read here anyway, so a\n// deleted entry linked to scopes again at that read (its id created again\n// by a write whose flush went first) stays in them, whole.\n\nimport { frameKind, type FrameKind } from \"../emit/frames\";\nimport { modelKey, type StorageAdapter, type StorageRow } from \"../storage\";\nimport { ANY_FIELD, type WriteRecord } from \"../uow/types\";\nimport type { BoundCollection } from \"./bind\";\nimport { linkQualifies, linkWhere, type ViaCollectionScope } from \"./define\";\nimport { indexColumns } from \"./index\";\nimport { matchesWhere, membershipColumns, scopeIn, selectWith } from \"./items\";\n\ntype Values = Readonly<Record<string, unknown>>;\n\ntype Via = ViaCollectionScope;\n\n/** What one flush did to one row of one collection. */\nexport interface Move {\n readonly id: string;\n /** Scopes it left: `removed`. */\n readonly left: readonly string[];\n /** Scopes it entered: `added`, with the full item. */\n readonly entered: readonly string[];\n /** Scopes it stayed in and changed in: `patched` or `updated`. */\n readonly stayed: readonly string[];\n /** How it goes out to the scopes it stayed in. */\n readonly kind: FrameKind;\n /** It left scopes the flush cannot name: every scope subscribed here gets `removed`. */\n readonly unknownLeft: boolean;\n}\n\n/** The moves of one flush in one collection, and the rows read to find them. */\nexport interface Moves {\n readonly moves: readonly Move[];\n /** Rows read with the item's select, by id; deltas take their items from them. */\n readonly rows: ReadonlyMap<string, StorageRow>;\n /** Junction rows were removed without values: every scope subscribed here gets `reset`. */\n readonly resetAll: boolean;\n}\n\nconst WHOLE: FrameKind = Object.freeze({ t: \"u\" });\n\nconst NONE: ReadonlySet<string> = Object.freeze(new Set<string>());\n\nfunction moveOf(\n id: string,\n before: ReadonlySet<string>,\n after: ReadonlySet<string>,\n kind: FrameKind | undefined,\n unknownLeft = false,\n): Move {\n return {\n id,\n left: [...before].filter((scope) => !after.has(scope)),\n entered: [...after].filter((scope) => !before.has(scope)),\n stayed: kind === undefined ? [] : [...after].filter((scope) => before.has(scope)),\n kind: kind ?? WHOLE,\n unknownLeft,\n };\n}\n\n/**\n * The move of a row the write took out of `before` (and put in `after`), as\n * the scopes it is in at the flush's read (`now`) decide it: it leaves every\n * scope the write named that it is not in now, and goes out whole to the\n * ones it is in now.\n */\nfunction movedTo(\n id: string,\n before: ReadonlySet<string>,\n after: ReadonlySet<string>,\n now: ReadonlySet<string>,\n unknownLeft: boolean,\n): Move {\n const named = new Set([...before, ...after]);\n return {\n id,\n left: [...named].filter((scope) => !now.has(scope)),\n entered: [...now].filter((scope) => !before.has(scope)),\n stayed: [...now].filter((scope) => before.has(scope)),\n kind: WHOLE,\n unknownLeft,\n };\n}\n\nfunction isEmpty(move: Move): boolean {\n return (\n move.left.length === 0 &&\n move.entered.length === 0 &&\n move.stayed.length === 0 &&\n !move.unknownLeft\n );\n}\n\nfunction setOf(scope: string | null | undefined): ReadonlySet<string> {\n return typeof scope === \"string\" ? new Set([scope]) : NONE;\n}\n\n/**\n * Reads rows of the collection's model with the item's select, the\n * membership columns, and the version column an indexed collection's index\n * rows take their `rev` from.\n */\nasync function readRows(\n storage: StorageAdapter,\n collection: BoundCollection,\n ids: readonly string[],\n): Promise<Map<string, StorageRow>> {\n if (ids.length === 0) {\n return new Map();\n }\n const rows = await storage.findMany(collection.model, {\n where: { id: { in: [...ids] } },\n select: selectWith(collection.item.select, [\n ...membershipColumns(collection),\n ...indexColumns(collection),\n ]),\n });\n return new Map(rows.flatMap((row) => (typeof row.id === \"string\" ? [[row.id, row]] : [])));\n}\n\n/** A column-scoped row's move, or `undefined` while its write lacks the values that decide it and no row was read. */\nfunction columnMove(\n collection: BoundCollection,\n write: WriteRecord,\n current: StorageRow | undefined,\n): Move | undefined {\n if (write.op === \"delete\") {\n const before = scopeIn(collection, write.before);\n return moveOf(write.id, setOf(before), NONE, undefined, before === undefined);\n }\n const values =\n scopeIn(collection, write.after) === undefined ? current : (write.after ?? current);\n const after = scopeIn(collection, values);\n if (after === undefined) {\n return undefined;\n }\n const whole = write.op === \"create\" || write.fields.includes(ANY_FIELD);\n if (whole && write.before !== undefined) {\n // Its old scope is known after all: deleted and created again in one unit,\n // or a tracked move merged with a touch. It moved from there, and goes out whole.\n const before = scopeIn(collection, { ...values, ...write.before });\n return moveOf(write.id, setOf(before), setOf(after), WHOLE);\n }\n if (whole) {\n return moveOf(write.id, NONE, setOf(after), undefined);\n }\n const before = scopeIn(collection, { ...values, ...write.before });\n const kind = frameKind(collection.item, write, collection.service.versionColumn);\n return moveOf(write.id, setOf(before), setOf(after), kind);\n}\n\n/** The moves of a column-scoped collection: `refresh` holds rows only an `affects` hop touched. */\nexport async function columnMoves(\n storage: StorageAdapter,\n collection: BoundCollection,\n writes: readonly WriteRecord[],\n refresh: readonly string[],\n): Promise<Moves> {\n const own = writes.filter((write) => modelKey(write.model) === collection.model);\n const known = own.map((write) => columnMove(collection, write, undefined));\n const unresolved = own.filter((_, index) => known[index] === undefined).map(({ id }) => id);\n const rows = await readRows(storage, collection, [...unresolved, ...refresh]);\n const moves: Move[] = [];\n for (const [index, write] of own.entries()) {\n // A row read as missing was deleted since: its own flush removes it.\n const move = known[index] ?? columnMove(collection, write, rows.get(write.id));\n if (move !== undefined) {\n moves.push(move);\n }\n }\n for (const id of refresh) {\n const scope = setOf(scopeIn(collection, rows.get(id)));\n moves.push(moveOf(id, scope, scope, WHOLE));\n }\n return { moves: moves.filter((move) => !isEmpty(move)), rows, resetAll: false };\n}\n\n/** The links a junction write made and removed, by entry. */\ninterface LinkEvents {\n readonly linked: Map<string, Set<string>>;\n readonly unlinked: Map<string, Set<string>>;\n /** Every entry a junction write named, whatever it changed: `refreshEntry` sends them again. */\n readonly named: Set<string>;\n /** Junction rows whose link the write does not carry: read them. */\n readonly unknown: WriteRecord[];\n /** A junction row was removed without values. */\n resetAll: boolean;\n}\n\nfunction linkOf(via: Via, values: Values | undefined): readonly [string, string] | undefined {\n const entry = values?.[via.entry];\n const scope = values?.[via.scope];\n const valid = typeof entry === \"string\" && entry !== \"\" && typeof scope === \"string\";\n return valid && scope !== \"\" ? [entry, scope] : undefined;\n}\n\nfunction addLink(\n links: Map<string, Set<string>>,\n link: readonly [string, string] | undefined,\n): void {\n if (link !== undefined) {\n links.set(link[0], new Set([...(links.get(link[0]) ?? []), link[1]]));\n }\n}\n\n/**\n * True when a write of a role column changed whether the junction row's\n * link counts under the scope's rules, or its old role is not known.\n */\nfunction roleMoved(via: Via, write: WriteRecord): boolean {\n const { before } = write;\n const written = (via.levels ?? []).filter((rule) => write.fields.includes(rule.column));\n if (written.length === 0) {\n return false;\n }\n if (before === undefined || written.some((rule) => !Object.hasOwn(before, rule.column))) {\n return true;\n }\n return linkQualifies(via, { ...write.after, ...before }) !== linkQualifies(via, write.after);\n}\n\n/**\n * True when a write may have moved a junction row's link: a create over a\n * row the same unit deleted (it carries that row's values), or an update of\n * its entry, its scope, or a role whose rules now count it differently.\n */\nfunction linkMoved(via: Via, write: WriteRecord): boolean {\n if (write.op === \"create\") {\n return write.before !== undefined;\n }\n return (\n write.fields.some((field) => field === via.entry || field === via.scope) ||\n roleMoved(via, write)\n );\n}\n\nfunction nameLink(events: LinkEvents, link: readonly [string, string] | undefined): void {\n if (link !== undefined) {\n events.named.add(link[0]);\n }\n}\n\n/** Removes the link a junction row's values before a write made, unless its role never counted. */\nfunction unlinkOld(events: LinkEvents, via: Via, before: Values): void {\n const old = linkOf(via, before);\n // A link below the role rules was never one; without its role, it is removed to be safe.\n if (linkQualifies(via, before) !== false) {\n addLink(events.unlinked, old);\n }\n nameLink(events, old);\n}\n\nfunction linkEvents(via: Via, writes: readonly WriteRecord[]): LinkEvents {\n const events: LinkEvents = {\n linked: new Map(),\n unlinked: new Map(),\n named: new Set(),\n unknown: [],\n resetAll: false,\n };\n for (const write of writes) {\n if (write.op === \"delete\") {\n unlinkOld(events, via, write.before ?? {});\n events.resetAll ||= linkOf(via, write.before) === undefined;\n continue;\n }\n const now = linkOf(via, write.after);\n const counts = linkQualifies(via, write.after);\n // Values missing (its link, or a role the rules need): the row is read instead.\n if (now === undefined || counts === undefined || write.fields.includes(ANY_FIELD)) {\n events.unknown.push(write);\n continue;\n }\n nameLink(events, now);\n const moved = linkMoved(via, write);\n if ((write.op === \"create\" || moved) && counts) {\n addLink(events.linked, now);\n }\n if (moved) {\n unlinkOld(events, via, { ...write.after, ...write.before });\n }\n }\n return events;\n}\n\n/**\n * Reads the junction rows written without the values that place their link\n * (a touch, a batch write that reported none), role and all: a link the\n * rules count is linked; one they do not is removed, unless the write's old\n * values say it never counted. Old values a merged tracked write carried\n * name the link the row left.\n */\nasync function readUnknown(storage: StorageAdapter, via: Via, events: LinkEvents): Promise<void> {\n if (events.unknown.length === 0) {\n return;\n }\n const writes = new Map(events.unknown.map((write) => [write.id, write]));\n const roles = (via.levels ?? []).map((rule) => [rule.column, true] as const);\n const rows = await storage.findMany(modelKey(via.model), {\n where: { id: { in: [...writes.keys()] } },\n select: { id: true, [via.entry]: true, [via.scope]: true, ...Object.fromEntries(roles) },\n });\n for (const row of rows) {\n const now = linkOf(via, row);\n const before = typeof row.id === \"string\" ? writes.get(row.id)?.before : undefined;\n nameLink(events, now);\n const counts = linkQualifies(via, row) === true;\n if (counts) {\n addLink(events.linked, now);\n }\n if (before !== undefined) {\n unlinkOld(events, via, { ...row, ...before });\n } else if (!counts) {\n addLink(events.unlinked, now);\n }\n }\n}\n\n/** The current links among the junction rows `where` matches (those the role rule counts), by entry. */\nasync function readLinks(\n storage: StorageAdapter,\n via: Via,\n where: Readonly<Record<string, unknown>>,\n): Promise<Map<string, Set<string>>> {\n const rows = await storage.findMany(modelKey(via.model), {\n where: linkWhere(via, where),\n select: { [via.entry]: true, [via.scope]: true },\n });\n const links = new Map<string, Set<string>>();\n for (const row of rows) {\n addLink(links, linkOf(via, row));\n }\n return links;\n}\n\ninterface ViaRow {\n readonly id: string;\n readonly write: WriteRecord | undefined;\n readonly links: ReadonlySet<string>;\n readonly row: StorageRow | undefined;\n readonly refreshed: boolean;\n}\n\n/** True when the collection declares a `where`: membership then needs the entry's values too. */\nfunction filtered(collection: BoundCollection): boolean {\n return Object.keys(collection.where).length > 0;\n}\n\n/**\n * False only when a deleted entry's last values (`before`, which carries the\n * `where` columns a filtered list registers) fail the list's `where`: no\n * scope of the list held it. True without them, to stay safe.\n */\nfunction listedBefore(collection: BoundCollection, before: Values | undefined): boolean {\n if (!filtered(collection) || before === undefined) {\n return true;\n }\n const columns = Object.keys(collection.where);\n return (\n columns.some((column) => !Object.hasOwn(before, column)) || matchesWhere(collection, before)\n );\n}\n\n/**\n * The scopes a deleted entry was linked to just before its delete, as the\n * tracked client read them (`WriteRecord.links`): its junction rows the role\n * rules count (or whose role was not read). `undefined` when the delete did\n * not read them.\n */\nfunction linkedBeforeDelete(via: Via, write: WriteRecord): ReadonlySet<string> | undefined {\n const rows = write.links?.[modelKey(via.model)];\n if (rows === undefined) {\n return undefined;\n }\n const scopes = new Set<string>();\n for (const row of rows) {\n const link = linkOf(via, row);\n if (link !== undefined && link[0] === write.id && linkQualifies(via, row) !== false) {\n scopes.add(link[1]);\n }\n }\n return scopes;\n}\n\n/**\n * The move of a deleted `via` entry (`viaMove`): out of the scopes its\n * delete read its links in, and the ones the flush's junction events\n * unlinked; out of scopes nobody can name when its links were not read;\n * out of none when its last values fail a filtered list's `where`. With\n * `current`, the scopes it is linked to at the read (`after`) keep it.\n */\nfunction deletedMove(\n collection: BoundCollection,\n write: WriteRecord,\n [unlinked, after]: readonly [ReadonlySet<string>, ReadonlySet<string>],\n current: boolean,\n): Move {\n const { id } = write;\n if (!listedBefore(collection, write.before)) {\n return current ? movedTo(id, NONE, NONE, after, false) : moveOf(id, NONE, NONE, undefined);\n }\n const linked = linkedBeforeDelete(collection.scope as Via, write);\n const left = linked === undefined ? unlinked : new Set([...unlinked, ...linked]);\n const unknown = linked === undefined;\n return current\n ? movedTo(id, left, NONE, after, unknown)\n : moveOf(id, left, NONE, undefined, unknown);\n}\n\n/**\n * A `via` entry's move: its links before the flush against its links now,\n * both filtered by `where`. A deleted entry left the scopes its delete read\n * its links in (`linkedBeforeDelete`), or, when it read none, scopes nobody\n * can name; none when its last values fail a filtered list's `where`\n * (`listedBefore`); with `current` (behind a cluster adapter), the scopes it\n * is linked to at the read keep it. An entry created or touched is `added`\n * to every scope it is in now and `removed` from the ones it left.\n */\nfunction viaMove(\n collection: BoundCollection,\n events: LinkEvents,\n entry: ViaRow,\n current: boolean,\n): Move {\n const { id, write, links, row } = entry;\n const unlinked = events.unlinked.get(id) ?? NONE;\n const matches = (values: Values | undefined): boolean =>\n !filtered(collection) || (values !== undefined && matchesWhere(collection, values));\n const after = matches(row) ? links : NONE;\n if (write?.op === \"delete\") {\n return deletedMove(collection, write, [unlinked, after], current);\n }\n const linked = events.linked.get(id) ?? NONE;\n const linksBefore = new Set([...[...links].filter((scope) => !linked.has(scope)), ...unlinked]);\n const before = matches(row === undefined ? undefined : { ...row, ...write?.before })\n ? linksBefore\n : NONE;\n if (write?.op === \"create\" || write?.fields.includes(ANY_FIELD) === true) {\n // Whole wherever it is now (an upsert where a client held it), gone where it left.\n return {\n id,\n left: [...before].filter((scope) => !after.has(scope)),\n entered: [...after],\n stayed: [],\n kind: WHOLE,\n unknownLeft: false,\n };\n }\n const changed = write !== undefined || entry.refreshed;\n // A refreshed entry's item changed beyond its own write (a count over the junction): whole.\n const kind =\n write === undefined || entry.refreshed\n ? WHOLE\n : frameKind(collection.item, write, collection.service.versionColumn);\n return moveOf(id, before, after, changed ? kind : undefined);\n}\n\n/**\n * One flush's moves per collection. The collection sink and the topic sink\n * (`../topics.ts`) both need them, and the rows a flush's moves read are read\n * once: the moves are kept by the flush's batch of writes, which every sink\n * of a flush receives as the same array, until it is garbage.\n */\nexport type FlushMoves = WeakMap<readonly WriteRecord[], Map<BoundCollection, Promise<Moves>>>;\n\n/**\n * The moves of `collection` in the flush of `writes`, found on the first\n * call for that flush and shared by every later one. `refresh` holds the\n * collection's rows only an `affects` hop touched; `current` is true behind\n * a cluster adapter.\n */\nexport function movesOf(\n memo: FlushMoves,\n storage: StorageAdapter,\n collection: BoundCollection,\n writes: readonly WriteRecord[],\n refresh: readonly string[],\n current = false,\n): Promise<Moves> {\n let flush = memo.get(writes);\n if (flush === undefined) {\n flush = new Map();\n memo.set(writes, flush);\n }\n let moves = flush.get(collection);\n if (moves === undefined) {\n moves =\n collection.scope.kind === \"column\"\n ? columnMoves(storage, collection, writes, refresh)\n : viaMoves(storage, collection, writes, refresh, current);\n flush.set(collection, moves);\n }\n return moves;\n}\n\n/**\n * The moves of a `via` collection: from its entry rows' writes, its\n * junction's writes and `affects` hops. With `current`, a deleted entry\n * linked to scopes at the read stays in them. With `refreshEntry`, every\n * entry a junction write named is sent again to the scopes it stayed in.\n */\nexport async function viaMoves(\n storage: StorageAdapter,\n collection: BoundCollection,\n writes: readonly WriteRecord[],\n refresh: readonly string[],\n current = false,\n): Promise<Moves> {\n const via = collection.scope as Via;\n const entries = new Map(\n writes.filter((write) => modelKey(write.model) === collection.model).map((w) => [w.id, w]),\n );\n const events = linkEvents(\n via,\n writes.filter((write) => modelKey(write.model) === modelKey(via.model)),\n );\n await readUnknown(storage, via, events);\n const refreshed = new Set([...refresh, ...(via.refreshEntry ? events.named : [])]);\n const ids = [\n ...new Set([\n ...entries.keys(),\n ...events.linked.keys(),\n ...events.unlinked.keys(),\n ...refreshed,\n ]),\n ];\n if (ids.length === 0) {\n return { moves: [], rows: new Map(), resetAll: events.resetAll };\n }\n // Without a `where`, links alone decide membership: items are read later, for subscribed scopes only.\n const [links, rows] = await Promise.all([\n readLinks(storage, via, { [via.entry]: { in: ids } }),\n filtered(collection) ? readRows(storage, collection, ids) : new Map<string, StorageRow>(),\n ]);\n const moves = ids.map((id) =>\n viaMove(\n collection,\n events,\n {\n id,\n write: entries.get(id),\n links: links.get(id) ?? NONE,\n row: rows.get(id),\n refreshed: refreshed.has(id),\n },\n current,\n ),\n );\n return { moves: moves.filter((move) => !isEmpty(move)), rows, resetAll: events.resetAll };\n}\n","// Who may subscribe to a collection scope (RFC 0003 sections 4.3 and 7.1),\n// decided as the `{ scope: access, of: anchor, id: scope }` method form is\n// decided (`access/engine.ts`): a service-wide `Admin` grant on the\n// collection's own service passes while it keeps `adminBypass`; otherwise\n// the anchor's policy must give the principal at least the collection's\n// `access` level (default `Read`) on the anchor row, and grants on the\n// anchor's service do not count, as they do not flow through `inherit`. A\n// missing anchor row has no level, so it is `FORBIDDEN` unless the grant\n// passes. A `\"self\"` scope passes when it is the principal's own user id;\n// it has no anchors, and on a service with a policy its items follow that\n// policy for its user (`selfAccess.ts`).\n// 4.1 asked each collection's `checkScopeAccess` (4.1 `src/server/collections.ts:45-49`).\n//\n// A change topic (RFC 0003 section 11.3) is watched on the same terms: a\n// collection scope's topic exactly as a subscribe to that scope, and a\n// service's topic by the service's `watchAccess`, closed to everyone when\n// the service declares none. A search kept to a scope (the search kit, RFC\n// 0003 section 12.2) is decided by the same rule (`allowedScopes`).\n\nimport type { AccessLevel } from \"../../contract/access\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { PolicyEngine } from \"../access/api\";\nimport { checkKind } from \"../access/kinds\";\nimport { meetsLevel, serviceGrant } from \"../access/levels\";\nimport type { AccessFilter } from \"../access/policy\";\nimport { anchorKey } from \"../access/tools\";\nimport type { AnyService } from \"../service\";\nimport type { Principal } from \"../types\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\n\n/** What a `qd:watch` names: a service's topic, or the topic of one scope of a collection. */\nexport type WatchTarget =\n | { readonly kind: \"service\"; readonly service: BoundCollection[\"service\"] }\n | {\n readonly kind: \"collection\";\n readonly collection: BoundCollection;\n readonly scope: string;\n };\n\n/**\n * What deciding a collection's scopes needs, wherever the scope arrives\n * from: a `qd:col:sub`, a topic watch, or a search kept to the scope.\n */\nexport interface ScopeRule {\n /** The collection's own service: its service-wide `Admin` grant passes while it keeps `adminBypass`. */\n readonly service: Pick<AnyService, \"name\" | \"adminBypass\">;\n /** The name of the service whose policy authorizes the scopes; `undefined` for a `\"self\"` scope. */\n readonly anchor: string | undefined;\n /** The level a subscriber needs on the scope's anchor row. */\n readonly access: AccessLevel;\n}\n\n/**\n * The scopes of `scopes` the principal may subscribe to under `rule`, each\n * with the rows its access is derived from (its anchors): the anchor row and\n * its `inherit` parents, none for a `\"self\"` scope, whose items follow the\n * item service's policy instead (`selfAccess.ts`). One engine call; a lookup\n * that fails rejects.\n */\nexport async function allowedScopes(\n policies: Pick<PolicyEngine, \"resolve\">,\n rule: ScopeRule,\n principal: Principal,\n scopes: readonly string[],\n): Promise<Map<string, readonly string[]>> {\n const allowed = new Map<string, readonly string[]>();\n const { anchor, service } = rule;\n const anchorRow = (scope: string): readonly string[] =>\n anchor === undefined ? [] : [anchorKey(anchor, scope)];\n if (service.adminBypass && serviceGrant(principal, service.name) === \"Admin\") {\n for (const scope of scopes) {\n allowed.set(scope, anchorRow(scope));\n }\n return allowed;\n }\n if (anchor === undefined) {\n for (const scope of scopes.filter((candidate) => candidate === principal.userId)) {\n allowed.set(scope, []);\n }\n return allowed;\n }\n const access = await policies.resolve(anchor, principal, scopes, { grants: false });\n for (const scope of scopes) {\n if (meetsLevel(access.levels.get(scope), rule.access)) {\n allowed.set(scope, access.anchors.get(scope) ?? anchorRow(scope));\n }\n }\n return allowed;\n}\n\n/**\n * True for a self scope on a service with an access policy: its items follow\n * that policy (`selfAccess.ts`).\n */\nexport function followsPolicy(collection: Pick<BoundCollection, \"anchor\" | \"service\">): boolean {\n return collection.anchor === undefined && collection.service.access !== undefined;\n}\n\n/**\n * The filter a read of a self scope's rows adds for `principal`: the item\n * service's `accessWhere` at the collection's `access` (`{}` for a\n * service-wide `Admin` with `adminBypass`, `\"none\"` when no row matches).\n * `undefined` for any other collection.\n */\nexport async function itemsWhere(\n hub: Pick<CollectionHub, \"policies\">,\n collection: BoundCollection,\n principal: Principal,\n): Promise<AccessFilter | undefined> {\n return followsPolicy(collection)\n ? await hub.policies.accessWhere(collection.service.name, principal, collection.access)\n : undefined;\n}\n\n/** The scopes of `scopes` the principal may subscribe to in a served collection: {@link allowedScopes}. */\nexport async function authorizeScopes(\n hub: CollectionHub,\n collection: BoundCollection,\n principal: Principal,\n scopes: readonly string[],\n): Promise<Map<string, readonly string[]>> {\n const rule: ScopeRule = {\n service: collection.service,\n anchor: collection.anchorService?.name,\n access: collection.access,\n };\n return await allowedScopes(hub.policies, rule, principal, scopes);\n}\n\n/** True when the service's `watchAccess` lets the principal watch its topic; never without one. */\nfunction mayWatchService(service: BoundCollection[\"service\"], principal: Principal): boolean {\n const form = service.watchAccess;\n if (form === undefined) {\n return false;\n }\n if (form === \"public\" || form === \"authenticated\") {\n return true;\n }\n return meetsLevel(serviceGrant(principal, service.name), form.service);\n}\n\n/**\n * Authorizes a watch of `target` by `principal` (`null` when anonymous): a\n * principal of a kind the service does not admit is refused first\n * (`../access/kinds.ts`), then a collection scope's topic is authorized as a\n * subscribe to that scope, and a service's topic by its `watchAccess`.\n * Resolves with the rows a scope's access is derived from (its anchors;\n * none for the service topic). Throws `UNAUTHENTICATED` or `FORBIDDEN`; a\n * lookup that fails rejects.\n */\nexport async function authorizeWatch(\n hub: CollectionHub,\n principal: Principal | null,\n target: WatchTarget,\n): Promise<readonly string[]> {\n const service = target.kind === \"service\" ? target.service : target.collection.service;\n checkKind(service.kinds, principal, service.name);\n if (target.kind === \"service\" && target.service.watchAccess === undefined) {\n throw new QuickdrawError(\n \"FORBIDDEN\",\n `${target.service.name} keeps its service topic closed: it declares no watchAccess`,\n );\n }\n if (target.kind === \"service\" && target.service.watchAccess === \"public\") {\n return [];\n }\n if (principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n const anchors =\n target.kind === \"service\"\n ? mayWatchService(target.service, principal)\n ? []\n : undefined\n : (await authorizeScopes(hub, target.collection, principal, [target.scope])).get(\n target.scope,\n );\n if (anchors === undefined) {\n throw new QuickdrawError(\"FORBIDDEN\", \"Insufficient permissions\");\n }\n return anchors;\n}\n","// A self scope's items follow the item service's row policy (RFC 0003\n// sections 4.3, 4.4 and 7.1; the 5.1 audit's COLL-1). A `scopeAccess:\n// \"self\"` scope is its user's to open (`access.ts`): its value is the\n// subscriber's own user id. Its items were every row whose scope column (or\n// junction) named that user, whatever the item service's policy said, so a\n// task still assigned to a user removed from its project kept reaching them,\n// title and all. On a service with an access policy, a self scope's items\n// are the rows the policy gives its user at least the collection's `access`:\n//\n// - pages, the first page's index, cursor pages and `qd:col:items` AND the\n// service's `accessWhere(principal, access)` into their reads, for the\n// subscriber's principal (`itemsWhere` in `access.ts`, beside\n// `followsPolicy`, which says which collections this is);\n// - each flush checks the deltas it sends a self scope against its user's\n// level (`denyUnreadable`, here): a row below `access` goes out\n// `removed`, marked `denied`, so a cluster's read-time decision never\n// turns it back into an item (`deltas.ts`);\n// - an access change re-checks the self scopes subscribed on this process,\n// and makes a resume of the others read a page (`selfRecheck.ts`).\n//\n// A flush decides for the scope's user: each distinct principal the user's\n// sockets of this process in the scope's room carry (a row any of them may\n// not read is removed for all), else `{ userId: scope }`, a principal that\n// holds the user id only: no grants, kind, claims or app fields. Behind a\n// cluster adapter the user's sockets may all be on other nodes, so a node\n// often decides with that one. On one server a removal reveals nothing and\n// reads nothing, so only the rows a frame carries are checked; behind a\n// cluster a removal may be decided back into an item at the read, so it is\n// checked too. At most 16 scopes are checked at once. A self scope on a\n// service without a policy is unchanged: nothing decides its rows but the\n// scope.\n\nimport { meetsLevel } from \"../access/levels\";\nimport type { Principal } from \"../types\";\nimport { followsPolicy } from \"./access\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\nimport { linkWhere } from \"./define\";\nimport type { ScopePlan } from \"./deltas\";\n\ntype Io = NonNullable<CollectionHub[\"io\"]>;\n\n/** How many self scopes one flush checks at once. */\nconst CONCURRENT_CHECKS = 16;\n\n/** Two principals with the same data (functions left out) decide alike; one that cannot be written is its own. */\nfunction principalKey(principal: Principal): string | Principal {\n try {\n const data = JSON.stringify(principal, (_key, value: unknown) =>\n typeof value === \"function\" ? undefined : value,\n );\n return data ?? principal;\n } catch {\n return principal;\n }\n}\n\n/**\n * The principals a flush decides a self scope's rows for: each distinct one\n * the scope's user's sockets of this process in its room carry, else\n * `{ userId: scope }`, which holds the user id only.\n */\nexport function ownersOf(io: Io, room: string, scope: string): Principal[] {\n const owners = new Map<string | Principal, Principal>();\n for (const socketId of io.sockets.adapter.rooms.get(room) ?? []) {\n const principal = io.sockets.sockets.get(socketId)?.data.principal;\n if (principal !== null && principal !== undefined && principal.userId === scope) {\n owners.set(principalKey(principal), principal);\n }\n }\n return owners.size === 0 ? [{ userId: scope }] : [...owners.values()];\n}\n\n/** Marks the deltas of one plan whose row some owner of the scope may not read. */\nasync function denyPlan(\n hub: Pick<CollectionHub, \"policies\">,\n io: Io,\n collection: BoundCollection,\n plan: ScopePlan,\n cluster: boolean,\n): Promise<void> {\n const checked = (delta: ScopePlan[\"deltas\"][number]): boolean => cluster || delta.t !== \"removed\";\n const ids = [...new Set(plan.deltas.filter(checked).map((delta) => delta.id))];\n const service = collection.service.name;\n const levels = await Promise.all(\n ownersOf(io, plan.room, plan.scope).map(\n async (owner) => await hub.policies.levelsFor(service, owner, ids),\n ),\n );\n for (const [index, delta] of plan.deltas.entries()) {\n const readable = levels.every((of) => meetsLevel(of.get(delta.id), collection.access));\n if (readable || !checked(delta)) {\n continue;\n }\n plan.deltas[index] =\n delta.t === \"removed\"\n ? { ...delta, denied: true }\n : { t: \"removed\", id: delta.id, denied: true };\n }\n}\n\n/**\n * Checks the deltas each plan sends a self scope against its user's level,\n * one batched `levelsFor` per scope and owner principal, 16 scopes at a\n * time: a row below the collection's `access` becomes `removed`, marked\n * `denied`. On one server (`cluster` false) a plan of removals alone is not\n * checked. Nothing for a collection that does not follow a policy\n * (`followsPolicy`). A plan that resets is left alone: its clients load the\n * scope again, filtered. A lookup that fails rejects, and the flush resets\n * the scopes it touched.\n */\nexport async function denyUnreadable(\n hub: Pick<CollectionHub, \"policies\">,\n io: Io,\n collection: BoundCollection,\n plans: readonly ScopePlan[],\n cluster = false,\n): Promise<void> {\n if (!followsPolicy(collection)) {\n return;\n }\n const checked = plans.filter(\n (plan) => !plan.reset && plan.deltas.some((delta) => cluster || delta.t !== \"removed\"),\n );\n for (let start = 0; start < checked.length; start += CONCURRENT_CHECKS) {\n const batch = checked.slice(start, start + CONCURRENT_CHECKS);\n await Promise.all(\n batch.map(async (plan) => await denyPlan(hub, io, collection, plan, cluster)),\n );\n }\n}\n\n/**\n * False when a `via` scope's junction no longer links row `id` to `scope`\n * (a link below its role rule counts as none): the flush that removed or\n * demoted the link sends the row's removal itself, so a member removed from\n * a project, in a list of their projects through the very membership table,\n * gets it once. True for a column scope, whose row is not read.\n */\nexport async function stillLinked(\n hub: Pick<CollectionHub, \"storage\">,\n collection: BoundCollection,\n scope: string,\n id: string,\n): Promise<boolean> {\n if (collection.scope.kind !== \"via\" || hub.storage === undefined) {\n return true;\n }\n const via = collection.scope;\n const links = await hub.storage.findMany(via.model, {\n where: linkWhere(via, { [via.scope]: scope, [via.entry]: id }),\n select: { [via.entry]: true },\n take: 1,\n });\n return links.length > 0;\n}\n","// The collection deltas a flush cannot address to a scope, across a cluster\n// (RFC 0003 section 7.2, and the gap section 17 recorded for pack C): a row\n// removed without the values that place it (a `ctx.touch` with `removed`, a\n// `via` entry whose links a database cascade removed) left scopes nobody can\n// name, and junction rows removed without values make every scope of their\n// collection unsure. The flushing node sends `removed` (or `reset`) to every\n// scope it has subscribers in; other nodes' scopes are not visible to it.\n// Behind a cluster adapter it therefore also broadcasts what it could not\n// address, and every other node sends the same deltas to its own subscribed\n// scopes of the collection, to its own sockets only (a scope subscribed on\n// both nodes may get them twice; a `removed` or `reset` repeated changes\n// nothing on the client). A row that exists again when the flushing node\n// reads it (its id created again by a write whose flush went first) is not\n// removed from the scopes it is in at that read (`kept`): that node sends\n// it there itself. No resume buffer keeps such a removal, here or on the\n// flushing node: the floor of every scope of the collection rises instead,\n// subscribed here or not (`skipAll`), so a client resuming any of them\n// across it reads a page. A `via` entry whose delete read its links is\n// placed, and never comes here (the 5.1 audit's COLL-3).\n\nimport { collectionRoom, SERVER_EVENTS } from \"../../contract/names\";\nimport { emitToNodes, onNodeEvent } from \"../cluster/deployment\";\nimport type { CollectionDelta, CollectionFrame, Revision } from \"../../protocol/envelope\";\nimport type { StorageRow } from \"../storage\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\nimport { scopeIn } from \"./items\";\nimport type { Move, Moves } from \"./moves\";\nimport { groupOf } from \"./scopes\";\n\n/** The server-to-server event unaddressed deltas are broadcast on behind a cluster adapter. */\nexport const UNNAMED_EVENT = \"quickdraw:collection-unnamed\";\n\n/** What a flush could not address to a scope of one collection. */\nexport interface UnnamedDeltas {\n readonly s: string;\n readonly c: string;\n readonly rev: Revision;\n /** Rows that left scopes nobody can name: `removed` in every subscribed scope. */\n readonly removed: readonly string[];\n /** `[id, scope]`: a scope one of those rows is in at the flush's read, which keeps it. */\n readonly kept?: readonly (readonly [string, string])[];\n /** Junction rows went unseen: every subscribed scope resets. */\n readonly reset: boolean;\n}\n\n/**\n * The scopes a row that left scopes nobody can name is in at the flush's\n * read: its column's scope, or the `via` links its move found; none when the\n * row is gone.\n */\nfunction keptScopes(\n collection: BoundCollection,\n move: Move,\n row: StorageRow | undefined,\n): readonly string[] {\n if (row === undefined) {\n return [];\n }\n if (collection.scope.kind !== \"column\") {\n return [...move.entered, ...move.stayed];\n }\n const scope = scopeIn(collection, row);\n return typeof scope === \"string\" ? [scope] : [];\n}\n\n/**\n * What the moves of one collection could not address, or `undefined` when\n * they addressed everything. `rows`, the rows read for the flush's frames\n * behind a cluster adapter, name the scopes such a row is in again.\n */\nexport function unnamedOf(\n collection: BoundCollection,\n moves: Moves,\n rev: Revision,\n rows?: ReadonlyMap<string, StorageRow>,\n): UnnamedDeltas | undefined {\n const unknown = moves.moves.filter((move) => move.unknownLeft);\n if (unknown.length === 0 && !moves.resetAll) {\n return undefined;\n }\n const kept = unknown.flatMap((move) =>\n keptScopes(collection, move, rows?.get(move.id)).map((scope) => [move.id, scope] as const),\n );\n return {\n s: collection.service.name,\n c: collection.name,\n rev,\n removed: unknown.map((move) => move.id),\n ...(kept.length > 0 ? { kept } : {}),\n reset: moves.resetAll,\n };\n}\n\n/**\n * What the flush could not address: no scope of the collection resumes\n * across it here, subscribed or not, and behind a cluster adapter the other\n * nodes are told it.\n */\nexport function broadcastUnnamed(hub: CollectionHub, unnamed: UnnamedDeltas | undefined): void {\n if (unnamed === undefined) {\n return;\n }\n hub.collections.buffer.skipAll(groupOf(unnamed.s, unnamed.c));\n if (hub.io !== undefined && !hub.probe.local()) {\n emitToNodes(hub.io, UNNAMED_EVENT, unnamed);\n }\n}\n\nfunction isPair(value: unknown): value is readonly [string, string] {\n return (\n Array.isArray(value) &&\n value.length === 2 &&\n typeof value[0] === \"string\" &&\n typeof value[1] === \"string\"\n );\n}\n\n/** A broadcast read, or `undefined` for anything malformed. */\nfunction readUnnamed(value: unknown): UnnamedDeltas | undefined {\n const { s, c, rev, removed, kept, reset } = (value ?? {}) as Readonly<Record<string, unknown>>;\n const ids = Array.isArray(removed) && removed.every((id) => typeof id === \"string\");\n const pairs = kept === undefined || (Array.isArray(kept) && kept.every(isPair));\n const valid = typeof s === \"string\" && typeof c === \"string\" && Number.isSafeInteger(rev) && ids;\n return valid && pairs && typeof reset === \"boolean\"\n ? {\n s,\n c,\n rev: rev as number,\n removed: removed as string[],\n ...(kept === undefined ? {} : { kept: kept as [string, string][] }),\n reset,\n }\n : undefined;\n}\n\n/** The deltas one scope gets of another node's unaddressed ones: none for a row it keeps. */\nfunction deltasFor(\n unnamed: UnnamedDeltas,\n kept: ReadonlySet<string>,\n scope: string,\n): CollectionDelta[] {\n if (unnamed.reset) {\n return [{ t: \"reset\" }];\n }\n return unnamed.removed\n .filter((id) => !kept.has(`${id}\\u0000${scope}`))\n .map((id) => ({ t: \"removed\", id }));\n}\n\n/** Sends another node's unaddressed deltas to every scope of the collection subscribed on this process. */\nfunction sendHere(hub: CollectionHub, unnamed: UnnamedDeltas): void {\n const { io } = hub;\n const collection = hub.collections.routes.find(unnamed.s, unnamed.c);\n if (io === undefined || collection === undefined) {\n return;\n }\n // No scope of the collection resumes across it here, subscribed or not.\n hub.collections.buffer.skipAll(groupOf(unnamed.s, unnamed.c));\n const kept = new Set((unnamed.kept ?? []).map(([id, scope]) => `${id}\\u0000${scope}`));\n for (const scope of hub.collections.scopes.scopes(unnamed.s, unnamed.c)) {\n const deltas = deltasFor(unnamed, kept, scope);\n if (deltas.length === 0) {\n continue;\n }\n const room = collectionRoom(unnamed.s, unnamed.c, scope);\n const frame: CollectionFrame = { s: unnamed.s, c: unnamed.c, scope, rev: unnamed.rev, deltas };\n io.local.to(room).emit(SERVER_EVENTS.collection, frame);\n if (unnamed.reset) {\n hub.collections.buffer.reset(room, unnamed.rev);\n } else {\n hub.collections.buffer.skip(room, unnamed.rev);\n }\n }\n}\n\n/** Listens for the deltas other nodes of its deployment could not address, on the server the live data was given. */\nexport function listenForUnnamed(hub: CollectionHub): void {\n if (hub.io === undefined) {\n return;\n }\n onNodeEvent(hub.io, hub.logger, UNNAMED_EVENT, (broadcast) => {\n const unnamed = readUnnamed(broadcast);\n if (unnamed !== undefined && (unnamed.reset || unnamed.removed.length > 0)) {\n sendHere(hub, unnamed);\n }\n });\n}\n","// Sending collection frames (RFC 0003 sections 5.3 and 7.2), and the scopes a\n// flush closes or resets rather than updates:\n//\n// - every frame goes to the scope's room as `qd:c { s, c, scope, rev,\n// deltas }`, and into the scope's resume buffer, except one that removes a\n// row nobody could place (a touch with `removed`, a `via` entry deleted\n// without its links read), which every subscribed scope gets: that one\n// raises the scope's resume floor instead, as `unnamed.ts` raises every\n// scope's of the collection, so a client resuming across it reads a page\n// rather than learn the row's id;\n// - deleting the row a scope is anchored on (a chat, for its messages) sends\n// `qd:revoked { kind: \"collection\", reason: \"anchor-deleted\" }` to every\n// scope room keyed by that row's id and empties those rooms: the rows a\n// database cascade removed with it produce no tracked writes, so closing\n// the scope is the whole answer, and nothing else goes to it;\n// - when the flush failed (this sink or another one), every scope its writes\n// name gets a `reset`, and a collection whose writes name no scope (a\n// touch, a `via` entry) resets every scope subscribed on this process, and\n// behind a cluster adapter on every other node (`unnamed.ts`);\n// - a collection nobody on this process subscribes to (with rooms visible\n// here) reads and sends nothing: the scopes its writes name lose their\n// resume from before the flush, and a write that names none (a touch, a\n// `via` entry, an `affects` hop) costs the whole collection its resume.\n//\n// 4.1 offered these as hand-written calls (`emitCollectionReset`,\n// `kickFromCollection`; 4.1 `src/server/collections.ts:300-318`).\n\nimport { collectionRoom, SERVER_EVENTS } from \"../../contract/names\";\nimport type { CollectionDelta, CollectionFrame, Revision } from \"../../protocol/envelope\";\nimport { modelKey } from \"../storage\";\nimport type { WriteRecord } from \"../uow/types\";\nimport { anchoredScopes, type BoundCollection, type CollectionHub } from \"./bind\";\nimport { groupOf } from \"./scopes\";\nimport { broadcastUnnamed } from \"./unnamed\";\n\ntype Io = NonNullable<CollectionHub[\"io\"]>;\n\n/**\n * Sends one scope's frame for a flush and keeps it for resumes; a `reset`\n * frame resets the buffer. `local` sends it to this process's sockets only:\n * a self scope's re-check, which every node makes for its own sockets\n * (`selfAccess.ts`). `unnamed`, a frame that removes a row nobody could\n * place, is not kept: it raises the scope's resume floor instead.\n */\nexport function sendFrame(\n hub: CollectionHub,\n io: Io | undefined,\n collection: BoundCollection,\n scope: string,\n rev: Revision,\n deltas: readonly CollectionDelta[],\n options: { readonly local?: boolean; readonly unnamed?: boolean } = {},\n): void {\n if (deltas.length === 0) {\n return;\n }\n const s = collection.service.name;\n const room = collectionRoom(s, collection.name, scope);\n const frame: CollectionFrame = { s, c: collection.name, scope, rev, deltas };\n const target = options.local === true ? io?.local.to(room) : io?.to(room);\n target?.emit(SERVER_EVENTS.collection, frame);\n if (deltas.some((delta) => delta.t === \"reset\")) {\n hub.collections.buffer.reset(room, rev);\n } else if (options.unnamed === true) {\n hub.collections.buffer.skip(room, rev);\n } else {\n hub.collections.buffer.record(room, rev, deltas);\n }\n}\n\n/** Revokes every subscription to one scope whose anchor row was deleted, and empties its room. */\nfunction closeScope(\n hub: CollectionHub,\n io: Io,\n collection: BoundCollection,\n scope: string,\n rev: Revision,\n): void {\n const s = collection.service.name;\n const room = collectionRoom(s, collection.name, scope);\n hub.collections.buffer.reset(room, rev);\n const local = [...(io.sockets.adapter.rooms.get(room) ?? [])];\n if (local.length === 0 && hub.probe.local()) {\n return;\n }\n io.to(room).emit(SERVER_EVENTS.revoked, {\n kind: \"collection\",\n reason: \"anchor-deleted\",\n s,\n c: collection.name,\n scope,\n });\n for (const socketId of local) {\n const socket = io.sockets.sockets.get(socketId);\n if (socket !== undefined) {\n hub.collections.scopes.delete(socket, room);\n }\n }\n // Behind a cluster adapter, the other nodes' sockets leave too.\n io.in(room).socketsLeave(room);\n}\n\n/** Closes the scopes keyed by each row the flush deleted that collections are anchored on; returns their rooms. */\nexport function closeAnchors(\n hub: CollectionHub,\n io: Io,\n writes: readonly WriteRecord[],\n rev: Revision,\n): Set<string> {\n const closed = new Set<string>();\n for (const [collection, scope] of anchoredScopes(hub.collections.routes, writes)) {\n closed.add(collectionRoom(collection.service.name, collection.name, scope));\n closeScope(hub, io, collection, scope, rev);\n }\n return closed;\n}\n\n/** A scope value a junction row holds, or `undefined`. */\nfunction scopeValue(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\n/**\n * The scopes a write's values name in a collection, or `undefined` when they\n * name none: an entry's own write in a `via` collection (but a delete that\n * read its links names the scopes they held), and with `refreshEntry` a\n * junction write too, which changes its entry in every scope that holds it.\n */\nfunction namedScopes(collection: BoundCollection, write: WriteRecord): string[] | undefined {\n const { scope } = collection;\n const junction = scope.kind === \"via\" && modelKey(write.model) === modelKey(scope.model);\n if (scope.kind === \"via\" && !junction) {\n const links = write.op === \"delete\" ? write.links?.[modelKey(scope.model)] : undefined;\n return links?.map((row) => row[scope.scope]).filter(scopeValue);\n }\n if (scope.kind === \"via\" && scope.refreshEntry) {\n return undefined;\n }\n const column = scope.kind === \"column\" ? scope.column : scope.scope;\n const named = [write.before?.[column], write.after?.[column]].filter(scopeValue);\n return named.length === 0 ? undefined : named;\n}\n\n/**\n * The flush changed a collection nobody here subscribes to: no frame, and no\n * resume from before it of the scopes it changed. `refresh` are rows only an\n * `affects` hop touched.\n */\nexport function skipTouched(\n hub: CollectionHub,\n collection: BoundCollection,\n writes: readonly WriteRecord[],\n refresh: readonly string[],\n rev: Revision,\n): void {\n const s = collection.service.name;\n const { scope } = collection;\n const junction = scope.kind === \"via\" ? modelKey(scope.model) : undefined;\n const concerns = (write: WriteRecord): boolean => {\n const model = modelKey(write.model);\n return model === collection.model || model === junction;\n };\n let unnamed = refresh.length > 0;\n for (const write of writes.filter(concerns)) {\n const named = namedScopes(collection, write);\n unnamed ||= named === undefined;\n for (const value of named ?? []) {\n hub.collections.buffer.skip(collectionRoom(s, collection.name, value), rev);\n }\n }\n if (unnamed) {\n hub.collections.buffer.skipAll(groupOf(s, collection.name));\n }\n}\n\n/** Sends a `reset` to every scope the flush's writes touched: the flush failed. */\nexport function resetTouched(\n hub: CollectionHub,\n io: Io,\n writes: readonly WriteRecord[],\n rev: Revision,\n): void {\n const touched = new Map<BoundCollection, Set<string>>();\n const unnamed = new Set<BoundCollection>();\n const { routes } = hub.collections;\n for (const write of writes) {\n const key = modelKey(write.model);\n for (const collection of [\n ...(routes.byModel.get(key) ?? []),\n ...(routes.byJunction.get(key) ?? []),\n ]) {\n const named = namedScopes(collection, write);\n if (named === undefined) {\n unnamed.add(collection);\n }\n const scopes =\n named ?? hub.collections.scopes.scopes(collection.service.name, collection.name);\n touched.set(collection, new Set([...(touched.get(collection) ?? []), ...scopes]));\n }\n }\n for (const [collection, scopes] of touched) {\n for (const scope of scopes) {\n sendFrame(hub, io, collection, scope, rev, [{ t: \"reset\" }]);\n }\n }\n for (const collection of unnamed) {\n const { name: s } = collection.service;\n broadcastUnnamed(hub, { s, c: collection.name, rev, removed: [], reset: true });\n }\n}\n","// The collection sink (RFC 0003 sections 5.3 and 7.2): what a flush does for\n// collection subscribers. It goes after the access and entity sinks on the\n// dispatcher's list, so a socket a flush revoked never gets its deltas. It\n// replaces 4.1's `notify` (4.1 `src/server/collections.ts:205-270`), which\n// only `this.create/update/delete` called, after reading the whole row first\n// (4.1 `src/server/BaseService.ts:741-751`).\n//\n// Per flush:\n//\n// 1. close the scopes anchored on rows the flush deleted (`send.ts`);\n// 2. per collection the writes concern (its model, its `via` junction, or an\n// `affects` hop onto its service), find each row's moves (`moves.ts`),\n// reading only rows whose write does not carry the values that decide\n// membership; the topic sink (`../topics.ts`) reuses them;\n// 3. per scope, batch the moves' deltas into one plan, or one `reset` past\n// `bulkThreshold` (`deltas.ts`);\n// 4. leave out scopes nobody here subscribes to, which raises their resume\n// floor instead; behind a cluster adapter other nodes' rooms are not\n// visible, so every scope is sent, and what no scope could be named for\n// (a removal without its scope, junction rows removed without values) is\n// broadcast for the other nodes' subscribed scopes (`unnamed.ts`);\n// 5. in a self scope that follows its service's policy, check the deltas\n// for the scope's user first, one batched lookup per scope: a row the\n// user may not read goes out `removed`, and is never read\n// (`selfAccess.ts`). Then read the items the remaining deltas need, in\n// one query per collection, and send one `qd:c` frame per scope, which\n// the resume buffer keeps. An indexed collection's `added` deltas carry\n// index rows built from those items (`index.ts`). Each delta of a column\n// scope that is not a removal is decided by its row as read then\n// (`deltas.ts`): a write that committed first can flush last, after\n// later units moved its rows. Behind a cluster adapter the same read\n// also takes the rows of removals, and every delta is decided so. A\n// frame that removes a row nobody could place is not kept for resumes.\n//\n// A collection with no subscriber on this process (and rooms visible here)\n// skips steps 2 to 5 and reads nothing (`skipTouched`).\n//\n// A failure sends a `reset` to the touched scopes and is rethrown to be\n// logged; another sink's failure does the same through `onFlushError`.\n\nimport { touchedRows, type TouchedRows } from \"../emit/affects\";\nimport { modelKey, type StorageAdapter } from \"../storage\";\nimport type { FlushInfo, FlushSink } from \"../uow/flushSink\";\nimport type { WriteRecord } from \"../uow/types\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\nimport { buildDeltas, planScopes, readItems, type ScopePlan } from \"./deltas\";\nimport { movesOf } from \"./moves\";\nimport { denyUnreadable } from \"./selfAccess\";\nimport { closeAnchors, resetTouched, sendFrame, skipTouched } from \"./send\";\nimport { broadcastUnnamed, unnamedOf } from \"./unnamed\";\n\ntype Io = NonNullable<CollectionHub[\"io\"]>;\n\n/** One collection's share of a flush. */\nexport interface Work {\n readonly collection: BoundCollection;\n /** Rows of its service only an `affects` hop touched: their items are sent again. */\n readonly refresh: readonly string[];\n}\n\n/** The collections the flush concerns, with the rows of each that only an `affects` hop touched. */\nexport function workOf(\n hub: CollectionHub,\n writes: readonly WriteRecord[],\n touched: TouchedRows,\n): Work[] {\n const { routes } = hub.collections;\n const concerned = new Set<BoundCollection>();\n for (const write of writes) {\n const key = modelKey(write.model);\n for (const collection of [\n ...(routes.byModel.get(key) ?? []),\n ...(routes.byJunction.get(key) ?? []),\n ]) {\n concerned.add(collection);\n }\n }\n for (const service of touched.keys()) {\n for (const name of service.collections.keys()) {\n const collection = routes.find(service.name, name);\n if (collection !== undefined) {\n concerned.add(collection);\n }\n }\n }\n return [...concerned].map((collection) => {\n const written = new Set(\n writes.filter((write) => modelKey(write.model) === collection.model).map(({ id }) => id),\n );\n const rows = touched.get(collection.service)?.keys() ?? [];\n return { collection, refresh: [...rows].filter((id) => !written.has(id)) };\n });\n}\n\n/** True when a socket of this process is in the room, or rooms cannot be seen here (a cluster adapter). */\nfunction occupied(hub: CollectionHub, io: Io, room: string): boolean {\n return !hub.probe.local() || (io.sockets.adapter.rooms.get(room)?.size ?? 0) > 0;\n}\n\n/** Steps 2 to 5 for one collection. */\nasync function emitCollection(\n hub: CollectionHub,\n io: Io,\n storage: StorageAdapter,\n work: Work,\n writes: readonly WriteRecord[],\n rev: number,\n closed: ReadonlySet<string>,\n): Promise<void> {\n const { collection, refresh } = work;\n const subscribed = hub.collections.scopes.scopes(collection.service.name, collection.name);\n const cluster = !hub.probe.local();\n if (subscribed.length === 0 && !cluster) {\n skipTouched(hub, collection, writes, refresh, rev);\n return;\n }\n const moves = await movesOf(hub.collections.moves, storage, collection, writes, refresh, cluster);\n const sending: ScopePlan[] = [];\n for (const plan of planScopes(collection, moves, subscribed)) {\n if (closed.has(plan.room)) {\n continue;\n }\n if (occupied(hub, io, plan.room)) {\n sending.push(plan);\n } else {\n hub.collections.buffer.skip(plan.room, rev);\n }\n }\n await denyUnreadable(hub, io, collection, sending, cluster);\n // Behind a cluster adapter, changes go out whole (frames of two nodes can arrive out of\n // order), decided by the rows read now; the rows of removals no scope could be named for\n // are read too, so the other nodes keep such a row where it is again.\n const unnamed = cluster ? moves.moves.filter((move) => move.unknownLeft) : [];\n if (sending.length === 0 && unnamed.length === 0) {\n broadcastUnnamed(hub, unnamedOf(collection, moves, rev));\n return;\n }\n const also = unnamed.map((move) => move.id);\n const rows = await readItems(storage, collection, sending, moves.rows, cluster, also);\n // What no scope could be named for reaches the scopes subscribed on the other nodes too.\n broadcastUnnamed(hub, unnamedOf(collection, moves, rev, cluster ? rows : undefined));\n for (const plan of sending) {\n const deltas = buildDeltas(collection, plan, rows, rev, cluster);\n // A removal nobody could place reaches every subscribed scope; no resume buffer keeps it.\n const unplaced = plan.deltas.some((delta) => delta.t === \"removed\" && delta.unnamed === true);\n sendFrame(hub, io, collection, plan.scope, rev, deltas, { unnamed: unplaced });\n }\n}\n\nasync function emitFlush(\n hub: CollectionHub,\n io: Io,\n storage: StorageAdapter,\n writes: readonly WriteRecord[],\n rev: number,\n): Promise<void> {\n const closed = closeAnchors(hub, io, writes, rev);\n const work = workOf(hub, writes, touchedRows(writes, hub.routes));\n await Promise.all(work.map((one) => emitCollection(hub, io, storage, one, writes, rev, closed)));\n}\n\n/** The collection sink of a dispatcher. */\nexport function createCollectionSink(hub: CollectionHub): FlushSink {\n return Object.freeze({\n async flush(writes: readonly WriteRecord[], info: FlushInfo): Promise<void> {\n const { io, storage } = hub;\n if (io === undefined || storage === undefined) {\n return;\n }\n try {\n await emitFlush(hub, io, storage, writes, info.rev);\n } catch (error) {\n resetTouched(hub, io, writes, info.rev);\n throw error;\n }\n },\n onFlushError(writes: readonly WriteRecord[], info: FlushInfo): void {\n if (hub.io !== undefined) {\n resetTouched(hub, hub.io, writes, info.rev);\n }\n },\n });\n}\n","// Per-connection query concurrency (RFC 0003 section 9, step 2): at most\n// `maxInFlight` queries of one connection run at once, up to `maxQueued`\n// more wait in order, and past that a query fails with `RATE_LIMITED`.\n// Mutations never come here, so they are never queued behind queries. 4.1\n// had no cap: every event ran as soon as it arrived.\n\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { cancelledError } from \"./errors\";\n\n/** The limits of {@link createConcurrencyLimiter}. */\nexport interface ConcurrencyLimits {\n /** Queries of one connection that may run at once. */\n readonly maxInFlight: number;\n /** Queries of one connection that may wait for a slot. */\n readonly maxQueued: number;\n /** The `retryAfterMs` sent with `RATE_LIMITED` when the queue is full. */\n readonly retryAfterMs: number;\n /** What a lane runs, for the `RATE_LIMITED` message. Default `\"queries\"`. */\n readonly work?: string;\n}\n\n/** A held query slot. */\nexport interface QuerySlot {\n /** How long the query waited in the queue, in milliseconds. */\n readonly queueMs: number;\n /** Frees the slot for the next queued query. Calling it again does nothing. */\n release(): void;\n}\n\n/** Hands out query slots per connection. */\nexport interface ConcurrencyLimiter {\n /**\n * Resolves with a slot of `connectionId`'s lane once one is free. Rejects\n * with `RATE_LIMITED` when the lane's queue is full, and with `CANCELLED`\n * when `signal` aborts first.\n */\n acquire(connectionId: string, signal?: AbortSignal): Promise<QuerySlot>;\n /** Connections that have queries running or queued. */\n readonly connections: number;\n}\n\ninterface Waiter {\n readonly grant: () => void;\n}\n\ninterface Lane {\n running: number;\n readonly queue: Waiter[];\n}\n\nexport function createConcurrencyLimiter(limits: ConcurrencyLimits): ConcurrencyLimiter {\n const lanes = new Map<string, Lane>();\n\n function dropIfIdle(connectionId: string, lane: Lane): void {\n if (lane.running === 0 && lane.queue.length === 0) {\n lanes.delete(connectionId);\n }\n }\n\n function slot(connectionId: string, lane: Lane, queueMs: number): QuerySlot {\n let released = false;\n return {\n queueMs,\n release() {\n if (released) {\n return;\n }\n released = true;\n lane.running -= 1;\n const next = lane.queue.shift();\n if (next === undefined) {\n dropIfIdle(connectionId, lane);\n return;\n }\n lane.running += 1;\n next.grant();\n },\n };\n }\n\n function enqueue(connectionId: string, lane: Lane, signal?: AbortSignal): Promise<QuerySlot> {\n return new Promise((resolve, reject) => {\n const enqueuedAt = performance.now();\n const waiter: Waiter = { grant };\n function grant(): void {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve(slot(connectionId, lane, performance.now() - enqueuedAt));\n }\n function onAbort(): void {\n const index = lane.queue.indexOf(waiter);\n if (index >= 0) {\n lane.queue.splice(index, 1);\n }\n dropIfIdle(connectionId, lane);\n reject(cancelledError());\n }\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n lane.queue.push(waiter);\n });\n }\n\n return {\n acquire(connectionId, signal) {\n if (signal?.aborted === true) {\n return Promise.reject(cancelledError());\n }\n let lane = lanes.get(connectionId);\n if (lane === undefined) {\n lane = { running: 0, queue: [] };\n lanes.set(connectionId, lane);\n }\n if (lane.running < limits.maxInFlight) {\n lane.running += 1;\n return Promise.resolve(slot(connectionId, lane, 0));\n }\n if (lane.queue.length >= limits.maxQueued) {\n const message = `Too many ${limits.work ?? \"queries\"} in flight on this connection`;\n return Promise.reject(\n new QuickdrawError(\"RATE_LIMITED\", message, { retryAfterMs: limits.retryAfterMs }),\n );\n }\n return enqueue(connectionId, lane, signal);\n },\n get connections() {\n return lanes.size;\n },\n };\n}\n","// Each socket's lane of subscription events (RFC 0003 sections 6, 7 and 9):\n// `qd:sub`, `qd:col:sub`, `qd:col:items` and `qd:watch` read the database,\n// and the socket rate limiter does not count them (a page mounts many at\n// once, `transports/middleware.ts`). Without a cap, one socket could start\n// any number of 500-id batches together. They run through the concurrency\n// stage's limiter instead (`pipeline/concurrency.ts`), one lane per socket\n// shared by the four events: `limits.subscriptions.maxInFlight` (8) at once,\n// `maxQueued` (64) waiting in order, then `RATE_LIMITED`. A socket's queued\n// work is dropped when it disconnects; work already running finishes, and\n// frees its slot.\n\nimport { createConcurrencyLimiter } from \"../pipeline/concurrency\";\nimport type { QuickdrawServerSocket, SocketContext } from \"../transports/types\";\n\n/** Runs one subscription event's work in its socket's lane; rejects `RATE_LIMITED` when the lane is full. */\nexport type Lane = <T>(work: () => Promise<T>) => Promise<T>;\n\nconst LANES = new WeakMap<QuickdrawServerSocket, Lane>();\n\n/** The socket's lane, made on first use with the dispatcher's `limits.subscriptions`. */\nexport function laneOf(\n socket: QuickdrawServerSocket,\n context: Pick<SocketContext, \"dispatcher\">,\n): Lane {\n const existing = LANES.get(socket);\n if (existing !== undefined) {\n return existing;\n }\n const { subscriptions, retryAfterMs } = context.dispatcher.limits;\n const limiter = createConcurrencyLimiter({\n maxInFlight: subscriptions.maxInFlight,\n maxQueued: subscriptions.maxQueued,\n retryAfterMs,\n work: \"subscription requests\",\n });\n const closed = new AbortController();\n socket.on(\"disconnect\", () => {\n closed.abort();\n });\n const lane: Lane = async (work) => {\n const slot = await limiter.acquire(socket.id, closed.signal);\n try {\n return await work();\n } finally {\n slot.release();\n }\n };\n LANES.set(socket, lane);\n return lane;\n}\n","// How the live data's socket listeners answer (RFC 0003 section 8.2): the\n// entity, collection and topic events share these, so none of them throws.\n// Socket.IO runs listeners from `process.nextTick`, where an exception ends\n// the process: whatever a frame makes go wrong is logged and answered\n// `INTERNAL` instead. The events that read the database (`qd:sub`,\n// `qd:col:sub`, `qd:col:items`, `qd:watch`) run in the socket's lane of\n// subscription work (`lane.ts`).\n\nimport type { Failure } from \"../../protocol/envelope\";\nimport { toWire } from \"../../protocol/errors\";\nimport { toQuickdrawError } from \"../pipeline/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport { acknowledge, INTERNAL_FAILURE, type Acknowledge } from \"../transports/ack\";\nimport type { QuickdrawServerSocket, SocketContext } from \"../transports/types\";\nimport { laneOf } from \"./lane\";\n\n/** Acknowledges a subscription event, when the client asked for an acknowledgement. Never throws. */\nexport function reply(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n ack: unknown,\n message: unknown,\n): void {\n if (typeof ack !== \"function\") {\n return;\n }\n acknowledge(context.meter, ack as Acknowledge, message, INTERNAL_FAILURE, (error) => {\n context.logger.error(\n \"A subscription reply could not be encoded; it was answered with INTERNAL\",\n {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n error: describeError(error),\n },\n );\n });\n}\n\n/** The failure a frame's handler answers with for what it threw; an `INTERNAL` one is logged. */\nexport function failureOf(\n context: Pick<SocketContext, \"logger\">,\n socket: QuickdrawServerSocket,\n event: string,\n error: unknown,\n): Failure {\n const failure = toQuickdrawError(error);\n if (failure.code === \"INTERNAL\") {\n context.logger.error(`A ${event} failed`, {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n error: describeError(failure.cause ?? failure),\n });\n }\n return { ok: false, e: toWire(failure) };\n}\n\n/**\n * Answers a frame whose handler is synchronous with what `work` returns, or\n * with the failure what it threw maps to (`INTERNAL`, logged, for anything\n * but a `QuickdrawError`). Never throws.\n */\nexport function answerNow(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n event: string,\n ack: unknown,\n work: () => unknown,\n): void {\n let answer: unknown;\n try {\n answer = work();\n } catch (error) {\n answer = failureOf(context, socket, event, error);\n }\n reply(socket, context, ack, answer);\n}\n\n/**\n * Answers a frame whose handler is asynchronous with what `work` resolves\n * with, or with the failure its rejection maps to. Never throws, and the\n * promise it starts never rejects.\n */\nexport function answerLater(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n event: string,\n ack: unknown,\n work: () => Promise<unknown>,\n): void {\n const settled = (async () => {\n try {\n return await work();\n } catch (error) {\n return failureOf(context, socket, event, error);\n }\n })();\n void settled.then((answer) => {\n reply(socket, context, ack, answer);\n });\n}\n\n/** Runs `cleanup` when the socket disconnects; what it throws is logged, never thrown. */\nexport function onDisconnect(\n socket: QuickdrawServerSocket,\n context: Pick<SocketContext, \"logger\">,\n cleanup: () => void,\n): void {\n socket.on(\"disconnect\", () => {\n try {\n cleanup();\n } catch (error) {\n context.logger.error(\"Cleaning up a disconnected socket's live data failed\", {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n error: describeError(error),\n });\n }\n });\n}\n\n/**\n * Registers a listener for a subscription event a client sends with an\n * acknowledgement, answered by `work` run in the socket's lane\n * (`answerLater`): `RATE_LIMITED` when the lane is full. An event sent\n * without an acknowledgement is ignored.\n */\nexport function answerEvent(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n event: string,\n work: (frame: unknown) => Promise<unknown>,\n): void {\n const lane = laneOf(socket, context);\n socket.on(event, (frame: unknown, ack: unknown) => {\n if (typeof ack !== \"function\") {\n context.logger.debug(`Ignored a ${event} sent without an acknowledgement`, {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n });\n return;\n }\n answerLater(socket, context, event, ack, () => lane(() => work(frame)));\n });\n}\n","// Reading the collection frames a client sends (RFC 0003 sections 7.3, 7.4\n// and 8.2), which `envelope.ts` defines: `qd:col:sub { s, c, scope, since?,\n// limit?, cursor? }`, `qd:col:unsub { s, c, scope }` and `qd:col:items { s,\n// c, scope, ids }`. A malformed frame is `VALIDATION`, naming the field; an\n// unknown service or collection is `NOT_FOUND`; an anonymous socket is\n// `UNAUTHENTICATED`.\n//\n// `qd:col:items` serves a socket that subscribed to the scope already: its\n// subscription is the authorization, kept current by revocation, so it reads\n// no access and costs one statement (two for a `via` scope). A self scope on\n// a service with a policy also asks the policy's filter for the subscriber\n// (`selfAccess.ts`): its items are only the rows the subscriber may read. A\n// socket that has not subscribed is `FORBIDDEN`, and more than 200 ids are\n// `VALIDATION`, as more than 500 are for `qd:sub`. A scope value longer than\n// 256 characters is `VALIDATION` in every frame.\n\nimport type { CollectionItemsReply, Ok } from \"../../protocol/envelope\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { MAX_SCOPE_LENGTH } from \"../../protocol/version\";\nimport { liveService } from \"../emit/hub\";\nimport { unreadable } from \"../transports/ack\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { itemsWhere } from \"./access\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\nimport { MAX_ITEM_IDS, readItemsById } from \"./items\";\nimport { roomOf, type ScopeRequest, type ScopeSubscription } from \"./scopes\";\n\ntype UnknownRecord = Readonly<Record<string, unknown>>;\n\ntype ScopeRef = Pick<ScopeSubscription, \"s\" | \"c\" | \"scope\">;\n\n/** A `qd:col:items` frame, read. */\nexport interface ItemsRequest extends ScopeRef {\n readonly ids: readonly string[];\n}\n\nfunction isRecord(value: unknown): value is UnknownRecord {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isName(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\n/** Reads `{ s, c, scope }`, or throws `VALIDATION`. */\nfunction readRef(frame: unknown, event: string): ScopeRef & { readonly frame: UnknownRecord } {\n if (!isRecord(frame) || !isName(frame.s) || !isName(frame.c) || !isName(frame.scope)) {\n throw unreadable(`A ${event} frame needs { s, c, scope } with each a non-empty string`);\n }\n if (frame.scope.length > MAX_SCOPE_LENGTH) {\n throw unreadable(`scope must be at most ${MAX_SCOPE_LENGTH} characters`, [\"scope\"]);\n }\n return { s: frame.s, c: frame.c, scope: frame.scope, frame };\n}\n\n/** Reads a `qd:col:sub` frame, or throws `VALIDATION`. */\nexport function readSubscribe(value: unknown): ScopeRequest {\n const { s, c, scope, frame } = readRef(value, \"qd:col:sub\");\n const { since, limit, cursor } = frame;\n if (since !== undefined && (typeof since !== \"number\" || !Number.isFinite(since))) {\n throw unreadable(\"since must be the revision the client holds the scope at\", [\"since\"]);\n }\n if (\n limit !== undefined &&\n (typeof limit !== \"number\" || !Number.isSafeInteger(limit) || limit < 1)\n ) {\n throw unreadable(\"limit must be a positive whole number\", [\"limit\"]);\n }\n if (cursor !== undefined && !isName(cursor)) {\n throw unreadable(\"cursor must be the cursor of a page this collection sent\", [\"cursor\"]);\n }\n if (since !== undefined && cursor !== undefined) {\n throw unreadable(\n \"A qd:col:sub frame resumes (since) or reads a later page (cursor), not both\",\n [\"cursor\"],\n );\n }\n return {\n s,\n c,\n scope,\n ...(since === undefined ? {} : { since }),\n ...(limit === undefined ? {} : { limit }),\n ...(cursor === undefined ? {} : { cursor }),\n };\n}\n\n/** Reads a `qd:col:items` frame, or throws `VALIDATION`. */\nexport function readItemsRequest(value: unknown): ItemsRequest {\n const { s, c, scope, frame } = readRef(value, \"qd:col:items\");\n const { ids } = frame;\n if (!Array.isArray(ids) || !ids.every(isName)) {\n throw unreadable(\"ids must be a list of row ids\", [\"ids\"]);\n }\n if (ids.length > MAX_ITEM_IDS) {\n throw unreadable(`A qd:col:items frame names at most ${MAX_ITEM_IDS} ids`, [\"ids\"]);\n }\n return { s, c, scope, ids };\n}\n\n/** The collection a frame names, or `NOT_FOUND`. */\nexport function collectionOf(hub: CollectionHub, service: string, name: string): BoundCollection {\n liveService(hub, service);\n const collection = hub.collections.routes.find(service, name);\n if (collection === undefined) {\n throw new QuickdrawError(\"NOT_FOUND\", `${service} has no collection \"${name}\"`);\n }\n return collection;\n}\n\n/**\n * The collection a request names and the storage it is read through: the\n * checks every collection request makes first. Throws `NOT_FOUND` for an\n * unknown service or collection, `UNAUTHENTICATED` for an anonymous socket,\n * and `INTERNAL` when the dispatcher has no storage adapter.\n */\nexport function servedCollection(\n hub: CollectionHub,\n socket: QuickdrawServerSocket,\n ref: Pick<ScopeRef, \"s\" | \"c\">,\n): {\n readonly collection: BoundCollection;\n readonly storage: NonNullable<CollectionHub[\"storage\"]>;\n readonly principal: NonNullable<QuickdrawServerSocket[\"data\"][\"principal\"]>;\n} {\n const collection = collectionOf(hub, ref.s, ref.c);\n const { principal } = socket.data;\n if (principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n if (hub.storage === undefined) {\n throw new QuickdrawError(\n \"INTERNAL\",\n \"Collections read rows through the dispatcher's storage adapter: pass db as trackPrisma(prisma)\",\n );\n }\n return { collection, storage: hub.storage, principal };\n}\n\n/**\n * Serves one `qd:col:items`: the items of the requested ids that are members\n * of the scope, in request order. Throws what `servedCollection` throws, and\n * `FORBIDDEN` when the socket is not subscribed to the scope.\n */\nexport async function loadItems(\n hub: CollectionHub,\n socket: QuickdrawServerSocket,\n request: ItemsRequest,\n): Promise<CollectionItemsReply> {\n const { collection, storage, principal } = servedCollection(hub, socket, request);\n if (hub.collections.scopes.get(socket, roomOf(request)) === undefined) {\n throw new QuickdrawError(\n \"FORBIDDEN\",\n \"qd:col:items needs the scope subscribed with qd:col:sub\",\n );\n }\n // The revision is claimed before any read: behind a cluster's counter, the counter's.\n const rev = await hub.revisions.claim();\n const filter = await itemsWhere(hub, collection, principal);\n return {\n ok: true,\n ...(await readItemsById(storage, collection, request.scope, request.ids, rev, filter)),\n };\n}\n\n/**\n * Serves `qd:col:unsub`: the socket leaves the scope, and a subscribe still\n * being made will not join it. Throws `VALIDATION` for a malformed frame,\n * `NOT_FOUND` for an unknown service or collection, and `UNAUTHENTICATED`\n * for an anonymous socket, which subscribes to nothing.\n */\nexport function unsubscribeScope(\n hub: CollectionHub,\n socket: QuickdrawServerSocket,\n value: unknown,\n): Ok {\n const ref = readRef(value, \"qd:col:unsub\");\n collectionOf(hub, ref.s, ref.c);\n if (socket.data.principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n hub.collections.scopes.unsubscribe(socket, roomOf(ref));\n return { ok: true };\n}\n","// One page of a collection scope (RFC 0003 section 7.3): the rows of the\n// scope (its scope column, or its `via` junction's links, and `where`) in\n// `order`, after the cursor when there is one, at most `limit` of them; the\n// scope's member count; the cursor of the next page; and, on a first page\n// (no cursor) of a collection that declares `index`, the scope's index\n// (section 7.4, `index.ts`). The revision is taken by the caller before any\n// read, so the page is never older than the revision it claims. 4.1 left all\n// of it to each collection's `snapshot` function and clamped only the page\n// size (4.1 `src/server/collections.ts:160-171`).\n//\n// A page costs two statements, the rows and the count, run together, and a\n// first page of an indexed collection a third beside them, the index; a\n// `via` scope reads its links first. The first page of a scope through an\n// adapter that answers `nullable` also asks it about each order column, once\n// per process (`StorageAdapter.nullable`). A self scope on a service with a\n// policy also keeps its rows, count and index to those the policy lets the\n// subscriber read (`selfAccess.ts`), at the cost of the policy filter's\n// reads.\n//\n// A cursor is the client's: when the read that applies it fails while the\n// count of the same scope succeeds, the cursor's values did not fit the\n// order columns, and the request is `VALIDATION`, not a server fault.\n\nimport type { CollectionSnapshot, Revision } from \"../../protocol/envelope\";\nimport type { AccessFilter } from \"../access/policy\";\nimport type { StorageAdapter, StorageRow, StorageWhere } from \"../storage\";\nimport { unreadable } from \"../transports/ack\";\nimport type { BoundCollection } from \"./bind\";\nimport { afterCursor, decodeCursor, encodeCursor, orderByOf, type CursorValues } from \"./cursor\";\nimport { linkWhere, type ServiceCollection } from \"./define\";\nimport { readIndex } from \"./index\";\nimport { itemOf, readableMembers, selectWith } from \"./items\";\n\nconst NOT_A_CURSOR = \"cursor is not a cursor of this collection\";\n\n/** What a page asks for. */\nexport interface PageRequest {\n readonly scope: string;\n /** The page size; the collection's `limit` when absent. */\n readonly limit?: number;\n /** The cursor of the page before; the first page when absent. */\n readonly cursor?: string;\n}\n\n/** The page size used: the request's or the collection's, lowered to `maxLimit` when above it. */\nexport function pageSize(\n collection: BoundCollection,\n requested: number | undefined,\n): { readonly limit: number; readonly clamped: boolean } {\n const limit = requested ?? collection.limit;\n return limit > collection.maxLimit\n ? { limit: collection.maxLimit, clamped: true }\n : { limit, clamped: false };\n}\n\nfunction isId(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\n/**\n * The filter matching the members of a scope: its scope column, or the ids\n * its `via` junction links to it, and `where`. `undefined` for a `via` scope\n * with no links: it has no members. The search kit reads a scope's members\n * with it too, through its database client, and passes `maxLinks`: then at\n * most that many links are read, the first by the linked row's id, so one\n * call never reads a scope's every link.\n */\nexport async function membersWhere(\n storage: Pick<StorageAdapter, \"findMany\">,\n collection: Pick<ServiceCollection, \"scope\" | \"where\">,\n scope: string,\n maxLinks?: number,\n): Promise<StorageWhere | undefined> {\n const { where } = collection;\n const filtered = (filter: StorageWhere): StorageWhere =>\n Object.keys(where).length === 0 ? filter : { AND: [filter, where] };\n if (collection.scope.kind === \"column\") {\n return filtered({ [collection.scope.column]: scope });\n }\n const { model, entry, scope: column } = collection.scope;\n const links = await storage.findMany(model, {\n where: linkWhere(collection.scope, { [column]: scope }),\n select: { [entry]: true },\n ...(maxLinks === undefined ? {} : { orderBy: { [entry]: \"asc\" }, take: maxLinks }),\n });\n const ids = [...new Set(links.map((link) => link[entry]).filter(isId))];\n return ids.length === 0 ? undefined : filtered({ id: { in: ids } });\n}\n\n/**\n * The order columns that may hold null, as the adapter answers. A cursor\n * holding null for a column the adapter says cannot hold it is not a cursor\n * of this collection.\n */\nasync function nullableColumns(\n storage: StorageAdapter,\n collection: BoundCollection,\n values: CursorValues | undefined,\n): Promise<Set<string>> {\n const columns = collection.order.map(([column]) => column);\n const answers = await Promise.all(\n columns.map(async (column) =>\n column === \"id\" ? false : ((await storage.nullable?.(collection.model, column)) ?? false),\n ),\n );\n const nullable = new Set<string>();\n for (const [index, column] of columns.entries()) {\n const known = storage.nullable !== undefined;\n if (values?.[index] === null && known && answers[index] !== true) {\n throw unreadable(NOT_A_CURSOR, [\"cursor\"]);\n }\n if (answers[index] === true || values?.[index] === null) {\n nullable.add(column);\n }\n }\n return nullable;\n}\n\n/** How one page's rows are read: the scope's filter, the cursor's values and the page size. */\ninterface RowsRead {\n readonly members: StorageWhere;\n readonly values: CursorValues | undefined;\n readonly nullable: ReadonlySet<string>;\n readonly limit: number;\n}\n\n/**\n * The page's rows (one more than `limit`, to tell whether a page follows)\n * and the scope's member count. A rows read that applied a cursor and failed\n * while the count succeeded throws `VALIDATION`: the cursor's values do not\n * fit the order columns.\n */\nasync function readRows(\n storage: StorageAdapter,\n collection: BoundCollection,\n read: RowsRead,\n): Promise<{ readonly rows: StorageRow[]; readonly total: number }> {\n const { members, values, nullable, limit } = read;\n const { order } = collection;\n const where =\n values === undefined ? members : { AND: [members, afterCursor(order, values, nullable)] };\n const [rows, total] = await Promise.allSettled([\n storage.findMany(collection.model, {\n where,\n select: selectWith(\n collection.item.select,\n order.map(([column]) => column),\n ),\n orderBy: orderByOf(order, nullable),\n take: limit + 1,\n }),\n storage.count(collection.model, { where: members }),\n ]);\n if (total.status === \"rejected\") {\n throw total.reason;\n }\n if (rows.status === \"fulfilled\") {\n return { rows: rows.value, total: total.value };\n }\n if (values === undefined) {\n throw rows.reason;\n }\n const refused = unreadable(NOT_A_CURSOR, [\"cursor\"]);\n refused.cause = rows.reason;\n throw refused;\n}\n\n/**\n * Reads one page of `request.scope` at revision `rev`: its items, the\n * scope's member count, and the next page's cursor (`null` on the last\n * page); on a first page of a collection that declares `index`, its index\n * too. A request above `maxLimit` gets `maxLimit` items and `clamped`.\n * `filter` keeps the rows, the count and the index to the rows a policy\n * lets the subscriber read (a self scope, `selfAccess.ts`). Throws\n * `VALIDATION` for a cursor that is not one of this collection.\n */\nexport async function readPage(\n storage: StorageAdapter,\n collection: BoundCollection,\n request: PageRequest,\n rev: Revision,\n filter?: AccessFilter,\n): Promise<CollectionSnapshot> {\n const { limit, clamped } = pageSize(collection, request.limit);\n const { order } = collection;\n const values = request.cursor === undefined ? undefined : decodeCursor(order, request.cursor);\n const nullable = await nullableColumns(storage, collection, values);\n const members = readableMembers(\n filter === \"none\" ? undefined : await membersWhere(storage, collection, request.scope),\n filter,\n );\n const page = { ok: true, rev, limit, ...(clamped ? { clamped: true as const } : {}) } as const;\n const indexed = values === undefined && collection.index !== undefined;\n if (members === undefined) {\n return { ...page, items: [], total: 0, cursor: null, ...(indexed ? { index: [] } : {}) };\n }\n const [{ rows, total }, index] = await Promise.all([\n readRows(storage, collection, { members, values, nullable, limit }),\n indexed ? readIndex(storage, collection, members, nullable, rev) : undefined,\n ]);\n const shown = rows.slice(0, limit);\n const last = shown.at(-1);\n return {\n ...page,\n items: shown.map((row) => itemOf(collection, row)),\n total,\n cursor: rows.length > limit && last !== undefined ? encodeCursor(order, last) : null,\n ...index,\n };\n}\n","// One `qd:col:sub` (RFC 0003 sections 4.3 and 7.3), in the order entity\n// subscriptions go (`emit/subscribe.ts`). 4.1 joined the scope's room before\n// reading (4.1 `src/server/collections.ts:155-158`) and answered an\n// unknown collection and a denied scope alike. Here:\n//\n// 1. authorize the scope (`access.ts`): a denied scope is `FORBIDDEN`, and\n// nothing is read;\n// 2. take the revision before any read: the last one taken (`currentRev`),\n// or a new one when the last is below the scope's resume floor (just\n// after a reset), so the client can resume from the page it gets;\n// 3. with a cursor, read that page and answer it: paging never joins;\n// 4. with `since`, when this process sees every change (no cluster adapter,\n// the change log on): join the scope's room, then answer the buffered\n// deltas since `since` when the buffer covers it. Joining first means a\n// change recorded after the buffer is read reaches the socket as a frame;\n// 5. otherwise read the first page, then join;\n// 6. settle the races: an access change while the subscribe ran (or a\n// replaced principal: new grants) authorizes again, with the socket's\n// principal as it is then, never the one the subscribe began with (the\n// 5.1 audit's LIVE-1); another identity, or none, is denied, and a denied\n// scope leaves its room. A flush that changed the scope after the\n// revision (its frame may have gone out before the join) reads the page\n// again, at a newer revision. So does any access change in a self scope\n// whose items follow its service's policy (`selfAccess.ts`): the page was\n// filtered before the change, which found no subscription to re-check,\n// and is read again for the principal last authorized. Then, while access\n// keeps changing, the scope is authorized again, at most `MAX_RECHECKS`\n// times, and refused when its anchors were still moving. A subscription\n// the subscribe recorded and revocation ended meanwhile is `FORBIDDEN`.\n//\n// Every page of a self scope on a service with a policy, cursor pages too,\n// is filtered by that policy for the subscriber (`selfAccess.ts`).\n//\n// A socket holds at most `MAX_SCOPES_PER_SOCKET` scopes (the 5.1 audit's\n// COLL-4): one more is `CONFLICT`, checked before step 1 (no read) and again\n// at the join, so subscribes running at once in the socket's lane cannot\n// overshoot. A scope held already never counts again, and a cursor page,\n// which joins nothing, is not checked.\n\nimport type {\n CollectionSnapshot,\n CollectionSubscribeReply,\n Revision,\n} from \"../../protocol/envelope\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { usableChangeLog } from \"../emit/hub\";\nimport { MAX_RECHECKS } from \"../emit/subscribe\";\nimport { currentRev, nextRev } from \"../rev\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { authorizeScopes, followsPolicy, itemsWhere } from \"./access\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\nimport { groupOf, roomOf, type ScopeRequest, type ScopeSubscription } from \"./scopes\";\nimport { readPage } from \"./snapshot\";\n\nexport type { ScopeRequest } from \"./scopes\";\n\ninterface Attempt {\n readonly hub: CollectionHub;\n readonly storage: NonNullable<CollectionHub[\"storage\"]>;\n readonly socket: QuickdrawServerSocket;\n readonly collection: BoundCollection;\n /** The principal the subscribe began with. */\n readonly principal: NonNullable<QuickdrawServerSocket[\"data\"][\"principal\"]>;\n /** The socket's principal when the subscribe last authorized the scope: pages are filtered for it. */\n resolvedWith: NonNullable<QuickdrawServerSocket[\"data\"][\"principal\"]>;\n readonly request: ScopeRequest;\n readonly room: string;\n /** The access changes the process had seen when the subscribe last authorized the scope. */\n checkedAt: number;\n /** How often the socket had unsubscribed from the scope when the subscribe began. */\n readonly unsubscribes: number;\n /** The subscription this subscribe recorded, while it manages it. */\n record: ScopeSubscription | undefined;\n /** Whether the last recheck gave the scope new anchors. */\n moving: boolean;\n}\n\nfunction forbidden(): QuickdrawError {\n return new QuickdrawError(\"FORBIDDEN\", \"Insufficient permissions\");\n}\n\n/** The anchors of the scope, or `undefined` when `principal` may not subscribe to it. */\nasync function anchorsOf(\n attempt: Attempt,\n principal: Attempt[\"principal\"],\n): Promise<readonly string[] | undefined> {\n const { hub, collection, request } = attempt;\n const allowed = await authorizeScopes(hub, collection, principal, [request.scope]);\n return allowed.get(request.scope);\n}\n\n/** True while the socket's subscription to the scope is still the one this subscribe recorded. */\nfunction isOwn(attempt: Attempt): boolean {\n const { hub, socket, room, record } = attempt;\n return record !== undefined && hub.collections.scopes.get(socket, room) === record;\n}\n\n/** Joins the scope's room, unless the socket has gone or the client unsubscribed meanwhile. */\nfunction join(attempt: Attempt, anchors: readonly string[]): void {\n const { hub, socket, request, room } = attempt;\n if (\n !socket.connected ||\n hub.collections.scopes.unsubscribes(socket, room) !== attempt.unsubscribes\n ) {\n return;\n }\n // Again at the join, so subscribes running at once cannot overshoot.\n hub.collections.scopes.checkRoom(socket, room);\n const record: ScopeSubscription = { s: request.s, c: request.c, scope: request.scope, anchors };\n hub.collections.scopes.set(socket, record);\n attempt.record = record;\n}\n\n/** Ends the subscription this subscribe made; another's is left alone. */\nfunction leave(attempt: Attempt): void {\n if (isOwn(attempt)) {\n attempt.hub.collections.scopes.delete(attempt.socket, attempt.room);\n }\n attempt.record = undefined;\n}\n\n/**\n * The subscription this subscribe recorded is no longer the socket's: ended\n * by revocation (or a disconnect), which is `FORBIDDEN` unless the client\n * unsubscribed, or replaced by a newer authorization, which stands.\n */\nfunction releaseTaken(attempt: Attempt): void {\n if (attempt.record === undefined || isOwn(attempt)) {\n return;\n }\n const { hub, socket, room } = attempt;\n attempt.record = undefined;\n const ended = hub.collections.scopes.get(socket, room) === undefined;\n if (ended && hub.collections.scopes.unsubscribes(socket, room) === attempt.unsubscribes) {\n throw forbidden();\n }\n}\n\nfunction sameAnchors(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((anchor, index) => anchor === b[index]);\n}\n\n/** True when access changed, or the socket's principal was replaced, since the subscribe last authorized the scope. */\nfunction accessMoved(attempt: Attempt): boolean {\n return (\n attempt.hub.subscriptions.accessChanges !== attempt.checkedAt ||\n attempt.socket.data.principal !== attempt.resolvedWith\n );\n}\n\n/**\n * Step 6: access changed since the subscribe last authorized the scope, so\n * it is authorized again, with the socket's principal as it is now: the\n * same user's current grants; another identity, or none, is `FORBIDDEN`.\n */\nasync function recheckAccess(attempt: Attempt): Promise<void> {\n if (!accessMoved(attempt)) {\n return;\n }\n attempt.checkedAt = attempt.hub.subscriptions.accessChanges;\n attempt.moving = false;\n const now = attempt.socket.data.principal;\n if (now === null || now.userId !== attempt.principal.userId) {\n leave(attempt);\n throw forbidden();\n }\n attempt.resolvedWith = now;\n const anchors = await anchorsOf(attempt, now);\n if (anchors === undefined) {\n leave(attempt);\n throw forbidden();\n }\n releaseTaken(attempt);\n const { record } = attempt;\n if (record !== undefined && !sameAnchors(record.anchors, anchors)) {\n const moved: ScopeSubscription = { ...record, anchors };\n attempt.hub.collections.scopes.set(attempt.socket, moved);\n attempt.record = moved;\n attempt.moving = true;\n }\n}\n\n/** Step 6, once the reads are done: authorize again while access keeps changing, at most `MAX_RECHECKS` times. */\nasync function settleRaces(attempt: Attempt): Promise<void> {\n for (let round = 0; round < MAX_RECHECKS && accessMoved(attempt); round += 1) {\n await recheckAccess(attempt);\n }\n if (accessMoved(attempt) && attempt.moving) {\n // Access changed during the last check too, and the scope's anchors moved: they may have missed it.\n leave(attempt);\n throw forbidden();\n }\n releaseTaken(attempt);\n}\n\n/**\n * Step 2: the revision a page is read at. The last one taken, unless it is\n * below the scope's resume floor (a reset or a change nobody here received\n * was the last thing to happen): then a new one, so a client resuming from\n * the page is covered. Behind a cluster's counter, the counter's last one:\n * a resume there always reads a page, and the floor is this process's.\n */\nfunction pageRev(attempt: Attempt): Revision | Promise<Revision> {\n const { hub, request, room } = attempt;\n if (hub.revisions.shared()) {\n return hub.revisions.claim();\n }\n const rev = currentRev();\n const floor = hub.collections.buffer.floor(room, groupOf(request.s, request.c));\n return rev < floor ? nextRev() : rev;\n}\n\n/**\n * Step 6: the revision to read the page again at when a flush changed the\n * scope after `rev` (its frame may have gone out before the join), or\n * `undefined`. This process's buffer knows its own flushes only, so behind\n * a cluster's counter any revision any node took after `rev` counts.\n */\nasync function changedSince(attempt: Attempt, rev: Revision): Promise<Revision | undefined> {\n const { hub, request, room } = attempt;\n if (hub.revisions.shared()) {\n return await hub.revisions.movedPast(rev);\n }\n return hub.collections.buffer.lastChange(room, groupOf(request.s, request.c)) > rev\n ? pageRev(attempt)\n : undefined;\n}\n\n/**\n * A page of the scope at `rev`, filtered by the item service's policy in a\n * self scope that follows it, for the principal the scope was last\n * authorized with.\n */\nasync function pageOf(attempt: Attempt, rev: Revision): Promise<CollectionSnapshot> {\n const { hub, storage, collection, request, resolvedWith } = attempt;\n return await readPage(\n storage,\n collection,\n request,\n rev,\n await itemsWhere(hub, collection, resolvedWith),\n );\n}\n\n/** What the first page was read under: the access changes seen, and the principal it was filtered for. */\ninterface ReadUnder {\n readonly changes: number;\n readonly principal: Attempt[\"resolvedWith\"];\n}\n\n/**\n * Step 6: the revision to read the page again at, or `undefined`: a flush\n * changed the scope after `rev` (`changedSince`), or, in a self scope that\n * follows its service's policy, access changed (or the principal the page\n * is filtered for) since the page was read.\n */\nasync function rereadAt(\n attempt: Attempt,\n rev: Revision,\n under: ReadUnder,\n): Promise<Revision | undefined> {\n const changed = await changedSince(attempt, rev);\n if (changed !== undefined) {\n return changed;\n }\n const moved =\n attempt.hub.subscriptions.accessChanges !== under.changes ||\n attempt.resolvedWith !== under.principal;\n return moved && followsPolicy(attempt.collection) ? await pageRev(attempt) : undefined;\n}\n\n/** Steps 4 to 6. */\nasync function answer(\n attempt: Attempt,\n anchors: readonly string[],\n): Promise<CollectionSubscribeReply> {\n const { hub, request, room } = attempt;\n const group = groupOf(request.s, request.c);\n if (request.since !== undefined && usableChangeLog(hub) !== undefined) {\n join(attempt, anchors);\n const replay = hub.collections.buffer.since(room, request.since, group);\n if (replay !== undefined) {\n await recheckAccess(attempt);\n await settleRaces(attempt);\n return { ok: true, resumed: true, rev: replay.rev, deltas: replay.deltas };\n }\n }\n const under: ReadUnder = {\n changes: hub.subscriptions.accessChanges,\n principal: attempt.resolvedWith,\n };\n const claimed = pageRev(attempt);\n const rev = typeof claimed === \"number\" ? claimed : await claimed;\n let page = await pageOf(attempt, rev);\n join(attempt, anchors);\n await recheckAccess(attempt);\n const again = attempt.record === undefined ? undefined : await rereadAt(attempt, rev, under);\n if (again !== undefined) {\n page = await pageOf(attempt, again);\n }\n await settleRaces(attempt);\n return page;\n}\n\n/**\n * Answers one `qd:col:sub` of a socket with a principal: a page, or the\n * deltas since `since`. Throws `FORBIDDEN` for a scope the principal may not\n * subscribe to, `VALIDATION` for a cursor of another collection, and the\n * error of a lookup or read that failed; a room the subscribe joined is then\n * left.\n */\nexport async function subscribeScope(\n hub: CollectionHub,\n socket: QuickdrawServerSocket,\n collection: BoundCollection,\n request: ScopeRequest,\n): Promise<CollectionSubscribeReply> {\n const { principal } = socket.data;\n const { storage } = hub;\n if (principal === null || storage === undefined) {\n throw new TypeError(\"subscribeScope: the socket has no principal, or the hub no storage\");\n }\n const room = roomOf(request);\n if (request.cursor === undefined) {\n // At most MAX_SCOPES_PER_SOCKET scopes a socket (paging joins none): refused before any read.\n hub.collections.scopes.checkRoom(socket, room);\n }\n const attempt: Attempt = {\n hub,\n storage,\n socket,\n collection,\n principal,\n resolvedWith: principal,\n request,\n room,\n checkedAt: hub.subscriptions.accessChanges,\n unsubscribes: hub.collections.scopes.begin(socket, room),\n record: undefined,\n moving: false,\n };\n try {\n const anchors = await anchorsOf(attempt, principal);\n if (anchors === undefined) {\n throw forbidden();\n }\n if (request.cursor !== undefined) {\n return await pageOf(attempt, await pageRev(attempt));\n }\n return await answer(attempt, anchors);\n } catch (error) {\n leave(attempt);\n throw error;\n } finally {\n hub.collections.scopes.end(socket, room);\n }\n}\n","// The socket listeners of collection subscriptions (RFC 0003 sections 7.3,\n// 7.4 and 8.2): `qd:col:sub`, answered with a page (`{ ok: true, rev, items,\n// total, cursor, limit, clamped?, index? | indexTruncated? }`), with the\n// deltas since `since` (`{ ok: true, resumed: true, rev, deltas }`), or\n// `{ ok: false, e }`; `qd:col:items`, answered `{ ok: true, rev, items }` or\n// `{ ok: false, e }`; and `qd:col:unsub`, optionally acknowledged. One\n// listener per event on every v5 socket, routed by the frame, never one per\n// service or scope. None of them counts against the socket rate limiter\n// (`transports/middleware.ts`), like `qd:sub`.\n//\n// A request fails with `VALIDATION` for a malformed frame, `NOT_FOUND` for an\n// unknown service or collection, `UNAUTHENTICATED` for an anonymous socket,\n// `FORBIDDEN` for a principal of a kind the service does not admit\n// (`../access/kinds.ts`), for a scope the principal may not subscribe to (4.1\n// answered an unknown collection and a denied scope alike) or, for\n// `qd:col:items`, one the socket has not subscribed to, which a refused kind\n// never has; `CONFLICT` for a `qd:col:sub` of a new scope on a socket that\n// holds `MAX_SCOPES_PER_SOCKET` (`subscribe.ts`); and `INTERNAL`, logged,\n// for a lookup or read that failed. No listener throws (`emit/answer.ts`).\n\nimport { CLIENT_EVENTS } from \"../../contract/names\";\nimport { checkKind } from \"../access/kinds\";\nimport { answerEvent, answerNow, onDisconnect } from \"../emit/answer\";\nimport type { QuickdrawServerSocket, SocketContext } from \"../transports/types\";\nimport type { CollectionHub } from \"./bind\";\nimport {\n loadItems,\n readItemsRequest,\n readSubscribe,\n servedCollection,\n unsubscribeScope,\n} from \"./requests\";\nimport { subscribeScope } from \"./subscribe\";\n\n/**\n * The socket extension (`transports/socketio.ts`) that serves `qd:col:sub`,\n * `qd:col:items` and `qd:col:unsub` for one dispatcher's collections.\n */\nexport function collectionSubscriptions(\n hub: CollectionHub,\n): (socket: QuickdrawServerSocket, context: SocketContext) => void {\n return (socket, context) => {\n answerEvent(socket, context, CLIENT_EVENTS.collectionSub, async (frame) => {\n const request = readSubscribe(frame);\n const { collection } = servedCollection(hub, socket, request);\n checkKind(collection.service.kinds, socket.data.principal, collection.service.name);\n return await subscribeScope(hub, socket, collection, request);\n });\n answerEvent(socket, context, CLIENT_EVENTS.collectionItems, async (frame) => {\n return await loadItems(hub, socket, readItemsRequest(frame));\n });\n socket.on(CLIENT_EVENTS.collectionUnsub, (frame: unknown, ack: unknown) => {\n answerNow(socket, context, CLIENT_EVENTS.collectionUnsub, ack, () =>\n unsubscribeScope(hub, socket, frame),\n );\n });\n onDisconnect(socket, context, () => {\n hub.collections.scopes.drop(socket);\n });\n };\n}\n","// What access changes do to self scopes whose items follow their service's\n// policy (RFC 0003 section 4.4; the 5.1 audit's COLL-1, `selfAccess.ts`). A\n// self scope records no anchors, so revocation cannot find it by row: it is\n// found by service instead. S is the item service, P an `inherit` ancestor\n// of S:\n//\n// | Change | What happens to self scopes of S |\n// |------------------------------|------------------------------------------------------------------|\n// | `{ service: S, id }` | nothing more: the same flush's deltas reach every self scope |\n// | | holding the row, and are checked |\n// | `{ service: S, id, userId }` | scope `userId`: `levelsFor` the row; below `access`, `removed` |\n// | | (a `via` scope that no longer links the row, or links it below |\n// | | its role rule, is left to the flush that removed or demoted the |\n// | | link, which sends the removal itself) |\n// | `{ service: S }` | every self scope of S: `reset` |\n// | `{ service: P, id, userId }` | scope `userId`: `reset`; the client loads it again, filtered |\n// | `{ service: P }` | every self scope of S: `reset` |\n// | `{ service: P, id }` | not checked again: its rows leave at their next write or at the |\n// | | list's next load, and no new data reaches the user meanwhile |\n// | grants reloaded | that user's self scopes: `reset` |\n//\n// Every change the table re-checks also raises the resume floor of the\n// scopes it concerns (the user's scope, or every scope of the collection),\n// whether or not anyone subscribes to them here: a client that closed the\n// list, or was offline, and resumes it later then reads a filtered page\n// instead of keeping the rows it lost. Frames go to this process's sockets\n// only: a broadcast change reaches every node, and each re-checks its own.\n// None of it throws: a lookup that fails is logged and its scope reset.\n\nimport type { AccessChange } from \"../access/changes\";\nimport { meetsLevel } from \"../access/levels\";\nimport { describeError } from \"../pipeline/metrics\";\nimport { currentRev, nextRev } from \"../rev\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { followsPolicy } from \"./access\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\nimport { groupOf, roomOf } from \"./scopes\";\nimport { ownersOf, stillLinked } from \"./selfAccess\";\nimport { sendFrame } from \"./send\";\n\ntype Io = NonNullable<CollectionHub[\"io\"]>;\n\nconst SELF_COLLECTIONS = new WeakMap<CollectionHub, readonly BoundCollection[]>();\n\n/** The served collections that follow a policy (`followsPolicy`), found once per hub. */\nfunction selfCollections(hub: CollectionHub): readonly BoundCollection[] {\n let found = SELF_COLLECTIONS.get(hub);\n if (found === undefined) {\n found = [...hub.registry.services.values()].flatMap((service) =>\n [...service.collections.keys()].flatMap((name) => {\n const collection = hub.collections.routes.find(service.name, name);\n return collection !== undefined && followsPolicy(collection) ? [collection] : [];\n }),\n );\n SELF_COLLECTIONS.set(hub, found);\n }\n return found;\n}\n\nconst POLICY_SERVICES = new WeakMap<CollectionHub, Map<string, ReadonlySet<string>>>();\n\n/**\n * The names of `service` and of every service its policy asks through\n * `inherit`, transitively: an access change on any of them can change a\n * level on its rows. Found once per hub and service.\n */\nfunction policyServices(\n hub: CollectionHub,\n service: BoundCollection[\"service\"],\n): ReadonlySet<string> {\n const known = POLICY_SERVICES.get(hub) ?? new Map<string, ReadonlySet<string>>();\n POLICY_SERVICES.set(hub, known);\n const kept = known.get(service.name);\n if (kept !== undefined) {\n return kept;\n }\n const names = new Set<string>();\n const pending = [service.name];\n for (let name = pending.pop(); name !== undefined; name = pending.pop()) {\n if (!names.has(name)) {\n names.add(name);\n const inherits = hub.registry.services.get(name)?.access?.reads.inherits ?? [];\n pending.push(...inherits.map((contract) => contract.name));\n }\n }\n known.set(service.name, names);\n return names;\n}\n\n/**\n * Makes a resume of the scopes a change concerns read a page: the scope of\n * `userId`, or every scope of the collection. A scope nobody here\n * subscribes to gets no frame of the change.\n */\nfunction raiseFloor(hub: CollectionHub, collection: BoundCollection, userId?: string): void {\n const s = collection.service.name;\n if (userId === undefined) {\n hub.collections.buffer.skipAll(groupOf(s, collection.name));\n return;\n }\n hub.collections.buffer.skip(roomOf({ s, c: collection.name, scope: userId }), currentRev());\n}\n\nfunction logFailure(hub: CollectionHub, collection: BoundCollection, error: unknown): void {\n hub.logger.error(\"Checking a self scope's rows again failed; the scope is reset\", {\n category: \"quickdraw.access\",\n service: collection.service.name,\n collection: collection.name,\n error: describeError(error),\n });\n}\n\n/**\n * Sends `reset` to one self scope's sockets on this process, at a revision\n * claimed as reads claim one (this process's next when the cluster's\n * counter does not answer). Never throws.\n */\nasync function resetScope(\n hub: CollectionHub,\n io: Io,\n collection: BoundCollection,\n scope: string,\n): Promise<void> {\n try {\n let rev: number;\n try {\n rev = await hub.revisions.claim();\n } catch (error) {\n logFailure(hub, collection, error);\n rev = nextRev();\n }\n sendFrame(hub, io, collection, scope, rev, [{ t: \"reset\" }], { local: true });\n } catch (error) {\n logFailure(hub, collection, error);\n }\n}\n\n/**\n * Sends `removed` for row `id` to one self scope when any of its owner's\n * principals here is below `access` on it, unless a `via` scope no longer\n * links it. Never throws: a failure resets the scope.\n */\nasync function removeUnreadable(\n hub: CollectionHub,\n io: Io,\n collection: BoundCollection,\n scope: string,\n id: string,\n): Promise<void> {\n const s = collection.service.name;\n try {\n if (!(await stillLinked(hub, collection, scope, id))) {\n return;\n }\n const owners = ownersOf(io, roomOf({ s, c: collection.name, scope }), scope);\n const levels = await Promise.all(\n owners.map(async (owner) => await hub.policies.levelsFor(s, owner, [id])),\n );\n if (levels.some((of) => !meetsLevel(of.get(id), collection.access))) {\n const rev = await hub.revisions.claim();\n sendFrame(hub, io, collection, scope, rev, [{ t: \"removed\", id }], { local: true });\n }\n } catch (error) {\n logFailure(hub, collection, error);\n await resetScope(hub, io, collection, scope);\n }\n}\n\n/** The re-checks of one collection's self scopes subscribed here that `change` concerns. */\nfunction recheckScopes(\n hub: CollectionHub,\n io: Io,\n collection: BoundCollection,\n change: AccessChange,\n): Promise<void>[] {\n const own = change.service === collection.service.name ? change.id : undefined;\n return hub.collections.scopes\n .scopes(collection.service.name, collection.name)\n .filter((scope) => change.userId === undefined || scope === change.userId)\n .map((scope) =>\n own === undefined\n ? resetScope(hub, io, collection, scope)\n : removeUnreadable(hub, io, collection, scope, own),\n );\n}\n\n/**\n * What an access change does to self scopes (the table above): raises the\n * resume floor of those it concerns, and re-checks those subscribed on this\n * process. Never throws.\n */\nexport async function recheckSelf(hub: CollectionHub, change: AccessChange): Promise<void> {\n // A row's own access columns: the flush's deltas are checked (S), or a documented gap (P).\n if (change.id !== undefined && change.userId === undefined) {\n return;\n }\n const { io } = hub;\n const work: Promise<void>[] = [];\n for (const collection of selfCollections(hub)) {\n if (!policyServices(hub, collection.service).has(change.service)) {\n continue;\n }\n raiseFloor(hub, collection, change.userId);\n if (io !== undefined) {\n work.push(...recheckScopes(hub, io, collection, change));\n }\n }\n await Promise.all(work);\n}\n\n/**\n * A reload of `userId`'s grants: raises the resume floor of every self\n * scope of that user, and sends `reset` to the self scopes the user's\n * `sockets` here subscribe to, once per room. Never throws.\n */\nexport async function resetSelf(\n hub: CollectionHub,\n sockets: readonly QuickdrawServerSocket[],\n userId?: string,\n): Promise<void> {\n for (const collection of userId === undefined ? [] : selfCollections(hub)) {\n raiseFloor(hub, collection, userId);\n }\n const { io } = hub;\n if (io === undefined) {\n return;\n }\n const rooms = new Map<string, readonly [BoundCollection, string]>();\n for (const socket of sockets) {\n for (const subscription of hub.collections.scopes.entries(socket)) {\n const collection = hub.collections.routes.find(subscription.s, subscription.c);\n if (collection !== undefined && followsPolicy(collection)) {\n rooms.set(roomOf(subscription), [collection, subscription.scope]);\n }\n }\n }\n await Promise.all(\n [...rooms.values()].map(\n async ([collection, scope]) => await resetScope(hub, io, collection, scope),\n ),\n );\n}\n","// Revoking collection subscriptions (RFC 0003 section 4.4), beside the\n// entity revocation of `emit/revocation.ts`, which calls this on every access\n// change it handles. Each scope subscription records the rows its access is\n// derived from (its anchors); when a flush may have changed someone's level\n// on one, the scopes anchored there are authorized again (`access.ts`), for\n// the user the change names or for everyone, one engine call per socket and\n// collection:\n//\n// - no longer allowed: the socket leaves the scope's room and gets\n// `qd:revoked { kind: \"collection\", reason: \"access\", s, c, scope }`;\n// - the flush deleted the anchor row: left alone, since the collection sink\n// closes that scope next with `reason: \"anchor-deleted\"`;\n// - a lookup that fails denies, as everywhere else.\n//\n// A changed `serviceAccess` re-authorizes every scope of the user's sockets.\n// A self scope has no anchors, since its user may always open it; when its\n// items follow its service's policy, the same changes re-check them\n// (`selfRecheck.ts`: a lost row is `removed`, or the scope resets, and a\n// resume of one nobody here subscribes to reads a page). 4.1 left\n// this to a hand-written `kickFromCollection`\n// (4.1 `src/server/collections.ts:305-318`).\n\nimport { SERVER_EVENTS } from \"../../contract/names\";\nimport { settleAll, type RevocationHook } from \"../emit/revocation\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { authorizeScopes } from \"./access\";\nimport type { BoundCollection, CollectionHub } from \"./bind\";\nimport { roomOf, type ScopeSubscription } from \"./scopes\";\nimport { recheckSelf, resetSelf } from \"./selfRecheck\";\n\ntype Found = ReadonlyMap<QuickdrawServerSocket, readonly ScopeSubscription[]>;\n\n/** The scopes the principal may still subscribe to, or `undefined` when the lookup failed. */\nasync function allowedScopes(\n hub: CollectionHub,\n socket: QuickdrawServerSocket,\n collection: BoundCollection | undefined,\n scopes: readonly string[],\n): Promise<Map<string, readonly string[]> | undefined> {\n const { principal } = socket.data;\n if (principal === null || collection === undefined) {\n return undefined;\n }\n try {\n return await authorizeScopes(hub, collection, principal, scopes);\n } catch (error) {\n hub.logger.error(\"Authorizing subscribers' collection scopes again failed; they are revoked\", {\n category: \"quickdraw.access\",\n service: collection.service.name,\n collection: collection.name,\n error: describeError(error),\n });\n return undefined;\n }\n}\n\n/** True when the flush deleted the scope's anchor row, whose own revocation goes out next. */\nfunction anchorDeleted(\n hub: CollectionHub,\n collection: BoundCollection | undefined,\n scope: string,\n): boolean {\n const anchor = collection?.anchorService;\n return anchor !== undefined && hub.changeLog.removed(anchor.name, scope);\n}\n\n/** Authorizes one socket's subscriptions to one collection again, and applies the answer. */\nasync function reauthorize(\n hub: CollectionHub,\n socket: QuickdrawServerSocket,\n subscriptions: readonly ScopeSubscription[],\n): Promise<void> {\n const [first] = subscriptions;\n if (first === undefined) {\n return;\n }\n const collection = hub.collections.routes.find(first.s, first.c);\n const scopes = subscriptions.map(({ scope }) => scope);\n const allowed = await allowedScopes(hub, socket, collection, scopes);\n for (const subscription of subscriptions) {\n const room = roomOf(subscription);\n // Unsubscribed, subscribed again or authorized again meanwhile: that is newer than this.\n const current = hub.collections.scopes.get(socket, room) === subscription;\n if (!socket.connected || !current || anchorDeleted(hub, collection, subscription.scope)) {\n continue;\n }\n const anchors = allowed?.get(subscription.scope);\n if (anchors !== undefined) {\n hub.collections.scopes.set(socket, { ...subscription, anchors });\n continue;\n }\n hub.collections.scopes.delete(socket, room);\n const { s, c, scope } = subscription;\n socket.emit(SERVER_EVENTS.revoked, { kind: \"collection\", reason: \"access\", s, c, scope });\n }\n}\n\n/** Authorizes the given subscriptions again, one engine call per socket and collection. */\nasync function reauthorizeAll(hub: CollectionHub, found: Found): Promise<void> {\n const work: Promise<void>[] = [];\n for (const [socket, subscriptions] of found) {\n const byCollection = new Map<string, ScopeSubscription[]>();\n for (const subscription of subscriptions) {\n const key = `${subscription.s}\\u0000${subscription.c}`;\n byCollection.set(key, [...(byCollection.get(key) ?? []), subscription]);\n }\n for (const own of byCollection.values()) {\n work.push(reauthorize(hub, socket, own));\n }\n }\n await settleAll(work);\n}\n\n/** The collection half of a dispatcher's revocation. */\nexport function createScopeRevocation(hub: CollectionHub): RevocationHook {\n return Object.freeze({\n changed: async (change) => {\n await settleAll([\n reauthorizeAll(hub, hub.collections.scopes.matching(change)),\n recheckSelf(hub, change),\n ]);\n },\n regranted: async (sockets, userId) => {\n const found = new Map(\n sockets.map((socket) => [socket, hub.collections.scopes.entries(socket)]),\n );\n await settleAll([reauthorizeAll(hub, found), resetSelf(hub, sockets, userId)]);\n },\n } satisfies RevocationHook);\n}\n","// The collections of one dispatcher's live data (RFC 0003 section 7): the\n// state they keep on the hub, the flush sink that sends their deltas, the\n// socket listeners of `qd:col:sub`, `qd:col:items` and `qd:col:unsub`, their\n// half of revocation, and `dispatcher.collections.reset` for the rare change\n// tracked writes cannot describe. Change topics (`../topics.ts`) are built on\n// the same state.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { Hub } from \"../emit/hub\";\nimport { nextRev } from \"../rev\";\nimport { createCollectionState, type CollectionHub } from \"./bind\";\nimport { createCollectionSink } from \"./collectionSink\";\nimport { collectionSubscriptions } from \"./extension\";\nimport { createScopeRevocation } from \"./revocation\";\nimport { sendFrame } from \"./send\";\nimport { listenForUnnamed } from \"./unnamed\";\n\n/** What a dispatcher's live data gets from its collections. */\nexport interface LiveCollections {\n /** The hub, now holding the collections' state. */\n readonly hub: CollectionHub;\n /** Sends the flush's collection deltas: after the entity sink on the dispatcher's list. */\n readonly sink: ReturnType<typeof createCollectionSink>;\n /** Serves `qd:col:sub`, `qd:col:items` and `qd:col:unsub` on every v5 socket. */\n readonly extension: ReturnType<typeof collectionSubscriptions>;\n /** Re-authorizes collection scopes on access changes. */\n readonly revocation: ReturnType<typeof createScopeRevocation>;\n /** Sends one scope a `reset`, so its clients load it again. */\n reset(contract: AnyContract, collection: string, scope: string): void;\n /** Listens on the server the hub was given for what other nodes' flushes could not address. */\n listen(): void;\n}\n\n/** Gives `hub` its collections. Throws a `TypeError` for an anchor the dispatcher cannot authorize through. */\nexport function createLiveCollections(hub: Hub): LiveCollections {\n const withCollections: CollectionHub = Object.assign(hub, {\n collections: createCollectionState(hub.registry, hub.storage),\n });\n return Object.freeze({\n hub: withCollections,\n sink: createCollectionSink(withCollections),\n extension: collectionSubscriptions(withCollections),\n revocation: createScopeRevocation(withCollections),\n reset(contract: AnyContract, collection: string, scope: string): void {\n const service = (contract as { readonly name?: unknown } | null)?.name;\n const found =\n typeof service === \"string\"\n ? withCollections.collections.routes.find(service, collection)\n : undefined;\n if (found === undefined) {\n throw new TypeError(\n `collections.reset: ${String(service)} has no collection \"${collection}\" this dispatcher serves`,\n );\n }\n if (typeof scope !== \"string\" || scope.length === 0) {\n throw new TypeError(\"collections.reset: scope must be the scope's value, as in its room\");\n }\n sendFrame(withCollections, withCollections.io, found, scope, nextRev(), [{ t: \"reset\" }]);\n },\n listen: () => {\n listenForUnnamed(withCollections);\n },\n });\n}\n","// Typed custom room events (RFC 0003 sections 8.3 and 15): `ctx.rooms.emit(room,\n// contract, event, payload)` and `emitToUser` (also `qd.rooms.emit`, from\n// code that is not a handler), which replace 4.1's\n// `emitToRoom` and `emitToUserRoom` and the augmentable `QuickdrawEventMap`\n// (4.1 `src/server/BaseService.ts:378-441`). The event must be one the\n// contract declares, and its payload is checked against the event's schema\n// before anything is sent: a payload that fails it throws `INTERNAL` (the\n// app's bug, logged by the pipeline when a handler emits it) and no socket\n// receives a frame. What goes out is the validated payload (a Zod object\n// strips keys its schema does not name: events have no projections), as one\n// `qd:event` frame, `[service, event, payload]`, to every socket in the room\n// (on every node, through the adapter). Without a server there is nobody to\n// send to.\n//\n// `emit` refuses the framework's rooms (`qd:`, `user:`) with `VALIDATION`\n// (the 5.1 audit's RT-I1): a handler that relays a payload's room would\n// otherwise reach every socket of a user, or every subscriber of a row.\n// `emitToUser` is the way to a user's sockets. A name with the shape of a\n// socket id is not refused here: an event sent to one socket grants it\n// nothing, while `ctx.rooms.join` refuses such names.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport { reservedRoomPrefix, SERVER_EVENTS, userRoom } from \"../../contract/names\";\nimport type { EventFrame } from \"../../protocol/envelope\";\nimport type { Hub } from \"../emit/hub\";\nimport { unreadable } from \"../transports/ack\";\nimport type { ContextRooms } from \"./types\";\nimport { checkOutgoing } from \"./validate\";\n\ntype UnknownRecord = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is UnknownRecord {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** The event's payload schema, or a `TypeError` for an event the contract does not declare. */\nfunction payloadSchemaOf(contract: AnyContract, event: string): AnyContract[\"events\"][string] {\n const events: unknown = isRecord(contract) ? contract.events : undefined;\n if (!isRecord(events) || typeof event !== \"string\" || !Object.hasOwn(events, event)) {\n const name = isRecord(contract) ? String(contract.name) : \"the contract\";\n throw new TypeError(`ctx.rooms.emit: ${name} declares no event \"${String(event)}\"`);\n }\n return events[event] as AnyContract[\"events\"][string];\n}\n\n/** The emitting half of `ctx.rooms`, which needs no socket. */\nexport type RoomEvents = Pick<ContextRooms, \"emit\" | \"emitToUser\">;\n\n/** `ctx.rooms.emit` and `emitToUser` for one dispatcher, sending through its server once one is attached. */\nexport function createRoomEvents(hub: Hub): RoomEvents {\n /** Checks the payload and sends it to `room`, whatever its name. */\n const deliver = (room: string, contract: AnyContract, event: string, payload: unknown): void => {\n const def = payloadSchemaOf(contract, event);\n const checked = checkOutgoing(\n def.payload,\n payload,\n `The payload of the ${contract.name}.${event} event`,\n );\n const frame: EventFrame = [contract.name, event, checked];\n hub.io?.to(room).emit(SERVER_EVENTS.event, frame);\n };\n return Object.freeze({\n emit: (room: string, contract: AnyContract, event: string, payload: unknown) => {\n if (typeof room !== \"string\" || room === \"\") {\n throw new TypeError(\"ctx.rooms.emit: room must be a non-empty string\");\n }\n if (reservedRoomPrefix(room) !== undefined) {\n throw unreadable(\n `ctx.rooms.emit: room \"${room}\" is reserved: rooms starting with qd: or user: are the framework's own; send to a user with emitToUser(userId, ...)`,\n );\n }\n deliver(room, contract, event, payload);\n },\n emitToUser: (userId: string, contract: AnyContract, event: string, payload: unknown) => {\n if (typeof userId !== \"string\" || userId === \"\") {\n throw new TypeError(\"ctx.rooms.emitToUser: userId must be a non-empty string\");\n }\n deliver(userRoom(userId), contract, event, payload);\n },\n }) as RoomEvents;\n}\n","// The `qd:presence` frames of app rooms (RFC 0003 section 12.5): a socket\n// that joins gets `{ room, users }`, the whole list (its own user included);\n// the room's other sockets get `{ room, joined }` when it is its user's first\n// socket there, and `{ room, left }` when a user's last socket leaves or\n// disconnects; a socket that leaves, or is taken out, gets `{ room, users: [] }`.\n//\n// On the in-memory adapter the list comes from this process's records, sent\n// in order with the join. Behind a cluster adapter it is read from every node\n// (the other nodes answer with their records' user ids, `presenceRequests.ts`;\n// asynchronously, and dropped when the socket left the room before it\n// arrived), and a user's last socket here leaving sends `left` only when no\n// node still has one of theirs in the room. A `joined` may then\n// repeat for a user already there on another node; a client keeps a set, so a\n// repeat changes nothing. A removal (`rooms.leave(room, { userId })`) reaches\n// every node, so each sends `left` for its last socket of the user without\n// asking the others: it may repeat, and is never missed.\n//\n// The same decision, whether a socket was its user's last in the room, is\n// what `onRoomLeave` hears as `last` (`leaving.ts`).\n\nimport { SERVER_EVENTS } from \"../../contract/names\";\nimport type { PresenceFrame } from \"../../protocol/envelope\";\nimport { track } from \"../emit/hub\";\nimport { ownRecord } from \"../emit/subscriptions\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { inRoom, usersInRoom, type PresenceState } from \"./presence\";\n\n/** Whether a socket that left a room was its user's last one there: known now, or once the other nodes answered. */\nexport type LastInRoom = boolean | Promise<boolean>;\n\n/** What the app rooms of one dispatcher share: its presence state. */\nexport type RoomState = PresenceState;\n\nfunction logFailure(state: RoomState, room: string, error: unknown): void {\n state.hub.logger.error(\"Reading a room's presence from the cluster failed\", {\n category: \"quickdraw.presence\",\n room,\n error: describeError(error),\n });\n}\n\nfunction sendList(socket: QuickdrawServerSocket, room: string, users: readonly string[]): void {\n const frame: PresenceFrame = { room, users };\n socket.emit(SERVER_EVENTS.presence, frame);\n}\n\n/** A socket entered app room `room`: it gets the list, the room hears of a new user. */\nexport function entered(state: RoomState, socket: QuickdrawServerSocket, room: string): void {\n const userId = socket.data.principal?.userId;\n const first = typeof userId === \"string\" && userId !== \"\" && state.records.entered(room, userId);\n if (first) {\n const frame: PresenceFrame = { room, joined: userId };\n socket.to(room).emit(SERVER_EVENTS.presence, frame);\n }\n if (state.hub.probe.local()) {\n sendList(socket, room, state.records.users(room) ?? []);\n return;\n }\n track(\n state.hub,\n usersInRoom(state, room).then(\n (users) => {\n // A socket that left (or was taken out) meanwhile was told it sees nobody: keep it so.\n if (socket.connected && ownRecord(socket.data.appRooms, room) !== undefined) {\n sendList(socket, room, users);\n }\n },\n (error: unknown) => {\n logFailure(state, room, error);\n },\n ),\n );\n}\n\n/**\n * A socket left app room `room` (`told`: it asked to, or was taken out, and\n * is told it sees nobody now) or disconnected: the room hears when its user\n * is gone. Returns whether it was its user's last socket in the room (true\n * for an anonymous socket): on one server at once; behind a cluster adapter\n * once every node was asked (true when they cannot be), unless `everywhere`\n * says the user is being taken out on every node anyway (a removal), when\n * this node's last socket is last without asking.\n */\nexport function exited(\n state: RoomState,\n socket: QuickdrawServerSocket,\n room: string,\n told: boolean,\n everywhere = false,\n): LastInRoom {\n if (told) {\n sendList(socket, room, []);\n }\n const userId = socket.data.principal?.userId;\n if (typeof userId !== \"string\" || userId === \"\") {\n return true;\n }\n const { io } = state.hub;\n if (!state.records.exited(room, userId)) {\n return false;\n }\n if (io === undefined) {\n return true;\n }\n const frame: PresenceFrame = { room, left: userId };\n if (state.hub.probe.local() || everywhere) {\n io.to(room).emit(SERVER_EVENTS.presence, frame);\n return true;\n }\n const last = inRoom(state, room, userId).then(\n (still) => {\n if (!still) {\n io.to(room).emit(SERVER_EVENTS.presence, frame);\n }\n return !still;\n },\n (error: unknown) => {\n logFailure(state, room, error);\n return true;\n },\n );\n track(state.hub, last);\n return last;\n}\n","// The names an app room may have (RFC 0003 section 12.5): `ctx.rooms` and\n// `qd.rooms` refuse the framework's own rooms (`qd:` entity, collection,\n// topic and stream rooms, and `user:` rooms), which a socket enters only\n// through their authorized paths, so a method cannot be talked into putting\n// a socket in another user's room or taking it out of one. They refuse a\n// name with the shape of a Socket.IO socket id too (the 5.1 audit's RT-I1):\n// every socket is alone in the room of its id, so joining one would put a\n// socket beside another, and `rooms.size` or `rooms.leave` would reach it.\n\nimport { RESERVED_ROOM_PREFIXES, socketIdShaped } from \"../../contract/names\";\nimport { MAX_SCOPE_LENGTH } from \"../../protocol/version\";\nimport { unreadable } from \"../transports/ack\";\n\n/** Throws `VALIDATION` unless `room` can name an app room. */\nexport function checkRoom(room: unknown): asserts room is string {\n if (typeof room !== \"string\" || room === \"\" || room.length > MAX_SCOPE_LENGTH) {\n throw unreadable(`A room name is a string of 1 to ${MAX_SCOPE_LENGTH} characters`);\n }\n if (RESERVED_ROOM_PREFIXES.some((prefix) => room.startsWith(prefix))) {\n throw unreadable(\n `Room \"${room}\" is reserved: rooms starting with ${RESERVED_ROOM_PREFIXES.join(\" or \")} are joined only through their own subscriptions`,\n );\n }\n if (socketIdShaped(room)) {\n throw unreadable(\n `Room \"${room}\" has the shape of a Socket.IO socket id (20 letters, digits, \"_\" or \"-\"): every socket is alone in the room of its id, so an app room never has that shape; give it a prefix (\"doc:${room}\")`,\n );\n }\n}\n","// Leaving app rooms (RFC 0003 section 12.5, pack H child 3's open questions):\n// a socket's own leave, a disconnect, a user taken out of a room from\n// anywhere, and the `onRoomLeave` hook that hears each of them.\n//\n// `leave(room, { userId })` takes every socket of a user out of a room, from\n// a handler or from code that is not one (`qd.rooms`): this node's sockets at\n// once, and behind a cluster adapter every other node's through an answered\n// broadcast (`ROOM_LEAVE_EVENT`, as access changes are:\n// `../cluster/broadcasts.ts`), so once it resolves the user hears nothing\n// more of the room on any node, and a channel that requires the room drops\n// their messages (the requirement reads `socket.data.appRooms`).\n//\n// Whenever a socket leaves app rooms the hooks hear of it once, on the node\n// that held the socket, with each room and whether the socket was its user's\n// last one there (`roomFrames.ts` decides it with the room's `left` frame).\n// The hooks are every service's own `onRoomLeave` (`defineService`) and the\n// server's (`createServer`), composed by `createServer` so no server root\n// can forget a service's. Each runs in a detached unit of work of its own\n// (`qd.run(fn, { detached: true })`): a leave a handler causes never joins\n// that handler's unit, and one hook's writes never flush with another's.\n// What one throws is logged with whose hook it is, and the others run all\n// the same; the hub keeps their runs in flight, so a server's `close()`\n// waits for them.\n\nimport { userRoom } from \"../../contract/names\";\nimport { onNodeEvent } from \"../cluster/deployment\";\nimport { track, type Hub } from \"../emit/hub\";\nimport { emptyRecords, ownRecord } from \"../emit/subscriptions\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { exited, type LastInRoom, type RoomState } from \"./roomFrames\";\nimport { checkRoom } from \"./roomNames\";\nimport type { RoomLeave, RoomLeaveHandler, RoomLeaveReason, RoomLeft } from \"./types\";\n\n/** The server-to-server event `rooms.leave(room, { userId })` is broadcast on behind a cluster adapter. */\nexport const ROOM_LEAVE_EVENT = \"quickdraw:room-leave\";\n\n/** Hears every socket that left app rooms: the app's `onRoomLeave` hooks, wrapped by {@link leaveListener}. */\nexport type RoomLeaveListener = (leave: RoomLeave) => Promise<void>;\n\n/** Runs a function in a detached unit of work of the dispatcher: `dispatcher.run(fn, { detached: true })`. */\nexport type DetachedRun = (\n fn: (ctx: Parameters<RoomLeaveHandler>[1]) => Promise<void>,\n) => Promise<void>;\n\n/** One `onRoomLeave` hook, and whose it is for the logs: a service's name, or `\"createServer\"`. */\nexport interface RoomLeaveHook {\n readonly owner: string;\n readonly handler: RoomLeaveHandler;\n}\n\n/** What the app rooms of one dispatcher share, with who hears sockets leave. */\nexport interface LeavingState extends RoomState {\n listener: RoomLeaveListener | undefined;\n /** Hears a socket that left an app room and is still connected, before the hooks do. */\n readonly left?: ((socket: QuickdrawServerSocket) => void) | undefined;\n}\n\n/**\n * The app's `onRoomLeave` hooks as one listener: for each leave, every hook\n * in a detached unit of work of its own, all at once, each with what it\n * throws logged, so one failing hook stops none of the others.\n */\nexport function leaveListener(\n hooks: readonly RoomLeaveHook[],\n run: DetachedRun,\n logger: Hub[\"logger\"],\n): RoomLeaveListener {\n return async (leave) => {\n await Promise.all(\n hooks.map(async ({ owner, handler }) => {\n try {\n await run(async (ctx) => {\n await handler(leave, ctx);\n });\n } catch (error) {\n logger.error(\"onRoomLeave threw\", {\n category: \"quickdraw.rooms\",\n owner,\n socketId: leave.socketId,\n reason: leave.reason,\n rooms: leave.rooms.map(({ room }) => room),\n error: describeError(error),\n });\n }\n }),\n );\n };\n}\n\n/**\n * Tells the listener that `socket` left `left` (each room with whether it was\n * its user's last socket there, known now or once the other nodes answered).\n */\nfunction heard(\n state: LeavingState,\n socket: QuickdrawServerSocket,\n reason: RoomLeaveReason,\n left: readonly (readonly [string, LastInRoom])[],\n): void {\n const { listener } = state;\n if (listener === undefined || left.length === 0) {\n return;\n }\n const principal = socket.data.principal ?? null;\n const deliver = (rooms: readonly RoomLeft[]): void => {\n track(state.hub, listener({ principal, socketId: socket.id, reason, rooms }));\n };\n if (left.every(([, last]) => typeof last === \"boolean\")) {\n deliver(left.map(([room, last]) => ({ room, last: last as boolean })));\n return;\n }\n track(\n state.hub,\n Promise.all(left.map(async ([room, last]) => ({ room, last: await last }))).then(deliver),\n );\n}\n\n/**\n * Takes `socket` out of app room `room` (its own leave, or a removal): it is\n * told it sees nobody now, the room hears its user left when it was their\n * last socket, and the listener hears of it. `false` when it was not in it.\n */\nexport function leaveRoom(\n state: LeavingState,\n socket: QuickdrawServerSocket,\n room: string,\n reason: Exclude<RoomLeaveReason, \"disconnect\">,\n): boolean {\n const joined = socket.data.appRooms;\n if (joined === undefined || ownRecord(joined, room) === undefined) {\n return false;\n }\n delete joined[room];\n void socket.leave(room);\n if (socket.connected) {\n state.left?.(socket);\n }\n const last = exited(state, socket, room, socket.connected, reason === \"removed\");\n heard(state, socket, reason, [[room, last]]);\n return true;\n}\n\n/** A socket disconnected (Socket.IO has emptied its rooms): it leaves every app room it was in. */\nexport function leaveAll(state: LeavingState, socket: QuickdrawServerSocket): void {\n const left = Object.keys(socket.data.appRooms ?? {}).map(\n (room) => [room, exited(state, socket, room, false)] as const,\n );\n socket.data.appRooms = emptyRecords();\n heard(state, socket, \"disconnect\", left);\n}\n\n/** The user `rooms.leave(room, target)` names; a `TypeError` for anything else. */\nfunction targetUser(target: unknown): string {\n const userId: unknown =\n typeof target === \"object\" && target !== null\n ? (target as { readonly userId?: unknown }).userId\n : undefined;\n if (typeof userId !== \"string\" || userId === \"\") {\n throw new TypeError(\"rooms.leave: pass { userId } to take a user's sockets out of a room\");\n }\n return userId;\n}\n\n/** Takes this node's sockets of `userId` out of app room `room`. */\nfunction removeHere(state: LeavingState, room: string, userId: string): void {\n const { io } = state.hub;\n for (const socketId of [...(io?.sockets.adapter.rooms.get(userRoom(userId)) ?? [])]) {\n const socket = io?.sockets.sockets.get(socketId);\n if (socket?.data.principal?.userId === userId) {\n leaveRoom(state, socket, room, \"removed\");\n }\n }\n}\n\n/**\n * `rooms.leave(room, { userId })`: this node's sockets of the user at once,\n * and behind a cluster adapter every other node's, resolving once they\n * answered (at most `cluster.timeoutMs`; at once while the broadcasts are\n * degraded).\n */\nexport async function removeUser(\n state: LeavingState,\n room: unknown,\n target: unknown,\n): Promise<void> {\n checkRoom(room);\n const userId = targetUser(target);\n const { hub } = state;\n const others =\n hub.io === undefined || hub.probe.local()\n ? undefined\n : hub.broadcasts?.broadcast(ROOM_LEAVE_EVENT, { room, userId });\n removeHere(state, room, userId);\n await others;\n}\n\n/**\n * Takes this node's sockets out of the rooms other nodes of its deployment's\n * `leave(room, { userId })` name, and answers (another deployment's too,\n * without taking anyone out).\n */\nexport function listenForRemovals(state: LeavingState): void {\n const { io } = state.hub;\n if (io === undefined) {\n return;\n }\n onNodeEvent(io, state.hub.logger, ROOM_LEAVE_EVENT, (broadcast, answer) => {\n const { room, userId } = (broadcast ?? {}) as Readonly<Record<string, unknown>>;\n try {\n checkRoom(room);\n removeHere(state, room, targetUser({ userId }));\n answer(true);\n } catch {\n answer(false);\n }\n });\n}\n","// `ctx.rooms` and `qd.rooms` (RFC 0003 sections 3 and 12.5): app-defined\n// rooms a method puts its calling socket in (a lobby, a document's viewers),\n// the typed events sent to rooms (`events.ts`), taking a user's sockets out\n// of a room from anywhere and hearing sockets leave (`leaving.ts`).\n//\n// Joining works for calls that arrived over a v5 socket; any other call gets\n// `false` back. The framework's own rooms (`qd:` entity, collection, topic\n// and stream rooms, and `user:` rooms) are refused (`roomNames.ts`).\n//\n// Each socket keeps the app rooms it joined on `socket.data.appRooms` (at\n// most `MAX_APP_ROOMS`, in an object without a prototype), so presence knows\n// what a disconnect leaves; `qd:presence` frames tell each room who comes and\n// goes (`roomFrames.ts`).\n\nimport { userRoom } from \"../../contract/names\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { emptyRecords, ownRecord } from \"../emit/subscriptions\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport { createRoomEvents } from \"./events\";\nimport {\n leaveAll,\n leaveListener,\n leaveRoom,\n listenForRemovals,\n removeUser,\n type DetachedRun,\n type LeavingState,\n type RoomLeaveHook,\n} from \"./leaving\";\nimport { markSeen, MAX_APP_ROOMS } from \"./presence\";\nimport { entered, type RoomState } from \"./roomFrames\";\nimport { checkRoom } from \"./roomNames\";\nimport type { ContextRooms, RoomTarget, ServerRooms } from \"./types\";\n\nexport { ROOM_LEAVE_EVENT, type DetachedRun, type RoomLeaveHook } from \"./leaving\";\n\nfunction join(state: LeavingState, socket: QuickdrawServerSocket, room: string): boolean {\n checkRoom(room);\n if (!socket.connected) {\n return false;\n }\n const joined = (socket.data.appRooms ??= emptyRecords<true>());\n if (ownRecord(joined, room) !== undefined) {\n return true;\n }\n if (Object.keys(joined).length >= MAX_APP_ROOMS) {\n throw new QuickdrawError(\n \"CONFLICT\",\n `A socket may be in at most ${MAX_APP_ROOMS} rooms; leave one before joining another`,\n );\n }\n joined[room] = true;\n void socket.join(room);\n entered(state, socket, room);\n return true;\n}\n\n/**\n * `rooms.size(room)`: this node's sockets in app room `room`, anonymous ones\n * included, read from the adapter's own room at once.\n */\nfunction sizeOf(state: LeavingState, room: string): number {\n checkRoom(room);\n return state.hub.io?.sockets.adapter.rooms.get(room)?.size ?? 0;\n}\n\n/** The `ctx.rooms` of each socket, of calls without one, and `qd.rooms`, for one dispatcher. */\nexport interface Rooms {\n /** The `ctx.rooms` of calls and channel messages from `socket`: made once per socket. */\n of(socket: QuickdrawServerSocket): ContextRooms;\n /** The `ctx.rooms` of calls without a socket: `join` and `leave(room)` answer `false`. */\n readonly detached: ContextRooms;\n /** `qd.rooms`, `server.rooms`, `dispatcher.rooms`: what needs no calling socket. */\n readonly server: ServerRooms;\n /** A socket disconnected (Socket.IO has emptied its rooms): its users leave its app rooms. */\n disconnected(socket: QuickdrawServerSocket): void;\n /**\n * Runs `hooks` for every socket that leaves app rooms from now on (each\n * service's `onRoomLeave` and `createServer`'s), each through `run`, a\n * detached unit of work of its own.\n */\n onLeave(hooks: readonly RoomLeaveHook[], run: DetachedRun): void;\n /** Takes this node's sockets out of rooms other nodes' `leave(room, { userId })` name. */\n listen(): void;\n}\n\n/** `leave(room)` and `leave(room, target)` in one function: `own` leaves the calling socket, if any. */\nfunction leaveOf(\n own: (room: string) => boolean,\n removal: (room: string, target: RoomTarget) => Promise<void>,\n): ContextRooms[\"leave\"] {\n return ((room: string, target?: RoomTarget) => {\n if (target !== undefined) {\n return removal(room, target);\n }\n checkRoom(room);\n return own(room);\n }) as ContextRooms[\"leave\"];\n}\n\n/**\n * Creates the rooms of one dispatcher, and their typed events (`events.ts`).\n * `left` hears each socket that left an app room and is still connected\n * (the streams open to a room's sockets check it again).\n */\nexport function createRooms(\n base: RoomState,\n left?: (socket: QuickdrawServerSocket) => void,\n): Rooms {\n const state: LeavingState = { ...base, listener: undefined, left };\n const events = createRoomEvents(state.hub);\n const removal = (room: string, target: RoomTarget): Promise<void> =>\n removeUser(state, room, target);\n const size = (room: string): number => sizeOf(state, room);\n const server: ServerRooms = Object.freeze({ ...events, leave: removal, size });\n const bySocket = new WeakMap<QuickdrawServerSocket, ContextRooms>();\n const detached: ContextRooms = Object.freeze({\n ...events,\n size,\n join: (room: string) => {\n checkRoom(room);\n return false;\n },\n leave: leaveOf(() => false, removal),\n });\n return Object.freeze({\n of(socket: QuickdrawServerSocket): ContextRooms {\n let rooms = bySocket.get(socket);\n if (rooms === undefined) {\n rooms = Object.freeze({\n ...events,\n size,\n join: (room: string) => join(state, socket, room),\n leave: leaveOf((room) => leaveRoom(state, socket, room, \"leave\"), removal),\n });\n bySocket.set(socket, rooms);\n }\n return rooms;\n },\n detached,\n server,\n disconnected(socket: QuickdrawServerSocket): void {\n leaveAll(state, socket);\n const userId = socket.data.principal?.userId;\n const sockets =\n typeof userId === \"string\"\n ? state.hub.io?.sockets.adapter.rooms.get(userRoom(userId))\n : undefined;\n if (typeof userId === \"string\" && userId !== \"\" && (sockets?.size ?? 0) === 0) {\n markSeen(state.hub, state.records, userId, Date.now());\n }\n },\n onLeave(hooks: readonly RoomLeaveHook[], run: DetachedRun): void {\n state.listener = hooks.length === 0 ? undefined : leaveListener(hooks, run, state.hub.logger);\n },\n listen(): void {\n listenForRemovals(state);\n },\n });\n}\n\n/**\n * `rooms` whose `join` and own `leave` throw `INTERNAL`: the `ctx.rooms` of\n * a method that shares its runs (`share`). A shared run serves several\n * callers with the first one's `ctx`, so it would join or leave that\n * caller's socket only. Its events (`emit`, `emitToUser`) and\n * `leave(room, { userId })` stay: they name their room or user.\n */\nexport function unjoinable(rooms: ContextRooms, share: string): ContextRooms {\n const refuse = (member: string): never => {\n throw new QuickdrawError(\n \"INTERNAL\",\n `ctx.rooms.${member} cannot run in a method that shares its runs (share: \"${share}\"): a shared run serves several callers and would ${member} only the first caller's socket; join rooms from a method without share`,\n );\n };\n return Object.freeze({\n ...rooms,\n join: () => refuse(\"join\"),\n leave: ((room: string, target?: RoomTarget) =>\n target === undefined ? refuse(\"leave\") : rooms.leave(room, target)) as ContextRooms[\"leave\"],\n });\n}\n","// The socket listeners of stream subscriptions (RFC 0003 sections 8.2 and\n// 12.5): `qd:stream:sub { s, stream, scope? }`, answered `{ ok: true, seed }`\n// or `{ ok: false, e }` (`streamSubscribe.ts`), and `qd:stream:unsub`,\n// optionally acknowledged `{ ok: true }`. One listener per event on every v5\n// socket, routed by the frame (`streamTargets.ts`). Neither counts against\n// the socket rate limiter (`transports/middleware.ts`); `qd:stream:sub` runs\n// in the socket's lane of subscription work (`emit/lane.ts`), and no\n// listener throws (`emit/answer.ts`). An unsubscribe leaves the feed's room\n// at once, and stops a subscribe of the same feed still being authorized\n// from joining it; Socket.IO empties a socket's rooms when it disconnects.\n\nimport { CLIENT_EVENTS } from \"../../contract/names\";\nimport { answerEvent, answerNow, onDisconnect } from \"../emit/answer\";\nimport type { Hub } from \"../emit/hub\";\nimport { PendingKeys } from \"../emit/pending\";\nimport type { QuickdrawServerSocket, SocketContext } from \"../transports/types\";\nimport type { StreamSeeds } from \"./seeds\";\nimport type { StreamIndex } from \"./streamIndex\";\nimport { subscribeFeed, type StreamState } from \"./streamSubscribe\";\nimport { checkUnsubscriber, streamTarget } from \"./streamTargets\";\n\nfunction unsubscribe(\n state: StreamState,\n socket: QuickdrawServerSocket,\n value: unknown,\n): { readonly ok: true } {\n const target = streamTarget(state.hub, value, CLIENT_EVENTS.streamUnsub);\n checkUnsubscriber(socket, target);\n state.pending.unsubscribed(socket, target.room);\n state.index.delete(socket, target.room);\n return { ok: true };\n}\n\n/**\n * The socket extension (`transports/socketio.ts`) that serves\n * `qd:stream:sub` and `qd:stream:unsub` for one dispatcher's streams, and\n * drops a disconnected socket's feeds from `index`.\n */\nexport function streamSubscriptions(\n hub: Hub,\n seeds: StreamSeeds,\n index: StreamIndex,\n): (socket: QuickdrawServerSocket, context: SocketContext) => void {\n const state: StreamState = { hub, seeds, index, pending: new PendingKeys() };\n return (socket, context) => {\n answerEvent(\n socket,\n context,\n CLIENT_EVENTS.streamSub,\n async (frame) =>\n await subscribeFeed(state, socket, streamTarget(hub, frame, CLIENT_EVENTS.streamSub)),\n );\n socket.on(CLIENT_EVENTS.streamUnsub, (frame: unknown, ack: unknown) => {\n answerNow(socket, context, CLIENT_EVENTS.streamUnsub, ack, () =>\n unsubscribe(state, socket, frame),\n );\n });\n onDisconnect(socket, context, () => {\n index.drop(socket);\n });\n };\n}\n","// The stream feeds of one dispatcher (RFC 0003 sections 4.4 and 12.5): the\n// index of its sockets' subscriptions (`streamIndex.ts`), the socket\n// listeners that subscribe and unsubscribe (`streamSubscriptions.ts`), and\n// the revocation hook that authorizes them again when access changes\n// (`streamRevocation.ts`), all over one index.\n\nimport type { Hub } from \"../emit/hub\";\nimport type { RevocationHook } from \"../emit/revocation\";\nimport type { QuickdrawServerSocket } from \"../transports/types\";\nimport type { StreamSeeds } from \"./seeds\";\nimport { StreamIndex } from \"./streamIndex\";\nimport { createStreamRevocation, revokeOutsideRooms } from \"./streamRevocation\";\nimport { streamSubscriptions } from \"./streamSubscriptions\";\n\n/** One dispatcher's stream feeds. */\nexport interface StreamFeeds {\n /** Serves `qd:stream:sub` and `qd:stream:unsub` on a v5 socket. */\n readonly extension: ReturnType<typeof streamSubscriptions>;\n /** Authorizes the feeds an access change or a changed grant concerns again. */\n readonly revocation: RevocationHook;\n /** The socket left an app room: revokes its feeds open to a room it is no longer in. */\n leftRooms(socket: QuickdrawServerSocket): void;\n}\n\n/** Creates the feeds of the dispatcher whose hub this is, over its streams' seeds. */\nexport function createStreamFeeds(hub: Hub, seeds: StreamSeeds): StreamFeeds {\n const index = new StreamIndex();\n return Object.freeze({\n extension: streamSubscriptions(hub, seeds, index),\n revocation: createStreamRevocation(hub, index),\n leftRooms: (socket: QuickdrawServerSocket) => {\n revokeOutsideRooms(hub, index, socket);\n },\n });\n}\n","// Sending a stream's pushed items (`streams.ts`): kept in the feed's seed\n// and sent to the feed's room as `qd:stream` frames. Behind a cluster\n// adapter a stream that keeps a seed is pushed to every node of the\n// server's deployment instead (`quickdraw:stream-push`, tagged with it:\n// `../cluster/deployment.ts`), and each node keeps the items in its own seed\n// and sends them to its own sockets in the feed's room, in one step; a push\n// of another deployment is never kept or sent.\n\nimport { SERVER_EVENTS, streamRoom } from \"../../contract/names\";\nimport type { StreamFrame } from \"../../protocol/envelope\";\nimport { emitToNodes, onNodeEvent } from \"../cluster/deployment\";\nimport type { Hub } from \"../emit/hub\";\nimport type { AnyService } from \"../service\";\nimport { streamKey, type StreamSeeds } from \"./seeds\";\nimport type { ServiceStream } from \"./types\";\n\n/** A stream the dispatcher serves, with its service. */\nexport interface Served {\n readonly service: AnyService;\n readonly stream: ServiceStream;\n}\n\n/** The server-to-server event a seeded stream's items are pushed to every node on, behind a cluster adapter. */\nexport const STREAM_PUSH_EVENT = \"quickdraw:stream-push\";\n\n/** A push another node broadcast: `{ s, stream, scope?, items }`. */\ninterface PushedItems {\n readonly s: string;\n readonly stream: string;\n readonly scope?: string;\n readonly items: readonly unknown[];\n}\n\n/**\n * Keeps `items` (already checked) in the feed's seed and sends each as a\n * frame, in order: to every node's sockets in the feed's room, or with\n * `local` (a push another node broadcast) to this node's only.\n */\nexport function sendItems(\n hub: Hub,\n seeds: StreamSeeds,\n served: Served,\n feed: string | undefined,\n items: readonly unknown[],\n local = false,\n): void {\n const { service, stream } = served;\n for (const item of items) {\n seeds.push(streamKey(service.name, stream.name), feed, item, stream.seed);\n }\n const { io } = hub;\n if (io === undefined) {\n return;\n }\n const replicated = local || (stream.seed > 0 && !hub.probe.local());\n if (replicated && !local) {\n const pushed: PushedItems = { s: service.name, stream: stream.name, items };\n emitToNodes(io, STREAM_PUSH_EVENT, feed === undefined ? pushed : { ...pushed, scope: feed });\n }\n const room = (replicated ? io.local : io).to(streamRoom(service.name, stream.name, feed));\n const target = stream.volatile ? room.volatile : room;\n const scope = feed ?? null;\n for (const item of items) {\n const frame: StreamFrame = [service.name, stream.name, scope, item];\n target.emit(SERVER_EVENTS.stream, frame);\n }\n}\n\n/** A push another node broadcast, read; `undefined` for anything malformed or a stream not served here. */\nfunction readPush(hub: Hub, value: unknown): { served: Served; pushed: PushedItems } | undefined {\n const { s, stream, scope, items } = (value ?? {}) as Readonly<Record<string, unknown>>;\n const service = typeof s === \"string\" ? hub.registry.services.get(s) : undefined;\n const found = typeof stream === \"string\" ? service?.streams.get(stream) : undefined;\n if (service === undefined || found === undefined || !Array.isArray(items)) {\n return undefined;\n }\n if (found.scoped ? typeof scope !== \"string\" : scope !== undefined) {\n return undefined;\n }\n const pushed: PushedItems = { s: service.name, stream: found.name, items: items as unknown[] };\n return {\n served: { service, stream: found },\n pushed: typeof scope === \"string\" ? { ...pushed, scope } : pushed,\n };\n}\n\n/** Keeps and sends the items other nodes of the server's deployment push to seeded streams. */\nexport function listenForPushes(hub: Hub, seeds: StreamSeeds): void {\n if (hub.io === undefined) {\n return;\n }\n onNodeEvent(hub.io, hub.logger, STREAM_PUSH_EVENT, (broadcast) => {\n const received = readPush(hub, broadcast);\n if (received !== undefined) {\n const { served, pushed } = received;\n sendItems(hub, seeds, served, pushed.scope, pushed.items, true);\n }\n });\n}\n","// Pushing to streams (RFC 0003 section 12.5): `qd.stream(contract,\n// name).push(scope, item)` (`push(item)` for a global stream). The item is\n// checked against the stream's item schema (a mismatch throws `INTERNAL`,\n// nothing is kept or sent); the validated item (a Zod object strips keys its\n// schema does not name) is kept in the scope's seed when the stream declares\n// one (`seeds.ts`), and sent to the feed's room as `qd:stream [service,\n// stream, scope, item]` (`scope` null for a global stream: positional, so a\n// frame at a game's tick rate carries no key names), volatile when the stream\n// says so. A push is synchronous and logs nothing: it may run at a game\n// loop's tick rate.\n//\n// `pushMany(scope, items)` (`pushMany(items)`) is the batch form: every item\n// is checked before any is kept or sent, then each goes out as its own frame\n// through one room operator, in order, so the client applies them exactly as\n// it applies single pushes.\n//\n// Behind a cluster adapter a stream that keeps a seed is pushed to every\n// node of its deployment instead (`serverSideEmit`, the same one publish a room broadcast\n// costs), and each node keeps the items in its own seed and sends them to its\n// own sockets in the feed's room, in one step: a subscriber on any node gets\n// the latest items as its seed, and an item is either in the seed a\n// subscriber gets or sent to it after, never both and never neither. A stream\n// without a seed goes out through the adapter's room broadcast as before.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { Hub } from \"../emit/hub\";\nimport { StreamSeeds } from \"./seeds\";\nimport { createStreamFeeds, type StreamFeeds } from \"./streamFeeds\";\nimport { listenForPushes, sendItems, type Served } from \"./streamPushes\";\nimport { scopeProblem } from \"./streamTargets\";\nimport type { StreamHandle } from \"./types\";\nimport { checkOutgoing, checksItems } from \"./validate\";\n\n/** The stream `name` of the service the dispatcher serves for `contract`, or a `TypeError`. */\nfunction servedStream(hub: Hub, contract: AnyContract, name: string): Served {\n const serviceName: unknown =\n typeof contract === \"object\" && contract !== null ? contract.name : undefined;\n const service =\n typeof serviceName === \"string\" ? hub.registry.services.get(serviceName) : undefined;\n if (service === undefined) {\n throw new TypeError(\n `stream: the dispatcher serves no service named ${String(serviceName)}; pass a contract of one of its services`,\n );\n }\n const stream = typeof name === \"string\" ? service.streams.get(name) : undefined;\n if (stream === undefined) {\n throw new TypeError(`stream: ${service.name} has no stream \"${String(name)}\"`);\n }\n return { service, stream };\n}\n\n/**\n * The feed and the value `push(scope, value)` or `push(value)` names, or a\n * `TypeError`; `what` names the value in the message (`item`, `items`).\n */\nfunction feedOf(\n served: Served,\n method: string,\n what: string,\n args: readonly unknown[],\n): { readonly feed: string | undefined; readonly value: unknown } {\n const { service, stream } = served;\n const scope = stream.scoped ? args[0] : undefined;\n const problem = scopeProblem(stream, scope);\n if (problem !== undefined || args.length !== (stream.scoped ? 2 : 1)) {\n const usage = stream.scoped ? `pass (scope, ${what})` : `pass (${what})`;\n throw new TypeError(`${service.name}.${stream.name}.${method}: ${problem ?? usage}`);\n }\n return { feed: scope as string | undefined, value: stream.scoped ? args[1] : args[0] };\n}\n\nfunction push(hub: Hub, seeds: StreamSeeds, served: Served, args: readonly unknown[]): void {\n const { feed, value } = feedOf(served, \"push\", \"item\", args);\n const label = `${served.service.name}.${served.stream.name}`;\n // What is kept and sent is the validated item: streams have no projections.\n const checked = checksItems(served.stream, hub.outputValidation)\n ? checkOutgoing(served.stream.item, value, `An item pushed to ${label}`)\n : value;\n sendItems(hub, seeds, served, feed, [checked]);\n}\n\nfunction pushMany(hub: Hub, seeds: StreamSeeds, served: Served, args: readonly unknown[]): void {\n const { feed, value } = feedOf(served, \"pushMany\", \"items\", args);\n const label = `${served.service.name}.${served.stream.name}`;\n if (!Array.isArray(value)) {\n throw new TypeError(`${label}.pushMany: pass the items as an array`);\n }\n if (!checksItems(served.stream, hub.outputValidation)) {\n sendItems(hub, seeds, served, feed, value);\n return;\n }\n // Every item is checked before any is kept or sent.\n const checked = value.map((item: unknown, index) =>\n checkOutgoing(served.stream.item, item, `Item ${String(index)} pushed to ${label}`),\n );\n sendItems(hub, seeds, served, feed, checked);\n}\n\n/** One dispatcher's streams: their seeds, the handles that push to them, and their socket listeners. */\nexport interface Streams {\n /**\n * The handle of stream `name` of `contract`'s service on this dispatcher.\n * Throws a `TypeError` when the dispatcher does not serve that stream.\n */\n handle(contract: AnyContract, name: string): StreamHandle<AnyContract, string>;\n /** Serves `qd:stream:sub` and `qd:stream:unsub` on a v5 socket. */\n readonly extension: Feeds[\"extension\"];\n /** Authorizes the feeds an access change or a changed grant concerns again (`streamRevocation.ts`). */\n readonly revocation: Feeds[\"revocation\"];\n /** Keeps and sends the items other nodes push to seeded streams, on the server the hub was given. */\n listen(): void;\n /** The socket left an app room: revokes its feeds open to a room it is no longer in. */\n readonly leftRooms: Feeds[\"leftRooms\"];\n}\n\ntype Feeds = StreamFeeds;\n\n/** Creates the streams of the dispatcher whose hub this is. */\nexport function createStreams(hub: Hub): Streams {\n const seeds = new StreamSeeds();\n const feeds = createStreamFeeds(hub, seeds);\n return Object.freeze({\n handle(contract: AnyContract, name: string): StreamHandle<AnyContract, string> {\n const served = servedStream(hub, contract, name);\n return Object.freeze({\n push: (...args: unknown[]) => {\n push(hub, seeds, served, args);\n },\n pushMany: (...args: unknown[]) => {\n pushMany(hub, seeds, served, args);\n },\n }) as StreamHandle<AnyContract, string>;\n },\n extension: feeds.extension,\n revocation: feeds.revocation,\n leftRooms: feeds.leftRooms,\n listen: () => {\n listenForPushes(hub, seeds);\n },\n });\n}\n","// Presence, streams, channels and typed room events for one dispatcher (RFC\n// 0003 section 12.5), made with its live data (`emit/live.ts`): the socket\n// listeners they add to every v5 socket, the room bookkeeping of every 4.x\n// socket, `ctx.rooms` and `ctx.presence` for each call, and the stream\n// handles `qd.stream(contract, name)` returns.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { RoomOccupancy } from \"../context\";\nimport { onDisconnect } from \"../emit/answer\";\nimport type { Hub } from \"../emit/hub\";\nimport type { QuickdrawServerSocket, SocketContext } from \"../transports/types\";\nimport { channelMessages } from \"./channels\";\nimport { createPresence, createPresenceState } from \"./presence\";\nimport { createRooms, unjoinable, type DetachedRun, type RoomLeaveHook } from \"./rooms\";\nimport { createStreams, type Streams } from \"./streams\";\nimport type {\n ContextRooms,\n Presence,\n RoomLeave,\n RoomLeaveHandler,\n ServerRooms,\n StreamHandle,\n} from \"./types\";\n\nexport type {\n DetachedRun,\n Presence,\n RoomLeave,\n RoomLeaveHandler,\n RoomLeaveHook,\n ServerRooms,\n StreamHandle,\n};\n\n/** The realtime half of one dispatcher's live data. */\nexport interface Realtime {\n /** Serves `qd:ch`, `qd:stream:sub` and `qd:stream:unsub`, and leaves app rooms on disconnect. */\n extension(socket: QuickdrawServerSocket, context: SocketContext): void;\n /**\n * Leaves a 4.x socket's app rooms on disconnect, as `extension` does for a\n * v5 one: its calls through the legacy shim can join rooms (`roomsFor`),\n * but it gets none of the v5 listeners.\n */\n legacyExtension(socket: QuickdrawServerSocket, context: SocketContext): void;\n /** `ctx.presence`, `dispatcher.presence` and `server.presence`. */\n readonly presence: Presence;\n /** `qd.rooms`, `dispatcher.rooms` and `server.rooms`: app rooms from code that is not a handler. */\n readonly rooms: ServerRooms;\n /**\n * Runs `hooks` for every socket that leaves app rooms, each through `run`,\n * a detached unit of work of the dispatcher: every service's `onRoomLeave`\n * and `createServer`'s.\n */\n onRoomLeave(hooks: readonly RoomLeaveHook[], run: DetachedRun): void;\n /**\n * The `ctx.rooms` of a call: its socket's for a call over a socket (v5 or\n * the 4.x legacy shim), else one that joins nothing. For a method that shares its runs (`share`),\n * `join` and `leave` throw `INTERNAL`: a shared run serves several callers,\n * and would join or leave only the first one's socket.\n */\n roomsFor(transport: string, connectionId: string | undefined, share?: string): ContextRooms;\n /** The handle of a stream this dispatcher serves; a `TypeError` for any other. */\n stream(contract: AnyContract, name: string): StreamHandle<AnyContract, string>;\n /** The sockets in a room of the attached server, for the kits (`KitRuntime.occupancy`). */\n readonly occupancy: RoomOccupancy;\n /** Revokes stream subscriptions on access changes and changed grants. */\n readonly revocation: Streams[\"revocation\"];\n /**\n * Listens on the server the hub was given for the items other nodes push\n * to seeded streams, for their `rooms.leave(room, { userId })`, and for\n * their presence requests.\n */\n listen(): void;\n}\n\n/** Creates the realtime half of a dispatcher's live data, on its hub. */\nexport function createRealtime(hub: Hub): Realtime {\n const state = createPresenceState(hub);\n const presence = createPresence(state);\n const streams = createStreams(hub);\n const rooms = createRooms(state, streams.leftRooms);\n const channels = channelMessages({ hub, rooms, presence, warned: new WeakSet() });\n return Object.freeze({\n extension(socket: QuickdrawServerSocket, context: SocketContext): void {\n channels(socket);\n streams.extension(socket, context);\n onDisconnect(socket, context, () => {\n rooms.disconnected(socket);\n });\n },\n legacyExtension(socket: QuickdrawServerSocket, context: SocketContext): void {\n onDisconnect(socket, context, () => {\n rooms.disconnected(socket);\n });\n },\n presence,\n rooms: rooms.server,\n onRoomLeave: (hooks: readonly RoomLeaveHook[], run: DetachedRun) => {\n rooms.onLeave(hooks, run);\n },\n roomsFor(transport: string, connectionId: string | undefined, share?: string): ContextRooms {\n const socket =\n (transport === \"socket\" || transport === \"legacy\") && connectionId !== undefined\n ? hub.io?.sockets.sockets.get(connectionId)\n : undefined;\n const own = socket === undefined ? rooms.detached : rooms.of(socket);\n return share === undefined ? own : unjoinable(own, share);\n },\n stream: (contract: AnyContract, name: string) => streams.handle(contract, name),\n occupancy: Object.freeze({\n sockets: (room: string) => hub.io?.sockets.adapter.rooms.get(room)?.size ?? 0,\n complete: () => hub.io === undefined || hub.probe.local(),\n }),\n revocation: streams.revocation,\n listen: () => {\n streams.listen();\n rooms.listen();\n state.requests.listen();\n },\n });\n}\n","// The change topics a flush changed (RFC 0003 sections 5.3 and 11.3), and the\n// sink that tells their watchers: `qd:changed { s, topic, rev }`, once per\n// flush per topic, to the topic's room. It carries no data; a client\n// invalidates the queries that watch the topic and reads them again. It\n// replaces 4.1's `invalidateOn`, which named hand-written events.\n//\n// Per flush:\n//\n// - the service topic of every service the flush changed: one of its rows\n// (written, touched, or reached by an `affects` hop), a junction link of\n// one of its `via` collections, a row of a model it lists in `writes` (a\n// game's high scores: a query over them watches the service), or a scope\n// it lost when the row it was anchored on was deleted. Its frame names\n// those models (`models`, finding F7.3 of the quickdraw-chat review), so\n// a query that watches only some (`watch: { service: [models] }`) ignores\n// a flush that wrote none of them: the service's model for its own rows\n// and lost scopes, the junction's for a link, the written one for\n// `writes`;\n// - the topic of every collection scope a touched row was in before or after\n// the flush, from the same moves the collection sink finds (`moves.ts`,\n// shared, so a flush reads their rows once); a row that left scopes nobody\n// can name, or junction rows removed without values, change every scope\n// watched here; and a scope closed by deleting its anchor row changed too.\n//\n// Only topics a socket here watches are computed, and a collection none of\n// whose topics is watched here reads nothing. Behind a cluster adapter other\n// nodes' rooms are not visible, so every changed topic is sent.\n//\n// A failure while finding the moves still tells the watchers: every topic\n// watched here that the flush may have changed gets `qd:changed`, and the\n// error is rethrown to be logged.\n\nimport { collectionTopic, SERVER_EVENTS, SERVICE_TOPIC, topicRoom } from \"../../contract/names\";\nimport type { ChangedFrame, Revision } from \"../../protocol/envelope\";\nimport { touchedRows, type TouchedRows } from \"../emit/affects\";\nimport { modelKey, type StorageAdapter } from \"../storage\";\nimport type { TopicIndex } from \"../topicIndex\";\nimport type { FlushInfo, FlushSink } from \"../uow/flushSink\";\nimport type { WriteRecord } from \"../uow/types\";\nimport { anchoredScopes, type BoundCollection, type CollectionHub } from \"./bind\";\nimport { workOf } from \"./collectionSink\";\nimport { movesOf, type Moves } from \"./moves\";\n\ntype Io = NonNullable<CollectionHub[\"io\"]>;\n\n/** The `qd:changed` frames of one flush, by topic room: one per topic. */\ntype Frames = Map<string, ChangedFrame>;\n\n/** Per model (`modelKey`), the services that list it in their `writes`. */\ntype Writers = ReadonlyMap<string, readonly BoundCollection[\"service\"][]>;\n\n/** What finding a flush's topics needs. */\ninterface Flush {\n readonly hub: CollectionHub;\n readonly index: TopicIndex;\n readonly writers: Writers;\n readonly writes: readonly WriteRecord[];\n readonly touched: TouchedRows;\n readonly rev: Revision;\n /** Whether every subscriber is a socket of this process (no cluster adapter). */\n readonly local: boolean;\n readonly frames: Frames;\n}\n\nfunction mark(flush: Flush, s: string, topic: string): void {\n flush.frames.set(topicRoom(s, topic), { s, topic, rev: flush.rev });\n}\n\n/** Marks a service's topic with the models whose writes changed it, sorted (finding F7.3). */\nfunction markService(flush: Flush, s: string, models: ReadonlySet<string>): void {\n const topic = SERVICE_TOPIC;\n flush.frames.set(topicRoom(s, topic), { s, topic, rev: flush.rev, models: [...models].sort() });\n}\n\n/** Marks one collection scope's topic when it may be watched: here, or anywhere behind a cluster adapter. */\nfunction markScope(flush: Flush, collection: BoundCollection, scope: string): void {\n const s = collection.service.name;\n if (!flush.local || flush.index.watchesScope(s, collection.name, scope)) {\n mark(flush, s, collectionTopic(collection.name, scope));\n }\n}\n\n/** The services that list each model in their `writes`, by `modelKey`. */\nfunction writersOf(hub: CollectionHub): Writers {\n const writers = new Map<string, BoundCollection[\"service\"][]>();\n for (const service of hub.registry.services.values()) {\n for (const model of service.writes) {\n const key = modelKey(model);\n writers.set(key, [...(writers.get(key) ?? []), service]);\n }\n }\n return writers;\n}\n\ntype Service = BoundCollection[\"service\"];\n\n/** Adds `model` to the models that changed `service`'s topic. */\nfunction changedBy(changed: Map<Service, Set<string>>, service: Service, model: string): void {\n const models = changed.get(service) ?? new Set<string>();\n models.add(modelKey(model));\n changed.set(service, models);\n}\n\n/**\n * The services whose rows or collection scopes the flush changed, and those\n * that list a written model in their `writes` (a query over such a model\n * watches the writing service's topic), each with the models that changed\n * it: the service's own model for its rows (written, touched, reached by\n * an `affects` hop) and for scopes a deleted anchor closed, which took its\n * rows with them; the junction model for a `via` link; the written model\n * for one in `writes`.\n */\nfunction changedServices(flush: Flush): Map<Service, Set<string>> {\n const changed = new Map<Service, Set<string>>();\n for (const service of flush.touched.keys()) {\n if (service.model !== undefined) {\n changedBy(changed, service, service.model);\n }\n }\n const { routes } = flush.hub.collections;\n for (const write of flush.writes) {\n const key = modelKey(write.model);\n for (const collection of routes.byJunction.get(key) ?? []) {\n changedBy(changed, collection.service, key);\n }\n for (const writer of flush.writers.get(key) ?? []) {\n changedBy(changed, writer, key);\n }\n }\n for (const [collection] of anchoredScopes(routes, flush.writes)) {\n const { service } = collection;\n if (service.model !== undefined) {\n changedBy(changed, service, service.model);\n }\n }\n return changed;\n}\n\n/** Marks the service topics and the scopes closed by a deleted anchor row: neither needs a read. */\nfunction markUnread(flush: Flush): void {\n for (const [service, models] of changedServices(flush)) {\n if (!flush.local || flush.index.watchesService(service.name)) {\n markService(flush, service.name, models);\n }\n }\n for (const [collection, scope] of anchoredScopes(flush.hub.collections.routes, flush.writes)) {\n markScope(flush, collection, scope);\n }\n}\n\n/** The scopes one collection's moves changed: every scope a row left, entered or changed in. */\nfunction scopesOf(moves: Moves, watched: ReadonlySet<string>): Set<string> {\n const scopes = new Set<string>();\n for (const move of moves.moves) {\n for (const scope of [...move.left, ...move.entered, ...move.stayed]) {\n scopes.add(scope);\n }\n for (const scope of move.unknownLeft ? watched : []) {\n scopes.add(scope);\n }\n }\n for (const scope of moves.resetAll ? watched : []) {\n scopes.add(scope);\n }\n return scopes;\n}\n\n/** Finds the topics `writes` changed, reading what their collections' moves need. */\nasync function findTopics(flush: Flush, storage: StorageAdapter): Promise<void> {\n markUnread(flush);\n const { hub, writes } = flush;\n await Promise.all(\n workOf(hub, writes, flush.touched).map(async ({ collection, refresh }) => {\n const watched = flush.index.scopes(collection.service.name, collection.name);\n if (flush.local && watched.size === 0) {\n return;\n }\n const moves = await movesOf(\n hub.collections.moves,\n storage,\n collection,\n writes,\n refresh,\n !flush.local,\n );\n for (const scope of scopesOf(moves, watched)) {\n markScope(flush, collection, scope);\n }\n }),\n );\n}\n\n/** Marks every watched topic the flush may have changed, without reading: the moves could not be found. */\nfunction markWatched(flush: Flush): void {\n markUnread(flush);\n for (const { collection } of workOf(flush.hub, flush.writes, flush.touched)) {\n for (const scope of flush.index.scopes(collection.service.name, collection.name)) {\n markScope(flush, collection, scope);\n }\n }\n}\n\nfunction send(io: Io, frames: Frames): void {\n for (const [room, frame] of frames) {\n io.to(room).emit(SERVER_EVENTS.changed, frame);\n }\n}\n\n/** The topic sink of a dispatcher: after the collection sink on the dispatcher's list. */\nexport function createTopicSink(hub: CollectionHub, index: TopicIndex): FlushSink {\n const writers = writersOf(hub);\n return Object.freeze({\n async flush(writes: readonly WriteRecord[], info: FlushInfo): Promise<void> {\n const { io, storage } = hub;\n if (io === undefined || storage === undefined) {\n return;\n }\n const flush: Flush = {\n hub,\n index,\n writers,\n writes,\n touched: touchedRows(writes, hub.routes),\n rev: info.rev,\n local: hub.probe.local(),\n frames: new Map(),\n };\n try {\n await findTopics(flush, storage);\n } catch (error) {\n markWatched(flush);\n throw error;\n } finally {\n send(io, flush.frames);\n }\n },\n });\n}\n","// The change topics this process's sockets watch (RFC 0003 section 11.3). A\n// query whose contract declares `watch` makes the client join that topic\n// with `qd:watch { s, topic }`: `{collection}:{scope}` for one scope of a\n// collection, or `service` for the whole service. Each socket keeps its own\n// watches on `socket.data.topics`, by room; the index counts them per scope\n// and per service, so a flush computes only the topics someone here watches,\n// and finds the watches an access change can concern by the rows a scope's\n// access is derived from (its anchors), as `collections/scopes.ts` does.\n// Rooms stay the source of truth for who receives `qd:changed`: a watch still\n// settling its races is recorded but out of the room (`hold`, then `join`).\n\nimport { SERVICE_TOPIC, topicRoom } from \"../contract/names\";\nimport { QuickdrawError } from \"../protocol/errors\";\nimport { MAX_SCOPE_LENGTH, MAX_TOPICS_PER_SOCKET } from \"../protocol/version\";\nimport type { AccessChange } from \"./access/changes\";\nimport { anchorKey } from \"./access/tools\";\nimport { PendingKeys } from \"./emit/pending\";\nimport { count, emptyRecords, ownRecord, serviceOf, type Counts } from \"./emit/subscriptions\";\nimport { unreadable } from \"./transports/ack\";\nimport type { QuickdrawServerSocket } from \"./transports/types\";\n\n/** One watched topic, as `socket.data.topics[room]` records it. */\nexport interface TopicWatch {\n /** The service name. */\n readonly s: string;\n /** The topic as the frame names it: `service`, or `{collection}:{scope}`. */\n readonly topic: string;\n /** The collection of a collection scope's topic; absent for the service topic. */\n readonly c?: string;\n /** The scope of a collection scope's topic; absent for the service topic. */\n readonly scope?: string;\n /**\n * The rows a collection scope's watch is authorized through (`anchorKey`s):\n * the anchor row, then its `inherit` parents. None for the service topic\n * or a `\"self\"` scope.\n */\n readonly anchors?: readonly string[];\n}\n\n/**\n * `socket.data.topics`: a socket's watched topics, by room. Plain data, in an\n * object without a prototype, read by own keys only.\n */\nexport type TopicWatches = Record<string, TopicWatch>;\n\nfunction isName(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\n/**\n * Reads a `qd:watch` or `qd:unwatch` frame, `{ s, topic }`, or throws\n * `VALIDATION`. A topic other than `service` is `{collection}:{scope}`,\n * split at its first colon: the collection name holds none, the scope may.\n */\nexport function readWatch(value: unknown, event: string): TopicWatch {\n const frame =\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Readonly<Record<string, unknown>>)\n : {};\n const { s, topic } = frame;\n if (!isName(s) || !isName(topic)) {\n throw unreadable(`A ${event} frame needs { s, topic } with each a non-empty string`);\n }\n if (topic.length > MAX_SCOPE_LENGTH) {\n throw unreadable(`topic must be at most ${MAX_SCOPE_LENGTH} characters`, [\"topic\"]);\n }\n if (topic === SERVICE_TOPIC) {\n return { s, topic };\n }\n const colon = topic.indexOf(\":\");\n if (colon <= 0 || colon === topic.length - 1) {\n throw unreadable(`topic must be \"${SERVICE_TOPIC}\" or {collection}:{scope}`, [\"topic\"]);\n }\n return { s, topic, c: topic.slice(0, colon), scope: topic.slice(colon + 1) };\n}\n\nfunction groupOf(service: string, collection: string): string {\n return `${service}\\u0000${collection}`;\n}\n\nconst NONE: ReadonlySet<string> = Object.freeze(new Set<string>());\n\n/** The topics sockets of this process watch, counted per service and per collection scope. */\nexport class TopicIndex {\n /** Per service, how many sockets here watch its service topic. */\n readonly #services = new Map<string, number>();\n /** Per collection (`service\\0collection`), how many sockets here watch each scope's topic. */\n readonly #scopes = new Map<string, Map<string, number>>();\n /** The topics each socket has a `qd:watch` in flight for, by room. */\n readonly #pending = new PendingKeys();\n readonly #byAnchor = new Map<string, Counts>();\n readonly #byAnchorService = new Map<string, Counts>();\n /** Per socket, the rooms of watches recorded by `hold` and not joined yet. */\n readonly #held = new WeakMap<QuickdrawServerSocket, Set<string>>();\n /** Per socket, how many topics it watches: counted, so checking the cap copies no keys. */\n readonly #sizes = new WeakMap<QuickdrawServerSocket, number>();\n\n #index(socket: QuickdrawServerSocket, watch: TopicWatch, by: 1 | -1): void {\n for (const anchor of watch.anchors ?? []) {\n count(this.#byAnchor, anchor, socket, by);\n count(this.#byAnchorService, serviceOf(anchor), socket, by);\n }\n }\n\n #count(watch: TopicWatch, by: 1 | -1): void {\n const { c, scope } = watch;\n if (c === undefined || scope === undefined) {\n const next = (this.#services.get(watch.s) ?? 0) + by;\n if (next > 0) {\n this.#services.set(watch.s, next);\n } else {\n this.#services.delete(watch.s);\n }\n return;\n }\n const key = groupOf(watch.s, c);\n const scopes = this.#scopes.get(key) ?? new Map<string, number>();\n const next = (scopes.get(scope) ?? 0) + by;\n if (next > 0) {\n scopes.set(scope, next);\n this.#scopes.set(key, scopes);\n return;\n }\n scopes.delete(scope);\n if (scopes.size === 0) {\n this.#scopes.delete(key);\n }\n }\n\n #record(socket: QuickdrawServerSocket, room: string, watch: TopicWatch): void {\n const watches = (socket.data.topics ??= emptyRecords());\n const previous = ownRecord(watches, room);\n watches[room] = watch;\n this.#index(socket, watch, 1);\n if (previous === undefined) {\n this.#count(watch, 1);\n this.#sizes.set(socket, this.size(socket) + 1);\n } else {\n this.#index(socket, previous, -1);\n }\n }\n\n /**\n * Records a watch and puts the socket in the topic's room; watching a\n * topic again records its anchors anew. One `hold` recorded stays out of\n * the room until `join`.\n */\n watch(socket: QuickdrawServerSocket, watch: TopicWatch): void {\n const room = topicRoom(watch.s, watch.topic);\n this.#record(socket, room, watch);\n if (this.#held.get(socket)?.has(room) !== true) {\n void socket.join(room);\n }\n }\n\n /**\n * Records a watch still settling its races: revocation finds it, but the\n * socket is not put in the topic's room (it stays there if an earlier\n * watch put it there) until `join`.\n */\n hold(socket: QuickdrawServerSocket, watch: TopicWatch): void {\n const room = topicRoom(watch.s, watch.topic);\n this.#record(socket, room, watch);\n const held = this.#held.get(socket) ?? new Set<string>();\n held.add(room);\n this.#held.set(socket, held);\n }\n\n /**\n * Puts the socket in the room of a watch `hold` recorded: the watch, or\n * `undefined` when nothing (an unwatch, a revocation or a disconnect ended\n * it), and the socket stays out.\n */\n join(socket: QuickdrawServerSocket, room: string): TopicWatch | undefined {\n this.#held.get(socket)?.delete(room);\n const watch = this.get(socket, room);\n if (watch !== undefined) {\n void socket.join(room);\n }\n return watch;\n }\n\n /** The socket's watch of a topic, by room, or `undefined`. */\n get(socket: QuickdrawServerSocket, room: string): TopicWatch | undefined {\n return ownRecord(socket.data.topics, room);\n }\n\n /** Every topic the socket watches. */\n entries(socket: QuickdrawServerSocket): TopicWatch[] {\n return Object.values(socket.data.topics ?? {});\n }\n\n /** How many topics the socket watches, a watch still settling included. */\n size(socket: QuickdrawServerSocket): number {\n return this.#sizes.get(socket) ?? 0;\n }\n\n /**\n * `CONFLICT` when the socket watches `MAX_TOPICS_PER_SOCKET` topics and\n * `room` is not one of them (the 5.1 audit's COLL-4): a topic watched\n * already never counts again.\n */\n checkRoom(socket: QuickdrawServerSocket, room: string): void {\n if (this.get(socket, room) === undefined && this.size(socket) >= MAX_TOPICS_PER_SOCKET) {\n throw new QuickdrawError(\n \"CONFLICT\",\n `A socket may watch at most ${MAX_TOPICS_PER_SOCKET} change topics; unwatch one first`,\n );\n }\n }\n\n /** Ends a watch the socket may no longer hold: it leaves the topic's room. */\n leave(socket: QuickdrawServerSocket, room: string): void {\n const watches = socket.data.topics;\n const watch = ownRecord(watches, room);\n if (watches !== undefined && watch !== undefined) {\n delete watches[room];\n this.#sizes.set(socket, this.size(socket) - 1);\n this.#count(watch, -1);\n this.#index(socket, watch, -1);\n }\n this.#held.get(socket)?.delete(room);\n void socket.leave(room);\n }\n\n /** A `qd:watch` of the topic begins; returns how often it was unwatched so far. */\n begin(socket: QuickdrawServerSocket, room: string): number {\n return this.#pending.begin(socket, [room]).get(room) ?? 0;\n }\n\n /** The watch `begin` started has ended. */\n end(socket: QuickdrawServerSocket, room: string): void {\n this.#pending.end(socket, [room]);\n }\n\n /** A client unwatched: the socket leaves the topic's room, and a watch still being authorized will not join it. */\n unwatch(socket: QuickdrawServerSocket, room: string): void {\n this.#pending.unsubscribed(socket, room);\n this.leave(socket, room);\n }\n\n /** How often the client unwatched the topic while a watch of it ran; it joins only if that did not move. */\n unwatches(socket: QuickdrawServerSocket, room: string): number {\n return this.#pending.count(socket, room);\n }\n\n /** A socket disconnected: Socket.IO has emptied its rooms; drop its watches from the counts. */\n drop(socket: QuickdrawServerSocket): void {\n for (const watch of this.entries(socket)) {\n this.#count(watch, -1);\n this.#index(socket, watch, -1);\n }\n socket.data.topics = emptyRecords();\n this.#held.delete(socket);\n this.#sizes.delete(socket);\n }\n\n /**\n * The watches an access change can concern: those of collection scopes\n * anchored on the changed row (any row of the service when `id` is\n * absent), of the changed user's sockets (every user's when `userId` is\n * absent).\n */\n matching(change: AccessChange): Map<QuickdrawServerSocket, TopicWatch[]> {\n const key = change.id === undefined ? undefined : anchorKey(change.service, change.id);\n const sockets =\n key === undefined ? this.#byAnchorService.get(change.service) : this.#byAnchor.get(key);\n const found = new Map<QuickdrawServerSocket, TopicWatch[]>();\n for (const socket of sockets?.keys() ?? []) {\n if (change.userId !== undefined && socket.data.principal?.userId !== change.userId) {\n continue;\n }\n const watches = this.entries(socket).filter(({ anchors = [] }) =>\n anchors.some((anchor) =>\n key === undefined ? serviceOf(anchor) === change.service : anchor === key,\n ),\n );\n if (watches.length > 0) {\n found.set(socket, watches);\n }\n }\n return found;\n }\n\n /** True when a socket of this process watches the service's topic. */\n watchesService(service: string): boolean {\n return this.#services.has(service);\n }\n\n /** The scopes of a collection whose topics sockets of this process watch. */\n scopes(service: string, collection: string): ReadonlySet<string> {\n const scopes = this.#scopes.get(groupOf(service, collection));\n return scopes === undefined ? NONE : new Set(scopes.keys());\n }\n\n /** True when a socket of this process watches the topic of one scope of a collection. */\n watchesScope(service: string, collection: string, scope: string): boolean {\n return this.#scopes.get(groupOf(service, collection))?.has(scope) ?? false;\n }\n}\n","// Revoking change topic watches (RFC 0003 sections 4.4 and 11.3), beside the\n// entity and collection revocations (`emit/revocation.ts`, which calls this\n// on every access change it handles). A `qd:changed` carries no data, but it\n// still tells a watcher when a scope changes: a socket that lost access to a\n// scope must stop hearing about it. Each watch of a collection scope records\n// the rows its access is derived from (its anchors); when a flush may have\n// changed someone's level on one, the watches anchored there are authorized\n// again, and a changed `serviceAccess` authorizes every watch of the user's\n// sockets again, service topics included (`watchAccess: { service }`).\n//\n// A watch no longer allowed leaves the topic's room. No new frame kind says\n// so: the socket gets one last `qd:changed` for the topic, its client reads\n// the watching query again, and that read is refused. A lookup that fails\n// denies, as everywhere else.\n//\n// A `qd:watch` is authorized and joined here too (`joinWatch`). One an\n// access change overlapped is settled first (through `emit/race.ts`):\n// recorded, so revocation finds it, but out of the topic's room, it is\n// authorized again with the socket's principal as it is then, and one that\n// lost access meanwhile is answered `FORBIDDEN` (the 5.1 audit's LIVE-2: a\n// member removed while watching kept the topic's `qd:changed`). It joins\n// the room only once it settled.\n\nimport { SERVER_EVENTS, topicRoom } from \"../contract/names\";\nimport { QuickdrawError } from \"../protocol/errors\";\nimport { authorizeWatch, type WatchTarget } from \"./collections/access\";\nimport type { CollectionHub } from \"./collections/bind\";\nimport { enterSettled, raceMoved, raceStart, settleJoin, type RaceStart } from \"./emit/race\";\nimport { settleAll, type RevocationHook } from \"./emit/revocation\";\nimport { describeError } from \"./pipeline/metrics\";\nimport { currentRev } from \"./rev\";\nimport type { TopicIndex, TopicWatch } from \"./topicIndex\";\nimport type { QuickdrawServerSocket } from \"./transports/types\";\n\n/** What a watch names, or `NOT_FOUND`. */\nexport function targetOf(hub: CollectionHub, watch: TopicWatch): WatchTarget {\n const service = hub.registry.services.get(watch.s);\n if (service === undefined) {\n throw new QuickdrawError(\"NOT_FOUND\", `Unknown service \"${watch.s}\"`);\n }\n const { c, scope } = watch;\n if (service.model === undefined && (c !== undefined || service.writes.length === 0)) {\n throw new QuickdrawError(\n \"NOT_FOUND\",\n `${watch.s} has no rows whose changes could be watched: it declares no model and writes nothing`,\n );\n }\n if (c === undefined || scope === undefined) {\n return { kind: \"service\", service };\n }\n const collection = hub.collections.routes.find(watch.s, c);\n if (collection === undefined) {\n throw new QuickdrawError(\"NOT_FOUND\", `${watch.s} has no collection \"${c}\"`);\n }\n return { kind: \"collection\", collection, scope };\n}\n\n/** The anchors the watch may keep, or `undefined` when it may no longer watch its topic. */\nexport async function anchorsNow(\n hub: CollectionHub,\n socket: QuickdrawServerSocket,\n watch: TopicWatch,\n): Promise<readonly string[] | undefined> {\n try {\n return await authorizeWatch(hub, socket.data.principal, targetOf(hub, watch));\n } catch (error) {\n if (!(error instanceof QuickdrawError) || error.code === \"INTERNAL\") {\n hub.logger.error(\"Authorizing a watched topic again failed; the watch is revoked\", {\n category: \"quickdraw.access\",\n service: watch.s,\n topic: watch.topic,\n error: describeError(error),\n });\n }\n return undefined;\n }\n}\n\n/** Authorizes one watch again, and applies the answer. */\nasync function rewatch(\n hub: CollectionHub,\n index: TopicIndex,\n socket: QuickdrawServerSocket,\n watch: TopicWatch,\n): Promise<void> {\n const anchors = await anchorsNow(hub, socket, watch);\n const room = topicRoom(watch.s, watch.topic);\n // Unwatched, watched again or authorized again meanwhile: that is newer than this.\n if (!socket.connected || index.get(socket, room) !== watch) {\n return;\n }\n if (anchors !== undefined) {\n index.watch(socket, { ...watch, anchors });\n return;\n }\n index.leave(socket, room);\n socket.emit(SERVER_EVENTS.changed, { s: watch.s, topic: watch.topic, rev: currentRev() });\n}\n\n/** A watch recorded: its record, what it settles against, and whether the client withdrew it since. */\ninterface Held {\n readonly own: TopicWatch;\n readonly start: RaceStart;\n readonly withdrawn: () => boolean;\n}\n\n/** Settles a recorded watch against the access changes made since it began (`emit/race.ts`). */\nasync function settleWatch(\n hub: CollectionHub,\n index: TopicIndex,\n socket: QuickdrawServerSocket,\n held: Held,\n): Promise<TopicWatch | undefined> {\n const room = topicRoom(held.own.s, held.own.topic);\n return await settleJoin(hub, socket, held.start, held.own, {\n current: () => index.get(socket, room),\n withdrawn: held.withdrawn,\n authorize: async (watch) => await anchorsNow(hub, socket, watch),\n reanchor: (watch, anchors) => {\n const next = { ...watch, anchors };\n index.watch(socket, next);\n return next;\n },\n leave: () => {\n index.leave(socket, room);\n },\n });\n}\n\n/**\n * Authorizes one `qd:watch` of `target` and joins the topic's room, unless\n * the client unwatched the topic meanwhile (the module header). Throws the\n * authorization's refusal, or `FORBIDDEN` when the watch lost access while\n * it was answered.\n */\nexport async function joinWatch(\n hub: CollectionHub,\n index: TopicIndex,\n socket: QuickdrawServerSocket,\n [watch, target]: readonly [TopicWatch, WatchTarget],\n): Promise<void> {\n const room = topicRoom(watch.s, watch.topic);\n // At most MAX_TOPICS_PER_SOCKET topics a socket: refused before any read.\n index.checkRoom(socket, room);\n const unwatches = index.begin(socket, room);\n const withdrawn = (): boolean => !socket.connected || index.unwatches(socket, room) !== unwatches;\n // What the watch settles against, noted before it is authorized.\n const start = raceStart(hub, socket);\n try {\n const anchors = await authorizeWatch(hub, start.principal, target);\n if (withdrawn()) {\n return;\n }\n // Again where the watch is recorded, so watches running at once cannot overshoot.\n index.checkRoom(socket, room);\n const own = { ...watch, anchors };\n index.hold(socket, own);\n const settled = raceMoved(hub, socket, start)\n ? await settleWatch(hub, index, socket, { own, start, withdrawn })\n : own;\n if (settled !== undefined) {\n enterSettled(() => index.join(socket, room), withdrawn);\n }\n } finally {\n index.end(socket, room);\n }\n}\n\n/** Authorizes the given watches again, each socket's one by one. */\nasync function rewatchAll(\n hub: CollectionHub,\n index: TopicIndex,\n found: Iterable<readonly [QuickdrawServerSocket, readonly TopicWatch[]]>,\n): Promise<void> {\n const work: Promise<void>[] = [];\n for (const [socket, watches] of found) {\n for (const watch of watches) {\n work.push(rewatch(hub, index, socket, watch));\n }\n }\n await settleAll(work);\n}\n\n/** The topic half of a dispatcher's revocation. */\nexport function createTopicRevocation(hub: CollectionHub, index: TopicIndex): RevocationHook {\n return Object.freeze({\n changed: async (change) => await rewatchAll(hub, index, index.matching(change)),\n regranted: async (sockets) =>\n await rewatchAll(\n hub,\n index,\n sockets.map((socket) => [socket, index.entries(socket)] as const),\n ),\n } satisfies RevocationHook);\n}\n","// Change topics (RFC 0003 section 11.3): how a query learns that the data it\n// read has changed without hand-written event names. A query whose contract\n// declares `watch: { collection, scope }` makes the client join the topic\n// `{collection}:{scope}` of its service; a query that depends on the whole\n// service joins `service`. The server then sends `qd:changed { s, topic, rev\n// }` once per flush that changed the topic (`collections/changed.ts`), and\n// the client invalidates the query. The frame carries no data: rows travel\n// as entity frames and collection deltas, never as a change signal. Topics\n// reuse collection scopes, so nothing is declared twice.\n//\n// `qd:watch { s, topic }` is answered `{ ok: true }` or `{ ok: false, e }`,\n// and joins the topic's room. It is authorized, and sends no snapshot:\n//\n// - `{collection}:{scope}` exactly as `qd:col:sub` of that scope is\n// (`collections/access.ts`): `UNAUTHENTICATED` for an anonymous socket,\n// `FORBIDDEN` for a scope the principal may not subscribe to;\n// - `service` by the service's `watchAccess` (`\"public\"`, `\"authenticated\"`\n// or `{ service: level }`); without one the topic is closed, `FORBIDDEN`\n// for everyone, since it changes whenever any row of the service does.\n//\n// A malformed frame is `VALIDATION`, an unknown service or collection (or a\n// service without a model that writes nothing, whose topic never changes)\n// `NOT_FOUND`. A socket watches at most `MAX_TOPICS_PER_SOCKET` topics (the\n// 5.1 audit's COLL-4): one more is `CONFLICT`, checked before the watch is\n// authorized and again where it is recorded (`joinWatch`); a topic watched\n// already never counts again. A service's topic also changes with every\n// write to a model it lists in `writes`, so a query over such a model\n// declares `watch: \"service\"`.\n// `qd:unwatch { s, topic }` is checked the same way, leaves the room,\n// optionally acknowledged, and stops a watch still being authorized from\n// joining. Neither counts against the socket rate limiter\n// (`transports/middleware.ts`), and neither listener throws\n// (`emit/answer.ts`). A watch whose access the socket loses leaves its room,\n// after one last `qd:changed` (`topicRevocation.ts`). A watch an access\n// change overlapped is authorized again before it joins, with the socket's\n// principal as it is then, and answered `FORBIDDEN` when it lost access\n// meanwhile (`joinWatch`).\n\nimport { CLIENT_EVENTS, topicRoom } from \"../contract/names\";\nimport type { Ok } from \"../protocol/envelope\";\nimport { QuickdrawError } from \"../protocol/errors\";\nimport type { CollectionHub } from \"./collections/bind\";\nimport { createTopicSink } from \"./collections/changed\";\nimport { answerEvent, answerNow, onDisconnect } from \"./emit/answer\";\nimport { readWatch, TopicIndex } from \"./topicIndex\";\nimport { createTopicRevocation, joinWatch, targetOf } from \"./topicRevocation\";\nimport type { QuickdrawServerSocket, SocketContext } from \"./transports/types\";\n\n/**\n * Serves one `qd:watch`: authorizes it, settles the races with the access\n * changes made meanwhile, and joins the topic's room unless the client\n * unwatched meanwhile (`joinWatch`).\n */\nasync function watchTopic(\n hub: CollectionHub,\n index: TopicIndex,\n socket: QuickdrawServerSocket,\n frame: unknown,\n): Promise<Ok> {\n const watch = readWatch(frame, CLIENT_EVENTS.watch);\n const target = targetOf(hub, watch);\n if (hub.storage === undefined) {\n throw new QuickdrawError(\n \"INTERNAL\",\n \"Change topics follow tracked writes: pass db as trackPrisma(prisma)\",\n );\n }\n await joinWatch(hub, index, socket, [watch, target]);\n return { ok: true };\n}\n\n/**\n * Serves one `qd:unwatch`: the socket leaves the topic's room. Throws\n * `VALIDATION` for a malformed frame, `NOT_FOUND` for an unknown service or\n * collection, and `UNAUTHENTICATED` for an anonymous socket, which can watch\n * nothing but a public service topic.\n */\nfunction unwatchTopic(\n hub: CollectionHub,\n index: TopicIndex,\n socket: QuickdrawServerSocket,\n frame: unknown,\n): Ok {\n const watch = readWatch(frame, CLIENT_EVENTS.unwatch);\n const target = targetOf(hub, watch);\n const open = target.kind === \"service\" && target.service.watchAccess === \"public\";\n if (socket.data.principal === null && !open) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n index.unwatch(socket, topicRoom(watch.s, watch.topic));\n return { ok: true };\n}\n\n/** The change topics of one dispatcher. */\nexport interface Topics {\n /** Sends `qd:changed` for the flush's topics: after the collection sink on the dispatcher's list. */\n readonly sink: ReturnType<typeof createTopicSink>;\n /** Serves `qd:watch` and `qd:unwatch` on every v5 socket. */\n readonly extension: (socket: QuickdrawServerSocket, context: SocketContext) => void;\n /** Authorizes watches again on access changes: a watch a socket lost leaves its room (`topicRevocation.ts`). */\n readonly revocation: ReturnType<typeof createTopicRevocation>;\n}\n\n/** Creates the change topics of a dispatcher whose hub holds its collections. */\nexport function createTopics(hub: CollectionHub): Topics {\n const index = new TopicIndex();\n return Object.freeze({\n sink: createTopicSink(hub, index),\n revocation: createTopicRevocation(hub, index),\n extension: (socket: QuickdrawServerSocket, context: SocketContext): void => {\n answerEvent(socket, context, CLIENT_EVENTS.watch, (frame) =>\n watchTopic(hub, index, socket, frame),\n );\n socket.on(CLIENT_EVENTS.unwatch, (frame: unknown, ack: unknown) => {\n answerNow(socket, context, CLIENT_EVENTS.unwatch, ack, () =>\n unwatchTopic(hub, index, socket, frame),\n );\n });\n onDisconnect(socket, context, () => {\n index.drop(socket);\n });\n },\n });\n}\n","// The entity sinks (RFC 0003 sections 5.3 and 6): what a flush does for\n// entity subscribers. It replaces 4.1's `emitUpdate`\n// (4.1 `src/server/BaseService.ts:454-466`), which only `this.update` and\n// hand-written code called.\n//\n// Two sinks, on either side of the access sink on the dispatcher's list:\n//\n// - `intake` works out which rows of which services the flush touched\n// (`affects` included) and records them in the change log, before access\n// is evicted and revoked, so revocation knows a deleted row from a\n// forbidden one;\n// - `emit` runs once revocation has moved or removed sockets, so a socket\n// whose access the flush removed never gets its frames. Per service with\n// touched rows it skips rows whose rooms are all empty, reads the rest in\n// one query with the entity projection's select (a patch reads only the\n// patched fields), builds each frame once and strips it once per group of\n// occupied tiers that see the same fields.\n//\n// Room occupancy is read from this process's adapter. Behind a cluster\n// adapter (Redis) other nodes' rooms are invisible, so every touched row is\n// read and its frame sent to every tier. Frames sent there go out whole\n// (`u`, never `p`): frames from two nodes can reach a client out of revision\n// order, and a patch it dropped as older would lose its fields, while an\n// older whole row is rightly dropped (the newer one was read after the older\n// write). A tier that would have got an empty patch still gets nothing.\n//\n// Behind a cluster adapter a deleted row is read too: a flush takes its\n// revision when it flushes, so a delete that committed first can flush after\n// a later create of the same id, and its `r` would win over that row on the\n// client. A row this flush deleted that exists at the read goes out whole\n// (`u`) instead, and the change log records it as existing. One server keeps\n// sending `r` without a read.\n\nimport type { AccessLevel } from \"../../contract/access\";\nimport { entityRoom, SERVER_EVENTS } from \"../../contract/names\";\nimport type { EntityFrame, Revision } from \"../../protocol/envelope\";\nimport type { AnyService } from \"../service\";\nimport type { FlushInfo, FlushSink } from \"../uow/flushSink\";\nimport type { WriteRecord } from \"../uow/types\";\nimport { touchedRows, type Touch, type TouchedRows } from \"./affects\";\nimport { buildFrame, frameKind, selectFor, type FrameKind } from \"./frames\";\nimport type { Hub } from \"./hub\";\nimport { strip, SUBSCRIBER_LEVELS } from \"./tiers\";\n\ntype Io = NonNullable<Hub[\"io\"]>;\n\n/** A touched row with subscribers: how it goes out, and the rooms of the tiers it goes to. */\ninterface Target {\n readonly id: string;\n readonly kind: FrameKind;\n readonly rooms: ReadonlyMap<AccessLevel, string>;\n /** Behind a cluster adapter, the fields a patch would have carried: the row goes out whole. */\n readonly patched?: readonly string[];\n}\n\nconst WHOLE: FrameKind = Object.freeze({ t: \"u\" });\n\n/** How a row goes out: as `frameKind` says, but whole instead of a patch behind a cluster adapter. */\nfunction targetOf(\n id: string,\n kind: FrameKind,\n rooms: ReadonlyMap<AccessLevel, string>,\n local: boolean,\n): Target {\n return local || kind.t !== \"p\"\n ? { id, kind, rooms }\n : { id, kind: WHOLE, rooms, patched: kind.fields };\n}\n\n/** True when the tier sees none of the fields the write changed: it gets no frame, as it would get no patch. */\nfunction seesNoChange(target: Target, hidden: ReadonlySet<string>): boolean {\n return target.patched !== undefined && target.patched.every((field) => hidden.has(field));\n}\n\n/** The tier rooms of a row that have subscribers here; behind a cluster adapter, every tier room. */\nfunction occupiedRooms(\n io: Io,\n service: string,\n id: string,\n local: boolean,\n): Map<AccessLevel, string> {\n const rooms = new Map<AccessLevel, string>();\n const known = io.sockets.adapter.rooms;\n for (const level of SUBSCRIBER_LEVELS) {\n const room = entityRoom(service, id, level);\n if (!local || (known.get(room)?.size ?? 0) > 0) {\n rooms.set(level, room);\n }\n }\n return rooms;\n}\n\n/** Sends a frame to its rooms: a removal once to all, data once per group of tiers that see the same fields. */\nfunction send(io: Io, frame: EntityFrame, target: Target, service: AnyService): void {\n if (frame.t === \"r\") {\n io.to([...target.rooms.values()]).emit(SERVER_EVENTS.entity, frame);\n return;\n }\n const tiers = service.projections.get(\"entity\")?.tiers;\n for (const group of tiers?.groups ?? []) {\n const rooms = group.levels.flatMap((level) => target.rooms.get(level) ?? []);\n const data = strip(frame.d as Readonly<Record<string, unknown>>, group.hidden);\n const empty =\n frame.t === \"p\" ? Object.keys(data).length === 0 : seesNoChange(target, group.hidden);\n if (rooms.length === 0 || empty) {\n continue;\n }\n io.to(rooms).emit(SERVER_EVENTS.entity, { ...frame, d: data });\n }\n}\n\n/** Reads the rows of `targets` that need data, in one query: behind a cluster adapter, removed rows too. */\nasync function readTargets(\n hub: Hub,\n service: AnyService,\n targets: readonly Target[],\n local: boolean,\n): Promise<Map<string, Readonly<Record<string, unknown>>>> {\n const projection = service.projections.get(\"entity\");\n const reading = local ? targets.filter((target) => target.kind.t !== \"r\") : targets;\n if (projection === undefined || service.model === undefined || reading.length === 0) {\n return new Map();\n }\n const rows =\n (await hub.storage?.findMany(service.model, {\n where: { id: { in: reading.map((target) => target.id) } },\n select: selectFor(\n projection,\n reading.map((target) => (target.kind.t === \"r\" ? WHOLE : target.kind)),\n ),\n })) ?? [];\n return new Map(rows.flatMap((row) => (typeof row.id === \"string\" ? [[row.id, row]] : [])));\n}\n\n/** One service's frames for one flush. */\nasync function emitService(\n hub: Hub,\n io: Io,\n service: AnyService,\n touched: ReadonlyMap<string, Touch>,\n rev: Revision,\n): Promise<void> {\n const projection = service.projections.get(\"entity\");\n if (projection === undefined || service.model === undefined) {\n return;\n }\n const local = hub.probe.local();\n const targets: Target[] = [];\n for (const [id, touch] of touched) {\n const rooms = occupiedRooms(io, service.name, id, local);\n if (rooms.size > 0) {\n targets.push(targetOf(id, frameKind(projection, touch, service.versionColumn), rooms, local));\n }\n }\n if (targets.length === 0) {\n return;\n }\n const rows = await readTargets(hub, service, targets, local);\n for (const target of targets) {\n const row = rows.get(target.id);\n // Behind a cluster adapter, a row this flush deleted that exists at the read was created\n // again by a write whose flush went first: it goes out whole, not removed.\n const again = target.kind.t === \"r\" && row !== undefined;\n if (again) {\n hub.changeLog.record(service.name, target.id, rev, false);\n }\n // A row read as missing was deleted since: its own flush sends the removal.\n const kind = again ? WHOLE : target.kind;\n const frame = buildFrame(service.name, target.id, kind, row, rev, projection);\n if (frame !== undefined) {\n send(io, frame, target, service);\n }\n }\n}\n\n/** The intake and emit sinks of a dispatcher's entity subscriptions. */\nexport function createEntitySinks(hub: Hub): { intake: FlushSink; emit: FlushSink } {\n const flushes = new WeakMap<readonly WriteRecord[], TouchedRows>();\n return {\n intake: Object.freeze({\n flush(writes: readonly WriteRecord[], info: FlushInfo): Promise<void> {\n const touched = touchedRows(writes, hub.routes);\n flushes.set(writes, touched);\n for (const [service, rows] of touched) {\n for (const [id, touch] of rows) {\n hub.changeLog.record(service.name, id, info.rev, touch.op === \"delete\");\n }\n }\n return Promise.resolve();\n },\n }),\n emit: Object.freeze({\n async flush(writes: readonly WriteRecord[], info: FlushInfo): Promise<void> {\n const { io } = hub;\n if (io === undefined) {\n return;\n }\n const touched = flushes.get(writes) ?? touchedRows(writes, hub.routes);\n await Promise.all(\n [...touched].map(([service, rows]) => emitService(hub, io, service, rows, info.rev)),\n );\n },\n }),\n };\n}\n","// The socket listeners of entity subscriptions (RFC 0003 sections 6 and 8.2):\n// `qd:sub { s, ids, revs? }`, answered `{ ok: true, r }` with one result per\n// id or `{ ok: false, e }` for the whole batch, and `qd:unsub { s, ids }`,\n// optionally acknowledged. One listener per event on every v5 socket, routed\n// by the frame's service, never one per service or row. The rate limiter\n// does not count either event (`transports/middleware.ts`): a board mounting\n// sixty rows would otherwise trip it.\n//\n// The whole batch fails when the frame is malformed or holds more than 500\n// ids (`VALIDATION`), names an unknown service or one without rows\n// (`NOT_FOUND`), comes from an anonymous socket (`UNAUTHENTICATED`), or from\n// a principal of a kind the service does not admit (`FORBIDDEN`,\n// `../access/kinds.ts`), or when its new ids would take the socket past\n// `MAX_ENTITY_IDS_PER_SOCKET` rows (`CONFLICT`); a failed lookup or read is\n// `INTERNAL`, logged. One row batches running at once left no room for is\n// answered `CONFLICT` on its own (`subscribe.ts`). `qd:unsub` is checked the\n// same way, kinds aside: leaving needs no kind.\n//\n// No listener of the live data throws (`answer.ts`), and `qd:sub` runs in\n// the socket's lane of subscription work (`lane.ts`).\n\nimport { CLIENT_EVENTS } from \"../../contract/names\";\nimport type { EntitySubscribeReply, Ok, Revision } from \"../../protocol/envelope\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { MAX_SUBSCRIBE_IDS } from \"../../protocol/version\";\nimport { checkKind } from \"../access/kinds\";\nimport { unreadable } from \"../transports/ack\";\nimport type { QuickdrawServerSocket, SocketContext } from \"../transports/types\";\nimport { answerEvent, answerNow, onDisconnect } from \"./answer\";\nimport { liveService, type Hub } from \"./hub\";\nimport { subscribe, type SubscribeRequest } from \"./subscribe\";\n\ntype UnknownRecord = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is UnknownRecord {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isIdList(value: unknown): value is readonly string[] {\n return Array.isArray(value) && value.every((id) => typeof id === \"string\" && id.length > 0);\n}\n\nfunction isHeld(value: unknown): value is Revision | null {\n return value === null || (typeof value === \"number\" && Number.isFinite(value));\n}\n\n/** Reads the `{ s, ids }` of a `qd:sub` or `qd:unsub` frame, or throws `VALIDATION`. */\nfunction readIds(\n frame: unknown,\n event: string,\n shape: string,\n): { readonly s: string; readonly ids: readonly string[]; readonly frame: UnknownRecord } {\n if (!isRecord(frame) || typeof frame.s !== \"string\" || frame.s === \"\" || !isIdList(frame.ids)) {\n throw unreadable(`A ${event} frame needs ${shape} with ids a list of row ids`);\n }\n if (frame.ids.length > MAX_SUBSCRIBE_IDS) {\n throw unreadable(`A ${event} frame names at most ${MAX_SUBSCRIBE_IDS} ids`, [\"ids\"]);\n }\n return { s: frame.s, ids: frame.ids, frame };\n}\n\n/** Reads a `qd:sub` frame, or throws `VALIDATION`. */\nfunction readSubscribe(value: unknown): SubscribeRequest {\n const { s, ids, frame } = readIds(value, CLIENT_EVENTS.sub, \"{ s, ids, revs? }\");\n const { revs } = frame;\n const listed = revs === undefined || (Array.isArray(revs) && revs.length === ids.length);\n if (!listed || (revs !== undefined && !revs.every(isHeld))) {\n throw unreadable(\"revs must hold a revision or null for each id, by position\", [\"revs\"]);\n }\n const held = new Map<string, Revision>();\n ids.forEach((id, index) => {\n const rev: unknown = revs?.[index];\n if (typeof rev === \"number\") {\n held.set(id, rev);\n }\n });\n return { s, ids, held };\n}\n\nasync function onSubscribe(\n hub: Hub,\n socket: QuickdrawServerSocket,\n frame: unknown,\n): Promise<EntitySubscribeReply> {\n const request = readSubscribe(frame);\n const target = liveService(hub, request.s);\n if (socket.data.principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n checkKind(target.service.kinds, socket.data.principal, target.service.name);\n if (hub.storage === undefined) {\n throw new QuickdrawError(\n \"INTERNAL\",\n \"Entity subscriptions read rows through the dispatcher's storage adapter: pass db as trackPrisma(prisma)\",\n );\n }\n return { ok: true, r: await subscribe(hub, socket, target, request) };\n}\n\n/** Serves `qd:unsub`: checked as `qd:sub` is, then each row's subscription ends. */\nfunction onUnsubscribe(hub: Hub, socket: QuickdrawServerSocket, frame: unknown): Ok {\n const { s, ids } = readIds(frame, CLIENT_EVENTS.unsub, \"{ s, ids }\");\n liveService(hub, s);\n if (socket.data.principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n for (const id of ids) {\n hub.subscriptions.unsubscribe(socket, s, id);\n }\n return { ok: true };\n}\n\n/**\n * The socket extension (`transports/socketio.ts`) that serves `qd:sub` and\n * `qd:unsub` for one dispatcher's services.\n */\nexport function entitySubscriptions(\n hub: Hub,\n): (socket: QuickdrawServerSocket, context: SocketContext) => void {\n return (socket, context) => {\n answerEvent(socket, context, CLIENT_EVENTS.sub, (frame) => onSubscribe(hub, socket, frame));\n socket.on(CLIENT_EVENTS.unsub, (frame: unknown, ack: unknown) => {\n answerNow(socket, context, CLIENT_EVENTS.unsub, ack, () => onUnsubscribe(hub, socket, frame));\n });\n onDisconnect(socket, context, () => {\n hub.subscriptions.drop(socket);\n });\n };\n}\n","// The live data of one dispatcher (RFC 0003 sections 4.4, 5.3, 6, 7, 11.3\n// and 12.5): entity subscriptions, collection scopes and change topics, the\n// frames flushes send them, revocation, \"not modified\" versions, and the\n// realtime half (presence, streams, channels and typed room events). A\n// dispatcher makes one; `createServer` attaches its Socket.IO server and\n// serves `qd:sub`, `qd:col:sub`, `qd:col:items`, `qd:watch`, `qd:stream:sub`\n// and `qd:ch` with it. Without a server the sinks still keep the change log,\n// so in-process callers get versions too.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport { createLiveCollections } from \"../collections/live\";\nimport {\n createRealtime,\n type Presence,\n type Realtime,\n type RoomLeave,\n type RoomLeaveHandler,\n type RoomLeaveHook,\n type ServerRooms,\n type StreamHandle,\n} from \"../realtime/realtime\";\nimport { createTopics } from \"../topics\";\nimport { createEntitySinks } from \"./entitySink\";\nimport { entitySubscriptions } from \"./extension\";\nimport { createHub, drain, type AdapterProbe, type Hub, type HubOptions } from \"./hub\";\nimport { createRevocation, listenForChanges } from \"./revocation\";\nimport { createVersionSource } from \"./versions\";\n\nexport type { Presence, RoomLeave, RoomLeaveHandler, RoomLeaveHook, ServerRooms, StreamHandle };\nexport type { ChangeLogOptions } from \"./changeLog\";\n\ntype Sinks = ReturnType<typeof createEntitySinks>;\n\ntype Collections = ReturnType<typeof createLiveCollections>;\n\n/** The live data of one dispatcher. */\nexport interface Live {\n /** Records the rows a flush touched in the change log; goes before the access sink. */\n readonly intake: Sinks[\"intake\"];\n /** Sends the flush's entity frames; goes after the access sink. */\n readonly emit: Sinks[\"emit\"];\n /** Sends the flush's collection deltas; goes after `emit`. */\n readonly collections: Collections[\"sink\"];\n /** Sends `qd:changed` for the flush's change topics; goes after `collections`. */\n readonly topics: ReturnType<typeof createTopics>[\"sink\"];\n /** \"Not modified\" for queries returning one projection row: the dispatcher's default `versions`. */\n readonly versions: ReturnType<typeof createVersionSource>;\n /**\n * Serves `qd:sub`, `qd:unsub`, `qd:col:sub`, `qd:col:items`,\n * `qd:col:unsub`, `qd:watch`, `qd:unwatch`, `qd:stream:sub`,\n * `qd:stream:unsub` and `qd:ch` on every v5 socket.\n */\n readonly extension: ReturnType<typeof entitySubscriptions>;\n /**\n * What a 4.x socket gets instead: it leaves the app rooms its calls through\n * the legacy shim joined when it disconnects. None of the v5 events are served.\n */\n readonly legacyExtension: Realtime[\"legacyExtension\"];\n /** Presence, streams, channels and typed room events: `ctx.rooms`, `ctx.presence`, `qd.stream`. */\n readonly realtime: Realtime;\n /** The revisions flushes take and reads claim: the process's clock, or a cluster's shared counter. */\n readonly revisions: Hub[\"revisions\"];\n /**\n * Gives the live data its Socket.IO server: frames go out on it, and\n * access changes broadcast by other nodes arrive on it. What such a change\n * names is evicted from the access cache (`cacheMs`) before it is resolved\n * again. `cluster` says where a cluster's shared state lives, and\n * `broadcasts` sends access changes to the other nodes.\n */\n attach(\n io: NonNullable<Hub[\"io\"]>,\n probe: AdapterProbe,\n cluster?: Hub[\"cluster\"],\n broadcasts?: Hub[\"broadcasts\"],\n ): void;\n /**\n * Re-resolves the subscriptions of `userId`'s sockets on this process after\n * their grants changed, reading the user's levels afresh.\n */\n regranted(userId: string): Promise<void>;\n /** Sends a `reset` to one scope of a collection: `dispatcher.collections.reset`. */\n resetCollection(contract: AnyContract, collection: string, scope: string): void;\n /** Resolves once the work the live data started for sockets' events has settled: a server's `close()`. */\n drain(): Promise<void>;\n /** The sockets in a room of the attached server, for the kits (`KitRuntime.occupancy`). */\n readonly occupancy: Realtime[\"occupancy\"];\n}\n\n/**\n * Creates a dispatcher's live data. Throws a `TypeError` for an `affects` it\n * cannot follow, or a collection anchor it cannot authorize through.\n */\nexport function createLive(options: HubOptions): Live {\n const hub = createHub(options);\n const collections = createLiveCollections(hub);\n const topics = createTopics(collections.hub);\n const sinks = createEntitySinks(hub);\n const realtime = createRealtime(hub);\n const revocation = createRevocation(hub, [\n collections.revocation,\n topics.revocation,\n realtime.revocation,\n ]);\n const entities = entitySubscriptions(hub);\n options.policies.onAccessChanged((change) => revocation.changed(change, false));\n return Object.freeze({\n intake: sinks.intake,\n emit: sinks.emit,\n collections: collections.sink,\n topics: topics.sink,\n versions: createVersionSource(hub),\n extension: (...args: Parameters<typeof entities>): void => {\n entities(...args);\n collections.extension(...args);\n topics.extension(...args);\n realtime.extension(...args);\n },\n legacyExtension: realtime.legacyExtension,\n realtime,\n revisions: hub.revisions,\n attach(\n io: NonNullable<Hub[\"io\"]>,\n probe: AdapterProbe,\n cluster?: Hub[\"cluster\"],\n broadcasts?: Hub[\"broadcasts\"],\n ): void {\n hub.io = io;\n hub.probe = probe;\n hub.cluster = cluster;\n hub.broadcasts = broadcasts;\n collections.listen();\n realtime.listen();\n listenForChanges(hub, revocation, (change) => {\n options.policies.forget(change);\n });\n },\n regranted: (userId: string) => {\n // The grants may come with writes this node's cache has not seen: read the user's levels afresh.\n options.policies.forget({ userId });\n return revocation.regranted(userId);\n },\n resetCollection: (contract: AnyContract, collection: string, scope: string) => {\n collections.reset(contract, collection, scope);\n },\n occupancy: realtime.occupancy,\n drain: () => drain(hub),\n });\n}\n\nconst LIVES = new WeakMap<object, Live>();\n\n/** Marks `dispatcher` as having `live` for its live data. */\nexport function registerLive(dispatcher: object, live: Live): void {\n LIVES.set(dispatcher, live);\n}\n\n/** The live data of a dispatcher `createDispatcher` returned. */\nexport function liveOf(dispatcher: object): Live | undefined {\n return LIVES.get(dispatcher);\n}\n","// `dispatcher.access` (RFC 0003 sections 4.2 and 4.3): one policy, every\n// surface. The levels and list filters a dispatcher's services' policies\n// give, counted the way an `{ entry }` check counts them, for the framework's\n// later surfaces (subscriptions, collections, kits) and for handlers that\n// filter a list themselves; plus the access-change events revocation\n// listens to.\n\nimport { isAccessLevel, type AccessLevel } from \"../../contract/access\";\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { FlushSink } from \"../uow/flushSink\";\nimport type { Principal } from \"../types\";\nimport type { Binding } from \"./bindings\";\nimport type { AccessChangeListener, Forgotten } from \"./changes\";\nimport { serviceGrant } from \"./levels\";\nimport type { AccessFilter, RowLevels } from \"./policy\";\nimport { anchorKey, startCall, type EngineState } from \"./tools\";\nimport type { AccessEngine, RowAccess } from \"./types\";\n\n/** Re-exported for the live data, which authorizes stream subscribers through the engine. */\nexport type { AccessEngine };\n\n/** The dispatcher's view of its services' access policies: `dispatcher.access`. */\nexport interface DispatcherAccess {\n /**\n * The principal's level on each of `ids` of `service`, as an `{ entry }`\n * check counts it: the service's policy, or `Admin` on every row when the\n * principal holds a service-wide `Admin` grant and the service keeps\n * `adminBypass` on. A grant below `Admin` does not count. A row that is\n * not found has no level. One batched lookup per policy.\n */\n levelsFor(\n service: AnyContract | string,\n principal: Principal,\n ids: readonly string[],\n ): Promise<RowLevels>;\n /**\n * A filter for `db.<model>.findMany({ where })` matching exactly the rows of\n * `service` on which `levelsFor` gives the principal at least `level`:\n * `{}` (every row) for a service-wide `Admin` with `adminBypass`, or\n * `\"none\"` when no row matches.\n */\n accessWhere(\n service: AnyContract | string,\n principal: Principal,\n level: AccessLevel,\n ): Promise<AccessFilter>;\n /**\n * Calls `listener` after each flush whose tracked writes may have changed\n * someone's access to a row (`AccessChange`), once the cache no longer\n * holds what they changed. A promise it returns is awaited before the\n * dispatcher's other flush sinks run. Returns a function that removes it.\n */\n onAccessChanged(listener: AccessChangeListener): () => void;\n}\n\n/** A principal's levels on rows, and the rows each level is derived from. */\nexport interface ResolvedAccess {\n readonly levels: RowLevels;\n /**\n * Per id, the `anchorKey`s of the rows its level is derived from (RFC 0003\n * section 4.4): the row itself, then its `inherit` parents. A service-wide\n * `Admin` grant anchors on the row only.\n */\n readonly anchors: ReadonlyMap<string, readonly string[]>;\n}\n\n/** Options of {@link PolicyEngine.resolve}. */\nexport interface ResolveOptions {\n /**\n * Whether the principal's service-wide `Admin` grant on the service counts,\n * as it does for `levelsFor`. Default `true`. A collection scope asks its\n * anchor's policy with `false`, as a `{ scope, of }` form asks `of`'s: the\n * grants that count there are those on the collection's own service.\n */\n readonly grants?: boolean;\n}\n\n/** What a dispatcher's policy engine provides. */\nexport interface PolicyEngine extends DispatcherAccess {\n /** Decides `entry` and `scope` forms for the basic engine. */\n readonly rows: RowAccess;\n /** Evicts the cache and reports access changes: first on the sink list. `undefined` without policies. */\n readonly sink: FlushSink | undefined;\n /**\n * `levelsFor` and the anchors of each level, from one engine call: the\n * anchors reuse the rows the levels read. Live subscriptions record them.\n */\n resolve(\n service: string,\n principal: Principal,\n ids: readonly string[],\n options?: ResolveOptions,\n ): Promise<ResolvedAccess>;\n /**\n * Evicts from the cross-request cache what an access change this process\n * did not flush names (another node broadcast it), or a regranted user's\n * levels, so the re-resolution that follows reads afresh (`forgetAccess`).\n */\n forget(forgotten: Forgotten): void;\n}\n\nfunction bindingFor(state: EngineState, service: AnyContract | string): Binding {\n const name =\n typeof service === \"string\" ? service : (service as { readonly name?: unknown })?.name;\n const binding = typeof name === \"string\" ? state.bindings.get(name) : undefined;\n if (binding === undefined) {\n throw new TypeError(\n `dispatcher.access: ${String(name)} is not a service of this dispatcher with an access policy`,\n );\n }\n return binding;\n}\n\nfunction checkPrincipal(principal: unknown): Principal {\n const userId = (principal as { readonly userId?: unknown } | null | undefined)?.userId;\n if (typeof userId !== \"string\" || userId.length === 0) {\n throw new TypeError(\"dispatcher.access: principal must be a principal with a userId\");\n }\n return principal as Principal;\n}\n\n/** True when the principal's service-wide `Admin` grant passes every check on the service. */\nfunction bypasses(binding: Binding, principal: Principal): boolean {\n const { service } = binding;\n return service.adminBypass && serviceGrant(principal, service.name) === \"Admin\";\n}\n\nfunction checkIds(ids: unknown): readonly string[] {\n const valid = Array.isArray(ids) && ids.every((id) => typeof id === \"string\" && id !== \"\");\n if (!valid) {\n throw new TypeError(\"dispatcher.access.levelsFor: ids must be an array of row ids\");\n }\n return ids as readonly string[];\n}\n\n/** The levels, filters and anchors of a dispatcher's policies. */\nexport function createAccessApi(\n state: EngineState,\n): Pick<PolicyEngine, \"levelsFor\" | \"accessWhere\" | \"resolve\"> {\n return {\n async levelsFor(service, principal, ids) {\n const binding = bindingFor(state, service);\n const who = checkPrincipal(principal);\n checkIds(ids);\n if (bypasses(binding, who)) {\n return new Map(ids.map((id) => [id, \"Admin\"]));\n }\n return await startCall(state).levels(binding, who, ids);\n },\n async resolve(service, principal, ids, options) {\n const binding = bindingFor(state, service);\n const who = checkPrincipal(principal);\n checkIds(ids);\n if (options?.grants !== false && bypasses(binding, who)) {\n return {\n levels: new Map(ids.map((id) => [id, \"Admin\"])),\n anchors: new Map(ids.map((id) => [id, [anchorKey(binding.service.name, id)]])),\n };\n }\n const call = startCall(state);\n const levels = await call.levels(binding, who, ids);\n return { levels, anchors: await call.anchors(binding, ids) };\n },\n async accessWhere(service, principal, level) {\n const binding = bindingFor(state, service);\n const who = checkPrincipal(principal);\n if (!isAccessLevel(level)) {\n throw new TypeError(\"dispatcher.access.accessWhere: level must be an access level\");\n }\n if (bypasses(binding, who)) {\n return {};\n }\n return await startCall(state).where(binding, who, level);\n },\n };\n}\n","// Binding the services' access policies to a dispatcher (RFC 0003 section\n// 4.2). A policy is plain data until a dispatcher serves its service: then\n// it gets the service's model, the storage adapter it reads through, and the\n// cache namespaces its lookups are kept in. Binding also checks, once, what\n// would otherwise fail on the first call:\n//\n// - every `inherit({ from })` and every `{ scope, of }` names a service this\n// dispatcher serves, and that service declares a policy;\n// - no chain of `inherit` comes back to where it started;\n// - a policy that reads the database has a storage adapter to read through;\n//\n// and registers the columns policies read with the storage adapter\n// (`registerInterest`), so tracked writes carry their `before` and `after`.\n// Whether the tracker can key those models at all is `createServer`'s check\n// at start (`trackedModels.ts`).\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { Registry } from \"../registry\";\nimport type { AnyService } from \"../service\";\nimport { modelKey, type StorageAdapter } from \"../storage\";\nimport { isCustomAccess } from \"./forms\";\nimport { namespace, type Namespace } from \"./cache\";\nimport type { AnyAccessPolicy, MembershipRead } from \"./policy\";\n\n/** A served service's policy, ready to evaluate. */\nexport interface Binding {\n readonly service: AnyService;\n /** The service's model, named as the client names it. */\n readonly model: string;\n readonly policy: AnyAccessPolicy;\n /** The columns of the model the policy reads; one query reads them all. */\n readonly columns: readonly string[];\n /** Where the rows' columns are memoized and cached. */\n readonly rows: Namespace;\n /** Where the policy's levels are memoized for one call. */\n readonly levels: Namespace;\n /** Where each membership table's levels are memoized and cached. */\n readonly memberships: ReadonlyMap<MembershipRead, Namespace>;\n}\n\nfunction fail(message: string): never {\n throw new TypeError(`createDispatcher: ${message}`);\n}\n\nfunction bind(service: AnyService, policy: AnyAccessPolicy, model: string): Binding {\n const { reads } = policy;\n return Object.freeze({\n service,\n model: modelKey(model),\n policy,\n columns: Object.freeze([...new Set(reads.columns)].filter((column) => column !== \"id\")),\n rows: namespace(`${service.name} rows`),\n levels: namespace(`${service.name} levels`),\n memberships: new Map(\n reads.memberships.map((read) => [read, namespace(`${service.name} ${read.model}`)]),\n ),\n });\n}\n\n/** The served service with a policy that `contract` names, or a `TypeError` saying why there is none. */\nfunction target(\n bindings: ReadonlyMap<string, Binding>,\n registry: Registry,\n contract: AnyContract,\n what: string,\n): Binding {\n const binding = bindings.get(contract.name);\n if (binding !== undefined) {\n return binding;\n }\n return registry.services.has(contract.name)\n ? fail(`${what} ${contract.name}, which declares no access policy`)\n : fail(`${what} ${contract.name}, which this dispatcher does not serve`);\n}\n\n/** Refuses an `inherit` chain that comes back to a service already on it. */\nfunction checkCycles(bindings: ReadonlyMap<string, Binding>, registry: Registry): void {\n const visit = (binding: Binding, path: readonly string[]): void => {\n for (const parent of binding.policy.reads.inherits) {\n const next = target(\n bindings,\n registry,\n parent,\n `${binding.service.name}'s access policy inherits from`,\n );\n if (path.includes(next.service.name)) {\n fail(\n `the access policies of ${[...path, next.service.name].join(\" -> \")} inherit in a cycle`,\n );\n }\n visit(next, [...path, next.service.name]);\n }\n };\n for (const binding of bindings.values()) {\n visit(binding, [binding.service.name]);\n }\n}\n\n/** Every `{ scope, of }` form must name a served service with a policy. */\nfunction checkScopeForms(bindings: ReadonlyMap<string, Binding>, registry: Registry): void {\n for (const service of registry.services.values()) {\n for (const method of Object.values(service.methods)) {\n const form = method.access;\n if (typeof form === \"object\" && !isCustomAccess(form) && form.scope !== undefined) {\n target(bindings, registry, form.of, `${service.name}.${method.name} uses scope access of`);\n }\n }\n }\n}\n\nfunction registerInterest(bindings: ReadonlyMap<string, Binding>, storage: StorageAdapter): void {\n for (const binding of bindings.values()) {\n if (binding.columns.length > 0) {\n storage.registerInterest(binding.model, binding.columns);\n }\n for (const read of binding.memberships.keys()) {\n storage.registerInterest(read.model, [read.entry, read.user, read.level]);\n }\n }\n}\n\n/**\n * Binds the policies of the services in `registry`, by service name. Throws\n * a `TypeError` for a policy the dispatcher could not evaluate.\n */\nexport function bindPolicies(\n registry: Registry,\n storage: StorageAdapter | undefined,\n): ReadonlyMap<string, Binding> {\n const bindings = new Map<string, Binding>();\n for (const service of registry.services.values()) {\n const { access, model } = service;\n if (access === undefined || model === undefined) {\n continue;\n }\n if (access.reads.storage && storage === undefined) {\n fail(\n `${service.name}'s access policy reads the database, so the dispatcher needs a storage adapter: pass db as trackPrisma(prisma), or pass storage`,\n );\n }\n bindings.set(service.name, bind(service, access, model));\n }\n checkCycles(bindings, registry);\n checkScopeForms(bindings, registry);\n if (storage !== undefined) {\n registerInterest(bindings, storage);\n }\n return bindings;\n}\n","// What tracked writes do to access (RFC 0003 sections 4.2 and 4.4): a flush\n// sink, first on the dispatcher's sink list, that evicts the cached lookups a\n// write may have changed and then tells `onAccessChanged` listeners which\n// rows' access may have changed and for whom. The revocation of live\n// subscriptions (section 4.4) listens here.\n//\n// Per write, from the bindings' policies:\n//\n// | Write | Evicts | Reports |\n// |-------------------------------------------|-------------------------------|---------------------------|\n// | a create or delete of a policy's row, or | the row's columns, for every | `{ service, id }` |\n// | an update setting a column it reads | user | |\n// | a membership row | the member's level on its row | `{ service, id, userId }` |\n// | | before and after the write | for each |\n// | a membership row whose row or user is not | the whole membership table | `{ service }`: any row |\n// | known (`ctx.touch`, array transactions) | | |\n// | the create or delete of a row with | every member's level on it | `{ service, id }` |\n// | memberships | | |\n//\n// A create is reported because an id can come back: a deleted row's\n// subscribers stay in its room (they get its removal), and a row created\n// again with that id must authorize them again before its first frame. A new\n// id concerns no subscription, so its report costs a lookup in an index.\n// An update that sets none of the columns a policy reads changes nothing.\n// Evictions all happen before the first listener is told.\n\nimport type { Logger } from \"../../contract/logger\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { FlushSink } from \"../uow/flushSink\";\nimport { ANY_FIELD, type WriteRecord } from \"../uow/types\";\nimport type { Binding } from \"./bindings\";\nimport type { AccessCache, Namespace } from \"./cache\";\nimport type { MembershipRead } from \"./policy\";\nimport { modelKey } from \"../storage\";\n\n/**\n * A row whose access may have changed: who may now see more or less of it.\n * `id` is the row (the anchor subscriptions record); without it, any row of\n * the service. `userId` is the user whose level may have changed; without it,\n * anyone's.\n */\nexport interface AccessChange {\n /** The service name. */\n readonly service: string;\n readonly id?: string;\n readonly userId?: string;\n}\n\n/** Receives access changes; a promise it returns is awaited before the flush moves on. */\nexport type AccessChangeListener = (change: AccessChange) => void | PromiseLike<void>;\n\ntype Rule =\n | { readonly kind: \"rows\"; readonly binding: Binding }\n | { readonly kind: \"anchor\"; readonly binding: Binding; readonly ns: Namespace }\n | {\n readonly kind: \"members\";\n readonly binding: Binding;\n readonly read: MembershipRead;\n readonly ns: Namespace;\n };\n\nfunction sets(write: WriteRecord, columns: readonly string[]): boolean {\n return (\n write.op !== \"update\" ||\n write.fields.includes(ANY_FIELD) ||\n write.fields.some((field) => columns.includes(field))\n );\n}\n\nfunction rulesByModel(bindings: ReadonlyMap<string, Binding>): Map<string, Rule[]> {\n const rules = new Map<string, Rule[]>();\n const add = (model: string, rule: Rule): void => {\n const key = modelKey(model);\n rules.set(key, [...(rules.get(key) ?? []), rule]);\n };\n for (const binding of bindings.values()) {\n if (binding.columns.length > 0) {\n add(binding.model, { kind: \"rows\", binding });\n }\n for (const [read, ns] of binding.memberships) {\n add(binding.model, { kind: \"anchor\", binding, ns });\n add(read.model, { kind: \"members\", binding, read, ns });\n }\n }\n return rules;\n}\n\ntype Values = WriteRecord[\"before\"];\n\nfunction stringIn(values: Values, key: string): string | undefined {\n const value = values?.[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/** The (user, row) pair in `values`, taking a column `values` lacks from `fallback`. */\nfunction keyIn(\n read: MembershipRead,\n values: Values,\n fallback: Values,\n): [string, string] | undefined {\n const user = stringIn(values, read.user) ?? stringIn(fallback, read.user);\n const entry = stringIn(values, read.entry) ?? stringIn(fallback, read.entry);\n return user === undefined || entry === undefined ? undefined : [user, entry];\n}\n\n/**\n * The (user, row) pairs a membership write touched: the old pair (from\n * `before`, which holds only the columns an update changed, then `after`)\n * unless the row was created, and the new pair (from `after`) unless it was\n * deleted. `undefined` when the write does not say: then any member's level\n * on any row may have changed.\n */\nfunction membershipKeys(write: WriteRecord, read: MembershipRead): [string, string][] | undefined {\n const old = write.op === \"create\" ? undefined : keyIn(read, write.before, write.after);\n const now = write.op === \"delete\" ? undefined : keyIn(read, write.after, undefined);\n if (\n (write.op !== \"create\" && old === undefined) ||\n (write.op !== \"delete\" && now === undefined)\n ) {\n return undefined;\n }\n const keys = new Map<string, [string, string]>();\n for (const key of [old, now]) {\n if (key !== undefined) {\n keys.set(`${key[0]}\\u0000${key[1]}`, key);\n }\n }\n return [...keys.values()];\n}\n\n/** Collects the access changes of one flush, without duplicates. */\nclass Changes {\n readonly #changes = new Map<string, AccessChange>();\n\n add(change: AccessChange): void {\n this.#changes.set(\n `${change.service}\\u0000${change.id ?? \"\"}\\u0000${change.userId ?? \"\"}`,\n change,\n );\n }\n\n get all(): AccessChange[] {\n return [...this.#changes.values()];\n }\n}\n\nfunction apply(\n rule: Rule,\n write: WriteRecord,\n cache: AccessCache | undefined,\n changes: Changes,\n): void {\n const service = rule.binding.service.name;\n if (rule.kind === \"rows\") {\n if (sets(write, rule.binding.columns)) {\n cache?.evict(rule.binding.rows, \"\", write.id);\n changes.add({ service, id: write.id });\n }\n return;\n }\n if (rule.kind === \"anchor\") {\n if (write.op !== \"update\") {\n cache?.evict(rule.ns, undefined, write.id);\n changes.add({ service, id: write.id });\n }\n return;\n }\n if (!sets(write, [rule.read.entry, rule.read.user, rule.read.level])) {\n return;\n }\n const keys = membershipKeys(write, rule.read);\n if (keys === undefined) {\n cache?.evict(rule.ns);\n changes.add({ service });\n return;\n }\n for (const [userId, id] of keys) {\n cache?.evict(rule.ns, userId, id);\n changes.add({ service, id, userId });\n }\n}\n\nasync function notify(\n listeners: ReadonlySet<AccessChangeListener>,\n changes: readonly AccessChange[],\n logger: Logger,\n): Promise<void> {\n const running: Promise<void>[] = [];\n for (const change of changes) {\n for (const listener of listeners) {\n running.push(\n (async () => {\n await listener(change);\n })().catch((error: unknown) => {\n logger.error(\"An onAccessChanged listener failed\", {\n category: \"quickdraw.access\",\n service: change.service,\n id: change.id,\n error: describeError(error),\n });\n }),\n );\n }\n }\n await Promise.all(running);\n}\n\n/** What {@link forgetAccess} evicts: an access change, or a user whose grants were reloaded. */\nexport interface Forgotten {\n readonly service?: string;\n readonly id?: string;\n readonly userId?: string;\n}\n\n/**\n * Evicts from this process's cache what an access change names, for a\n * change this process did not flush (another node broadcast it), or a user\n * whose grants were reloaded: the revocation that follows must read afresh.\n * `{ service, id }` drops the row's columns and every member's level on it,\n * with `userId` that member's level only; `{ service }` drops everything the\n * service's policy kept; `{ userId }` alone drops that user's levels in every\n * membership table.\n */\nexport function forgetAccess(\n bindings: ReadonlyMap<string, Binding>,\n cache: AccessCache | undefined,\n forgotten: Forgotten,\n): void {\n const { service, id, userId } = forgotten;\n const binding = service === undefined ? undefined : bindings.get(service);\n if (cache === undefined || (service !== undefined && binding === undefined)) {\n return;\n }\n for (const each of binding === undefined ? bindings.values() : [binding]) {\n if (service !== undefined) {\n cache.evict(each.rows, id === undefined ? undefined : \"\", id);\n }\n for (const ns of each.memberships.values()) {\n cache.evict(ns, service !== undefined && id === undefined ? undefined : userId, id);\n }\n }\n}\n\n/**\n * The flush sink that evicts cached lookups and reports access changes, or\n * `undefined` when no served service has a policy.\n */\nexport function createChangeSink(\n bindings: ReadonlyMap<string, Binding>,\n cache: AccessCache | undefined,\n listeners: ReadonlySet<AccessChangeListener>,\n logger: Logger,\n): FlushSink | undefined {\n const rules = rulesByModel(bindings);\n if (rules.size === 0) {\n return undefined;\n }\n return Object.freeze({\n async flush(writes: readonly WriteRecord[]): Promise<void> {\n const changes = new Changes();\n for (const write of writes) {\n for (const rule of rules.get(modelKey(write.model)) ?? []) {\n apply(rule, write, cache, changes);\n }\n }\n if (listeners.size > 0) {\n await notify(listeners, changes.all, logger);\n }\n },\n });\n}\n","// The row access the policy engine gives the basic engine: `{ entry: L }`\n// asks the service's own policy, `{ scope: L, of }` the policy of `of`'s\n// service, about every id the form names, in one batched lookup. The basic\n// engine has already let `\"public\"` through, answered `UNAUTHENTICATED` for\n// an anonymous caller, applied the service-wide `Admin` bypass and the\n// `service` half of a combined form; a `false` here becomes `FORBIDDEN`.\n\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { accessIds } from \"./forms\";\nimport { meetsLevel } from \"./levels\";\nimport { startCall, type EngineState } from \"./tools\";\nimport type { RowAccess } from \"./types\";\n\n/** Decides `entry` and `scope` forms from the bound policies. */\nexport function createRowAccess(state: EngineState): RowAccess {\n return Object.freeze({\n async allows(form, request) {\n const asks = form.scope === undefined ? request.service.name : form.of.name;\n const binding = state.bindings.get(asks);\n if (binding === undefined) {\n const kind = form.scope === undefined ? \"entry\" : \"scope\";\n throw new QuickdrawError(\n \"INTERNAL\",\n `${request.service.name}.${request.method} uses ${kind} access, but no access policy is configured for ${asks}`,\n );\n }\n const { principal } = request;\n // Policies compare user ids: a principal without one has no level anywhere.\n if (principal === null || typeof principal.userId !== \"string\" || principal.userId === \"\") {\n return false;\n }\n // A missing or empty id is FORBIDDEN: a failed lookup denies.\n const ids = accessIds(form, request.input);\n const required = form.scope === undefined ? form.entry : form.scope;\n const levels = await startCall(state).levels(binding, principal, ids);\n return ids.every((id) => meetsLevel(levels.get(id), required));\n },\n } satisfies RowAccess);\n}\n","// The policy engine (RFC 0003 section 4): one per dispatcher, over the\n// access policies its services declare. The dispatcher's default access\n// engine is the basic engine with this one's row access, so every form is\n// decided in one place:\n//\n// | Form | No principal | Passes when |\n// |------------------------------|-------------------|--------------------------------------------------|\n// | `\"public\"` | passes | always |\n// | `\"authenticated\"` | `UNAUTHENTICATED` | a principal exists |\n// | `{ service: L }` | `UNAUTHENTICATED` | the service grant is at least `L` |\n// | `{ entry: L, id? }` | `UNAUTHENTICATED` | the policy's level on every row is at least `L` |\n// | `{ service: L1, entry: L2 }` | `UNAUTHENTICATED` | either of the two |\n// | `{ scope: L, of, id }` | `UNAUTHENTICATED` | `of`'s policy gives at least `L` on the row |\n// | `custom(fn)` | `UNAUTHENTICATED` | `fn(ctx, input)` resolves `true` |\n//\n// A service-wide `Admin` grant on the method's service passes every form but\n// `\"public\"` when the service keeps `adminBypass` on; a grant below `Admin`\n// counts only where the form names `service`. A principal that fails gets\n// `FORBIDDEN`. Everything fails closed: a missing grant, an unknown level, a\n// missing id, a row that is not found and a malformed access column deny,\n// and a lookup that throws fails the call with `INTERNAL`. 4.1 let any\n// signed-in user call a `Read` method with no row id, and let a service\n// grant satisfy row checks at the same level\n// (4.1 `src/server/BaseService.ts:581-600`); neither survives.\n\nimport type { Logger } from \"../../contract/logger\";\nimport type { Registry } from \"../registry\";\nimport type { StorageAdapter } from \"../storage\";\nimport { createAccessApi, type PolicyEngine } from \"./api\";\nimport { bindPolicies } from \"./bindings\";\nimport { createAccessCache } from \"./cache\";\nimport {\n createChangeSink,\n forgetAccess,\n type AccessChangeListener,\n type Forgotten,\n} from \"./changes\";\nimport { createRowAccess } from \"./rowAccess\";\n\n/** The access options of a dispatcher: its `access` option, when it is not an engine. */\nexport interface AccessOptions {\n /**\n * Keep the database reads of access policies (row columns and membership\n * levels) across requests for this long, in milliseconds. Tracked writes to\n * the columns and models the policies read evict what they change; writes\n * the tracked client cannot see (raw SQL without `ctx.touch`, database\n * cascades, other processes) are seen only once the time passes. Default:\n * off, every request reads afresh (lookups are always memoized within one).\n */\n readonly cacheMs?: number;\n}\n\n/** Options of {@link createPolicyEngine}. */\nexport interface PolicyEngineOptions extends AccessOptions {\n readonly registry: Registry;\n readonly storage: StorageAdapter | undefined;\n readonly logger: Logger;\n}\n\nfunction checkCacheMs(cacheMs: unknown): number | undefined {\n if (cacheMs === undefined || cacheMs === 0) {\n return undefined;\n }\n if (typeof cacheMs !== \"number\" || !Number.isFinite(cacheMs) || cacheMs < 0) {\n throw new TypeError(\"createDispatcher: access.cacheMs must be a number of milliseconds\");\n }\n return cacheMs;\n}\n\n/**\n * Binds the services' access policies (`bindings.ts`; throws a `TypeError`\n * for one that could not be evaluated) and returns the engine that\n * evaluates them.\n */\nexport function createPolicyEngine(options: PolicyEngineOptions): PolicyEngine {\n const cacheMs = checkCacheMs(options.cacheMs);\n const bindings = bindPolicies(options.registry, options.storage);\n const state = {\n bindings,\n storage: options.storage,\n cache: cacheMs === undefined ? undefined : createAccessCache({ ttlMs: cacheMs }),\n };\n const listeners = new Set<AccessChangeListener>();\n return Object.freeze({\n ...createAccessApi(state),\n onAccessChanged(listener: AccessChangeListener): () => void {\n if (typeof listener !== \"function\") {\n throw new TypeError(\"dispatcher.access.onAccessChanged: listener must be a function\");\n }\n // A listener added twice is called twice and removed one at a time.\n const entry: AccessChangeListener = (change) => listener(change);\n listeners.add(entry);\n return () => {\n listeners.delete(entry);\n };\n },\n rows: createRowAccess(state),\n sink: createChangeSink(bindings, state.cache, listeners, options.logger),\n forget: (forgotten: Forgotten) => forgetAccess(bindings, state.cache, forgotten),\n });\n}\n","// The `resolver-without-reads` development warning (finding R1.1 of the\n// 5.0.0 review). A resolver's levels come from app code, so the engine knows\n// what they depend on only from its `reads` (`policies/resolver.ts`). With\n// none, no tracked write re-checks what the policy authorized: a user removed\n// from a table the resolver reads keeps the live rows, collection scopes and\n// change topics it let them subscribe to, and keeps receiving their updates.\n//\n// When a dispatcher is made, each service with a model whose policy is a\n// resolver without `reads`, alone or in `anyOf`, raises the warning once:\n// logged, or thrown by a test app made with `strictWarnings`, which fails its\n// creation (as `tiered-field-in-output` does). `reads: \"none\"` says the\n// levels depend on nothing a tracked write changes, and raises nothing.\n\nimport type { DevWarning, DevWarnings } from \"../devWarnings\";\nimport type { Registry } from \"../registry\";\nimport type { AnyService } from \"../service\";\nimport { anyOfPolicies } from \"./policies/anyOf\";\nimport { declaresNoReads } from \"./policies/resolver\";\nimport type { AnyAccessPolicy } from \"./policy\";\n\n/** True when `policy` is, or combines in `anyOf`, a resolver made without `reads`. */\nfunction hasUndeclaredResolver(policy: AnyAccessPolicy): boolean {\n return declaresNoReads(policy) || (anyOfPolicies(policy)?.some(hasUndeclaredResolver) ?? false);\n}\n\n/** The warning `service` raises: one when its policy has a resolver without `reads`. */\nexport function resolverReadsWarnings(service: AnyService): DevWarning[] {\n const { access, model } = service;\n if (access === undefined || model === undefined || !hasUndeclaredResolver(access)) {\n return [];\n }\n return [\n {\n kind: \"resolver-without-reads\",\n service: service.name,\n message:\n `${service.name}: its access policy uses a resolver that declares no reads, so no tracked write ` +\n `re-checks the levels it gives: a live row, collection scope or change topic it authorized stays ` +\n `open after the user loses access. Declare what the levels depend on, resolver({ levelsFor, ` +\n `reads: { columns, memberships } }) (columns of the ${model} model, membership tables as ` +\n `members() takes them), or reads: \"none\" when nothing a tracked write changes can change them`,\n meta: { model },\n },\n ];\n}\n\n/**\n * Raises the `resolver-without-reads` warnings of every service a\n * dispatcher serves: logged once each, or thrown by a test app made with\n * `strictWarnings`, failing its creation.\n */\nexport function warnResolverReads(registry: Registry, warnings: DevWarnings): void {\n if (!warnings.enabled) {\n return;\n }\n for (const service of registry.services.values()) {\n for (const warning of resolverReadsWarnings(service)) {\n warnings.warn(warning);\n }\n }\n}\n","// The dispatcher's `access` option, resolved (RFC 0003 section 4): the policy\n// engine over the services' policies, and the access engine that decides each\n// method's form, the app's own or the basic engine with the policies' row\n// access. Once the policies are bound, a resolver that declares no reads\n// raises the `resolver-without-reads` development warning.\n\nimport type { Logger } from \"../../contract/logger\";\nimport type { PolicyEngine } from \"../access/api\";\nimport { createBasicAccessEngine } from \"../access/basicEngine\";\nimport { createPolicyEngine, type AccessOptions } from \"../access/engine\";\nimport { warnResolverReads } from \"../access/resolverReads\";\nimport type { AccessEngine } from \"../access/types\";\nimport type { DevWarnings } from \"../devWarnings\";\nimport type { Registry } from \"../registry\";\nimport type { StorageAdapter } from \"../storage\";\n\nexport type { AccessEngine, AccessOptions, PolicyEngine };\n\nfunction isAccessEngine(value: unknown): value is AccessEngine {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as Partial<AccessEngine>).authorize === \"function\"\n );\n}\n\n/** The policy engine, and the access engine: the app's own, or the basic engine with the policies' row access. */\nexport function resolveAccess(\n access: AccessEngine | AccessOptions | undefined,\n registry: Registry,\n storage: StorageAdapter | undefined,\n report: { readonly logger: Logger; readonly warnings: DevWarnings },\n): { access: AccessEngine; policies: PolicyEngine } {\n const { logger, warnings } = report;\n if (access !== undefined && (typeof access !== \"object\" || access === null)) {\n throw new TypeError(\"createDispatcher: access must be an access engine or { cacheMs }\");\n }\n const engine = isAccessEngine(access) ? access : undefined;\n const accessOptions: AccessOptions = isAccessEngine(access) ? {} : (access ?? {});\n const policies = createPolicyEngine({\n registry,\n storage,\n logger,\n cacheMs: accessOptions.cacheMs,\n });\n warnResolverReads(registry, warnings);\n return { access: engine ?? createBasicAccessEngine({ rows: policies.rows }), policies };\n}\n","// The `tiered-field-in-output` development warning (finding F7.4 of the\n// quickdraw-chat review, widened by the final review of the release\n// candidates). Field tiers (RFC 0003 section 6) strip what a reader may not\n// receive from projection outputs only: `\"entity\"`, a named projection, and\n// `nullable(...)` or `listOf(...)` of one. A method whose output is a schema\n// of its own is sent as that schema declares it (section 9, step 8;\n// `pipeline/schemaOutput.ts`), so a key the schema declares and the contract\n// tiers reaches every caller the method's access admits: the template's\n// `updateUser` answered `email`, an `Admin` field, to a service-wide\n// `Moderate` grant. Two checks say so:\n//\n// - When a dispatcher is made, each tiered key a method's output schema\n// declares, at any depth (a nested `{ user: { id, email } }`, the rows of\n// a list, the values of a record), raises the warning once, naming the\n// method, the key, where the schema declares it, and the fix: answer\n// `\"entity\"` (or a projection), which is stripped per caller, or drop the\n// key from the schema. A key the schema does not declare needs no warning:\n// it is dropped before the reply leaves.\n// - An output without JSON Schema (a Zod 3 schema) cannot be reduced and is\n// sent as the handler returns it. In development its replies are checked\n// instead: the first reply that carries a tiered key, at any depth, raises\n// the warning for that key.\n//\n// A method whose access admits no caller below the field's level is left\n// alone: a service-wide `Admin` grant (`{ service: \"Admin\" }`, while the\n// service's Admin bypass is on, as it is by default), and `{ entry: L }`\n// with `L` at or above the field's level, whose caller holds that level on\n// the row its input names (the row such a method answers with). A form with\n// both halves must pass on both. Every other form warns: `\"public\"`,\n// `\"authenticated\"`, `{ service: L }` below `Admin`, `{ scope }` (a level on\n// another service's row) and `custom`. A kit's methods are left alone too:\n// a kit strips what its readers may not see itself.\n\nimport type { AccessLevel } from \"../../contract/access\";\nimport { isCustomAccess } from \"../access/forms\";\nimport { meetsLevel } from \"../access/levels\";\nimport type { AccessForm } from \"../access/types\";\nimport type { DevWarning, DevWarnings } from \"../devWarnings\";\nimport type { Registry, RegisteredMethod } from \"../registry\";\nimport { isKitHandler, type AnyService, type ServiceMethod } from \"../service\";\n\n/** True when every caller `form` admits holds `level` on the row the method answers about. */\nfunction admitsOnlyAt(form: AccessForm, level: AccessLevel, adminBypass: boolean): boolean {\n if (typeof form !== \"object\" || isCustomAccess(form) || form.scope !== undefined) {\n return false;\n }\n const serviceHalf = form.service === undefined || (form.service === \"Admin\" && adminBypass);\n const entryHalf =\n form.entry === undefined ? form.service !== undefined : meetsLevel(form.entry, level);\n return serviceHalf && entryHalf;\n}\n\n/** The tiered keys a method's access may hand to a caller below their level, with those levels. */\nfunction exposedTiers(\n service: AnyService,\n method: ServiceMethod,\n): ReadonlyMap<string, AccessLevel> {\n const exposed = new Map<string, AccessLevel>();\n if (isKitHandler(method.handler)) {\n return exposed;\n }\n for (const [key, level] of Object.entries(service.contract.fields)) {\n if (!admitsOnlyAt(method.access, level, service.adminBypass)) {\n exposed.set(key, level);\n }\n }\n return exposed;\n}\n\n/** ` (at user.email)`, or nothing for a key at the top level. */\nfunction where(key: string, path: string): string {\n return path === key ? \"\" : ` (at ${path})`;\n}\n\nfunction schemaWarning(\n service: AnyService,\n method: string,\n key: string,\n path: string,\n level: AccessLevel,\n): DevWarning {\n return {\n kind: \"tiered-field-in-output\",\n service: service.name,\n method,\n subject: key,\n message:\n `its output schema names \"${key}\"${where(key, path)}, which the contract gives only to readers with ` +\n `${level} on the row (fields: { ${key}: \"${level}\" }), but a schema output is sent as its schema declares ` +\n `it to every caller the method's access admits: field tiers strip only projection outputs. Answer ` +\n `\"entity\" or a projection (or nullable(...) or listOf(...) of one), which is stripped per caller, or drop ` +\n `\"${key}\" from the schema`,\n meta: { field: key, level, path },\n };\n}\n\nfunction replyWarning(\n service: AnyService,\n method: string,\n key: string,\n path: string,\n level: AccessLevel,\n): DevWarning {\n return {\n kind: \"tiered-field-in-output\",\n service: service.name,\n method,\n subject: key,\n message:\n `its reply carries \"${key}\"${where(key, path)}, which the contract gives only to readers with ${level} on ` +\n `the row (fields: { ${key}: \"${level}\" }), and was sent as the handler returned it to every caller the ` +\n `method's access admits: its output schema has no JSON Schema (a Zod 3 schema), so the reply cannot be ` +\n `reduced to it. Answer \"entity\" or a projection, which is stripped per caller, give the output a schema ` +\n `with JSON Schema (Zod 4.2 or later), or leave \"${key}\" out of what the handler returns`,\n meta: { field: key, level, path },\n };\n}\n\n/** The warnings `service`'s methods raise: one per tiered key an output schema declares. */\nexport function tieredOutputWarnings(service: AnyService): DevWarning[] {\n const warnings: DevWarning[] = [];\n for (const [name, method] of Object.entries(service.methods)) {\n const { schemaOutput } = method;\n if (schemaOutput === undefined) {\n continue;\n }\n const exposed = exposedTiers(service, method);\n if (exposed.size === 0) {\n continue;\n }\n const paths = schemaOutput.keyPaths();\n for (const [key, level] of exposed) {\n const path = paths.get(key);\n if (path !== undefined) {\n warnings.push(schemaWarning(service, name, key, path, level));\n }\n }\n }\n return warnings;\n}\n\n/**\n * Raises the `tiered-field-in-output` warnings of every service a\n * dispatcher serves: logged once each, or thrown by a test app made with\n * `strictWarnings`, failing its creation.\n */\nexport function warnTieredOutputs(registry: Registry, warnings: DevWarnings): void {\n if (!warnings.enabled) {\n return;\n }\n for (const service of registry.services.values()) {\n for (const warning of tieredOutputWarnings(service)) {\n warnings.warn(warning);\n }\n }\n}\n\n/** The plain objects and arrays a reply check reads at most: a development check, never a reply's cost. */\nconst MAX_CHECKED = 10_000;\n\n/** Where `value` carries each of `keys`, at any depth of plain objects and arrays: the first path found. */\nfunction carried(value: unknown, keys: ReadonlyMap<string, unknown>): Map<string, string> {\n const found = new Map<string, string>();\n const seen = new Set<object>();\n const queue: { readonly value: unknown; readonly path: string }[] = [{ value, path: \"\" }];\n for (let index = 0; index < queue.length && seen.size < MAX_CHECKED; index += 1) {\n const { value: item, path } = queue[index] as {\n readonly value: unknown;\n readonly path: string;\n };\n if (typeof item !== \"object\" || item === null || seen.has(item)) {\n continue;\n }\n seen.add(item);\n if (Array.isArray(item)) {\n for (const member of item) {\n queue.push({ value: member, path: `${path}[]` });\n }\n continue;\n }\n for (const [key, member] of Object.entries(item)) {\n const at = path === \"\" ? key : `${path}.${key}`;\n if (keys.has(key) && !found.has(key)) {\n found.set(key, at);\n }\n queue.push({ value: member, path: at });\n }\n }\n return found;\n}\n\n/** Each method's exposed tiers, for the reply check: worked out on its first reply. */\nconst replyChecks = new WeakMap<ServiceMethod, ReadonlyMap<string, AccessLevel>>();\n\n/**\n * The development check of a reply whose output schema has no JSON Schema\n * (see the top of this file): raises the warning for each exposed tiered key\n * the reply carries. Every other output is reduced to its schema, or\n * stripped per caller, and needs none.\n */\nexport function warnTieredReply(\n target: RegisteredMethod,\n value: unknown,\n warnings: DevWarnings,\n): void {\n const { service, method } = target;\n if (method.projection !== undefined || method.schemaOutput !== undefined) {\n return;\n }\n let exposed = replyChecks.get(method);\n if (exposed === undefined) {\n exposed = exposedTiers(service, method);\n replyChecks.set(method, exposed);\n }\n if (exposed.size === 0) {\n return;\n }\n for (const [key, path] of carried(value, exposed)) {\n warnings.warn(replyWarning(service, method.name, key, path, exposed.get(key) as AccessLevel));\n }\n}\n","// The `channel-without-requires` development warning (the 5.1 audit's\n// RT-3). A channel whose contract declares no `requires` takes a message\n// from every signed-in socket, about any row or room its payload names: a\n// handler that relays it to a room (`ctx.rooms.emit`) lets any user reach\n// that room. Delivery stays as it was; the warning asks the app to say what\n// the sender must hold (`requires`), or that any signed-in user may send.\n//\n// When a dispatcher is made, each such channel raises the warning once:\n// logged, or thrown by a test app made with `strictWarnings`, which fails\n// its creation (as `resolver-without-reads` does). A service that declares\n// the channel's `access` (`{ access: \"authenticated\", handler }` included)\n// says any user it admits may send, and raises nothing.\n\nimport type { DevWarning, DevWarnings } from \"../devWarnings\";\nimport type { Registry } from \"../registry\";\nimport type { AnyService } from \"../service\";\n\n/** The warnings `service` raises: one per channel without `requires` whose access it left to the default. */\nexport function channelWarnings(service: AnyService): DevWarning[] {\n const warnings: DevWarning[] = [];\n for (const channel of service.channels.values()) {\n if (channel.requires !== undefined || channel.accessDeclared) {\n continue;\n }\n const name = `${service.name}.${channel.name}`;\n warnings.push({\n kind: \"channel-without-requires\",\n service: service.name,\n subject: channel.name,\n message:\n `${name}: the channel declares no requires, so every signed-in user may send it, about any ` +\n `row or room its payload names; a handler that relays it to a room (ctx.rooms.emit) lets ` +\n `anyone reach that room. Declare what the sender must hold in the contract (requires: ` +\n `{ room: (payload) => \\`project:\\${payload.projectId}\\` }, or { entity } / { collection, ` +\n `scope }), or, when any signed-in user may send it, say so on the service: channels: ` +\n `{ ${channel.name}: { access: \"authenticated\", handler } }`,\n meta: { channel: channel.name },\n });\n }\n return warnings;\n}\n\n/**\n * Raises the `channel-without-requires` warnings of every service a\n * dispatcher serves: logged once each, or thrown by a test app made with\n * `strictWarnings`, failing its creation.\n */\nexport function warnChannels(registry: Registry, warnings: DevWarnings): void {\n if (!warnings.enabled) {\n return;\n }\n for (const service of registry.services.values()) {\n for (const warning of channelWarnings(service)) {\n warnings.warn(warning);\n }\n }\n}\n","// The development warnings a dispatcher raises from its services'\n// definitions alone, when it is made: `tiered-field-in-output`\n// (`../emit/tieredOutputs.ts`) and `channel-without-requires`\n// (`../realtime/channelWarnings.ts`); `resolver-without-reads` comes with\n// the access settings (`../access/resolverReads.ts`). Each is logged once,\n// or thrown by a test app made with `strictWarnings`, which then fails to\n// start.\n\nimport type { DevWarnings } from \"../devWarnings\";\nimport { warnTieredOutputs } from \"../emit/tieredOutputs\";\nimport { warnChannels } from \"../realtime/channelWarnings\";\nimport type { Registry } from \"../registry\";\n\n/** Raises the warnings of the services `registry` holds that their definitions alone show. */\nexport function warnDefinitions(registry: Registry, warnings: DevWarnings): void {\n warnTieredOutputs(registry, warnings);\n warnChannels(registry, warnings);\n}\n","// The default unit of work: it records no writes, but it already has the\n// shape tracked writes need. `run` awaits the handler's result inside its\n// own frame (RFC 0003 section 5.1), so swapping in the tracked implementation\n// changes no call site.\n\nimport type { UnitOfWork, UnitOfWorkFactory } from \"./types\";\n\nconst UNTRACKED: UnitOfWork = Object.freeze({\n sqlStatements: undefined,\n async run<T>(fn: () => T | PromiseLike<T>): Promise<T> {\n return await fn();\n },\n flush: (): Promise<void> => Promise.resolve(),\n});\n\n/** Units of work that record nothing. The dispatcher's default until writes are tracked. */\nexport const untrackedUnitOfWork: UnitOfWorkFactory = Object.freeze({\n begin: (): UnitOfWork => UNTRACKED,\n});\n","// Tracked writes in the dispatcher (RFC 0003 sections 5.1 and 5.3): the\n// units of work handler runs open, where they flush, and `ctx.touch`. A\n// tracked database client (`trackPrisma` on `./prisma`) carries its storage\n// adapter, so passing it as `db` is all an app does:\n//\n// export const db = trackPrisma(new PrismaClient({ adapter }));\n// qd.createServer({ app, services, db });\n//\n// Without one, units of work record nothing and `ctx.touch` does nothing.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { Logger } from \"../../contract/logger\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { BaseContext } from \"../context\";\nimport type { Registry } from \"../registry\";\nimport { modelKey, storageOf, type StorageAdapter } from \"../storage\";\nimport { combineSinks, inRevisionOrder, type FlushRevisions } from \"../uow/flush\";\nimport type { FlushSink } from \"../uow/flushSink\";\nimport type { UnitOfWorkFactory } from \"../uow/types\";\nimport { untrackedUnitOfWork } from \"../uow/untracked\";\n\n/** The dispatcher's tracked-writes options. */\nexport interface TrackingOptions {\n /**\n * How the server reads the database and learns of writes. Default: the\n * adapter a tracked `db` carries (`storageOf(db)`), or none.\n */\n readonly storage?: StorageAdapter;\n /** Opens the unit of work of each handler run. Default: the storage adapter's, or units that track nothing. */\n readonly unitOfWork?: UnitOfWorkFactory;\n /**\n * Where units of work flush their writes, in order: each flush goes to\n * every sink, and a sink that throws is logged and reported to the others\n * (`FlushSink.onFlushError`). Default: nowhere.\n */\n readonly flushSink?: FlushSink | readonly FlushSink[];\n}\n\n/** The tracked-writes part of the pipeline's settings. */\nexport interface Tracking {\n readonly storage: StorageAdapter | undefined;\n readonly unitOfWork: UnitOfWorkFactory;\n /** The sinks, combined into one that runs flushes in revision order. */\n readonly flushSink: FlushSink;\n /** Every call's `ctx.touch`. */\n readonly touch: BaseContext[\"touch\"];\n /**\n * Runs `fn` in a detached unit of work of the dispatcher, flushed once\n * `fn` settles, whatever unit or transaction is open where it starts:\n * `dispatcher.run(fn, { detached: true })` for a kit's work after a call\n * (the admin kit's `onCommitted`). Rejects with what `fn` throws.\n */\n readonly runDetached: (fn: () => unknown) => Promise<unknown>;\n}\n\nfunction sinksOf(option: TrackingOptions[\"flushSink\"]): readonly FlushSink[] {\n if (option === undefined) {\n return [];\n }\n const sinks: readonly unknown[] = Array.isArray(option) ? option : [option];\n for (const sink of sinks) {\n if (typeof (sink as Partial<FlushSink> | null)?.flush !== \"function\") {\n throw new TypeError(\"createDispatcher: flushSink must be a flush sink or an array of them\");\n }\n }\n return sinks as readonly FlushSink[];\n}\n\n/**\n * The model `ctx.touch` names: a model name as is, or a contract's model,\n * which its service declares with `model` (RFC 0003 section 3).\n */\nfunction modelOf(registry: Registry, target: string | AnyContract): string {\n if (typeof target === \"string\" && target.length > 0) {\n return modelKey(target);\n }\n if (typeof target !== \"object\" || target === null) {\n throw new TypeError('ctx.touch: name the model, as in ctx.touch(\"task\", ids)');\n }\n for (const service of registry.services.values()) {\n if (service.contract === target && service.model !== undefined) {\n return modelKey(service.model);\n }\n }\n throw new QuickdrawError(\n \"INTERNAL\",\n `ctx.touch: no service of this dispatcher declares the database model of ${target.name}; pass the model name, as in ctx.touch(\"task\", ids)`,\n );\n}\n\nfunction idsOf(ids: string | readonly string[]): readonly string[] {\n const list: unknown = typeof ids === \"string\" ? [ids] : ids;\n if (!Array.isArray(list) || list.some((id) => typeof id !== \"string\" || id.length === 0)) {\n throw new TypeError(\"ctx.touch: ids must be a row id or an array of row ids\");\n }\n return list as readonly string[];\n}\n\n/** The storage adapter the dispatcher reads through: the one given, or the one a tracked `db` carries. */\nexport function storageFor(options: TrackingOptions, db: unknown): StorageAdapter | undefined {\n return options.storage ?? storageOf(db);\n}\n\n/**\n * Resolves the dispatcher's tracked-writes options. The framework's own\n * sinks go first on the sink list, in the order given (the live data's\n * intake, the access cache's evictions and access-change events,\n * `createServer`'s grants refresh, the entity frames, the collection deltas,\n * the change topics), so nothing a flush revokes gets its frames, and the\n * app's sinks after them read access afresh. `revisions` hand flushes the\n * cluster's shared revisions when the server is behind a counter.\n */\nexport function resolveTracking(\n options: TrackingOptions,\n registry: Registry,\n db: unknown,\n logger: Logger,\n framework: readonly (FlushSink | undefined)[] = [],\n revisions?: FlushRevisions,\n): Tracking {\n const storage = storageFor(options, db);\n const unitOfWork = options.unitOfWork ?? storage?.unitOfWork ?? untrackedUnitOfWork;\n const touch: BaseContext[\"touch\"] = (target, ids, touchOptions) => {\n const model = modelOf(registry, target);\n const rows = idsOf(ids);\n unitOfWork.touch?.(model, rows, touchOptions);\n };\n const own = framework.filter((sink): sink is FlushSink => sink !== undefined);\n const flushSink = inRevisionOrder(\n combineSinks([...own, ...sinksOf(options.flushSink)], logger),\n revisions,\n );\n const runDetached = async (fn: () => unknown): Promise<unknown> => {\n const unit = unitOfWork.begin({\n requestId: crypto.randomUUID(),\n transport: \"internal\",\n sink: flushSink,\n detached: true,\n });\n try {\n return await unit.run(fn);\n } finally {\n // A flush never rejects: its failures are logged where it runs.\n await unit.flush();\n }\n };\n return { storage, unitOfWork, flushSink, touch, runDetached };\n}\n","// The dispatcher's options and their defaults, resolved once into the\n// settings every pipeline stage reads.\n\nimport { consoleLogger, type Logger } from \"../../contract/logger\";\nimport {\n createDevWarnings,\n createLoopWatch,\n strictWarningsOf,\n type DevWarnings,\n type LoopWatch,\n} from \"../devWarnings\";\nimport { createLive, type ChangeLogOptions, type Live } from \"../emit/live\";\nimport type { Registry } from \"../registry\";\nimport type { FlushSink } from \"../uow/flushSink\";\nimport {\n resolveAccess,\n type AccessEngine,\n type AccessOptions,\n type PolicyEngine,\n} from \"./accessSettings\";\nimport { warnDefinitions } from \"./definitionWarnings\";\nimport { createRecorder, type CallRecord, type RecordDetails } from \"./metrics\";\nimport type { VersionSource } from \"./notModified\";\nimport { resolveTracking, storageFor, type Tracking, type TrackingOptions } from \"./tracking\";\n\n// The dispatcher's logs write errors with it, through this module, within its import budget.\nexport { errorText } from \"../../contract/logger\";\n\n/**\n * The lane each socket's subscription events (`qd:sub`, `qd:col:sub`,\n * `qd:col:items`, `qd:watch`) run in, as queries run in theirs: the socket\n * rate limiter does not count those events, so this caps them instead.\n */\nexport interface SubscriptionLimits {\n /** Subscription events one socket may have running at once. Default 8. */\n readonly maxInFlight: number;\n /** Subscription events one socket may have waiting; past that, `RATE_LIMITED`. Default 64. */\n readonly maxQueued: number;\n}\n\n/**\n * The dispatcher's limits. The first three are what a server announces to\n * clients in `qd:hello` (`HelloLimits`).\n */\nexport interface DispatcherLimits {\n /** Queries one connection may run at once. Default 16. */\n readonly maxInFlightQueries: number;\n /** Queries one connection may have waiting; past that, `RATE_LIMITED`. Default 64. */\n readonly maxQueuedQueries: number;\n /** A handler's time limit when its method sets no `timeoutMs`, in milliseconds. Default 30,000. */\n readonly callTimeoutMs: number;\n /** The `retryAfterMs` of the `RATE_LIMITED` error a full queue answers with. Default 1,000. */\n readonly retryAfterMs: number;\n /** Each socket's lane of subscription events. Default 8 in flight and 64 queued. */\n readonly subscriptions: SubscriptionLimits;\n}\n\n/** The dispatcher's `limits` option: any of the limits, and any part of `subscriptions`. */\nexport type LimitsOptions = Partial<Omit<DispatcherLimits, \"subscriptions\">> & {\n readonly subscriptions?: Partial<SubscriptionLimits>;\n};\n\n/** The defaults of RFC 0003 section 9, and the subscription lane's. */\nexport const DEFAULT_LIMITS: DispatcherLimits = Object.freeze({\n maxInFlightQueries: 16,\n maxQueuedQueries: 64,\n callTimeoutMs: 30_000,\n retryAfterMs: 1_000,\n subscriptions: Object.freeze({ maxInFlight: 8, maxQueued: 64 }),\n});\n\n/** The longest time limit `setTimeout` honours, in milliseconds. */\nexport const MAX_TIMEOUT_MS = 2_147_483_647;\n\n/** The pipeline's options: every seam and limit has a default. */\nexport interface PipelineOptions extends TrackingOptions {\n /**\n * Receives one entry per call, and the original error of every `INTERNAL`\n * failure; a Prisma error is summarized (class, code, `meta`, frames),\n * never its message, which renders the call's values. Default: the\n * console (`consoleLogger`), which drops `debug` when `NODE_ENV` is\n * \"production\"; `createConsoleLogger({ level })` names another level.\n */\n readonly logger?: Logger;\n /**\n * The access options (`{ cacheMs }`), or an engine of the app's own that\n * decides each method's access form. Default: the basic engine with the\n * row access of the services' policies (RFC 0003 section 4), no cache.\n */\n readonly access?: AccessEngine | AccessOptions;\n /**\n * Answers query versions for \"not modified\" replies, for queries that\n * declare no `version` of their own. Default: the version of the row a\n * query returns, for a query whose output is one projection row and whose\n * input has an `id`: the service's `versionColumn`, or the change log;\n * only when the method's form checked that row (an `entry` form on `id`, a\n * `rowless` method, or the service's `Admin` bypass). A source of the\n * app's own must answer only for rows the form let the caller read: a\n * version is a one-bit oracle, answered before the handler runs.\n */\n readonly versions?: VersionSource;\n /**\n * The in-process change log (RFC 0003 section 6): the revision of the last\n * flush that touched each row, which answers \"not modified\" for services\n * without a `versionColumn`. It sees only this process's writes, so an app\n * running several processes behind a load balancer passes `false` (the log\n * then answers nothing) or declares `versionColumn`s; behind a Socket.IO\n * cluster adapter it answers nothing either. Default: answering, keeping\n * 100,000 rows.\n */\n readonly changeLog?: ChangeLogOptions | false;\n readonly limits?: LimitsOptions;\n /** Calls slower than this are logged at `warn`, in milliseconds. Default 1,000. */\n readonly slowMs?: number;\n /**\n * Replies larger than this are logged at `warn`, in bytes, and raise the\n * `oversized-response` development warning. Default 1 MiB.\n */\n readonly maxResponseBytes?: number;\n /**\n * Check every handler result against its method's contract output; a\n * mismatch fails the call with `INTERNAL`. Default: on unless `NODE_ENV`\n * is `\"production\"`, so always on in tests. A stream that declares\n * `validate: \"development\"` checks its items only while this is on.\n */\n readonly outputValidation?: boolean;\n /** Deep-freeze the results of sharing queries. Default: on unless `NODE_ENV` is `\"production\"`. */\n readonly freezeSharedResults?: boolean;\n /** Receives every call's completion record. An error it throws is logged and ignored. */\n readonly onCall?: (record: CallRecord) => void;\n}\n\n/** Everything the pipeline stages read, resolved from the dispatcher's options. */\nexport interface PipelineSettings extends Tracking {\n readonly registry: Registry;\n readonly db: unknown;\n readonly logger: Logger;\n readonly access: AccessEngine;\n /** The services' access policies, evaluated: `dispatcher.access`. */\n readonly policies: PolicyEngine;\n readonly versions: VersionSource | undefined;\n /** Entity subscriptions, collections, their frames and revocation (RFC 0003 sections 4.4, 6 and 7). */\n readonly live: Live;\n readonly limits: DispatcherLimits;\n readonly outputValidation: boolean;\n readonly freezeSharedResults: boolean;\n /** The development warnings of this dispatcher and of the write tracker it attaches to (`../devWarnings.ts`). */\n readonly warnings: DevWarnings;\n /** Counts each connection's calls and refusals, and warns when they look like a client loop (`../devWarnings.ts`). */\n readonly loops: LoopWatch;\n readonly record: (record: CallRecord, details: RecordDetails) => void;\n /** The dispatcher's `serviceAccessSource`: the admin kit's grants column on its model. */\n readonly grantsSource: { readonly model: string; readonly column: string } | undefined;\n}\n\nfunction checkCount(name: string, value: number, max: number): number {\n if (!Number.isInteger(value) || value < 0 || value > max) {\n throw new TypeError(`createDispatcher: ${name} must be an integer from 0 to ${max}`);\n }\n return value;\n}\n\nfunction resolveSubscriptionLimits(\n limits: Partial<SubscriptionLimits> | undefined,\n): SubscriptionLimits {\n if (limits !== undefined && (typeof limits !== \"object\" || limits === null)) {\n throw new TypeError(\n \"createDispatcher: limits.subscriptions must be { maxInFlight, maxQueued }\",\n );\n }\n const merged = { ...DEFAULT_LIMITS.subscriptions, ...limits };\n checkCount(\"limits.subscriptions.maxQueued\", merged.maxQueued, Number.MAX_SAFE_INTEGER);\n const inFlight = merged.maxInFlight;\n if (checkCount(\"limits.subscriptions.maxInFlight\", inFlight, Number.MAX_SAFE_INTEGER) === 0) {\n throw new TypeError(\"createDispatcher: limits.subscriptions.maxInFlight must be at least 1\");\n }\n return Object.freeze(merged);\n}\n\nfunction resolveLimits(limits: LimitsOptions = {}): DispatcherLimits {\n const subscriptions = resolveSubscriptionLimits(limits.subscriptions);\n const merged = { ...DEFAULT_LIMITS, ...limits, subscriptions };\n checkCount(\"limits.maxInFlightQueries\", merged.maxInFlightQueries, Number.MAX_SAFE_INTEGER);\n checkCount(\"limits.maxQueuedQueries\", merged.maxQueuedQueries, Number.MAX_SAFE_INTEGER);\n checkCount(\"limits.retryAfterMs\", merged.retryAfterMs, MAX_TIMEOUT_MS);\n if (checkCount(\"limits.callTimeoutMs\", merged.callTimeoutMs, MAX_TIMEOUT_MS) === 0) {\n throw new TypeError(\"createDispatcher: limits.callTimeoutMs must be at least 1\");\n }\n if (merged.maxInFlightQueries === 0) {\n throw new TypeError(\"createDispatcher: limits.maxInFlightQueries must be at least 1\");\n }\n return Object.freeze(merged);\n}\n\n/**\n * Applies the defaults to the dispatcher's options. `parts`:\n * `accessSinks`, which `createServer` adds, run right after the access sink,\n * before any frame of a flush is sent, and `grantsSource` is the checked\n * `serviceAccessSource`.\n */\nexport function resolveSettings(\n options: PipelineOptions,\n registry: Registry,\n db: unknown,\n parts: {\n readonly accessSinks: readonly FlushSink[];\n readonly grantsSource: PipelineSettings[\"grantsSource\"];\n } = { accessSinks: [], grantsSource: undefined },\n): PipelineSettings {\n const { accessSinks } = parts;\n const development = process.env.NODE_ENV !== \"production\";\n const logger = options.logger ?? consoleLogger;\n const warnings = createDevWarnings({ logger, development, strict: strictWarningsOf(options) });\n warnDefinitions(registry, warnings);\n const storage = storageFor(options, db);\n const { access, policies } = resolveAccess(options.access, registry, storage, {\n logger,\n warnings,\n });\n const outputValidation = options.outputValidation ?? development;\n const live = createLive({\n registry,\n storage,\n policies,\n access,\n logger,\n changeLog: options.changeLog,\n outputValidation,\n });\n return Object.freeze({\n registry,\n db,\n logger,\n access,\n policies,\n ...resolveTracking(\n options,\n registry,\n db,\n logger,\n [live.intake, policies.sink, ...accessSinks, live.emit, live.collections, live.topics],\n live.revisions,\n ),\n versions: options.versions ?? live.versions,\n live,\n limits: resolveLimits(options.limits),\n outputValidation,\n freezeSharedResults: options.freezeSharedResults ?? development,\n warnings,\n loops: createLoopWatch(warnings, logger),\n record: createRecorder({\n logger,\n onCall: options.onCall,\n slowMs: options.slowMs ?? 1_000,\n maxResponseBytes: options.maxResponseBytes ?? 1_048_576,\n warnings,\n }),\n grantsSource: parts.grantsSource,\n });\n}\n","// A method's `claims` (RFC 0003 section 4.1): a requirement on the caller's\n// verified claims (`principal.claims`, a token's `scope`), declared beside\n// `access`, never inside a form. It adds to the form: `{ entry: \"Moderate\" }`\n// with `claims: (claims) => claims?.scope === \"triage\"` needs Moderate on the\n// row and a triage token.\n//\n// It exists because a claim check written as a `custom` form replaced the\n// row check, so any token holding the claim reached every tenant's rows\n// (ACCESS-1), and a service-wide `Admin` grant skipped the check, so a\n// narrowed token of an Admin user was not narrowed (ACCESS-4). Like `kinds`\n// (`kinds.ts`), the check runs in the pipeline right after the method's\n// kinds and outside the access engine, so neither an app's own engine (which\n// sees only the form) nor any grant passes it.\n//\n// Without a principal the call is `UNAUTHENTICATED`; when the check returns\n// anything but `true`, `FORBIDDEN`. It is synchronous: an `async` function\n// is refused when the service is defined, and a check that returns a\n// promise anyway (through a cast) fails the call with `INTERNAL`, its\n// promise caught so a rejection cannot go unhandled. A check that throws\n// fails the call with `INTERNAL` too, closed. A `\"public\"` method takes\n// none, since an anonymous caller, whom `\"public\"` admits, has no claims.\n\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { Principal } from \"../types\";\nimport { checkKind } from \"./kinds\";\nimport type { ClaimsCheck } from \"./types\";\n\nexport type { ClaimsCheck };\n\ntype Fail = (message: string) => never;\n\n/**\n * A method's `claims` option, checked: a function, on a method whose form\n * needs a principal; `undefined` when it declares none. `owner` names the\n * method in messages (`method \"triage\"`).\n */\nexport function claimsOption(\n owner: string,\n entry: Readonly<Record<string, unknown>>,\n fail: Fail,\n): ClaimsCheck | undefined {\n const { claims } = entry;\n if (claims === undefined) {\n return undefined;\n }\n if (typeof claims !== \"function\") {\n fail(\n `${owner}: claims must be a function of (claims, input) that returns true when the caller's claims allow the call`,\n );\n }\n if (claims.constructor.name === \"AsyncFunction\") {\n fail(\n `${owner}: claims must be synchronous: it decides from the caller's verified claims and the input alone, so it returns true or false, never a promise`,\n );\n }\n if (entry.access === \"public\") {\n fail(\n `${owner} is \"public\", so claims cannot hold: an anonymous caller, whom \"public\" admits, has no claims. Leave claims out, or give it a form that needs a principal`,\n );\n }\n return claims as ClaimsCheck;\n}\n\n/**\n * Refuses the call unless `check` admits the principal's claims for `input`:\n * `UNAUTHENTICATED` without a principal, `FORBIDDEN` when the check returns\n * anything but `true`. No check, nothing to refuse. `what` names the method\n * (`taskService.triage`) in the message.\n */\nexport function checkClaims(\n check: ClaimsCheck | undefined,\n principal: Principal | null,\n input: unknown,\n what: string,\n): void {\n if (check === undefined) {\n return;\n }\n if (principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n const allowed: unknown = check(principal.claims, input);\n if (isThenable(allowed)) {\n // A cast past the types: refused, and its rejection observed.\n Promise.resolve(allowed).catch(() => undefined);\n throw new QuickdrawError(\n \"INTERNAL\",\n `${what}: claims returned a promise; it must be synchronous`,\n );\n }\n if (allowed !== true) {\n throw new QuickdrawError(\"FORBIDDEN\", `${what} is not open to the caller's claims`);\n }\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n (typeof value === \"object\" || typeof value === \"function\") &&\n value !== null &&\n typeof (value as { readonly then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * The checks on the caller that run outside the access engine, before the\n * form is asked: the method's `kinds` (`kinds.ts`), then its `claims`.\n */\nexport function checkKindAndClaims(\n method: {\n readonly kinds: readonly string[] | undefined;\n readonly claims: ClaimsCheck | undefined;\n },\n principal: Principal | null,\n input: unknown,\n what: string,\n): void {\n checkKind(method.kinds, principal, what);\n checkClaims(method.claims, principal, input, what);\n}\n","// One handler run (RFC 0003 section 9, step 7): the handler inside its unit\n// of work, with an abort signal and a time limit. Callers join a run; a\n// shared query run has several. The run settles every caller exactly once:\n// with the handler's outcome, with `TIMEOUT` when the time limit of the call\n// that started the run passes first, or with `CANCELLED` (or `TIMEOUT`) for a\n// caller whose own signal aborts first. The time limit covers the output\n// check too, not the handler alone. The handler's signal aborts on the time\n// limit, or when every caller has left. A result that arrives after that is\n// dropped.\n\nimport type { QuickdrawError } from \"../../protocol/errors\";\nimport { quietly } from \"../devWarnings\";\nimport type { UnitOfWork } from \"../uow/types\";\nimport { abortError, toQuickdrawError } from \"./errors\";\n\n/** How a run, or one caller's share of it, ended. */\nexport type Outcome =\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: QuickdrawError };\n\n/** Options of {@link startRun}. */\nexport interface RunOptions {\n /**\n * The time limit of the call that starts the run: it aborts, with the\n * `TIMEOUT` error as its reason, once the limit passes, and the run then\n * settles every caller with that error and aborts the handler.\n */\n readonly timeLimit: AbortSignal;\n readonly unit: UnitOfWork;\n /** Calls the handler with the run's signal. */\n readonly invoke: (signal: AbortSignal) => unknown;\n /** Run the handler `quietly`: no development checks of its statements (a kit's handler). */\n readonly quiet?: boolean;\n /** Turns the handler's value into the run's outcome: output validation, freezing. */\n readonly accept: (value: unknown) => Promise<Outcome>;\n}\n\n/** A handler run in progress, or finished. */\nexport interface Run {\n /** The run's own outcome. It never rejects. */\n readonly outcome: Promise<Outcome>;\n /** The run's outcome once it has one, read synchronously. */\n readonly settled: Outcome | undefined;\n readonly unit: UnitOfWork;\n /** Resolves once the handler itself has settled, which may be after the run timed out. Never rejects. */\n readonly handlerDone: Promise<void>;\n /** True once the handler itself has settled. */\n readonly handlerSettled: boolean;\n /**\n * Adds a caller. Resolves with the run's outcome, or, when `signal` aborts\n * first, with `TIMEOUT` if the caller's time limit aborted it and\n * `CANCELLED` otherwise. A caller without a signal waits for the outcome.\n */\n join(signal: AbortSignal | undefined): Promise<Outcome>;\n}\n\n/** How a caller whose signal aborted leaves the run. */\nfunction stopped(signal: AbortSignal): Outcome {\n return { ok: false, error: abortError(signal) };\n}\n\n/** The mutable state of one run, shared by its helpers. */\ninterface RunState {\n final: Outcome | undefined;\n handlerSettled: boolean;\n participants: number;\n readonly outcome: Promise<Outcome>;\n /** Settles the run unless it already settled; aborts the handler for an error that ends it early. */\n readonly end: (result: Outcome, abort: boolean) => void;\n}\n\nfunction createState(options: RunOptions, controller: AbortController): RunState {\n let resolveOutcome: (outcome: Outcome) => void = () => undefined;\n const outcome = new Promise<Outcome>((resolve) => {\n resolveOutcome = resolve;\n });\n const { timeLimit } = options;\n const onTimeLimit = (): void => state.end(stopped(timeLimit), true);\n const state: RunState = {\n final: undefined,\n handlerSettled: false,\n participants: 0,\n outcome,\n end(result, abort) {\n if (state.final !== undefined) {\n return;\n }\n state.final = result;\n timeLimit.removeEventListener(\"abort\", onTimeLimit);\n resolveOutcome(result);\n if (abort && !result.ok) {\n controller.abort(result.error);\n }\n },\n };\n if (timeLimit.aborted) {\n onTimeLimit();\n } else {\n timeLimit.addEventListener(\"abort\", onTimeLimit, { once: true });\n }\n return state;\n}\n\nfunction runHandler(options: RunOptions, state: RunState, signal: AbortSignal): Promise<void> {\n const invoke = (): unknown => options.invoke(signal);\n let started: Promise<unknown>;\n try {\n started = options.unit.run(options.quiet === true ? () => quietly(invoke) : invoke);\n } catch (error) {\n started = Promise.reject(error);\n }\n return started.then(\n async (value) => {\n state.handlerSettled = true;\n if (state.final !== undefined) {\n return;\n }\n try {\n state.end(await options.accept(value), false);\n } catch (error) {\n state.end({ ok: false, error: toQuickdrawError(error) }, false);\n }\n },\n (error: unknown) => {\n state.handlerSettled = true;\n state.end({ ok: false, error: toQuickdrawError(error) }, false);\n },\n );\n}\n\nfunction joinRun(state: RunState, signal: AbortSignal | undefined): Promise<Outcome> {\n if (signal?.aborted === true) {\n return Promise.resolve(stopped(signal));\n }\n state.participants += 1;\n if (signal === undefined) {\n return state.outcome;\n }\n return new Promise<Outcome>((resolve) => {\n const onAbort = (): void => {\n state.participants -= 1;\n const left = stopped(signal);\n resolve(left);\n // The last caller to leave ends the run with its reason, and aborts the handler.\n if (state.participants === 0) {\n state.end(left, true);\n }\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n void state.outcome.then((result) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(result);\n });\n });\n}\n\n/** Starts the handler inside its unit of work, with a time limit. Add callers with `join`. */\nexport function startRun(options: RunOptions): Run {\n const controller = new AbortController();\n const state = createState(options, controller);\n const handlerDone = runHandler(options, state, controller.signal);\n return {\n outcome: state.outcome,\n get settled() {\n return state.final;\n },\n unit: options.unit,\n handlerDone,\n get handlerSettled() {\n return state.handlerSettled;\n },\n join: (signal) => joinRun(state, signal),\n };\n}\n","// Sharing identical reads (RFC 0003 section 9, step 6). A query that declares\n// `share` runs its handler once for every identical call in flight: same\n// service, method, input and, for `share: \"caller\"`, the same principal over\n// the same transport with the same `ctx.mcp`. The key is built from the\n// parsed input, after validation and after each caller was authorized, so a\n// bad payload never joins a good run and a joiner never skips its own access\n// check. With `ttlMs`, a successful result is reused for that long after the\n// run; an error is never kept.\n//\n// Two calls share only when their keys are equal, so a key must tell apart\n// everything a handler can tell apart. JSON does not: it drops function\n// members and symbol keys, and it writes whatever a `toJSON` returns. Two\n// sessions of one user whose principals differ only in a `can()` method, or\n// in claims a `toJSON` leaves out, would share a run computed with the first\n// one's rights. The key writer below is strict instead: it writes plain data\n// only, and a value it cannot write in full makes the call run unshared.\n\nimport type { McpContext, Principal, Transport } from \"../types\";\n\nclass NotShareable extends Error {}\n\nfunction refuse(): never {\n throw new NotShareable();\n}\n\n/** The own members of a plain object or array, by name; anything else in it is refused. */\nfunction ownValues(value: object): Map<string, unknown> {\n if (Object.getOwnPropertySymbols(value).length > 0) {\n refuse();\n }\n const values = new Map<string, unknown>();\n for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {\n // A getter could answer differently for each caller; only data is keyed.\n if (!(\"value\" in descriptor)) {\n refuse();\n }\n values.set(key, descriptor.value);\n }\n return values;\n}\n\nfunction writeArray(value: readonly unknown[], seen: Set<object>): string {\n const values = ownValues(value);\n // Dense, with no members besides its items and `length`.\n if (values.size !== value.length + 1) {\n refuse();\n }\n const items: string[] = [];\n for (let index = 0; index < value.length; index += 1) {\n const key = String(index);\n if (!values.has(key)) {\n refuse();\n }\n items.push(write(values.get(key), seen));\n }\n return `[${items.join(\",\")}]`;\n}\n\nfunction writeRecord(value: object, seen: Set<object>): string {\n const values = ownValues(value);\n const entries = [...values.keys()]\n .sort()\n .map((key) => `${JSON.stringify(key)}:${write(values.get(key), seen)}`);\n return `{${entries.join(\",\")}}`;\n}\n\n/** A plain object, an array, or a `Date`; anything else (a class instance, a `Map`, a `toJSON`) is refused. */\nfunction writeObject(value: object, seen: Set<object>): string {\n const prototype: unknown = Object.getPrototypeOf(value);\n if (prototype === Date.prototype && Reflect.ownKeys(value).length === 0) {\n return `Date(${(value as Date).getTime()})`;\n }\n const array = prototype === Array.prototype && Array.isArray(value);\n if (!array && prototype !== Object.prototype && prototype !== null) {\n refuse();\n }\n if (seen.has(value)) {\n refuse();\n }\n seen.add(value);\n const written = array ? writeArray(value as unknown[], seen) : writeRecord(value, seen);\n seen.delete(value);\n return written;\n}\n\nfunction write(value: unknown, seen: Set<object>): string {\n switch (typeof value) {\n case \"string\":\n case \"boolean\":\n return JSON.stringify(value);\n case \"number\":\n if (Object.is(value, -0)) {\n return \"-0\";\n }\n return Number.isFinite(value) ? JSON.stringify(value) : String(value);\n case \"bigint\":\n return `${value}n`;\n case \"undefined\":\n return \"undefined\";\n case \"object\":\n return value === null ? \"null\" : writeObject(value, seen);\n default:\n // A function or a symbol: nothing a key could compare.\n return refuse();\n }\n}\n\n/**\n * Writes a value as a share key: object keys sorted, so equal values give\n * equal strings whatever their key order, and two values that differ in any\n * member give different strings. It writes strings, numbers (`-0`, `NaN` and\n * the infinities included), booleans, `null`, `undefined`, bigints (`12n`),\n * dates (`Date(0)`), arrays and plain objects. It returns `undefined` for\n * anything else, so the call runs unshared: a function or symbol anywhere, a\n * symbol key, a getter, a sparse array, a cycle, or an object that is not\n * plain (a class instance, with or without `toJSON`, a `Map`, a `Buffer`).\n */\nexport function stableStringify(value: unknown): string | undefined {\n try {\n return write(value, new Set());\n } catch (error) {\n if (error instanceof NotShareable) {\n return undefined;\n }\n throw error;\n }\n}\n\n/** Who a `share: \"caller\"` run belongs to. */\nexport interface ShareCaller {\n readonly principal: Principal | null;\n readonly transport: Transport;\n /** The call's `ctx.mcp`, when the MCP bridge set one. */\n readonly mcp: McpContext | undefined;\n}\n\n/**\n * The key one call's share run is stored under, or `undefined` when the\n * input or the caller cannot be keyed (the call then runs unshared). A\n * `\"caller\"` key includes the whole principal, the transport and the call's\n * `ctx.mcp`, so two sessions of one user with different claims, grants or\n * MCP token scopes never share, and neither do one principal's calls over two\n * transports; an `\"all\"` key uses `*`.\n */\nexport function shareKey(\n service: string,\n method: string,\n caller: ShareCaller | \"*\",\n input: unknown,\n): string | undefined {\n const who =\n caller === \"*\" ? \"*\" : stableStringify([caller.principal, caller.transport, caller.mcp]);\n const what = stableStringify(input);\n if (who === undefined || what === undefined) {\n return undefined;\n }\n return JSON.stringify([service, method, who, what]);\n}\n\n/** Recursively freezes plain objects and arrays, the way a shared result is frozen in development. */\nexport function deepFreeze<T>(value: T): T {\n if (typeof value !== \"object\" || value === null || Object.isFrozen(value)) {\n return value;\n }\n const prototype: unknown = Object.getPrototypeOf(value);\n if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) {\n return value;\n }\n Object.freeze(value);\n for (const member of Object.values(value)) {\n deepFreeze(member);\n }\n return value;\n}\n\n/** A run in the share table: anything with a settled-or-pending outcome. */\nexport interface ShareEntry<Outcome> {\n readonly outcome: Promise<Outcome>;\n}\n\n/** Runs in flight, and successful results kept for their `ttlMs`, by share key. */\nexport interface ShareTable<Entry extends ShareEntry<{ readonly ok: boolean }>> {\n get(key: string): Entry | undefined;\n /**\n * Stores a run under `key` until it settles. A failed run is removed at\n * once; a successful one after `ttlMs`, or at once without it.\n */\n add(key: string, entry: Entry, ttlMs: number | undefined): void;\n readonly size: number;\n}\n\nexport function createShareTable<\n Entry extends ShareEntry<{ readonly ok: boolean }>,\n>(): ShareTable<Entry> {\n const entries = new Map<string, Entry>();\n const remove = (key: string, entry: Entry): void => {\n if (entries.get(key) === entry) {\n entries.delete(key);\n }\n };\n return {\n get: (key) => entries.get(key),\n add(key, entry, ttlMs) {\n entries.set(key, entry);\n void entry.outcome.then((outcome) => {\n if (!outcome.ok || ttlMs === undefined) {\n remove(key, entry);\n return;\n }\n const timer = setTimeout(() => remove(key, entry), ttlMs);\n (timer as { unref?: () => void }).unref?.();\n });\n },\n get size() {\n return entries.size;\n },\n };\n}\n","// Each caller's reply after the run (RFC 0003 sections 6 and 9): a projection\n// output's rows without the fields the caller's level on each row does not\n// reach. It runs on each caller's copy, never inside the run, so a shared\n// run's `Admin` result is never handed to a `Read` joiner whole.\n//\n// Every caller of a shared run reads its own levels, but callers whose levels\n// hide the same fields on every row get one copy, stripped once, and its JSON\n// text is written once for all of them: a transport that writes JSON sends\n// the same text to each. Encoded per caller instead, a board query shared by\n// twenty viewers is encoded twenty times back to back, holding the event loop\n// for the whole stretch (the 5.0 benchmark, `bench/reports/5.0.0.md`).\n\nimport { serviceGrant } from \"../access/levels\";\nimport type { RowLevels } from \"../access/policy\";\nimport { readerView, wholeView, type ReaderView } from \"../emit/projection\";\nimport type { RegisteredMethod } from \"../registry\";\nimport type { Principal } from \"../types\";\nimport type { SharedData } from \"./request\";\nimport type { Run } from \"./run\";\nimport type { PipelineSettings } from \"./settings\";\nimport { deepFreeze } from \"./share\";\n\n/** A caller's result, with its group's shared JSON text when it came from a shared run. */\nexport interface CallerReply {\n readonly data: unknown;\n readonly shared: SharedData | undefined;\n}\n\n/** A group's copy of a run's result; its JSON text is written on first use. */\nfunction variant(data: unknown): SharedData {\n let written = false;\n let text: string | undefined;\n return {\n data,\n json() {\n if (!written) {\n // `JSON.stringify` returns `undefined` for `undefined` and functions, whatever its type says.\n text = JSON.stringify(data) as string | undefined;\n written = true;\n }\n return text;\n },\n };\n}\n\n/** The copies of each shared run's result, by reader view key, for as long as the run is kept. */\nconst variants = new WeakMap<Run, Map<string, SharedData>>();\n\n/**\n * The reply of a caller who took its result from `run` and sees it as `view`\n * shows: the copy made for the first caller with the same view, or a new one.\n * Views are equal only when they hide the same fields on every row, so a\n * caller never gets a copy made for a level above its own. Copies are frozen\n * when shared results are (`freezeSharedResults`), since callers share them.\n */\nfunction sharedReply(run: Run, view: ReaderView, freeze: boolean): CallerReply {\n let copies = variants.get(run);\n if (copies === undefined) {\n copies = new Map();\n variants.set(run, copies);\n }\n let copy = copies.get(view.key);\n if (copy === undefined) {\n const data = view.strip();\n copy = variant(freeze ? deepFreeze(data) : data);\n copies.set(view.key, copy);\n }\n return { data: copy.data, shared: copy };\n}\n\n/**\n * The caller's level on each row: the one `dispatcher.access.levelsFor`\n * gives; without a policy, only a service-wide `Admin` grant (with\n * `adminBypass`) reaches tiered fields.\n */\nfunction levelsReader(\n settings: PipelineSettings,\n target: RegisteredMethod,\n principal: Principal | null,\n): (ids: readonly string[]) => Promise<RowLevels> {\n const { service } = target;\n return async (ids) => {\n if (principal === null) {\n return new Map();\n }\n if (service.access !== undefined && service.model !== undefined) {\n return await settings.policies.levelsFor(service.name, principal, ids);\n }\n const bypass = service.adminBypass && serviceGrant(principal, service.name) === \"Admin\";\n return new Map(ids.map((id) => [id, bypass ? \"Admin\" : null]));\n };\n}\n\n/**\n * The caller's result: the run's value as the caller's levels let it see it,\n * shared with the other callers of `call.source` (the shared run the call\n * started or joined) who see the same fields.\n */\nexport async function forCaller(\n settings: PipelineSettings,\n target: RegisteredMethod,\n call: { readonly principal: Principal | null; readonly source: Run | undefined },\n value: unknown,\n): Promise<CallerReply> {\n const { projection } = target.method;\n const view =\n projection === undefined\n ? wholeView(value)\n : await readerView(projection, value, levelsReader(settings, target, call.principal));\n return call.source === undefined\n ? { data: view.strip(), shared: undefined }\n : sharedReply(call.source, view, settings.freezeSharedResults);\n}\n","// The pipeline stages that run the handler (RFC 0003 section 9, steps 6 to\n// 8): join an identical run in flight when the query shares, otherwise start\n// one inside a unit of work, then project a projection output's rows, or\n// reduce a schema output to what its schema declares (`schemaOutput.ts`),\n// and check the result against the contract. Field tiers are stripped later,\n// per caller (`tiers.ts`), because a shared run's result goes to every\n// caller; callers who see the same fields share one copy (`replies.ts`).\n\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport {\n NEVER_ABORTED,\n watchCallerReads,\n withSignal,\n type AnyContext,\n type CallerMember,\n} from \"../context\";\nimport { projectOutput } from \"../emit/projection\";\nimport { warnTieredReply } from \"../emit/tieredOutputs\";\nimport type { RegisteredMethod } from \"../registry\";\nimport { isKitHandler } from \"../service\";\nimport { startRun, type Outcome, type Run } from \"./run\";\nimport { deepFreeze, shareKey, type ShareTable } from \"./share\";\nimport type { PipelineSettings } from \"./settings\";\nimport { outputIssues } from \"./validation\";\n\nexport { forCaller } from \"./replies\";\n\n/** What `execute` needs to know about the call, and what it reports back. */\nexport interface ExecuteCall {\n readonly requestId: string;\n readonly transport: AnyContext[\"transport\"];\n readonly principal: AnyContext[\"principal\"];\n /**\n * Aborts when the caller cancels (a query; a mutation cannot be cancelled)\n * or the call's time limit passes. The call then leaves the run it joined.\n */\n readonly signal: AbortSignal | undefined;\n /** Aborts when the call's time limit passes. A run this call starts ends with it. */\n readonly expired: AbortSignal | undefined;\n /** Set when the result came from another call's run. */\n shared: boolean;\n /** Set when this call started the run, and so flushes it. */\n run: Run | undefined;\n /** The shared run this call takes its result from, started or joined; unset when it runs unshared. */\n source: Run | undefined;\n}\n\n/** The handler's result in the shape its output sends: a projection's rows, or what a schema declares. */\nfunction shaped(target: RegisteredMethod, returned: unknown): unknown {\n const { projection, schemaOutput } = target.method;\n if (projection !== undefined) {\n return projectOutput(projection, returned);\n }\n return schemaOutput === undefined ? returned : schemaOutput.pick(returned);\n}\n\n/**\n * Step 8: projects a projection output's rows (RFC 0003 section 6: the\n * projection's keys only, dates as ISO strings) or reduces a schema output\n * to what its schema declares (`schemaOutput.ts`), on every transport and\n * whatever `outputValidation` is; checks the result against the method's\n * output, and freezes shared results.\n */\nasync function accept(\n settings: PipelineSettings,\n target: RegisteredMethod,\n returned: unknown,\n): Promise<Outcome> {\n const { service, method } = target;\n const value = shaped(target, returned);\n if (settings.warnings.enabled) {\n warnTieredReply(target, value, settings.warnings);\n }\n if (settings.outputValidation) {\n const issues = await outputIssues(method.output, value);\n if (issues !== undefined) {\n const error = new QuickdrawError(\n \"INTERNAL\",\n `${service.name}.${method.name} returned a value that does not match its contract output`,\n { issues },\n );\n return { ok: false, error };\n }\n }\n const freeze = method.share !== undefined && settings.freezeSharedResults;\n return { ok: true, value: freeze ? deepFreeze(value) : value };\n}\n\n/**\n * The development warning of a `share: \"all\"` run whose handler read who\n * the caller is: the run has the first caller's, and every caller gets its\n * result. Strict, it throws inside the read, and the run ends `INTERNAL`.\n */\nfunction warnSharedRead(\n settings: PipelineSettings,\n target: RegisteredMethod,\n member: CallerMember,\n): void {\n settings.warnings.warn({\n kind: \"shared-principal\",\n service: target.service.name,\n method: target.method.name,\n subject: member,\n message:\n `its handler read ctx.${member} in a run every caller shares (share: \"all\"): the run sees the first ` +\n `caller's ctx.${member}, and every caller gets its result, another principal's included. A result ` +\n `shared across principals must depend on the input only: read nothing of the caller (copying or ` +\n `logging ctx reads it too), or use share: \"caller\"`,\n meta: { member },\n });\n}\n\n/** Steps 6 to 8 for one authorized call with its parsed input. */\nexport function execute(\n settings: PipelineSettings,\n shares: ShareTable<Run>,\n target: RegisteredMethod,\n call: ExecuteCall,\n input: unknown,\n ctx: AnyContext,\n): Promise<Outcome> {\n const { service, method } = target;\n const key =\n method.share === undefined\n ? undefined\n : shareKey(\n service.name,\n method.name,\n method.share === \"all\"\n ? \"*\"\n : { principal: call.principal, transport: call.transport, mcp: ctx.mcp },\n input,\n );\n const existing = key === undefined ? undefined : shares.get(key);\n if (existing !== undefined && existing.settled?.ok !== false) {\n call.shared = true;\n call.source = existing;\n return existing.join(call.signal);\n }\n const unit = settings.unitOfWork.begin({\n service: service.name,\n method: method.name,\n kind: method.kind,\n requestId: call.requestId,\n transport: call.transport,\n sink: settings.flushSink,\n warnings: settings.warnings,\n });\n // A kit's handler is framework code: the development checks are for the app's.\n const kit = isKitHandler(method.handler);\n const watch = settings.warnings.enabled && !kit && method.share === \"all\";\n const run = startRun({\n // The pipeline starts every call's time limit at admission, before this.\n timeLimit: call.expired ?? NEVER_ABORTED,\n unit,\n invoke: (signal) => {\n // Watched after withSignal, whose copy of ctx reads every member.\n const runCtx = withSignal(ctx, signal);\n const handlerCtx = watch\n ? watchCallerReads(runCtx, (member) => warnSharedRead(settings, target, member))\n : runCtx;\n return method.handler({ input, ctx: handlerCtx, db: settings.db });\n },\n quiet: settings.warnings.enabled && kit,\n accept: (value) => accept(settings, target, value),\n });\n call.run = run;\n if (key !== undefined) {\n shares.add(key, run, method.ttlMs);\n call.source = run;\n }\n return run.join(call.signal);\n}\n","// The \"not modified\" seam (RFC 0003 section 9, step 5). Before a query runs,\n// the dispatcher asks for the current version of its result. When the caller\n// sent that same version as `v`, the call answers `{ ok: true, nm: true, v }`\n// without running the handler; otherwise the reply carries the version so the\n// caller can send it next time.\n//\n// A query that declares `version(input, ctx)` answers for itself. For every\n// other query the dispatcher asks its `versions` option, which the entity\n// subscriptions card implements for queries whose output is one projection\n// row (from the service's `versionColumn` or the in-process change log),\n// when the method's access form checked that row (`emit/versions.ts`).\n\nimport type { Version } from \"../../protocol/envelope\";\nimport type { AnyContext } from \"../context\";\nimport type { AnyService, ServiceMethod } from \"../service\";\nimport type { MaybePromise } from \"../types\";\n\n/** The query a version is asked for. */\nexport interface VersionRequest {\n readonly service: AnyService;\n readonly method: ServiceMethod;\n /** The input after its schema ran. */\n readonly input: unknown;\n /** The call's context; the caller has already been authorized. */\n readonly ctx: AnyContext;\n}\n\n/**\n * Answers the current version of a query's result, or `undefined` when it\n * does not know one (the query then always runs). Called after access was\n * checked, for queries that declare no `version` of their own. It must take\n * the version before any row is read, so a reply is never older than the\n * version it claims.\n *\n * A version is a one-bit oracle: \"not modified\" comes before the handler\n * runs, and tells the caller that what the version stands for exists and\n * has not changed. Answer only for rows the method's access form let the\n * caller read; the default answers for an `entry` form on `id`, a `rowless`\n * method and a caller the service's `Admin` bypass passes.\n */\nexport interface VersionSource {\n versionOf(request: VersionRequest): MaybePromise<Version | undefined>;\n /**\n * Whether the version `versionOf` answered describes `result`, the\n * caller's result of the query once it ran: the reply carries the version\n * only when it does, so a caller never holds a version of something else.\n * Absent: always.\n */\n describes?(request: VersionRequest, result: unknown): boolean;\n}\n\n/** True when `value` can be a call's version: a finite number or a string. */\nexport function isVersion(value: unknown): value is Version {\n return typeof value === \"string\" || (typeof value === \"number\" && Number.isFinite(value));\n}\n","// The pipeline stages before the handler runs (RFC 0003 section 9, steps 1\n// to 5): look the method up, take a query slot, start the call's time limit,\n// build the context, and ask for the result's current version.\n\nimport type { Version } from \"../../protocol/envelope\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { createContext, NEVER_ABORTED, type AnyContext, type ContextFields } from \"../context\";\nimport type { RegisteredMethod, Registry } from \"../registry\";\nimport { runtimeOf } from \"../service\";\nimport type { QuerySlot, ConcurrencyLimiter } from \"./concurrency\";\nimport { abortError, timeoutError } from \"./errors\";\nimport { isVersion } from \"./notModified\";\nimport type { DispatchRequest } from \"./request\";\nimport type { PipelineSettings } from \"./settings\";\n\n/** Step 1: the method a call names, or `NOT_FOUND`. */\nexport function lookup(registry: Registry, request: DispatchRequest): RegisteredMethod {\n const found = registry.find(request.service, request.method);\n if (found !== undefined) {\n return found;\n }\n const message = registry.services.has(request.service)\n ? `Unknown method \"${request.method}\" on service \"${request.service}\"`\n : `Unknown service \"${request.service}\"`;\n throw new QuickdrawError(\"NOT_FOUND\", message);\n}\n\n/**\n * Step 2: a query slot on the call's connection. Mutations and calls without\n * a connection are not capped, so they get no slot.\n */\nexport function admit(\n limiter: ConcurrencyLimiter,\n request: DispatchRequest,\n target: RegisteredMethod,\n signal: AbortSignal | undefined,\n): Promise<QuerySlot | undefined> {\n if (target.method.kind !== \"query\" || request.connectionId === undefined) {\n return Promise.resolve(undefined);\n }\n return limiter.acquire(request.connectionId, signal);\n}\n\n/** A call's time limit, from {@link startTimeLimit}. */\nexport interface TimeLimit {\n /** Aborts when the caller cancels (a query) or the time limit passes. */\n readonly signal: AbortSignal;\n /** Aborts when the time limit passes, with the call's `TIMEOUT` error as its reason. */\n readonly expired: AbortSignal;\n /** Stops the clock. */\n stop(): void;\n}\n\n/**\n * Starts a call's time limit (RFC 0003 section 9, step 7) once the call is\n * admitted, so it covers every stage after step 2: validation, the access\n * check, `version()`, the handler and the output check. Time spent waiting\n * for a query slot does not count. `cancel` is the caller's own signal,\n * which only a query has.\n */\nexport function startTimeLimit(timeoutMs: number, cancel: AbortSignal | undefined): TimeLimit {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(timeoutError(timeoutMs)), timeoutMs);\n return {\n signal: cancel === undefined ? controller.signal : AbortSignal.any([cancel, controller.signal]),\n expired: controller.signal,\n stop: () => clearTimeout(timer),\n };\n}\n\n/**\n * Waits for `work`, or rejects as soon as `signal` aborts: with `TIMEOUT`\n * when the call's time limit aborted it, and `CANCELLED` otherwise. `work`\n * keeps running; its late result is ignored.\n */\nexport function untilStopped<T>(work: PromiseLike<T>, signal: AbortSignal | undefined): Promise<T> {\n if (signal === undefined) {\n return Promise.resolve(work);\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => reject(abortError(signal));\n if (signal.aborted) {\n onAbort();\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n work.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n },\n );\n });\n}\n\n/**\n * The context of one call: the framework's fields, then the app's from\n * `initQuickdraw({ context })`. `dispatch` is the dispatcher's own, which\n * `ctx.services` calls through.\n */\nexport function contextFor(\n settings: PipelineSettings,\n request: DispatchRequest,\n requestId: string,\n target: RegisteredMethod,\n signal: AbortSignal | undefined,\n dispatch: NonNullable<ContextFields[\"dispatch\"]>,\n): AnyContext {\n const log = settings.logger.child({\n service: target.service.name,\n method: target.method.name,\n requestId,\n });\n const { realtime } = settings.live;\n const fields = {\n principal: request.principal,\n signal: signal ?? NEVER_ABORTED,\n log,\n requestId,\n transport: request.transport,\n ...((request.transport === \"socket\" || request.transport === \"legacy\") &&\n request.connectionId !== undefined\n ? { socketId: request.connectionId }\n : {}),\n ...(request.mcp === undefined ? {} : { mcp: request.mcp }),\n touch: settings.touch,\n rooms: realtime.roomsFor(request.transport, request.connectionId, target.method.share),\n presence: realtime.presence,\n // `ctx.services` calls the app's services as this principal through this\n // dispatcher; their units of work join this call's, so their writes flush with it.\n dispatch,\n kit: {\n service: target.service,\n services: settings.registry.services,\n access: settings.policies,\n storage: settings.storage,\n occupancy: settings.live.occupancy,\n claimRevision: settings.live.revisions.claim,\n runDetached: settings.runDetached,\n grantsSource: settings.grantsSource,\n },\n };\n return createContext(fields, runtimeOf(target.service)?.extendContext);\n}\n\n/**\n * Step 5: the current version of a query's result, from the method's own\n * `version`, or else the dispatcher's `versions` source. Mutations have none.\n */\nexport async function currentVersion(\n settings: PipelineSettings,\n target: RegisteredMethod,\n input: unknown,\n ctx: AnyContext,\n): Promise<Version | undefined> {\n const { service, method } = target;\n if (method.kind !== \"query\") {\n return undefined;\n }\n const version =\n method.version === undefined\n ? await settings.versions?.versionOf({ service, method, input, ctx })\n : await method.version(input, ctx);\n return isVersion(version) ? version : undefined;\n}\n\n/**\n * The version a query's reply carries once it ran: the one step 5 took,\n * when it describes the caller's result. A method's own `version` always\n * does; the dispatcher's `versions` source is asked (`describes`).\n */\nexport function versionOfResult(\n settings: PipelineSettings,\n target: RegisteredMethod,\n call: {\n readonly input: unknown;\n readonly ctx: AnyContext;\n readonly version: Version | undefined;\n },\n result: unknown,\n): Version | undefined {\n const { service, method } = target;\n const { input, ctx, version } = call;\n if (version === undefined || method.version !== undefined) {\n return version;\n }\n const request = { service, method, input, ctx };\n return settings.versions?.describes?.(request, result) === false ? undefined : version;\n}\n","// The method pipeline: the one path every call takes, whatever transport it\n// arrived on (RFC 0003 section 9). It replaces 4.1's per-method socket\n// listener (4.1 `src/server/ServiceRegistry.ts:271-407`):\n//\n// 1. look up the method NOT_FOUND\n// 2. take a query slot on the connection RATE_LIMITED, CANCELLED\n// 3. validate the input VALIDATION\n// 4. check the principal's kind and claims, UNAUTHENTICATED, FORBIDDEN\n// then authorize UNAUTHENTICATED, FORBIDDEN\n// 5. answer \"not modified\" when the caller's version is current\n// 6. join an identical shared run in flight\n// 7. run the handler in a unit of work TIMEOUT, CANCELLED\n// 8. project and check the output INTERNAL\n// then strip field tiers for this caller (one copy, encoded\n// once, per group of a shared run's callers who see the same fields)\n// 9. respond, flush, and emit one completion record\n//\n// The time limit starts once the call is admitted (after step 2) and covers\n// steps 3 to 8; a query's cancel signal does too. Either answers the caller\n// at once, and work already started (a slow access check, a handler that\n// ignores its signal) runs on unanswered. A query keeps its slot until that\n// work has settled, so a connection never runs more of it than its cap.\n\nimport { checkKindAndClaims } from \"../access/claims\";\nimport { createConcurrencyLimiter, type ConcurrencyLimiter, type QuerySlot } from \"./concurrency\";\nimport { throwIfCancelled, toQuickdrawError } from \"./errors\";\nimport { execute, forCaller, type ExecuteCall } from \"./execute\";\nimport { describeError, type CallOutcome, type CallRecord } from \"./metrics\";\nimport type { DispatchRequest, DispatchResult, SharedData } from \"./request\";\nimport type { PipelineSettings } from \"./settings\";\nimport { createShareTable, type ShareTable } from \"./share\";\nimport {\n admit,\n contextFor,\n currentVersion,\n lookup,\n startTimeLimit,\n untilStopped,\n versionOfResult,\n type TimeLimit,\n} from \"./stages\";\nimport { parseInput } from \"./validation\";\n\nexport type { DispatchRequest, DispatchResult };\n\n/** A run of a handler, which identical shared calls join (`run.ts`). */\ntype Run = NonNullable<ExecuteCall[\"run\"]>;\n\n/**\n * Runs one call through the pipeline. Resolves once the reply was sent,\n * flushed and recorded. It never rejects, except in a test app made with\n * `strictWarnings`, where an oversized reply, or a call one connection\n * repeats in a loop (`../devWarnings.ts`), rejects with its `DevWarningError` once it\n * was sent and recorded.\n */\nexport type Dispatch = (request: DispatchRequest) => Promise<DispatchResult>;\n\ninterface Pipeline {\n readonly settings: PipelineSettings;\n readonly limiter: ConcurrencyLimiter;\n readonly shares: ShareTable<Run>;\n /** The pipeline's own dispatch function, which `ctx.services` calls through. */\n dispatch: Dispatch;\n}\n\ninterface CallState extends ExecuteCall {\n readonly request: DispatchRequest;\n signal: AbortSignal | undefined;\n expired: AbortSignal | undefined;\n kind: CallRecord[\"kind\"];\n queueMs: number;\n /** The work of the stage the call is in, or last finished. It may outlive the call's answer. */\n stageWork: Promise<unknown> | undefined;\n /** The shared copy the call's data is, handed to `respond` with its result. */\n sharedData: SharedData | undefined;\n}\n\n/**\n * One of steps 3 to 5: waits for `work` until the call's signal stops it\n * (`CANCELLED` or `TIMEOUT`), and keeps it as the call's stage work.\n */\nfunction stage<T>(call: CallState, work: T | PromiseLike<T>): Promise<T> {\n const running = Promise.resolve(work);\n call.stageWork = running;\n return untilStopped(running, call.signal);\n}\n\n/** Steps 3 to 8, for a call that has its method, its time limit and, for a query, its slot. */\nasync function proceed(\n pipeline: Pipeline,\n call: CallState,\n target: ReturnType<typeof lookup>,\n): Promise<DispatchResult> {\n const { settings } = pipeline;\n const { request } = call;\n const label = `${target.service.name}.${target.method.name}`;\n const input = await stage(call, parseInput(target.method.input, request.input, label));\n // The method's `kinds` (`../access/kinds.ts`), then its `claims`\n // (`../access/claims.ts`): outside the access engine, so before any Admin\n // bypass, and before the app's context runs. An anonymous caller is left\n // to the form by `kinds`, and refused by `claims`.\n checkKindAndClaims(target.method, request.principal, input, label);\n const ctx = contextFor(settings, request, call.requestId, target, call.signal, pipeline.dispatch);\n const access = {\n service: target.service,\n method: target.method.name,\n principal: request.principal,\n input,\n ctx,\n };\n await stage(call, settings.access.authorize(target.method.access, access));\n const version = await stage(call, currentVersion(settings, target, input, ctx));\n if (version !== undefined && request.v === version) {\n return { ok: true, notModified: true, version };\n }\n const outcome = await execute(settings, pipeline.shares, target, call, input, ctx);\n if (!outcome.ok) {\n return { ok: false, error: outcome.error };\n }\n const { data, shared } = await stage(call, forCaller(settings, target, call, outcome.value));\n call.sharedData = shared;\n const reported = versionOfResult(settings, target, { input, ctx, version }, data);\n return reported === undefined ? { ok: true, data } : { ok: true, data, version: reported };\n}\n\n/**\n * Frees what a call held. The slot goes back to its connection once nothing\n * the call started is still running: the stage it was answered in the middle\n * of, or the handler run it started. The clock stops now, or, for a call that\n * started a run, once that run settles: the run ends at this call's time\n * limit, whichever of its callers is still waiting.\n */\nfunction release(call: CallState, slot: QuerySlot | undefined, limit: TimeLimit | undefined): void {\n const { run } = call;\n if (run === undefined) {\n limit?.stop();\n } else if (limit !== undefined) {\n void run.outcome.then(limit.stop);\n }\n if (slot === undefined) {\n return;\n }\n // The handler run this call started, and the stage it is in or last\n // finished (for a call that started a run, the per-caller strip after it).\n const running = [run?.handlerDone, call.stageWork].filter(\n (work): work is Promise<unknown> => work !== undefined,\n );\n if (running.length === 0) {\n slot.release();\n return;\n }\n void Promise.allSettled(running).then(slot.release);\n}\n\n/** Steps 1 to 8. Every failure becomes a result; the slot is freed however the call ends. */\nasync function settle(pipeline: Pipeline, call: CallState): Promise<DispatchResult> {\n let slot: QuerySlot | undefined;\n let limit: TimeLimit | undefined;\n try {\n const target = lookup(pipeline.settings.registry, call.request);\n call.kind = target.method.kind;\n // Only a query can be cancelled.\n const cancel = target.method.kind === \"query\" ? call.request.signal : undefined;\n throwIfCancelled(cancel);\n slot = await admit(pipeline.limiter, call.request, target, cancel);\n call.queueMs = slot?.queueMs ?? 0;\n limit = startTimeLimit(\n target.method.timeoutMs ?? pipeline.settings.limits.callTimeoutMs,\n cancel,\n );\n call.signal = limit.signal;\n call.expired = limit.expired;\n return await proceed(pipeline, call, target);\n } catch (error) {\n return { ok: false, error: toQuickdrawError(error) };\n } finally {\n release(call, slot, limit);\n }\n}\n\n/**\n * Step 9a: hands the result to the transport, which reports the reply's\n * size, with the shared copy its data is when it came from a shared run.\n */\nfunction respond(settings: PipelineSettings, call: CallState, result: DispatchResult): number {\n const { respond: send } = call.request;\n if (send === undefined) {\n return 0;\n }\n const { sharedData } = call;\n const shared =\n result.ok && result.notModified !== true && sharedData?.data === result.data\n ? sharedData\n : undefined;\n try {\n const bytes = shared === undefined ? send(result) : send(result, shared);\n return typeof bytes === \"number\" && Number.isFinite(bytes) && bytes > 0 ? bytes : 0;\n } catch (error) {\n settings.logger.error(\"A transport failed to send a reply\", {\n category: \"quickdraw.call\",\n requestId: call.requestId,\n error: describeError(error),\n });\n return 0;\n }\n}\n\n/**\n * Step 9b: flushes the run this call started, once its handler has settled.\n * A handler still running after `TIMEOUT` or `CANCELLED` is flushed when it\n * settles, without holding up this call.\n */\nasync function flushRun(settings: PipelineSettings, call: CallState): Promise<void> {\n const { run } = call;\n if (run === undefined) {\n return;\n }\n const flush = async (): Promise<void> => {\n try {\n await run.unit.flush();\n } catch (error) {\n settings.logger.error(\"Flushing a call's writes failed; its reply was already sent\", {\n category: \"quickdraw.call\",\n requestId: call.requestId,\n error: describeError(error),\n });\n }\n };\n if (run.handlerSettled) {\n await flush();\n return;\n }\n void run.handlerDone.then(flush);\n}\n\nfunction outcomeOf(result: DispatchResult): CallOutcome {\n if (!result.ok) {\n return result.error.code;\n }\n return result.notModified === true ? \"not-modified\" : \"ok\";\n}\n\nfunction recordOf(\n call: CallState,\n result: DispatchResult,\n durationMs: number,\n bytes: number,\n): CallRecord {\n const { request } = call;\n return {\n service: request.service,\n method: request.method,\n kind: call.kind,\n transport: request.transport,\n requestId: call.requestId,\n outcome: outcomeOf(result),\n durationMs,\n queueMs: call.queueMs,\n bytes,\n shared: call.shared,\n sqlStatements: call.run?.unit.sqlStatements,\n };\n}\n\n/** Builds the pipeline's `Dispatch` function over the resolved settings. */\nexport function createPipeline(settings: PipelineSettings): Dispatch {\n const pipeline: Pipeline = {\n settings,\n limiter: createConcurrencyLimiter({\n maxInFlight: settings.limits.maxInFlightQueries,\n maxQueued: settings.limits.maxQueuedQueries,\n retryAfterMs: settings.limits.retryAfterMs,\n }),\n shares: createShareTable<Run>(),\n dispatch: () => Promise.reject(new Error(\"the pipeline is being created\")),\n };\n pipeline.dispatch = async (request) => {\n const startedAt = performance.now();\n const call: CallState = {\n request,\n requestId: request.requestId ?? crypto.randomUUID(),\n transport: request.transport,\n principal: request.principal,\n signal: undefined,\n expired: undefined,\n kind: undefined,\n queueMs: 0,\n stageWork: undefined,\n shared: false,\n run: undefined,\n source: undefined,\n sharedData: undefined,\n };\n const result = await settle(pipeline, call);\n const durationMs = performance.now() - startedAt;\n const bytes = respond(settings, call, result);\n await flushRun(settings, call);\n const record = recordOf(call, result, durationMs, bytes);\n settings.record(record, {\n error: result.ok ? undefined : result.error,\n userId: request.principal?.userId,\n });\n settings.loops.call(request, record.outcome);\n return result;\n };\n return pipeline.dispatch;\n}\n","// The services a dispatcher serves, by name. 4.1's `ServiceRegistry` also\n// wired one Socket.IO listener per method per socket\n// (4.1 `src/server/ServiceRegistry.ts:118-136`); in 5.0 the registry only\n// resolves names, and the transports keep a fixed listener set.\n\nimport { runtimeOf, type AnyService, type ServiceMethod } from \"./service\";\n\n/** A method found by name, with the service it belongs to. */\nexport interface RegisteredMethod {\n readonly service: AnyService;\n readonly method: ServiceMethod;\n}\n\n/** The services of one dispatcher, by service name. */\nexport interface Registry {\n /** Every service, by name. */\n readonly services: ReadonlyMap<string, AnyService>;\n /** The method `method` of service `service`, or `undefined` when either is unknown. */\n find(service: string, method: string): RegisteredMethod | undefined;\n}\n\n/**\n * Indexes services by name. Throws when two services share a name, or when\n * a value is not a service `defineService` returned.\n */\nexport function createRegistry(services: readonly AnyService[]): Registry {\n if (!Array.isArray(services)) {\n throw new TypeError(\"createRegistry: services must be an array of services\");\n }\n const byName = new Map<string, AnyService>();\n for (const service of services) {\n if (runtimeOf(service) === undefined) {\n throw new TypeError(\"createRegistry: every service must come from qd.defineService\");\n }\n if (byName.has(service.name)) {\n throw new TypeError(`createRegistry: two services are named \"${service.name}\"`);\n }\n byName.set(service.name, service);\n }\n return Object.freeze({\n services: byName,\n find(serviceName: string, methodName: string): RegisteredMethod | undefined {\n const service = byName.get(serviceName);\n if (service === undefined || !Object.hasOwn(service.methods, methodName)) {\n return undefined;\n }\n const method = service.methods[methodName];\n return method === undefined ? undefined : { service, method };\n },\n });\n}\n","// The dispatcher: a registry of services plus the method pipeline, with one\n// `call(request)` for every transport and a typed in-process caller.\n// `qd.createServer` builds one; tests, jobs and the MCP bridge can build one\n// directly.\n\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { DispatcherAccess } from \"./access/api\";\nimport { callerGrantsOf, createCaller, type Caller } from \"./caller\";\nimport type { RunContext, RunOptions } from \"./context\";\nimport { registerLive, type Presence, type ServerRooms, type StreamHandle } from \"./emit/live\";\nimport { createPipeline, type DispatchRequest, type DispatchResult } from \"./pipeline/pipeline\";\nimport {\n errorText,\n resolveSettings,\n type DispatcherLimits,\n type PipelineOptions,\n type PipelineSettings,\n} from \"./pipeline/settings\";\nimport { createRegistry, type Registry } from \"./registry\";\nimport { servedProblem, type AnyService, type ServedContext, type Service } from \"./service\";\nimport type { DbOf, Principal, PrincipalOf } from \"./types\";\n\nexport type { Presence, ServerRooms, Service, StreamHandle };\n\ntype TypesOf<S extends readonly AnyService[]> = NonNullable<S[number][\"~types\"]>;\n\n/** The database client the services of `S` were declared with. */\nexport type DbOfServices<S extends readonly AnyService[]> = [S[number]] extends [never]\n ? unknown\n : DbOf<TypesOf<S>>;\n\n/** The principal type the services of `S` were declared with. */\nexport type PrincipalOfServices<S extends readonly AnyService[]> = [S[number]] extends [never]\n ? Principal\n : PrincipalOf<TypesOf<S>>;\n\n/** The contracts the services of `S` were defined from. */\nexport type ContractOfServices<S extends readonly AnyService[]> = [S[number]] extends [never]\n ? AnyContract\n : S[number][\"contract\"];\n\n/**\n * The options `createDispatcher` and `createServer` share: the services and\n * the database client handlers receive, plus the pipeline's seams and\n * limits. `db` may be left out only when the services declared no database\n * type.\n */\nexport type DispatcherBaseOptions<S extends readonly AnyService[]> = PipelineOptions & {\n /** The services to serve. Two services with one name are an error. */\n readonly services: S;\n} & (unknown extends DbOfServices<S>\n ? { readonly db?: DbOfServices<S> }\n : { readonly db: DbOfServices<S> });\n\n/** Options of {@link createDispatcher}: the shared ones, and where users' grants are stored. */\nexport type DispatcherOptions<S extends readonly AnyService[]> = DispatcherBaseOptions<S> & {\n /**\n * Where users' service-wide grants are stored, as `{ model: \"user\",\n * column: \"serviceAccess\" }`: the admin kit on that model treats the\n * column as the grants field, whatever its name (hidden unless\n * `grants: true`, and then for service-wide Admins only). `createServer`\n * takes it as `auth.serviceAccessSource`, which also refreshes the grants\n * it stores; a dispatcher made without `createServer` (an app that serves\n * HTTP with `createHttpRouter`, an MCP process) names it here, or the\n * column is an ordinary field there.\n */\n readonly serviceAccessSource?: { readonly model: string; readonly column: string };\n};\n\n/** `dispatcher.collections` and `qd.collections`: the services' collections (RFC 0003 section 7). */\nexport interface DispatcherCollections {\n /**\n * Sends one scope of a collection a `reset`, so its clients load it again:\n * for a change tracked writes cannot describe, such as a raw SQL write the\n * app did not `ctx.touch`. Throws a `TypeError` for a collection this\n * dispatcher does not serve.\n *\n * @example\n * qd.collections.reset(task, \"byProject\", projectId);\n */\n reset<C extends AnyContract>(\n contract: C,\n collection: keyof C[\"collections\"] & string,\n scope: string,\n ): void;\n}\n\n/** A registry of services and the method pipeline that serves them. */\nexport interface Dispatcher<S extends readonly AnyService[] = readonly AnyService[]> {\n /**\n * Runs one call through the pipeline. Resolves once the result was handed\n * to `request.respond`, the run flushed and the completion record emitted.\n * Never rejects: a failure is a result with `ok: false`.\n */\n call(request: DispatchRequest): Promise<DispatchResult>;\n /**\n * A typed in-process caller acting as `principal`, `null` for anonymous:\n * `dispatcher.caller(user).taskService.rename(input)`. Calls go through the\n * whole pipeline with transport `\"internal\"` and no connection, so they are\n * not capped. Through a server's dispatcher, a principal that carries no\n * `serviceAccess` gets the grants `auth.loadServiceAccess` loads, once per\n * caller and again after the server applied new grants, as a socket's\n * handshake does; one that carries grants keeps exactly those.\n */\n caller(principal: PrincipalOfServices<S> | null): Caller<ContractOfServices<S>>;\n /**\n * Runs `fn` inside a unit of work, as a method's handler runs (RFC 0003\n * section 5.1): the tracked writes it makes flush to the dispatcher's\n * sinks once it settles, whether it resolved or threw, and before `run`\n * returns. Inside an open unit of work or transaction, `fn` joins it\n * instead, unless `detached` (see {@link RunOptions}) gives it a unit of\n * its own. For jobs, scripts and webhooks that write outside a method, and\n * a handler's background work. `fn` gets a {@link RunContext}: `ctx.touch`\n * records the rows a raw SQL write changed.\n */\n run<T>(fn: (ctx: RunContext) => T | PromiseLike<T>, options?: RunOptions): Promise<T>;\n /**\n * The services' access policies (RFC 0003 section 4): a principal's levels\n * on rows, list filters, and access-change events.\n */\n readonly access: DispatcherAccess;\n /** The services' collections: a manual `reset`. Deltas themselves come from tracked writes. */\n readonly collections: DispatcherCollections;\n /**\n * Who is online, when they were last seen, and who is in a room (RFC 0003\n * section 12.5), from the sockets of the server `createServer` attached;\n * without a server nobody is online.\n */\n readonly presence: Presence;\n /**\n * App rooms from code that is not a handler (RFC 0003 section 12.5): typed\n * room events (`emit`, `emitToUser`) and `leave(room, { userId })`, on\n * every node of the attached server; without a server nothing is sent.\n */\n readonly rooms: ServerRooms;\n /**\n * The handle of one of the services' streams (RFC 0003 section 12.5), whose\n * `push` appends an item: `dispatcher.stream(task, \"logs\").push(taskId,\n * line)`. Throws a `TypeError` for a stream the dispatcher does not serve.\n */\n stream<C extends AnyContract, K extends keyof C[\"streams\"] & string>(\n contract: C,\n name: K,\n ): StreamHandle<C, K>;\n readonly registry: Registry;\n /** The resolved limits, for a server to announce in `qd:hello`. */\n readonly limits: DispatcherLimits;\n /**\n * Where users' service-wide grants are stored, as the dispatcher was made\n * with it (`serviceAccessSource`, which `createServer` takes from\n * `auth.serviceAccessSource`): the admin kit on that model treats the\n * column as the grants field. `undefined` without one.\n */\n readonly serviceAccessSource: { readonly model: string; readonly column: string } | undefined;\n}\n\n/** What `createServer` gives the dispatcher it makes, beside the app's options. */\nexport interface ServerParts {\n /**\n * Sinks to run right after the access sink, before any frame of a flush\n * is sent: `createServer`'s grants refresh, so a flush that lowers a\n * user's grants revokes what they held before that flush's frames reach\n * them.\n */\n readonly accessSinks: readonly PipelineSettings[\"flushSink\"][];\n}\n\nconst SERVER_PARTS = new WeakMap<object, ServerParts>();\n\n/** A copy of `options` whose dispatcher gets `parts` (one marker: each copy would lose another's). */\nexport function withServerParts<O extends object>(options: O, parts: ServerParts): O {\n const copy = { ...options };\n SERVER_PARTS.set(copy, parts);\n return copy;\n}\n\n/** The `serviceAccessSource` option, checked: `{ model, column }`, or `undefined`. */\nfunction grantsSourceOf(source: unknown): ServedContext[\"grantsSource\"] {\n if (source === undefined) {\n return undefined;\n }\n const { model, column } = (source ?? {}) as {\n readonly model?: unknown;\n readonly column?: unknown;\n };\n if (typeof model !== \"string\" || model === \"\" || typeof column !== \"string\" || column === \"\") {\n throw new TypeError(\n 'createDispatcher: serviceAccessSource must be { model, column }, as { model: \"user\", column: \"serviceAccess\" }',\n );\n }\n return Object.freeze({ model, column });\n}\n\n/** `TypeError` for the first handler a service cannot be served with (`checkWhenServed`). */\nfunction checkServed(\n services: readonly AnyService[],\n grantsSource: ServedContext[\"grantsSource\"],\n): void {\n for (const service of services) {\n for (const method of Object.values(service.methods)) {\n const problem = servedProblem(method.handler, { service, grantsSource });\n if (problem !== undefined) {\n throw new TypeError(`createDispatcher: ${service.name}: ${problem}`);\n }\n }\n }\n}\n\n/** `run`'s `detached` option, checked. */\nfunction detachedOf(options: RunOptions | undefined): boolean {\n if (options === undefined) {\n return false;\n }\n if (typeof options !== \"object\" || options === null) {\n throw new TypeError(\"run: options must be an object, { detached?: boolean }\");\n }\n const { detached } = options;\n if (detached !== undefined && typeof detached !== \"boolean\") {\n throw new TypeError(\"run: detached must be true or false\");\n }\n return detached === true;\n}\n\n/** `dispatcher.run`: a unit of work around `fn`, flushed once `fn` settles. */\nexport async function runInUnit<T>(\n settings: PipelineSettings,\n fn: (ctx: RunContext) => T | PromiseLike<T>,\n options?: RunOptions,\n): Promise<T> {\n if (typeof fn !== \"function\") {\n throw new TypeError(\"run: pass the function to run inside a unit of work\");\n }\n const detached = detachedOf(options);\n const requestId = crypto.randomUUID();\n const unit = settings.unitOfWork.begin({\n requestId,\n transport: \"internal\",\n sink: settings.flushSink,\n ...(detached ? { detached } : {}),\n });\n const ctx: RunContext = Object.freeze({\n touch: settings.touch,\n log: settings.logger.child({ requestId }),\n principal: null,\n });\n try {\n return await unit.run(() => fn(ctx));\n } finally {\n try {\n await unit.flush();\n } catch (error) {\n settings.logger.error(\"Flushing a run's writes failed\", {\n category: \"quickdraw.flush\",\n error: errorText(error),\n });\n }\n }\n}\n\n/**\n * Creates a dispatcher for `services`.\n *\n * @example\n * const dispatcher = createDispatcher({ services: [taskService], db: prisma });\n * await dispatcher.caller(user).taskService.rename({ id, title });\n */\nexport function createDispatcher<const S extends readonly AnyService[]>(\n options: DispatcherOptions<S>,\n): Dispatcher<S> {\n if (typeof options !== \"object\" || options === null) {\n throw new TypeError(\"createDispatcher: options must be an object with services and db\");\n }\n const registry = createRegistry(options.services);\n const grantsSource = grantsSourceOf(options.serviceAccessSource);\n checkServed(options.services, grantsSource);\n const settings = resolveSettings(options, registry, options.db, {\n accessSinks: SERVER_PARTS.get(options)?.accessSinks ?? [],\n grantsSource,\n });\n // Writes made outside any unit of work flush to this dispatcher's sinks,\n // and the tracker's development warnings go out as this dispatcher's,\n // until a server's `close()` detaches it.\n const detach = settings.unitOfWork.attach?.(\n settings.flushSink,\n settings.logger,\n settings.warnings,\n );\n const call = createPipeline(settings);\n const { levelsFor, accessWhere, onAccessChanged } = settings.policies;\n const dispatcher: Dispatcher<S> = Object.freeze({\n call,\n caller: (principal: PrincipalOfServices<S> | null) =>\n createCaller(() => call, principal, {\n grants: () => callerGrantsOf(dispatcher),\n }) as Caller<ContractOfServices<S>>,\n run: <T>(fn: (ctx: RunContext) => T | PromiseLike<T>, runOptions?: RunOptions) =>\n runInUnit(settings, fn, runOptions),\n access: Object.freeze({ levelsFor, accessWhere, onAccessChanged }),\n collections: Object.freeze({\n reset: (contract: AnyContract, collection: string, scope: string) => {\n settings.live.resetCollection(contract, collection, scope);\n },\n }),\n presence: settings.live.realtime.presence,\n rooms: settings.live.realtime.rooms,\n stream: <C extends AnyContract, K extends keyof C[\"streams\"] & string>(contract: C, name: K) =>\n settings.live.realtime.stream(contract, name) as unknown as StreamHandle<C, K>,\n registry,\n limits: settings.limits,\n serviceAccessSource: grantsSource,\n });\n // `createServer` attaches its Socket.IO server to the dispatcher's live data.\n registerLive(dispatcher, settings.live);\n LOOPS.set(dispatcher, settings.loops);\n if (typeof detach === \"function\") {\n DETACHES.set(dispatcher, detach);\n }\n return dispatcher;\n}\n\nconst DETACHES = new WeakMap<object, () => void>();\n\nconst LOOPS = new WeakMap<object, PipelineSettings[\"loops\"]>();\n\n/**\n * The loop watch of a dispatcher `createDispatcher` returned: `createServer`\n * counts its socket rate limiter's refusals there too (`devWarnings.ts`).\n */\nexport function loopsOf(dispatcher: object): PipelineSettings[\"loops\"] | undefined {\n return LOOPS.get(dispatcher);\n}\n\n/**\n * Detaches `dispatcher` from its tracked database client: ambient writes\n * and the warnings outside calls go back to the dispatcher attached before\n * it (or nowhere). A server's `close()` calls it once the server stopped.\n */\nexport function detachDispatcher(dispatcher: object): void {\n DETACHES.get(dispatcher)?.();\n}\n","// The event-loop stall watchdog (`createServer({ stallWatchdog })`). A server\n// whose event loop is blocked (a long synchronous loop, a huge\n// `JSON.stringify`, synchronous crypto) answers nobody until it is free\n// again, and nothing in a call's own record says so. The watchdog samples the\n// loop's delay with Node's histogram (`perf_hooks.monitorEventLoopDelay`) at\n// a 20 ms resolution, reads it every 10 s, and logs a warning when the 99th\n// percentile delay of that window is above the threshold (200 ms), or when\n// its longest delay is above `maxMs` (1 s), naming the window's slowest\n// methods from the calls' completion records.\n//\n// Cost: the histogram is one libuv timer firing every 20 ms, and the read is\n// one timer every 10 s; recording a call is one map update. A watchdog that\n// samples much more finely becomes a load of its own, which is why the\n// resolution is fixed. On an idle process it costs about 5 ms of CPU per\n// 10 s, 0.05% of one CPU (`scripts/stall-watchdog-overhead.mjs`).\n//\n// A percentile needs repeated stalls to move: at the default window one\n// 300 ms block is one sample of about 500, and the 99th percentile stays\n// low; that warning is about a loop that keeps stalling, not one slow tick.\n// One block long enough to be felt by every caller at once, 1 s by default,\n// warns through the window's maximum instead.\n\nimport { monitorEventLoopDelay, type ELDHistogram } from \"node:perf_hooks\";\nimport type { Logger } from \"../../contract/logger\";\nimport type { CallRecord } from \"../pipeline/metrics\";\n\n/** The histogram's sampling resolution, in milliseconds. Fixed: finer sampling costs CPU. */\nexport const STALL_RESOLUTION_MS = 20;\n\n/** The default threshold for the window's 99th percentile delay, in milliseconds. */\nexport const DEFAULT_STALL_THRESHOLD_MS = 200;\n\n/** The default threshold for the window's single longest delay, in milliseconds. */\nexport const DEFAULT_STALL_MAX_MS = 1_000;\n\n/** The default window: how often the delay is read, in milliseconds. */\nexport const DEFAULT_STALL_INTERVAL_MS = 10_000;\n\n/** The shortest window the watchdog accepts, in milliseconds. */\nexport const MIN_STALL_INTERVAL_MS = 1_000;\n\nconst DEFAULT_SLOWEST = 5;\n\nconst MAX_INTERVAL_MS = 2_147_483_647;\n\n/** Options of `createServer({ stallWatchdog })`. */\nexport interface StallWatchdogOptions {\n /** Warn when the window's 99th percentile event-loop delay is above this, in milliseconds. Default 200. */\n readonly thresholdMs?: number;\n /** Warn when the window's single longest event-loop delay is above this, in milliseconds. Default 1,000. */\n readonly maxMs?: number;\n /** How often the delay is read and a new window starts, in milliseconds; at least 1,000. Default 10,000. */\n readonly intervalMs?: number;\n /** How many of the window's slowest methods a warning names. Default 5. */\n readonly slowest?: number;\n}\n\n/** One method among a window's slowest, by its slowest call. */\nexport interface SlowMethod {\n /** `\"taskService.list\"`. */\n readonly method: string;\n readonly calls: number;\n readonly maxMs: number;\n readonly meanMs: number;\n}\n\n/** What one read of the window found. */\nexport interface StallReport {\n /** How long the window ran, in milliseconds. */\n readonly windowMs: number;\n /** The event loop's delays over the window, in milliseconds; 0 when nothing was sampled. */\n readonly p50Ms: number;\n readonly p99Ms: number;\n readonly maxMs: number;\n readonly meanMs: number;\n /** True when `p99Ms` was above the threshold or `maxMs` above its limit, and so a warning was logged. */\n readonly stalled: boolean;\n /** The window's slowest methods, slowest first. */\n readonly slowest: readonly SlowMethod[];\n}\n\n/** A running watchdog. */\nexport interface StallWatchdog {\n /** Counts one call of the window: give it every completion record (the dispatcher's `onCall`). */\n observe(record: CallRecord): void;\n /** Reads the window, starts a new one, and logs a warning when the window stalled. Its timer calls it. */\n check(): StallReport;\n /** Stops sampling and reading. */\n stop(): void;\n}\n\ninterface MethodWindow {\n calls: number;\n maxMs: number;\n totalMs: number;\n}\n\ninterface Settings {\n readonly thresholdMs: number;\n readonly maxMs: number;\n readonly intervalMs: number;\n readonly slowest: number;\n}\n\nfunction fail(message: string): never {\n throw new TypeError(`createServer: stallWatchdog.${message}`);\n}\n\n/** The watchdog's settings from `createServer`'s option; `undefined` when it is off. */\nexport function stallWatchdogSettings(\n option: boolean | StallWatchdogOptions | undefined,\n): Settings | undefined {\n if (option === undefined || option === false) {\n return undefined;\n }\n const given: StallWatchdogOptions = option === true ? {} : option;\n if (typeof given !== \"object\" || given === null) {\n throw new TypeError(\"createServer: stallWatchdog must be true, false or its options\");\n }\n const thresholdMs = given.thresholdMs ?? DEFAULT_STALL_THRESHOLD_MS;\n const maxMs = given.maxMs ?? DEFAULT_STALL_MAX_MS;\n const intervalMs = given.intervalMs ?? DEFAULT_STALL_INTERVAL_MS;\n const slowest = given.slowest ?? DEFAULT_SLOWEST;\n if (!(Number.isFinite(thresholdMs) && thresholdMs > 0)) {\n fail(\"thresholdMs must be a positive number of milliseconds\");\n }\n if (!(Number.isFinite(maxMs) && maxMs > 0)) {\n fail(\"maxMs must be a positive number of milliseconds\");\n }\n if (\n !(\n Number.isSafeInteger(intervalMs) &&\n intervalMs >= MIN_STALL_INTERVAL_MS &&\n intervalMs <= MAX_INTERVAL_MS\n )\n ) {\n fail(`intervalMs must be a whole number of milliseconds, at least ${MIN_STALL_INTERVAL_MS}`);\n }\n if (!(Number.isSafeInteger(slowest) && slowest >= 0)) {\n fail(\"slowest must be a whole number, 0 or more\");\n }\n return { thresholdMs, maxMs, intervalMs, slowest };\n}\n\nconst NS_PER_MS = 1e6;\n\nfunction toMs(nanoseconds: number): number {\n return Math.round((nanoseconds / NS_PER_MS) * 10) / 10;\n}\n\nfunction rank(methods: ReadonlyMap<string, MethodWindow>, slowest: number): SlowMethod[] {\n return [...methods]\n .map(([method, window]) => ({\n method,\n calls: window.calls,\n maxMs: Math.round(window.maxMs),\n meanMs: Math.round(window.totalMs / window.calls),\n }))\n .sort((a, b) => b.maxMs - a.maxMs)\n .slice(0, slowest);\n}\n\n/** Reads `histogram` for the window that started at `startedAt`. */\nfunction readWindow(\n histogram: ELDHistogram,\n startedAt: number,\n): Omit<StallReport, \"stalled\" | \"slowest\"> {\n const windowMs = Math.round(performance.now() - startedAt);\n if (histogram.count === 0) {\n return { windowMs, p50Ms: 0, p99Ms: 0, maxMs: 0, meanMs: 0 };\n }\n return {\n windowMs,\n p50Ms: toMs(histogram.percentile(50)),\n p99Ms: toMs(histogram.percentile(99)),\n maxMs: toMs(histogram.max),\n meanMs: toMs(histogram.mean),\n };\n}\n\n/**\n * The warning a window gives, or `undefined` when it did not stall: the\n * 99th percentile above the threshold (a loop that keeps stalling), else one\n * delay above `maxMs` (one long block).\n */\nfunction stallMessage(\n read: Omit<StallReport, \"stalled\" | \"slowest\">,\n settings: Settings,\n): string | undefined {\n if (read.p99Ms > settings.thresholdMs) {\n return `The event loop stalled: its 99th percentile delay was ${read.p99Ms} ms over the last ${read.windowMs} ms (threshold ${settings.thresholdMs} ms)`;\n }\n if (read.maxMs > settings.maxMs) {\n return `The event loop stalled: one delay of ${read.maxMs} ms over the last ${read.windowMs} ms (max ${settings.maxMs} ms)`;\n }\n return undefined;\n}\n\n/**\n * Starts sampling the event loop's delay, reading it every `intervalMs`. The\n * timer does not keep the process alive. `createServer({ stallWatchdog })`\n * starts one and stops it on `close()`.\n */\nexport function startStallWatchdog(settings: Settings, logger: Logger): StallWatchdog {\n const histogram = monitorEventLoopDelay({ resolution: STALL_RESOLUTION_MS });\n const methods = new Map<string, MethodWindow>();\n let startedAt = performance.now();\n histogram.enable();\n const check = (): StallReport => {\n const read = readWindow(histogram, startedAt);\n const slowest = rank(methods, settings.slowest);\n histogram.reset();\n methods.clear();\n startedAt = performance.now();\n const message = stallMessage(read, settings);\n if (message !== undefined) {\n logger.warn(message, {\n category: \"quickdraw.stall\",\n ...read,\n thresholdMs: settings.thresholdMs,\n maxThresholdMs: settings.maxMs,\n slowest,\n });\n }\n return { ...read, stalled: message !== undefined, slowest };\n };\n const timer = setInterval(check, settings.intervalMs);\n timer.unref();\n return {\n observe(record) {\n // A method that does not exist is named by the client: never a key.\n if (record.kind === undefined) {\n return;\n }\n const key = `${record.service}.${record.method}`;\n const window = methods.get(key);\n if (window === undefined) {\n methods.set(key, { calls: 1, maxMs: record.durationMs, totalMs: record.durationMs });\n return;\n }\n window.calls += 1;\n window.totalMs += record.durationMs;\n window.maxMs = Math.max(window.maxMs, record.durationMs);\n },\n check,\n stop() {\n clearInterval(timer);\n histogram.disable();\n },\n };\n}\n","// The HTTP transport (RFC 0003 section 10): `POST {path}/{service}/{method}`\n// with the input as the JSON body, through the same pipeline and the same\n// `authenticate` as sockets, for server-side prefetch, load tests and\n// webhooks. The principal comes from the session cookie or a bearer token\n// (`httpCredentialsOf`), and `authenticate` is told which one the transport\n// chose, so the ambient cookie's `Origin` can be checked (`socketAuth` does;\n// finding F7.1 of the quickdraw-chat review). The cookie is `auth.token`\n// only for `socketAuth`'s `authenticate`, which checks that Origin and the\n// session store; every other finds it in `request.sessionCookie` alone, so\n// code written for bearer tokens never takes the ambient cookie for one\n// (the 5.1 audit's AUTH-1/CLIENT-2). The reply is the `qd:call`\n// acknowledgement shape, `{ ok: true, d }` or `{ ok: false, e }`, with the\n// error code's HTTP status (`httpStatus`). The call is cancelled when the\n// client goes away.\n//\n// The router is a plain Node request handler rather than an `express.Router`,\n// so it never imports Express: it mounts with `app.use(router)` on Express 4\n// or 5 alike, whichever the app installed, and also serves a bare Node HTTP\n// server.\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { consoleLogger, type Logger } from \"../../contract/logger\";\nimport { httpStatus, INTERNAL_MESSAGE, QuickdrawError, toWire } from \"../../protocol/errors\";\nimport type { Dispatcher } from \"../dispatcher\";\nimport { describeError } from \"../pipeline/metrics\";\nimport { toCallReply, type DispatchResult } from \"../pipeline/request\";\nimport type { Principal } from \"../types\";\nimport { INTERNAL_FAILURE, unreadable } from \"./ack\";\nimport {\n createPrincipalResolver,\n isForbiddenCredential,\n isRefusal,\n socketAuthOf,\n type ResolvePrincipal,\n type ServerAuth,\n} from \"./auth\";\nimport {\n httpCredentialsOf,\n isJsonRequest,\n readJsonInput,\n transportCookieNaming,\n type HttpCredentials,\n type HttpCredentialSource,\n type HttpRequest,\n type SessionCookieNaming,\n} from \"./body\";\n\n/**\n * A Node request handler that serves calls: mount it with `app.use(router)`\n * on an Express app, or pass it to `http.createServer`. A request it does not\n * serve goes to `next`, or gets a 404 when there is no `next`.\n */\nexport type HttpRouter = (\n req: IncomingMessage,\n res: ServerResponse,\n next?: (error?: unknown) => void,\n) => void;\n\n/**\n * An Express-style middleware, such as an `express-rate-limit` limiter: it\n * answers the request itself, or calls `next()` to let it through.\n */\nexport type HttpMiddleware = (req: never, res: never, next: (error?: unknown) => void) => unknown;\n\n/** How the HTTP transport serves calls. */\nexport interface HttpTransportOptions {\n /** The path calls are served under: `POST {path}/{service}/{method}`. Default `\"/qd\"`. */\n readonly path?: string;\n /**\n * The largest request body read, in bytes. Default 1 MiB. A body the app's\n * own JSON parser already read (`express.json()`) is used as it is.\n */\n readonly maxBodyBytes?: number;\n /**\n * The session cookie a token is read from. Default: the name the auth\n * routes set on the same request: `\"session\"` when `COOKIE_DOMAIN` gives\n * the cookie a domain; else `\"__Host-session\"` on a request over HTTPS\n * (`req.secure`, `X-Forwarded-Proto: https` or an `https:` `Origin`),\n * which never reads the plain name a sibling site could plant, and\n * `\"session\"` on a plain HTTP one, where `\"__Host-session\"` is read first\n * all the same. A name given\n * here is the only one read, on any request. A name the request repeats\n * counts as no cookie.\n */\n readonly cookieName?: string;\n /**\n * A rate limiter run before each call the transport serves, and only\n * those: `createCallLimiter()` from `./server/express`, which refuses in\n * the transport's own `RATE_LIMITED` reply. It runs on the app's Express\n * request and response, so the transport must be mounted on Express.\n * Default: none (the socket rate limiter does not see HTTP calls).\n */\n readonly rateLimit?: HttpMiddleware;\n}\n\n/** Options of {@link createHttpRouter}. */\nexport interface HttpRouterOptions<P extends Principal = Principal> extends HttpTransportOptions {\n /** The dispatcher whose methods the router serves. */\n readonly dispatcher: Pick<Dispatcher, \"call\"> & Partial<Pick<Dispatcher, \"serviceAccessSource\">>;\n /**\n * Authenticates each request, with the same hooks as `createServer`'s\n * `auth`. Its `serviceAccessSource` must be the dispatcher's own (made\n * with `createDispatcher({ serviceAccessSource })`), or the router throws:\n * the admin kit protects the grants column only where the dispatcher\n * names it.\n */\n readonly auth?: ServerAuth<P>;\n /** Default: the console. */\n readonly logger?: Logger;\n}\n\n/** What the router runs on, resolved from its options. */\nexport interface HttpRouterSettings {\n readonly call: Dispatcher[\"call\"];\n readonly resolvePrincipal: ResolvePrincipal;\n readonly logger: Logger;\n readonly prefix: string;\n readonly maxBodyBytes: number;\n /** `cookieName`, and `COOKIE_DOMAIN` read when the router is made: a cookie with a domain is `session`. */\n readonly cookieNaming: SessionCookieNaming;\n /**\n * True when `authenticate` is `socketAuth`'s, which takes the session\n * cookie as `auth.token` (checking its Origin and the store); every other\n * `authenticate` gets it as `request.sessionCookie` alone.\n */\n readonly cookieAsToken: boolean;\n readonly rateLimit: HttpMiddleware | undefined;\n}\n\nconst DEFAULT_MAX_BODY_BYTES = 1_048_576;\n\ninterface Target {\n readonly service: string;\n readonly method: string;\n}\n\nfunction decodeSegment(segment: string): string | undefined {\n try {\n return decodeURIComponent(segment);\n } catch {\n return undefined;\n }\n}\n\n/** The service and method a `POST {prefix}/{service}/{method}` request names, or `undefined`. */\nfunction targetOf(req: IncomingMessage, prefix: string): Target | undefined {\n const path = (req.url ?? \"\").split(\"?\", 1)[0] ?? \"\";\n if (req.method !== \"POST\" || !path.startsWith(`${prefix}/`)) {\n return undefined;\n }\n const segments = path.slice(prefix.length + 1).split(\"/\");\n const [service, method] = segments.map(decodeSegment);\n if (segments.length !== 2 || !service || !method) {\n return undefined;\n }\n return { service, method };\n}\n\nfunction retryAfterSeconds(result: DispatchResult): number | undefined {\n if (result.ok || result.error.code !== \"RATE_LIMITED\") {\n return undefined;\n }\n const { retryAfterMs } = (result.error.data ?? {}) as { readonly retryAfterMs?: unknown };\n return typeof retryAfterMs === \"number\" && retryAfterMs > 0\n ? Math.ceil(retryAfterMs / 1000)\n : undefined;\n}\n\nfunction encode(settings: HttpRouterSettings, result: DispatchResult): [number, string] {\n // The status of the code the reply carries, which `toWire` keeps to the known codes.\n const status = result.ok ? 200 : httpStatus(toWire(result.error).code);\n try {\n return [status, JSON.stringify(toCallReply(result))];\n } catch (error) {\n settings.logger.error(\"A call's reply could not be encoded; it was answered with INTERNAL\", {\n category: \"quickdraw.http\",\n error: describeError(error),\n });\n return [500, JSON.stringify(INTERNAL_FAILURE)];\n }\n}\n\n/** Writes a call's reply, unless the response already ended; returns its size in bytes. */\nfunction sendResult(\n settings: HttpRouterSettings,\n res: ServerResponse,\n result: DispatchResult,\n): number | undefined {\n if (res.headersSent || res.writableEnded || res.destroyed) {\n return undefined;\n }\n const [status, body] = encode(settings, result);\n const bytes = Buffer.byteLength(body);\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n res.setHeader(\"content-length\", bytes);\n // A reply is one caller's data: no cache keeps it, and no browser reads it as anything but JSON.\n res.setHeader(\"cache-control\", \"no-store\");\n res.setHeader(\"x-content-type-options\", \"nosniff\");\n const retryAfter = retryAfterSeconds(result);\n if (retryAfter !== undefined) {\n res.setHeader(\"retry-after\", String(retryAfter));\n }\n res.end(body);\n return bytes;\n}\n\nfunction failure(error: QuickdrawError): DispatchResult {\n return { ok: false, error };\n}\n\n/** The credential the transport chose: the session cookie, else the bearer token. */\nfunction chosenCredential(credentials: HttpCredentials): HttpCredentialSource | undefined {\n if (credentials.cookie !== null) {\n return \"cookie\";\n }\n return credentials.bearer === null ? undefined : \"bearer\";\n}\n\nasync function authenticate(\n settings: HttpRouterSettings,\n req: HttpRequest,\n): Promise<Principal | null | QuickdrawError> {\n const credentials = httpCredentialsOf(req, settings.cookieNaming);\n const { cookie, bearer } = credentials;\n const token = settings.cookieAsToken ? (cookie ?? bearer) : bearer;\n const credential = chosenCredential(credentials);\n try {\n return await settings.resolvePrincipal({\n transport: \"http\",\n auth: token === null ? {} : { token },\n // The session cookie is ambient: `socketAuth` checks such a call's Origin (F7.1).\n ...(credential === undefined ? {} : { credential }),\n ...(cookie === null ? {} : { sessionCookie: cookie }),\n headers: req.headers,\n req,\n });\n } catch (error) {\n const forbidden = isForbiddenCredential(error);\n settings.logger[isRefusal(error) || forbidden ? \"debug\" : \"error\"](\n \"HTTP authentication failed\",\n { category: \"quickdraw.http\", error: describeError(error) },\n );\n return forbidden\n ? new QuickdrawError(\"FORBIDDEN\", error.message)\n : new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication failed\");\n }\n}\n\nasync function serve(\n settings: HttpRouterSettings,\n req: HttpRequest,\n res: ServerResponse,\n target: Target,\n): Promise<void> {\n const controller = new AbortController();\n // `req` closes once its body was read; `res` closes when the client leaves.\n res.once(\"close\", () => {\n if (!res.writableFinished) {\n controller.abort();\n }\n });\n if (!isJsonRequest(req)) {\n const message = \"Send the input as a JSON body with Content-Type: application/json\";\n sendResult(settings, res, failure(unreadable(message)));\n return;\n }\n const principal = await authenticate(settings, req);\n if (principal instanceof QuickdrawError) {\n sendResult(settings, res, failure(principal));\n return;\n }\n let input: unknown;\n try {\n input = await readJsonInput(req, settings.maxBodyBytes);\n } catch (error) {\n const reason =\n error instanceof QuickdrawError ? error : unreadable(\"The request body could not be read\");\n sendResult(settings, res, failure(reason));\n return;\n }\n await settings.call({\n ...target,\n input,\n principal,\n transport: \"http\",\n signal: controller.signal,\n respond: (result) => sendResult(settings, res, result),\n });\n}\n\nfunction notFound(settings: HttpRouterSettings, res: ServerResponse): void {\n sendResult(settings, res, failure(new QuickdrawError(\"NOT_FOUND\", \"Not found\")));\n}\n\n/** Serves a call, answering `INTERNAL` when serving it fails. */\nfunction serveCall(\n settings: HttpRouterSettings,\n req: IncomingMessage,\n res: ServerResponse,\n target: Target,\n): void {\n const fail = (error: unknown): void => {\n settings.logger.error(\"The HTTP transport failed to serve a call\", {\n category: \"quickdraw.http\",\n error: describeError(error),\n });\n sendResult(settings, res, failure(new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE)));\n };\n const { rateLimit } = settings;\n if (rateLimit === undefined) {\n serve(settings, req, res, target).catch(fail);\n return;\n }\n // The limiter answers a refused call itself; it calls `next` to let one through.\n const next = (error?: unknown): void => {\n if (error === undefined) {\n serve(settings, req, res, target).catch(fail);\n } else {\n fail(error);\n }\n };\n try {\n Promise.resolve(rateLimit(req as never, res as never, next)).catch(fail);\n } catch (error) {\n fail(error);\n }\n}\n\n/** The router over resolved settings; `createServer` builds it with its own principal resolver. */\nexport function httpRouter(settings: HttpRouterSettings): HttpRouter {\n return (req, res, next) => {\n const target = targetOf(req, settings.prefix);\n if (target === undefined) {\n if (next === undefined) {\n notFound(settings, res);\n } else {\n next();\n }\n return;\n }\n serveCall(settings, req, res, target);\n };\n}\n\n/** `\"/qd/\"` and `\"qd\"` become `\"/qd\"`; `\"/\"` becomes `\"\"`, serving `/{service}/{method}`. */\nfunction normalizePath(path: string): string {\n const trimmed = path.replace(/^\\/+|\\/+$/g, \"\");\n return trimmed === \"\" ? \"\" : `/${trimmed}`;\n}\n\n/** Resolves the HTTP transport's options. */\nexport function httpRouterSettings(\n options: HttpTransportOptions,\n base: Pick<HttpRouterSettings, \"call\" | \"resolvePrincipal\" | \"logger\" | \"cookieAsToken\">,\n): HttpRouterSettings {\n const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n if (!Number.isSafeInteger(maxBodyBytes) || maxBodyBytes < 1) {\n throw new TypeError(\"http.maxBodyBytes must be a whole number of bytes, 1 or more\");\n }\n const { rateLimit } = options;\n if (rateLimit !== undefined && typeof rateLimit !== \"function\") {\n throw new TypeError(\n \"http.rateLimit must be an Express middleware, such as createCallLimiter()\",\n );\n }\n return {\n ...base,\n prefix: normalizePath(options.path ?? \"/qd\"),\n maxBodyBytes,\n cookieNaming: transportCookieNaming(options.cookieName),\n rateLimit,\n };\n}\n\n/**\n * `TypeError` when the router's `auth.serviceAccessSource` is not its\n * dispatcher's (the 5.1 audit's ADMIN-2): the admin kit hides and guards the\n * grants column only where the dispatcher names it, so a router that names\n * it alone would leave it an ordinary, writable field.\n */\nfunction checkGrantsSource(\n own: Dispatcher[\"serviceAccessSource\"],\n named: Dispatcher[\"serviceAccessSource\"],\n): void {\n if (named === undefined || (own?.model === named.model && own.column === named.column)) {\n return;\n }\n const made = own === undefined ? \"without one\" : `with ${own.model}.${own.column}`;\n throw new TypeError(\n `createHttpRouter: auth.serviceAccessSource names ${named.model}.${named.column}, but its dispatcher was made ${made}: pass serviceAccessSource: { model: \"${named.model}\", column: \"${named.column}\" } to createDispatcher, so the admin kit there protects that column`,\n );\n}\n\n/**\n * Creates the HTTP transport for a dispatcher: `POST /qd/{service}/{method}`\n * with a JSON body. `createServer` mounts one on the app's Express app; use\n * this to serve calls from an app without sockets, or under another path.\n *\n * @example\n * app.use(createHttpRouter({ dispatcher, auth: { authenticate } }));\n */\nexport function createHttpRouter<P extends Principal = Principal>(\n options: HttpRouterOptions<P>,\n): HttpRouter {\n checkGrantsSource(options.dispatcher.serviceAccessSource, options.auth?.serviceAccessSource);\n return httpRouter(\n httpRouterSettings(options, {\n call: options.dispatcher.call,\n resolvePrincipal: createPrincipalResolver(options.auth),\n logger: options.logger ?? consoleLogger,\n cookieAsToken: socketAuthOf(options.auth?.authenticate) !== undefined,\n }),\n );\n}\n","/**\n * Rate limiting middleware for Socket.io events.\n *\n * Provides per-socket rate limiting to prevent abuse and ensure\n * fair resource usage across clients.\n *\n * @example\n * ```typescript\n * import { createRateLimiter, applyRateLimitMiddleware } from '@fitzzero/quickdraw-core/server';\n *\n * // Create a rate limiter\n * const rateLimiter = createRateLimiter({\n * windowMs: 60000, // 1 minute window\n * maxRequests: 100, // 100 requests per window\n * });\n *\n * // Apply to Socket.io server\n * applyRateLimitMiddleware(io, rateLimiter);\n * ```\n */\n\nimport type { Server as SocketIOServer, Socket } from \"socket.io\";\nimport type { Logger } from \"../contract/logger\";\nimport { consoleLogger } from \"../contract/logger\";\n\n/**\n * Rate limiter configuration options.\n */\nexport interface RateLimitOptions {\n /**\n * Time window in milliseconds (default: 60000 = 1 minute)\n */\n windowMs?: number;\n\n /**\n * Maximum number of requests per window (default: 600, which `createServer`'s\n * socket limiter uses too; 4.x defaulted to 100)\n */\n maxRequests?: number;\n\n /**\n * Events to exclude from rate limiting (e.g., ['ping', 'pong'])\n */\n excludeEvents?: string[];\n\n /**\n * Event-name prefixes to exclude from rate limiting.\n * Pass `[CHANNEL_EVENT_PREFIX]` (\"channel:\") so channel traffic bypasses\n * the global limiter — channels enforce their own per-socket token buckets.\n */\n excludePrefixes?: string[];\n\n /**\n * Custom key generator for grouping requests.\n * Default uses socket.id.\n */\n keyGenerator?: (socket: Socket, eventName: string) => string;\n\n /**\n * Callback when rate limit is exceeded.\n */\n onRateLimitExceeded?: (socket: Socket, eventName: string) => void;\n\n /**\n * The acknowledgement a dropped event's callback receives, given the socket,\n * the event name and the milliseconds until the limit resets. Default: the\n * 4.x `{ success: false, error: \"Rate limit exceeded\", code: 429 }`.\n */\n ackPayload?: (socket: Socket, eventName: string, retryAfterMs: number) => unknown;\n\n /**\n * Logger instance\n */\n logger?: Logger;\n}\n\n/**\n * Requests allowed per window by default: 600 a minute, so a socket can\n * refetch a watched query four times a second (the coordinator's window)\n * with room to spare. 4.x allowed 100, which refused part of a busy\n * board's work in the 5.0 benchmark (`bench/reports/5.0.0.md`).\n */\nconst DEFAULT_MAX_REQUESTS = 600;\n\n/**\n * Rate limit entry tracking requests in a window.\n */\ninterface RateLimitEntry {\n count: number;\n resetAt: number;\n}\n\n/**\n * Rate limiter instance.\n */\nexport interface RateLimiter {\n /**\n * Check if a request should be allowed.\n * Returns true if allowed, false if rate limited.\n */\n check: (key: string) => boolean;\n\n /**\n * Get remaining requests for a key.\n */\n getRemaining: (key: string) => number;\n\n /**\n * Get time until rate limit resets for a key.\n */\n getResetTime: (key: string) => number;\n\n /**\n * Clear all rate limit entries (useful for testing).\n */\n clear: () => void;\n\n /**\n * Configuration options.\n */\n options: Required<\n Pick<RateLimitOptions, \"windowMs\" | \"maxRequests\" | \"excludeEvents\" | \"excludePrefixes\">\n >;\n}\n\n/**\n * Create a rate limiter instance.\n *\n * @param options - Rate limiter configuration\n * @returns Rate limiter instance\n *\n * @example\n * ```typescript\n * const limiter = createRateLimiter({\n * windowMs: 60000,\n * maxRequests: 100,\n * });\n *\n * if (limiter.check('user-123')) {\n * // Request allowed\n * } else {\n * // Rate limited\n * }\n * ```\n */\nexport function createRateLimiter(options: RateLimitOptions = {}): RateLimiter {\n const {\n windowMs = 60000,\n maxRequests = DEFAULT_MAX_REQUESTS,\n excludeEvents = [],\n excludePrefixes = [],\n } = options;\n\n const entries = new Map<string, RateLimitEntry>();\n\n // Cleanup old entries periodically\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of entries) {\n if (entry.resetAt <= now) {\n entries.delete(key);\n }\n }\n }, windowMs);\n\n // Prevent the interval from keeping the process alive\n if (cleanupInterval.unref) {\n cleanupInterval.unref();\n }\n\n return {\n check(key: string): boolean {\n const now = Date.now();\n const entry = entries.get(key);\n\n if (!entry || entry.resetAt <= now) {\n // New window\n entries.set(key, {\n count: 1,\n resetAt: now + windowMs,\n });\n return true;\n }\n\n if (entry.count >= maxRequests) {\n return false;\n }\n\n entry.count++;\n return true;\n },\n\n getRemaining(key: string): number {\n const now = Date.now();\n const entry = entries.get(key);\n\n if (!entry || entry.resetAt <= now) {\n return maxRequests;\n }\n\n return Math.max(0, maxRequests - entry.count);\n },\n\n getResetTime(key: string): number {\n const now = Date.now();\n const entry = entries.get(key);\n\n if (!entry || entry.resetAt <= now) {\n return 0;\n }\n\n return entry.resetAt - now;\n },\n\n clear(): void {\n entries.clear();\n },\n\n options: {\n windowMs,\n maxRequests,\n excludeEvents,\n excludePrefixes,\n },\n };\n}\n\n/**\n * Apply rate limiting middleware to a Socket.io server.\n *\n * This intercepts all incoming events and checks them against\n * the rate limiter before allowing them to proceed.\n *\n * @param io - Socket.io server instance\n * @param rateLimiter - Rate limiter instance\n * @param options - Additional options\n *\n * @example\n * ```typescript\n * const rateLimiter = createRateLimiter({ maxRequests: 100 });\n *\n * applyRateLimitMiddleware(io, rateLimiter, {\n * keyGenerator: (socket) => socket.userId ?? socket.id,\n * onRateLimitExceeded: (socket, event) => {\n * socket.emit('error', { code: 'RATE_LIMITED', event });\n * },\n * });\n * ```\n */\nexport function applyRateLimitMiddleware(\n io: SocketIOServer,\n rateLimiter: RateLimiter,\n options: Pick<\n RateLimitOptions,\n \"keyGenerator\" | \"onRateLimitExceeded\" | \"logger\" | \"ackPayload\"\n > = {},\n): void {\n const logger =\n options.logger?.child({ service: \"RateLimiter\" }) ??\n consoleLogger.child({ service: \"RateLimiter\" });\n\n const keyGenerator = options.keyGenerator ?? ((socket) => socket.id);\n const onRateLimitExceeded =\n options.onRateLimitExceeded ??\n ((socket, eventName) => {\n socket.emit(\"error\", {\n code: \"RATE_LIMITED\",\n message: `Rate limit exceeded for event: ${eventName}`,\n retryAfter: rateLimiter.getResetTime(keyGenerator(socket, eventName)),\n });\n });\n\n const ackPayload =\n options.ackPayload ??\n (() => ({\n success: false,\n error: \"Rate limit exceeded\",\n code: 429,\n }));\n\n const { excludeEvents, excludePrefixes } = rateLimiter.options;\n\n io.on(\"connection\", (socket) => {\n // Use Socket.io's built-in middleware for incoming packets\n socket.use(([eventName, ...args], next) => {\n // A client may name an event with a number, which Socket.IO accepts;\n // no listener serves one, so it passes uncounted.\n if (typeof eventName !== \"string\") {\n next();\n return;\n }\n\n // Skip excluded events\n if (excludeEvents.includes(eventName)) {\n next();\n return;\n }\n\n // Skip excluded prefixes (e.g., \"channel:\" — channels self-limit)\n if (excludePrefixes.some((prefix) => eventName.startsWith(prefix))) {\n next();\n return;\n }\n\n // Skip internal Socket.io events\n if (eventName.startsWith(\"$\")) {\n next();\n return;\n }\n\n const key = keyGenerator(socket, eventName);\n\n if (rateLimiter.check(key)) {\n next();\n } else {\n logger.warn(`Rate limit exceeded for socket ${socket.id} on event ${eventName}`);\n onRateLimitExceeded(socket, eventName);\n\n // Don't call next() - this drops the event\n // If there's a callback, call it with an error\n const lastArg = args[args.length - 1];\n if (typeof lastArg === \"function\") {\n lastArg(ackPayload(socket, eventName, rateLimiter.getResetTime(key)));\n }\n }\n });\n });\n\n logger.info(\n `Rate limiting enabled: ${rateLimiter.options.maxRequests} requests per ${rateLimiter.options.windowMs}ms`,\n );\n}\n\n/**\n * Create a tiered rate limiter with different limits for different event types.\n *\n * @param tiers - Map of event patterns to rate limit options\n * @param defaultOptions - Default options for events not matching any tier\n * @returns Rate limiter that applies different limits based on event name\n *\n * @example\n * ```typescript\n * const tieredLimiter = createTieredRateLimiter(\n * {\n * // Strict limits for write operations\n * 'create*': { maxRequests: 10, windowMs: 60000 },\n * 'update*': { maxRequests: 20, windowMs: 60000 },\n * 'delete*': { maxRequests: 5, windowMs: 60000 },\n * // Generous limits for reads\n * 'list*': { maxRequests: 200, windowMs: 60000 },\n * 'get*': { maxRequests: 200, windowMs: 60000 },\n * },\n * { maxRequests: 100, windowMs: 60000 } // Default\n * );\n * ```\n */\nexport function createTieredRateLimiter(\n tiers: Record<string, RateLimitOptions>,\n defaultOptions: RateLimitOptions = {},\n): {\n check: (key: string, eventName: string) => boolean;\n getRemaining: (key: string, eventName: string) => number;\n clear: () => void;\n} {\n // Create a limiter for each tier\n const tierLimiters = new Map<string, RateLimiter>();\n const tierPatterns: Array<{ pattern: RegExp; limiter: RateLimiter }> = [];\n\n for (const [pattern, options] of Object.entries(tiers)) {\n const limiter = createRateLimiter({ ...defaultOptions, ...options });\n tierLimiters.set(pattern, limiter);\n\n // Convert glob-like pattern to regex\n const regexPattern = pattern.replace(/\\*/g, \".*\").replace(/\\?/g, \".\");\n tierPatterns.push({\n pattern: new RegExp(`^${regexPattern}$`),\n limiter,\n });\n }\n\n const defaultLimiter = createRateLimiter(defaultOptions);\n\n function getLimiterForEvent(eventName: string): RateLimiter {\n for (const { pattern, limiter } of tierPatterns) {\n if (pattern.test(eventName)) {\n return limiter;\n }\n }\n return defaultLimiter;\n }\n\n return {\n check(key: string, eventName: string): boolean {\n const limiter = getLimiterForEvent(eventName);\n // Include event name in key to separate limits per event type\n return limiter.check(`${key}:${eventName}`);\n },\n\n getRemaining(key: string, eventName: string): number {\n const limiter = getLimiterForEvent(eventName);\n return limiter.getRemaining(`${key}:${eventName}`);\n },\n\n clear(): void {\n for (const limiter of tierLimiters.values()) {\n limiter.clear();\n }\n defaultLimiter.clear();\n },\n };\n}\n","// `createServer` (RFC 0003 sections 3, 8 and 10): serves a dispatcher over\n// Socket.IO and HTTP, on the Express app and HTTP server the app already\n// owns. It replaces 4.1's `createQuickdrawServer`, which built its own\n// Express app and listened itself (4.1 `src/server/createServer.ts:57-67`),\n// so every app that needed its own middleware copied the whole bootstrap\n// instead, and which called `process.exit` on shutdown (`:195-204`). This one\n// creates the HTTP server only when none is passed, never listens, never exits\n// the process, and handles signals only when asked.\n\nimport {\n createServer as createHttpServer,\n type IncomingMessage,\n type Server as HttpServer,\n type ServerResponse,\n} from \"node:http\";\nimport { consoleLogger, type Logger } from \"../contract/logger\";\nimport {\n createDispatcher,\n detachDispatcher,\n loopsOf,\n withServerParts,\n type Dispatcher,\n type DispatcherBaseOptions,\n type PrincipalOfServices,\n} from \"./dispatcher\";\nimport { liveOf, type RoomLeaveHandler, type RoomLeaveHook } from \"./emit/live\";\nimport {\n closer,\n prepareWatchdog,\n startStartupChecks,\n trackCalls,\n watchSignals,\n type StallWatchdogOptions,\n} from \"./lifecycle\";\nimport { editsGrants, type AnyService } from \"./service\";\nimport {\n createGrantsSink,\n createPrincipalResolver,\n socketAuthOf,\n type ServerAuth,\n type ServiceGrants,\n} from \"./transports/auth\";\nimport {\n httpRouter,\n httpRouterSettings,\n type HttpRouter,\n type HttpTransportOptions,\n} from \"./transports/http\";\nimport {\n checkKeyPrefix,\n createSocketServer,\n type ClusterOptions,\n type DisconnectUserOptions,\n resolveLegacyWire,\n type LegacyWireOptions,\n type QuickdrawIo,\n type SocketCors,\n type SocketOptions,\n type SocketRateLimitOptions,\n} from \"./transports/socketServer\";\nimport type { Principal } from \"./types\";\n\nexport { startupChecksOf } from \"./lifecycle\";\n\n/**\n * The parts of an Express app (4 or 5) `createServer` uses: it is a request\n * listener, and `use` mounts the HTTP transport.\n */\nexport interface HttpApp {\n (req: IncomingMessage, res: ServerResponse): void;\n use(router: HttpRouter): unknown;\n}\n\n/** `createServer`'s own options, besides the dispatcher's. */\nexport interface ServerOnlyOptions<P extends Principal = Principal> {\n /**\n * The app's Express app. The HTTP transport is mounted on it with\n * `app.use`, and when `httpServer` is not given the HTTP server is created\n * from it. Mount the app's own routes and parsers first.\n */\n readonly app?: HttpApp;\n /**\n * The app's HTTP server, for Socket.IO to attach to; pass the one made from\n * `app`, and `app` with it (or `http: false`): the HTTP transport is\n * mounted on `app`. Without it one is created, from `app` when given.\n * Either way the app calls `server.httpServer.listen(...)` itself.\n */\n readonly httpServer?: HttpServer;\n /** Authenticates sockets and HTTP calls. Without it every caller is anonymous. */\n readonly auth?: ServerAuth<P>;\n /** Socket.IO's CORS for its handshake. The app configures CORS for its own routes. */\n readonly cors?: SocketCors;\n /**\n * Other Socket.IO server options, such as `path` or `pingInterval`.\n * `connectionStateRecovery` is refused: a recovered socket would come back\n * with its principal and rooms without authenticating again, so a revoked\n * session or a lowered grant would return; quickdraw clients resume by\n * revision on every reconnect.\n */\n readonly socket?: SocketOptions;\n /**\n * Use the stock Socket.IO parser, so events may carry binary. Default\n * `false`: the JSON-only parser, which also measures each reply's size.\n */\n readonly binary?: boolean;\n /**\n * Serve 4.x clients, which connect without `auth.qd`, through the legacy\n * shim: request/response calls only. Default `false`: they are refused with\n * `PROTOCOL_MISMATCH`. `{ aliases: { taskService: \"cardService\" } }` also\n * serves a renamed service under its old name, to 4.x clients only, and\n * logs each caller of an old name once.\n */\n readonly legacyWire?: boolean | LegacyWireOptions;\n /**\n * The socket rate limiter (`createRateLimiter`'s options), or `false` for\n * none. Default: 600 events per minute per socket. `qd:ch` (channels keep\n * their own per-socket token buckets), `qd:cancel`, the entity and\n * collection subscription events (`qd:sub`, `qd:unsub`, `qd:col:sub`,\n * `qd:col:unsub`, `qd:col:items`), the topic watches (`qd:watch`,\n * `qd:unwatch`) and the stream subscriptions (`qd:stream:sub`,\n * `qd:stream:unsub`) are never counted; the ones that read run in a\n * per-socket lane instead (`limits.subscriptions`: 8 at once, 64 waiting,\n * then `RATE_LIMITED`).\n */\n readonly rateLimit?: SocketRateLimitOptions | false;\n /**\n * The HTTP transport's options, or `false` to serve no HTTP calls. It has\n * no rate limit unless `rateLimit` is given: `http: { rateLimit:\n * createCallLimiter() }` (from `./server/express`).\n */\n readonly http?: HttpTransportOptions | false;\n /** Close the server on `SIGTERM` and `SIGINT`. Default `false`. The process is never exited. */\n readonly handleSignals?: boolean;\n /**\n * Watch the event loop for stalls: sample its delay (every 20 ms), read it\n * every `intervalMs` (10 s), and log a warning naming the window's slowest\n * methods when the 99th percentile delay is above `thresholdMs` (200 ms)\n * or one delay is above `maxMs` (1 s). `true` for the defaults. Default\n * `false`. Stops on `close()`.\n */\n readonly stallWatchdog?: boolean | StallWatchdogOptions;\n /**\n * How long `close()` waits for calls and HTTP requests in flight before it\n * stops waiting and closes their connections, in milliseconds. Default\n * 10,000.\n */\n readonly shutdownTimeoutMs?: number;\n /**\n * Behind a cluster adapter: where the cluster's shared state lives (the\n * revision counter every node's flushes take their revision from, and\n * users' last-seen times). By default the Socket.IO Redis adapter's own\n * Valkey or Redis client, under keys prefixed `quickdraw:`. Its\n * `keyPrefix` also names the deployment every server-to-server event\n * carries (a node ignores another deployment's) and is\n * `setupRedisAdapter`'s default key: each deployment sharing a Valkey\n * needs its own. See `docs/deploying.md`.\n */\n readonly cluster?: ClusterOptions;\n /**\n * Called once for every socket that leaves app rooms: its own\n * `ctx.rooms.leave(room)` (`reason: \"leave\"`), `rooms.leave(room, { userId })`\n * (`\"removed\"`), or a disconnect, which leaves every app room it was in\n * (`\"disconnect\"`). It gets the socket's principal (`null` when\n * anonymous), its id and the rooms it left, each with `last`: true when\n * no socket of that user is in the room any more, on any node (a second\n * tab keeps it false; a socket reconnecting after `qd:rotate` is a new\n * socket, so the old one's disconnect is the user's last only if they had\n * no other). It runs on the node that held the socket, after the room\n * heard the socket go, in a unit of work of its own (`qd.run` with\n * `detached`: never the unit of the handler that left), with that run's\n * `ctx`; an error it throws is logged, and `close()` waits for it.\n *\n * A service that joins sockets to rooms declares its own hook instead\n * (`defineService`'s `onRoomLeave`), so no server root can forget it:\n * every service's hook runs beside this one, each in a unit of work of\n * its own, and one that throws stops none of the others.\n *\n * @example\n * onRoomLeave: ({ principal, rooms }) => {\n * if (principal !== null && rooms.some(({ room, last }) => room === WORLD_ROOM && last)) {\n * removePlayer(principal.userId);\n * qd.rooms.emit(WORLD_ROOM, gameContract, \"playerLeft\", { id: principal.userId });\n * }\n * },\n */\n readonly onRoomLeave?: RoomLeaveHandler<P>;\n}\n\n/**\n * Options of {@link createServer}: the dispatcher's (`services`, `db`,\n * `logger`, `limits`, `onCall` and the pipeline seams) and the server's own.\n * The grants column is `auth.serviceAccessSource` here, which the server\n * gives its dispatcher.\n */\nexport type ServerOptions<S extends readonly AnyService[]> = DispatcherBaseOptions<S> &\n ServerOnlyOptions<PrincipalOfServices<S>>;\n\n/** Options of `server.rotate`. */\nexport interface RotateOptions {\n /** Each client reconnects at a random moment within this many milliseconds. */\n readonly withinMs: number;\n}\n\n/** A running quickdraw server: what {@link createServer} returns. */\nexport interface QuickdrawServer<S extends readonly AnyService[] = readonly AnyService[]> {\n /** The Socket.IO server, attached to `httpServer`. */\n readonly io: QuickdrawIo<PrincipalOfServices<S>>;\n /** The HTTP server: the app's, or the one created. Not listening until the app says so. */\n readonly httpServer: HttpServer;\n /**\n * The dispatcher every transport calls; `dispatcher.caller(principal)`\n * calls in process, giving a principal that carries no grants the ones\n * `auth.loadServiceAccess` loads, as a socket's handshake does (once per\n * caller, and again after the server applied new grants). `close()` waits\n * for its calls in flight.\n */\n readonly dispatcher: Dispatcher<S>;\n /**\n * Graceful shutdown: removes the signal handlers, disconnects every socket\n * (cancelling its queries; a mutation runs to its end), waits for the calls\n * still in flight, and closes the HTTP server once its requests finish.\n * After `shutdownTimeoutMs` it stops waiting and closes the remaining\n * connections. Resolves when it is done, so an app can then close its\n * database; calling it again returns the same promise. It never exits the\n * process.\n */\n close(): Promise<void>;\n /**\n * Sends `qd:rotate` to every client: reconnect at a random moment within\n * `withinMs`, for platforms that cap a connection's lifetime.\n */\n rotate(options: RotateOptions): void;\n readonly access: {\n /**\n * Reloads `userId`'s grants with `auth.loadServiceAccess`, puts them in the\n * principal of that user's sockets (on every node: behind a cluster\n * adapter the grants are broadcast), sends them `qd:access`, and resolves\n * the user's entity subscriptions again. Resolves with the grants.\n */\n refresh(userId: string): Promise<ServiceGrants>;\n /**\n * Disconnects every socket of `userId` (only those that authenticated\n * with `sessionId`, when given), on every node: behind a cluster adapter\n * the request is broadcast. For a session the app revoked (wire\n * `createAuthRoutes`' `onRevoke` to it): an open socket keeps the\n * principal it authenticated with, and its reconnect is authenticated\n * afresh. Returns how many sockets this node disconnected.\n */\n disconnectUser(userId: string, options?: DisconnectUserOptions): number;\n };\n /**\n * Who is online, when they were last seen, and who is in a room (RFC 0003\n * section 12.5); the same as `ctx.presence`. Behind a cluster adapter it\n * asks every node.\n */\n readonly presence: Dispatcher<S>[\"presence\"];\n /** The handle of one of the services' streams: `server.stream(task, \"logs\").push(taskId, line)`. */\n readonly stream: Dispatcher<S>[\"stream\"];\n /**\n * App rooms from code that is not a handler (RFC 0003 section 12.5): typed\n * room events and `leave(room, { userId })`, on every node; the same as\n * `qd.rooms` and the socket-free half of `ctx.rooms`.\n */\n readonly rooms: Dispatcher<S>[\"rooms\"];\n}\n\nconst DEFAULT_SHUTDOWN_TIMEOUT_MS = 10_000;\n\n/**\n * The startup warnings about `auth`: grants no tracked write refreshes\n * (`warnUnsourcedGrants`), and `socketAuth`'s `devCredentials` while it is\n * on (the 5.1 audit's AUTH-3).\n */\nfunction warnOnAuth(\n services: readonly AnyService[],\n auth: { readonly authenticate?: unknown; readonly serviceAccessSource?: unknown } | undefined,\n logger: Logger,\n): void {\n warnUnsourcedGrants(services, auth?.serviceAccessSource !== undefined, logger);\n if (socketAuthOf(auth?.authenticate)?.devCredentials === true) {\n logger.warn(\n \"socketAuth's devCredentials is on: a socket handshake that names a user id signs in as that user, from any page; never set it outside development\",\n { category: \"quickdraw.auth\" },\n );\n }\n}\n\nfunction checkOptions<P extends Principal>(options: ServerOnlyOptions<P>): void {\n // Before any server, adapter subscription or background check exists.\n checkKeyPrefix(options.cluster);\n if (options.app !== undefined && typeof options.app.use !== \"function\") {\n throw new TypeError(\"createServer: app must be an Express app\");\n }\n if (options.httpServer !== undefined && typeof options.httpServer.listen !== \"function\") {\n throw new TypeError(\"createServer: httpServer must be a Node HTTP server\");\n }\n // The HTTP transport is mounted on `app`; a server passed without it would\n // build the transport, attach it nowhere, and answer every call with the\n // app's own handler.\n if (options.httpServer !== undefined && options.app === undefined && options.http !== false) {\n throw new TypeError(\n \"createServer: httpServer was given without app, so the HTTP transport has nowhere to mount; pass the Express app the server was created from as app, or set http: false to serve sockets only\",\n );\n }\n const timeout = options.shutdownTimeoutMs;\n if (timeout !== undefined && !(Number.isSafeInteger(timeout) && timeout >= 0)) {\n throw new TypeError(\"createServer: shutdownTimeoutMs must be a whole number of milliseconds\");\n }\n if (options.onRoomLeave !== undefined && typeof options.onRoomLeave !== \"function\") {\n throw new TypeError(\n \"createServer: onRoomLeave must be a function of the leave and a run context\",\n );\n }\n // Socket.IO turns recovery on for any truthy value, `{}` included.\n const socket = options.socket as Readonly<Record<string, unknown>> | undefined;\n if (socket?.connectionStateRecovery) {\n throw new TypeError(\n \"createServer: socket.connectionStateRecovery is refused: Socket.IO's connection state recovery restores a reconnecting socket's principal and rooms without authenticating it again, so a revoked session or a lowered grant would come back. quickdraw clients resume by revision on every reconnect; remove the option\",\n );\n }\n}\n\n/**\n * Runs every service's `onRoomLeave` and the server's own for every socket\n * that leaves app rooms, each in a detached unit of work of the dispatcher\n * of its own; what one throws is logged, and the others still run.\n */\nfunction listenForLeaves<P extends Principal>(\n dispatcher: Dispatcher,\n handler: RoomLeaveHandler<P> | undefined,\n): void {\n const services = [...dispatcher.registry.services.values()];\n const hooks: RoomLeaveHook[] = services.flatMap((service) =>\n service.onRoomLeave === undefined\n ? []\n : [{ owner: service.name, handler: service.onRoomLeave }],\n );\n if (handler !== undefined) {\n hooks.push({ owner: \"createServer\", handler: handler as RoomLeaveHandler });\n }\n liveOf(dispatcher)?.realtime.onRoomLeave(\n hooks,\n async (fn) => await dispatcher.run(fn, { detached: true }),\n );\n}\n\n/** The HTTP transport, mounted on `app` when there is one. */\nfunction mountRouter<P extends Principal>(\n options: ServerOnlyOptions<P>,\n base: Omit<Parameters<typeof httpRouterSettings>[1], \"cookieAsToken\">,\n): HttpRouter | undefined {\n if (options.http === false) {\n return undefined;\n }\n // socketAuth's authenticate takes the session cookie as auth.token; any other gets it beside.\n const cookieAsToken = socketAuthOf(options.auth?.authenticate) !== undefined;\n const router = httpRouter(httpRouterSettings(options.http ?? {}, { ...base, cookieAsToken }));\n options.app?.use(router);\n return router;\n}\n\nfunction notFound(_req: IncomingMessage, res: ServerResponse): void {\n res.statusCode = 404;\n res.end();\n}\n\n/**\n * Warns, once at startup, when an admin screen edits users' service-wide\n * grants (`admin.handlers(c, { grants: true })`) but `auth.serviceAccessSource`\n * does not say where they are stored: a lowered grant then stays on the\n * user's open sockets until they connect again (the final review of the\n * release candidates).\n */\nfunction warnUnsourcedGrants(\n services: readonly AnyService[],\n sourced: boolean,\n logger: Logger,\n): void {\n if (sourced) {\n return;\n }\n const editors = services\n .filter((service) =>\n Object.values(service.methods).some((method) => editsGrants(method.handler)),\n )\n .map((service) => service.name);\n if (editors.length > 0) {\n logger.warn(\n `createServer: ${editors.join(\", \")} edit users' service-wide grants (the admin kit's grants: true), but auth.serviceAccessSource does not name where they are stored, so a user whose grant is lowered keeps it on open sockets until they connect again. Set auth.serviceAccessSource: { model, column }`,\n { category: \"quickdraw.access\", services: editors },\n );\n }\n}\n\n/**\n * `options` with what the server adds to its dispatcher: the grants sink\n * right after the access sink (a flush that lowers grants revokes before its\n * frames go out), and `auth.serviceAccessSource`, which the admin kit reads.\n */\nfunction withGrants<O extends object>(\n options: O,\n grants: ReturnType<typeof createGrantsSink>,\n grantsSource: { readonly model: string; readonly column: string } | undefined,\n): O & { readonly serviceAccessSource?: { readonly model: string; readonly column: string } } {\n if ((options as { readonly serviceAccessSource?: unknown }).serviceAccessSource !== undefined) {\n throw new TypeError(\n \"createServer: name the grants column as auth.serviceAccessSource, which also refreshes the grants it stores; serviceAccessSource is createDispatcher's option\",\n );\n }\n return withServerParts(\n { ...options, ...(grantsSource === undefined ? {} : { serviceAccessSource: grantsSource }) },\n { accessSinks: grants === undefined ? [] : [grants] },\n );\n}\n\n/**\n * Serves `services` over Socket.IO and HTTP on the app's own Express app and\n * HTTP server: socket authentication, the `user:{id}` room, `qd:hello`, the\n * v5 transport (or the 4.x shim), the HTTP transport at `POST /qd/{service}/{method}`,\n * disconnect cleanup and graceful shutdown. It does not listen: the app calls\n * `server.httpServer.listen(port)`.\n *\n * @example\n * const app = express();\n * app.use(express.json());\n * const server = createServer({ app, services: [taskService], db: prisma, auth: { authenticate } });\n * server.httpServer.listen(4000);\n */\nexport function createServer<const S extends readonly AnyService[]>(\n options: ServerOptions<S>,\n): QuickdrawServer<S> {\n checkOptions(options);\n const legacyWire = resolveLegacyWire(options.legacyWire, options.services);\n const logger = options.logger ?? consoleLogger;\n warnOnAuth(options.services, options.auth, logger);\n const watchdog = prepareWatchdog(options, options.stallWatchdog);\n let refresh: ((userId: string) => Promise<ServiceGrants>) | undefined;\n const grants = createGrantsSink(options.auth, () => refresh, logger);\n const created = createDispatcher(\n withGrants(watchdog.options, grants, options.auth?.serviceAccessSource),\n );\n const calls = trackCalls(created);\n const { dispatcher } = calls;\n // In the background: a test app awaits them (`startupChecksOf`).\n startStartupChecks(dispatcher, options, logger);\n listenForLeaves(created as Dispatcher, options.onRoomLeave);\n const resolvePrincipal = createPrincipalResolver(options.auth);\n const router = mountRouter(options, { call: dispatcher.call, resolvePrincipal, logger });\n const httpServer = options.httpServer ?? createHttpServer(options.app ?? router ?? notFound);\n const sockets = createSocketServer(httpServer, {\n dispatcher,\n logger,\n resolvePrincipal,\n loadServiceAccess: options.auth?.loadServiceAccess,\n binary: options.binary === true,\n legacyWire,\n cors: options.cors,\n socket: options.socket,\n rateLimit: options.rateLimit ?? {},\n extensions: [],\n live: liveOf(created),\n loops: loopsOf(created),\n cluster: options.cluster,\n });\n refresh = (userId) => sockets.refresh(userId);\n // In-process callers (`dispatcher.caller`, `qd.caller`) load a principal's grants as the\n // handshake does, and again once this node applied new grants to a user.\n const load = options.auth?.loadServiceAccess;\n if (load !== undefined) {\n calls.loadGrantsWith({ load, version: () => sockets.regrants() });\n }\n const shutdown = closer(\n sockets,\n httpServer,\n () => calls.idle(),\n options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS,\n {\n drain: () => liveOf(created)?.drain() ?? Promise.resolve(),\n timeoutMs: options.cluster?.timeoutMs,\n },\n );\n const { onClose } = shutdown;\n onClose(sockets.stop);\n // Once stopped (its sockets leave first, and what their last events started settles while the\n // adapter still reaches the other nodes: `closer`), and once anything started after that has\n // settled too, the tracked client goes back to the dispatcher attached before.\n let closing: Promise<void> | undefined;\n const close = (): Promise<void> =>\n (closing ??= shutdown.close().then(async () => {\n await liveOf(created)?.drain();\n detachDispatcher(created);\n }));\n if (options.handleSignals === true) {\n onClose(watchSignals(close, logger));\n }\n if (watchdog.start !== undefined) {\n onClose(watchdog.start(logger).stop);\n }\n return Object.freeze({\n io: sockets.io as QuickdrawIo<PrincipalOfServices<S>>,\n httpServer,\n dispatcher,\n close,\n rotate: ({ withinMs }: RotateOptions) => sockets.rotate(withinMs),\n access: Object.freeze({\n refresh: (userId: string) => sockets.refresh(userId),\n disconnectUser: (userId: string, disconnect?: DisconnectUserOptions) =>\n sockets.disconnectUser(userId, disconnect),\n }),\n presence: dispatcher.presence,\n stream: dispatcher.stream,\n rooms: dispatcher.rooms,\n });\n}\n","// The models access depends on must be tracked (the 5.1 audit's DATA-3). The\n// write tracker keys rows by a string `id`, so a table keyed by a composite\n// `@@id([projectId, userId])` with no `id` column is never tracked: its first\n// write stops tracking it for the life of the process, with one warning. A\n// membership table of that shape (`members()` read it, `bindings.ts`\n// registered interest in it) then never revoked anything: removing a member\n// left them the live rows, collection scopes, change topics and stream feeds\n// it had let them subscribe to.\n//\n// `createServer` asks the storage adapter, at start, whether it can track\n// each model an access policy, a membership table or a `via` junction\n// depends on (`StorageAdapter.trackable`), in the background since it\n// starts synchronously. Each it cannot is named with\n// `[quickdraw:untracked-access-model]`, logged as an error in every\n// environment; a test app made with `strictWarnings` fails to start instead.\n// A probe that fails (the database down) is logged as a warning and never\n// fails the server.\n\nimport type { Logger } from \"../../contract/logger\";\nimport {\n DevWarningError,\n formatDevWarning,\n strictWarningsOf,\n type DevWarning,\n} from \"../devWarnings\";\nimport { describeError } from \"../pipeline/metrics\";\nimport { storageFor, type TrackingOptions } from \"../pipeline/tracking\";\nimport type { Registry } from \"../registry\";\nimport { modelKey, type StorageAdapter } from \"../storage\";\n\n/**\n * The models access depends on, as `modelKey` spells them, each with who\n * reads it: every policed service's own model, every membership table a\n * policy reads, and every `via` collection's junction table.\n */\nexport function accessModels(registry: Registry): Map<string, string[]> {\n const models = new Map<string, string[]>();\n const add = (model: string, reader: string): void => {\n const key = modelKey(model);\n const readers = models.get(key) ?? [];\n if (!readers.includes(reader)) {\n readers.push(reader);\n }\n models.set(key, readers);\n };\n for (const service of registry.services.values()) {\n const { access, model } = service;\n if (access !== undefined && model !== undefined) {\n add(model, `${service.name}'s access policy`);\n }\n for (const membership of access?.reads.memberships ?? []) {\n add(membership.model, `${service.name}'s access policy`);\n }\n for (const collection of service.collections.values()) {\n if (collection.scope.kind === \"via\") {\n add(collection.scope.model, `${service.name}'s ${collection.name} collection`);\n }\n }\n }\n return models;\n}\n\n/** The warning for a model access depends on that the tracker cannot key. */\nfunction untrackedWarning(model: string, readBy: readonly string[]): DevWarning {\n return {\n kind: \"untracked-access-model\",\n subject: model,\n message:\n `${model} has no id column the write tracker can key its rows by, so none of its writes are tracked, ` +\n `yet ${readBy.join(\" and \")} read it: removing a row from it never revokes the live rows, collection ` +\n `scopes, change topics and stream feeds it let someone subscribe to. Give it an id ` +\n `(id String @id @default(cuid())) and keep its pair unique with @@unique([...]) instead of a composite @@id`,\n meta: { model, readBy: [...readBy] },\n };\n}\n\n/**\n * Names each model access depends on that `storage` cannot track: logged as\n * an error, or, when `strict`, thrown as a `DevWarningError` for the first.\n * Nothing when the adapter cannot say (`trackable` is optional). A probe\n * that fails is logged as a warning; the check never rejects otherwise.\n */\nexport async function checkTrackedModels(\n registry: Registry,\n storage: StorageAdapter | undefined,\n options: { readonly logger: Logger; readonly strict: boolean },\n): Promise<void> {\n const trackable = storage?.trackable;\n if (trackable === undefined) {\n return;\n }\n const { logger, strict } = options;\n const models = [...accessModels(registry)];\n const answers = await Promise.all(\n models.map(async ([model]) => {\n try {\n return await trackable.call(storage, model);\n } catch (error) {\n logger.warn(`createServer: could not check whether ${model} is tracked`, {\n category: \"quickdraw.access\",\n model,\n error: describeError(error),\n });\n return true;\n }\n }),\n );\n for (const [index, [model, readBy]] of models.entries()) {\n if (answers[index] !== false) {\n continue;\n }\n const warning = untrackedWarning(model, readBy);\n if (strict) {\n throw new DevWarningError(warning);\n }\n logger.error(formatDevWarning(warning), {\n category: \"quickdraw.access\",\n warning: warning.kind,\n model,\n readBy: [...readBy],\n });\n }\n}\n\n/**\n * Starts `createServer`'s check of the models access depends on, in the\n * background: strict for a test app made with `strictWarnings`. The promise\n * is handled, so nothing is left unhandled when only a test awaits it.\n */\nexport function startTrackedModelsCheck(\n registry: Registry,\n options: TrackingOptions & { readonly db?: unknown },\n logger: Logger,\n): Promise<void> {\n const check = checkTrackedModels(registry, storageFor(options, options.db), {\n logger,\n strict: strictWarningsOf(options),\n });\n check.catch(() => undefined);\n return check;\n}\n","// The parts of `createServer` that outlive one call (RFC 0003 section 3): the\n// calls in flight `close()` waits for, the one shutdown however often\n// `close()` is called, the opt-in signal handlers, and the opt-in event-loop\n// stall watchdog (`observability/stallWatchdog.ts`).\n\nimport type { Server as HttpServer } from \"node:http\";\nimport type { Logger } from \"../contract/logger\";\nimport { startTrackedModelsCheck } from \"./access/trackedModels\";\nimport {\n callerGrantsOf,\n createCaller,\n setCallerGrants,\n type Caller,\n type CallerGrants,\n} from \"./caller\";\nimport { DEFAULT_CLUSTER_TIMEOUT_MS, within } from \"./cluster/acks\";\nimport type { ContractOfServices, Dispatcher, PrincipalOfServices } from \"./dispatcher\";\nimport {\n stallWatchdogSettings,\n startStallWatchdog,\n type StallWatchdog,\n type StallWatchdogOptions,\n} from \"./observability/stallWatchdog\";\nimport type { CallRecord } from \"./pipeline/metrics\";\nimport type { AnyService } from \"./service\";\nimport type { SocketServer } from \"./transports/socketServer\";\n\nexport type { StallWatchdogOptions };\n\n/** Watches `SIGTERM` and `SIGINT` until the server closes; returns the function that stops watching. */\nexport function watchSignals(close: () => Promise<void>, logger: Logger): () => void {\n const onSignal = (signal: NodeJS.Signals): void => {\n logger.info(`Received ${signal}; closing the quickdraw server`, {\n category: \"quickdraw.server\",\n });\n close().catch((error: unknown) => {\n logger.error(\"Closing the quickdraw server failed\", {\n category: \"quickdraw.server\",\n error: error instanceof Error ? error.message : String(error),\n });\n });\n };\n process.once(\"SIGTERM\", onSignal);\n process.once(\"SIGINT\", onSignal);\n return () => {\n process.off(\"SIGTERM\", onSignal);\n process.off(\"SIGINT\", onSignal);\n };\n}\n\n/** A dispatcher whose calls in flight can be awaited. */\nexport interface TrackedDispatcher<S extends readonly AnyService[]> {\n readonly dispatcher: Dispatcher<S>;\n /** Resolves once no call is in flight. */\n idle(): Promise<void>;\n /**\n * Makes the in-process callers of both dispatchers, the tracked one and\n * the one it wraps (and `qd.caller` through either), load the grants of a\n * principal that carries none through `grants`.\n */\n loadGrantsWith(grants: CallerGrants): void;\n}\n\n/**\n * Counts the calls in flight through `dispatcher`, the transports' and the\n * in-process caller's alike, so `close()` can wait for them. Its caller loads\n * grants once `loadGrantsWith` gave it where from.\n */\nexport function trackCalls<S extends readonly AnyService[]>(\n dispatcher: Dispatcher<S>,\n): TrackedDispatcher<S> {\n const running = new Set<Promise<unknown>>();\n const call: Dispatcher<S>[\"call\"] = (request) => {\n const result = dispatcher.call(request);\n running.add(result);\n const done = (): void => {\n running.delete(result);\n };\n void result.then(done, done);\n return result;\n };\n const tracked: Dispatcher<S> = Object.freeze({\n ...dispatcher,\n call,\n caller: (principal: PrincipalOfServices<S> | null) =>\n createCaller(() => call, principal, {\n grants: () => callerGrantsOf(tracked),\n }) as Caller<ContractOfServices<S>>,\n });\n return {\n dispatcher: tracked,\n async idle() {\n while (running.size > 0) {\n await Promise.allSettled([...running]);\n }\n },\n loadGrantsWith(grants) {\n setCallerGrants(tracked, grants);\n setCallerGrants(dispatcher, grants);\n },\n };\n}\n\n/** The server's `close`, and what else stops when it runs. */\nexport interface Closer {\n /** One shutdown, however often it is called. */\n readonly close: () => Promise<void>;\n /** Adds something to stop as the shutdown starts: the signal handlers, the watchdog. */\n readonly onClose: (stop: () => void) => void;\n}\n\n/** What a closing server lets settle before Socket.IO closes: the work its sockets' last events start. */\nexport interface Departure {\n /** Resolves once the live data's work in flight settled (a room's presence read from every node). */\n readonly drain: () => Promise<void>;\n /** How long it is waited for at most: `cluster.timeoutMs`. Default 1,000. */\n readonly timeoutMs?: number;\n}\n\n/** The server's `close`: one shutdown, however often it is called. */\nexport function closer(\n sockets: SocketServer,\n httpServer: HttpServer,\n idle: () => Promise<void>,\n timeoutMs: number,\n departure?: Departure,\n): Closer {\n let closing: Promise<void> | undefined;\n const stops: (() => void)[] = [];\n const shutdown = async (): Promise<void> => {\n for (const stop of stops) {\n stop();\n }\n let expire = (): void => undefined;\n const expired = new Promise<void>((resolve) => {\n expire = resolve;\n });\n const timer = setTimeout(() => {\n httpServer.closeAllConnections();\n expire();\n }, timeoutMs);\n try {\n // This node's sockets go first, while a cluster adapter still reaches the\n // other nodes: each app room a socket was in asks them whether its user\n // is still there and tells them it left, which settles (bounded) before\n // the adapter closes, instead of waiting out its `requestsTimeout`. Each\n // socket's connection is closed, as `io.close()` closes them, rather than\n // disconnected: a client told \"io server disconnect\" would not reconnect\n // (to another node, in a rolling deploy).\n for (const socket of sockets.io.sockets.sockets.values()) {\n socket.conn.close();\n }\n if (departure !== undefined) {\n const bound = departure.timeoutMs ?? DEFAULT_CLUSTER_TIMEOUT_MS;\n await within(departure.drain(), bound).catch(() => undefined);\n }\n // Closes `httpServer` once its requests end, while the calls still\n // running finish: a mutation runs to its end.\n await Promise.all([sockets.io.close(), Promise.race([idle(), expired])]);\n } finally {\n clearTimeout(timer);\n }\n };\n return {\n close: () => (closing ??= shutdown()),\n onClose: (stop) => {\n stops.push(stop);\n },\n };\n}\n\n/** The stall watchdog `createServer({ stallWatchdog })` asked for, wired to the dispatcher's records. */\nexport interface ServerWatchdog<O> {\n /** `options` with an `onCall` that gives the watchdog every record first, then the app's `onCall`. */\n readonly options: O;\n /** Starts sampling, once the server is built; `undefined` when the watchdog is off. */\n readonly start: ((logger: Logger) => StallWatchdog) | undefined;\n}\n\n/**\n * Checks the `stallWatchdog` option at once (a bad one throws before anything\n * starts) and routes the completion records to the watchdog started later.\n */\nexport function prepareWatchdog<O extends { readonly onCall?: (record: CallRecord) => void }>(\n options: O,\n option: boolean | StallWatchdogOptions | undefined,\n): ServerWatchdog<O> {\n const settings = stallWatchdogSettings(option);\n if (settings === undefined) {\n return { options, start: undefined };\n }\n let watchdog: StallWatchdog | undefined;\n const { onCall } = options;\n return {\n options: {\n ...options,\n onCall: (record: CallRecord) => {\n watchdog?.observe(record);\n onCall?.(record);\n },\n },\n start: (logger) => {\n watchdog = startStallWatchdog(settings, logger);\n return watchdog;\n },\n };\n}\n\n/** The checks each server started at start, by the server's dispatcher, which a test app awaits. */\nconst STARTUP_CHECKS = new WeakMap<object, Promise<void>>();\n\n/**\n * Starts the checks `createServer` makes at start, in the background since\n * it starts synchronously: that every model access depends on is tracked\n * (`access/trackedModels.ts`). They are kept by `dispatcher`, the server's,\n * for {@link startupChecksOf}.\n */\nexport function startStartupChecks(\n dispatcher: Pick<Dispatcher, \"registry\">,\n options: Parameters<typeof startTrackedModelsCheck>[1],\n logger: Logger,\n): void {\n STARTUP_CHECKS.set(dispatcher, startTrackedModelsCheck(dispatcher.registry, options, logger));\n}\n\n/**\n * The checks `server` started at start: resolved once they are done, or\n * rejected with the `DevWarningError` of a strict test app. `createTestApp`\n * awaits them; an app need not.\n */\nexport function startupChecksOf(server: { readonly dispatcher: object }): Promise<void> {\n return STARTUP_CHECKS.get(server.dispatcher) ?? Promise.resolve();\n}\n","// The Socket.IO server of a quickdraw server: the parser, the protocol and\n// authentication middlewares, the rate limiter and the connection handler,\n// the dispatcher's live data (entity subscriptions), plus the two pushes a\n// server sends on the app's request, `qd:rotate` and `qd:access`.\n\nimport type { Server as HttpServer } from \"node:http\";\nimport { Server, type ServerOptions } from \"socket.io\";\nimport {\n MAX_ENTITY_IDS_PER_SOCKET,\n MAX_SCOPES_PER_SOCKET,\n MAX_SUBSCRIBE_IDS,\n MAX_TOPICS_PER_SOCKET,\n PROTOCOL_VERSION,\n} from \"../../protocol/version\";\nimport { QUICKDRAW_VERSION } from \"../../version\";\nimport { createReplyMeter } from \"./ack\";\nimport type { ResolvePrincipal, ServerAuth, ServiceGrants } from \"./auth\";\nimport {\n applySocketRateLimit,\n authMiddleware,\n protocolMiddleware,\n type SocketLimitContext,\n type SocketRateLimitOptions,\n} from \"./middleware\";\nimport {\n adapterProbe,\n disconnectUser,\n listenForDisconnects,\n listenForGrants,\n refreshGrants,\n regrantsOf,\n registerClusterDeployment,\n rotate,\n serveBroadcasts,\n type ClusterOptions,\n type DisconnectUserOptions,\n type LiveData,\n} from \"./pushes\";\nimport {\n onConnection,\n type ConnectionSettings,\n type ServerHello,\n type SocketExtension,\n} from \"./socketio\";\nimport type { QuickdrawIo, SocketContext } from \"./types\";\n\nexport type { SocketRateLimitOptions } from \"./middleware\";\nexport type { ClusterOptions, DisconnectUserOptions } from \"./pushes\";\nexport type { QuickdrawIo } from \"./types\";\nexport { resolveLegacyWire, type LegacyWireOptions } from \"./legacy\";\n// `createServer` checks the deployment before anything starts, within its import budget.\nexport { checkKeyPrefix } from \"../cluster/deployment\";\n\n/**\n * Socket.IO server options `createServer` passes through; it sets `parser`\n * and `cors` itself, and refuses `connectionStateRecovery`: a recovered\n * socket would come back with its principal and rooms without\n * authenticating again.\n */\nexport type SocketOptions = Partial<\n Omit<ServerOptions, \"parser\" | \"cors\" | \"connectionStateRecovery\">\n>;\n\n/** Socket.IO's CORS setting for the handshake and polling requests. */\nexport type SocketCors = Partial<ServerOptions>[\"cors\"];\n\n/** Settings of {@link createSocketServer}. */\nexport interface SocketServerSettings extends Omit<SocketContext, \"meter\"> {\n readonly resolvePrincipal: ResolvePrincipal;\n readonly loadServiceAccess: ServerAuth[\"loadServiceAccess\"];\n readonly binary: boolean;\n /** The legacy shim's settings, or `undefined` when 4.x clients are refused. */\n readonly legacyWire: ConnectionSettings[\"legacyWire\"] | undefined;\n readonly cors: SocketCors;\n readonly socket: SocketOptions | undefined;\n readonly rateLimit: SocketRateLimitOptions | false;\n readonly extensions: readonly SocketExtension[];\n /** The dispatcher's live data: its extension serves `qd:sub`, and it is given the server. */\n readonly live?: LiveData;\n /** Where a cluster's shared state lives, behind a cluster adapter (`createServer`'s `cluster`). */\n readonly cluster?: ClusterOptions;\n /** The dispatcher's loop watch, which counts the rate limiter's refusals too. */\n readonly loops?: SocketLimitContext[\"loops\"];\n}\n\n/** The Socket.IO side of a quickdraw server. */\nexport interface SocketServer {\n readonly io: QuickdrawIo;\n /** Tells every client to reconnect at a random moment within `withinMs`. */\n rotate(withinMs: number): void;\n /** Reloads `userId`'s service grants into their sockets' principals and sends them `qd:access`. */\n refresh(userId: string): Promise<ServiceGrants>;\n /**\n * How many times this process applied new grants to a user (`refresh`,\n * another node's broadcast): the server's in-process callers load the\n * grants they hold again once it rises.\n */\n regrants(): number;\n /** Disconnects `userId`'s sockets (of one session) on every node; returns how many this node ended. */\n disconnectUser(userId: string, options?: DisconnectUserOptions): number;\n /** Stops what runs in the background (a degraded node's probes): the server closes. */\n stop(): void;\n}\n\n/** The part of `qd:hello` every socket of the server shares; `onConnection` adds the principal's. */\nfunction helloFrame(settings: SocketServerSettings): ServerHello {\n const { limits } = settings.dispatcher;\n return Object.freeze({\n protocol: PROTOCOL_VERSION,\n server: QUICKDRAW_VERSION,\n // New each time a server starts: a client tells a restart from a blip by it.\n serverId: crypto.randomUUID(),\n limits: Object.freeze({\n maxInFlightQueries: limits.maxInFlightQueries,\n maxQueuedQueries: limits.maxQueuedQueries,\n maxSubscribeIds: MAX_SUBSCRIBE_IDS,\n callTimeoutMs: limits.callTimeoutMs,\n subscriptions: Object.freeze({\n maxInFlight: limits.subscriptions.maxInFlight,\n maxQueued: limits.subscriptions.maxQueued,\n maxEntityIds: MAX_ENTITY_IDS_PER_SOCKET,\n maxScopes: MAX_SCOPES_PER_SOCKET,\n maxTopics: MAX_TOPICS_PER_SOCKET,\n }),\n }),\n features: Object.freeze(settings.binary ? [\"binary\"] : []),\n });\n}\n\n/** Attaches a Socket.IO server to `httpServer` and serves the dispatcher over it. */\nexport function createSocketServer(\n httpServer: HttpServer,\n settings: SocketServerSettings,\n): SocketServer {\n const meter = createReplyMeter(settings.binary);\n const io: QuickdrawIo = new Server(httpServer, {\n ...settings.socket,\n ...(settings.cors === undefined ? {} : { cors: settings.cors }),\n ...(meter.parser === undefined ? {} : { parser: meter.parser }),\n });\n // Before anything sends to or hears from the other nodes: every event carries the deployment.\n registerClusterDeployment(io, settings.cluster);\n const context: SocketContext = {\n dispatcher: settings.dispatcher,\n logger: settings.logger,\n meter,\n };\n const probe = adapterProbe(io, settings.socket?.adapter !== undefined);\n const broadcasts = serveBroadcasts(io, settings.logger, settings.cluster?.timeoutMs);\n settings.live?.attach(io, probe, settings.cluster, broadcasts);\n listenForGrants(io, settings.live, settings.logger);\n listenForDisconnects(io, settings.logger);\n io.use(protocolMiddleware(settings.legacyWire !== undefined, context));\n io.use(authMiddleware(settings.resolvePrincipal, context));\n // Before the connection handler: the limiter's `socket.use` middleware must\n // come before the legacy shim's, so it counts each 4.x call before it runs.\n if (settings.rateLimit !== false) {\n applySocketRateLimit(io, settings.rateLimit, { ...context, loops: settings.loops });\n }\n io.on(\n \"connection\",\n onConnection({\n ...context,\n hello: helloFrame(settings),\n extensions:\n settings.live === undefined\n ? settings.extensions\n : [...settings.extensions, settings.live.extension],\n legacyExtensions: settings.live === undefined ? [] : [settings.live.legacyExtension],\n legacyCallers: new Set(),\n // A server that refuses 4.x clients has no 4.x socket to read it.\n legacyWire: settings.legacyWire ?? { aliases: new Map() },\n }),\n );\n return {\n io,\n rotate: (withinMs) => rotate(io, withinMs),\n refresh: (userId) =>\n refreshGrants(\n {\n io,\n load: settings.loadServiceAccess,\n live: settings.live,\n probe,\n broadcasts,\n },\n userId,\n ),\n regrants: () => regrantsOf(io),\n disconnectUser: (userId, options) =>\n disconnectUser(io, probe, settings.logger, userId, options),\n stop: () => {\n broadcasts.close();\n },\n };\n}\n","// The 4.x legacy shim (RFC 0003 section 8.5). A 4.x client connects without\n// `auth.qd` and calls a method by emitting `\"{service}:{method}\"` with its\n// payload and an acknowledgement (4.1 `src/server/ServiceRegistry.ts:277-406`).\n// With `legacyWire: true` such a socket gets one `socket.use` middleware\n// instead of the v5 listeners: it maps each call onto the dispatcher with\n// transport `\"legacy\"` and answers in the 4.x `ServiceResponse` shape\n// (4.1 `src/shared/types.ts:88-90`), with the error code's HTTP status as\n// the numeric `code`.\n//\n// The shim is a middleware, not an `onAny` listener, because Socket.IO runs\n// `onAny` listeners before any middleware: the rate limiter, whose middleware\n// is registered first, would count a call only after the shim had started it,\n// and its 429 would then take the call's acknowledgement.\n//\n// A call runs with the `ctx.socketId` and `ctx.rooms` of the socket it\n// arrived on, and the socket gets the live data's legacy extension, which\n// leaves its app rooms on disconnect (`socketio.ts`).\n//\n// A service renamed during the migration keeps its old name for the 4.x\n// clients still calling it: `legacyWire: { aliases: { old: \"new\" } }` maps\n// an event's service prefix onto the service it now names. The call runs as\n// that service's method (its validation, access and `onCall`), and its log\n// names the alias. Protocol 5, HTTP and MCP calls are never aliased.\n//\n// The shim serves request/response calls only. 4.x subscriptions,\n// collections and channels are not served: their events match no method, so\n// the shim passes them on to whatever else listens. The stock decoder reads\n// both protocols, so the shim needs no parser of its own.\n\nimport { httpStatus, toWire, type ErrorCode } from \"../../protocol/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { DispatchResult } from \"../pipeline/request\";\nimport type { Registry } from \"../registry\";\nimport type { Principal } from \"../types\";\nimport { acknowledge, type Acknowledge } from \"./ack\";\nimport type { QuickdrawServerSocket, SocketContext } from \"./types\";\n\n/** 4.x's `ServiceResponse`, the shape every reply of the shim takes. */\nexport type LegacyReply =\n | { readonly success: true; readonly data: unknown }\n | { readonly success: false; readonly error: string; readonly code: number };\n\n/** A 4.x failure with the HTTP status of `code`. */\nexport function legacyFailure(code: ErrorCode, error: string): LegacyReply {\n return { success: false, error, code: httpStatus(code) };\n}\n\n/** A dispatch result in the 4.x reply shape. An `INTERNAL` failure keeps the generic message. */\nexport function toLegacyReply(result: DispatchResult): LegacyReply {\n if (!result.ok) {\n const wire = toWire(result.error);\n return legacyFailure(wire.code, wire.message);\n }\n return { success: true, data: result.notModified === true ? undefined : result.data };\n}\n\nconst LEGACY_INTERNAL: LegacyReply = Object.freeze(legacyFailure(\"INTERNAL\", \"Internal error\"));\n\n/** `createServer`'s `legacyWire` as an object: what the shim serves beyond the services' own names. */\nexport interface LegacyWireOptions {\n /**\n * Old service names 4.x clients still call, each mapped to the registered\n * service it now names, e.g. `{ taskService: \"cardService\" }`. A key may\n * not be a registered service's name or contain `:`.\n */\n readonly aliases?: Readonly<Record<string, string>>;\n}\n\n/** The legacy shim's settings, resolved from `createServer`'s `legacyWire`. */\nexport interface LegacyWire {\n /** Old service name to the registered service's name. */\n readonly aliases: ReadonlyMap<string, string>;\n}\n\n/**\n * Resolves `createServer`'s `legacyWire`: `undefined` when the shim is off.\n * Throws a `TypeError` naming the entry for an unknown key or an alias that\n * is empty, contains `:`, shadows a service or names no service.\n */\nexport function resolveLegacyWire(\n option: boolean | LegacyWireOptions | undefined,\n registered: readonly { readonly name: string }[],\n): LegacyWire | undefined {\n if (option === undefined || option === false) {\n return undefined;\n }\n if (option === true) {\n return { aliases: new Map() };\n }\n if (typeof option !== \"object\" || option === null || Array.isArray(option)) {\n throw new TypeError(\"createServer: legacyWire must be a boolean or { aliases }\");\n }\n for (const key of Object.keys(option)) {\n if (key !== \"aliases\") {\n throw new TypeError(`createServer: legacyWire has an unknown option \"${key}\"`);\n }\n }\n const { aliases = {} } = option;\n if (typeof aliases !== \"object\" || aliases === null || Array.isArray(aliases)) {\n throw new TypeError(\"createServer: legacyWire.aliases must map old service names to new ones\");\n }\n const services = new Set(registered.map((service) => service.name));\n const resolved = new Map<string, string>();\n for (const [alias, target] of Object.entries(aliases)) {\n const entry = `legacyWire.aliases[${JSON.stringify(alias)}]`;\n if (alias === \"\" || alias.includes(\":\")) {\n throw new TypeError(`createServer: ${entry} must be a service name without \":\"`);\n }\n if (services.has(alias)) {\n throw new TypeError(\n `createServer: ${entry} is a registered service's own name, so it cannot be an alias`,\n );\n }\n if (typeof target !== \"string\" || !services.has(target)) {\n throw new TypeError(\n `createServer: ${entry} names ${JSON.stringify(target)}, which is not a registered service`,\n );\n }\n resolved.set(alias, target);\n }\n return { aliases: resolved };\n}\n\n/**\n * The 4.x callers seen so far, one key per service name called, method and\n * principal kind. Each is logged once, so the clients still on 4.x (and\n * still on an old name) can be found.\n */\nexport type LegacyCallers = Set<string>;\n\ninterface LegacyTarget {\n /** The registered service, after aliases. */\n readonly service: string;\n readonly method: string;\n /** The old name the client called the service by, when it was an alias. */\n readonly alias?: string;\n}\n\n/** The registered method a 4.x event names, through `aliases`, or `undefined`. */\nfunction targetOf(\n event: unknown,\n registry: Registry,\n aliases: ReadonlyMap<string, string>,\n): LegacyTarget | undefined {\n if (typeof event !== \"string\") {\n return undefined;\n }\n const colon = event.indexOf(\":\");\n const called = event.slice(0, colon);\n const method = event.slice(colon + 1);\n const service = aliases.get(called);\n if (colon <= 0 || registry.find(service ?? called, method) === undefined) {\n return undefined;\n }\n return service === undefined ? { service: called, method } : { service, method, alias: called };\n}\n\nfunction principalKind(principal: Principal | null): string {\n if (principal === null) {\n return \"anonymous\";\n }\n return principal.kind ?? \"unspecified\";\n}\n\nfunction noteCaller(\n context: SocketContext,\n seen: LegacyCallers,\n target: LegacyTarget,\n principal: Principal | null,\n): void {\n const kind = principalKind(principal);\n const { service, method, alias } = target;\n const key = `${alias ?? service}\\u0000${method}\\u0000${kind}`;\n if (seen.has(key)) {\n return;\n }\n seen.add(key);\n const as = alias === undefined ? \"\" : ` as ${alias}.${method}`;\n context.logger.warn(`A 4.x client called ${service}.${method}${as} through the legacy shim`, {\n category: \"quickdraw.legacy\",\n ...target,\n principalKind: kind,\n });\n}\n\nfunction serve(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n calls: Set<AbortController>,\n call: {\n readonly service: string;\n readonly method: string;\n readonly input: unknown;\n readonly ack: Acknowledge;\n },\n): void {\n const controller = new AbortController();\n calls.add(controller);\n const report = (error: unknown): void => {\n context.logger.error(\"A 4.x call's reply could not be encoded; it was answered with 500\", {\n category: \"quickdraw.legacy\",\n socketId: socket.id,\n error: describeError(error),\n });\n };\n const release = (): void => {\n calls.delete(controller);\n };\n void context.dispatcher\n .call({\n service: call.service,\n method: call.method,\n input: call.input,\n principal: socket.data.principal,\n transport: \"legacy\",\n connectionId: socket.id,\n signal: controller.signal,\n respond: (result) =>\n acknowledge(context.meter, call.ack, toLegacyReply(result), LEGACY_INTERNAL, report),\n })\n .then(release, release);\n}\n\n/**\n * Serves a 4.x socket: one `socket.use` middleware for its calls, the\n * `auth:info` event 4.x clients read their identity from\n * (4.1 `src/server/createServer.ts:134-140`), and cancellation of its\n * calls on disconnect. Call it from the `connection` handler, after the rate\n * limiter's middleware is in place, so the limiter sees each call first. A\n * call the shim serves goes no further; any other event passes on. An event\n * whose service prefix is one of `wire.aliases` runs as the service it maps\n * to; `auth:info` lists grants by the services' own names only.\n */\nexport function attachLegacyShim(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n seen: LegacyCallers,\n wire: LegacyWire,\n): void {\n const calls = new Set<AbortController>();\n socket.use((packet: unknown[], next) => {\n const [event, ...args] = packet;\n const ack = args.at(-1);\n const target = targetOf(event, context.dispatcher.registry, wire.aliases);\n if (target === undefined || typeof ack !== \"function\") {\n next();\n return;\n }\n noteCaller(context, seen, target, socket.data.principal);\n const input = args.length > 1 ? args[0] : undefined;\n const { service, method } = target;\n serve(socket, context, calls, { service, method, input, ack: ack as Acknowledge });\n });\n socket.on(\"disconnect\", () => {\n for (const controller of calls) {\n controller.abort();\n }\n calls.clear();\n });\n const { principal } = socket.data;\n socket.emit(\"auth:info\", {\n userId: principal?.userId ?? null,\n serviceAccess: principal?.serviceAccess ?? {},\n principalType: principal?.kind,\n });\n}\n","// What every socket passes before `connection` (RFC 0003 section 8.1): the\n// protocol check, then authentication. And the socket rate limiter carried\n// over from 4.1 (`../rateLimit.ts`), which answers each socket in its own\n// protocol's reply shape.\n\nimport type { ExtendedError } from \"socket.io\";\nimport { CLIENT_EVENTS } from \"../../contract/names\";\nimport type { Failure } from \"../../protocol/envelope\";\nimport {\n PROTOCOL_MISMATCH,\n PROTOCOL_VERSION,\n isQdHandshake,\n type AuthenticationRefused,\n type ProtocolMismatch,\n} from \"../../protocol/version\";\nimport type { LoopWatch } from \"../devWarnings\";\nimport { describeError } from \"../pipeline/metrics\";\nimport {\n applyRateLimitMiddleware,\n createRateLimiter,\n type RateLimiter,\n type RateLimitOptions,\n} from \"../rateLimit\";\nimport { isRefusal, socketSessionExpiryOf, type ResolvePrincipal } from \"./auth\";\nimport { legacyFailure } from \"./legacy\";\nimport type { QuickdrawIo, QuickdrawServerSocket, SocketContext } from \"./types\";\n\ntype Next = (error?: ExtendedError) => void;\n\n/** A refused handshake: Socket.IO sends `message` and `data` as the client's `connect_error`. */\nfunction refusal(message: string, data: ProtocolMismatch | AuthenticationRefused): ExtendedError {\n const error: ExtendedError = new Error(message);\n error.data = data;\n return error;\n}\n\nconst MISMATCH: ProtocolMismatch = Object.freeze({\n code: PROTOCOL_MISMATCH,\n expected: PROTOCOL_VERSION,\n});\n\nconst UNAUTHENTICATED: AuthenticationRefused = Object.freeze({ code: \"UNAUTHENTICATED\" });\n\n/**\n * Reads the handshake's `auth.qd`. Protocol 5 is served. A client without\n * `auth.qd` is a 4.x client: the legacy shim serves it when `legacyWire` is\n * on, and otherwise it is refused, like a client that names another protocol\n * or sends a malformed `qd`, with `{ code: \"PROTOCOL_MISMATCH\", expected: 5 }`\n * as the `connect_error` data.\n */\nexport function protocolMiddleware(\n legacyWire: boolean,\n context: Pick<SocketContext, \"logger\">,\n): (socket: QuickdrawServerSocket, next: Next) => void {\n return (socket, next) => {\n const auth: unknown = socket.handshake.auth;\n const qd =\n typeof auth === \"object\" && auth !== null ? (auth as { qd?: unknown }).qd : undefined;\n if (isQdHandshake(qd) && qd.protocol === PROTOCOL_VERSION) {\n socket.data.protocol = PROTOCOL_VERSION;\n socket.data.client = qd.client;\n next();\n return;\n }\n if (qd === undefined && legacyWire) {\n socket.data.protocol = \"legacy\";\n next();\n return;\n }\n const spoke = qd === undefined ? \"a 4.x client (no auth.qd)\" : \"another protocol\";\n context.logger.debug(`Refused a socket that speaks ${spoke}`, {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n });\n next(refusal(`This server speaks quickdraw protocol ${PROTOCOL_VERSION}`, MISMATCH));\n };\n}\n\n/** Epoch milliseconds of 2001-09-09: an expiry before it was almost surely given in seconds. */\nconst SECONDS_LIKE = 1e12;\n\n/**\n * Logs a socket refused because the session its `authenticate` recorded had\n * expired by the time the handshake ended: at debug, as a session that ran\n * out during a slow `loadPrincipal`; at warn for an expiry so old it was\n * likely given in seconds (a JWT's `exp`) where milliseconds are taken.\n */\nfunction logExpired(\n context: Pick<SocketContext, \"logger\">,\n socket: QuickdrawServerSocket,\n expiresAt: number,\n): void {\n const meta = { category: \"quickdraw.socket\", socketId: socket.id, expiresAt };\n if (expiresAt < SECONDS_LIKE) {\n context.logger.warn(\n \"Refused a socket whose recorded session expired in 1970: recordSocketSession takes a Date or epoch milliseconds, and a JWT's exp is in seconds\",\n meta,\n );\n return;\n }\n context.logger.debug(\"Refused a socket whose session expired during its handshake\", meta);\n}\n\n/**\n * Authenticates the socket and keeps its principal on `socket.data`. A\n * failure refuses the connection with \"Authentication failed\", as 4.1 did,\n * and `{ code: \"UNAUTHENTICATED\" }` as the `connect_error` data, so a client\n * can tell it from a protocol mismatch. A refusal `authenticate` makes on\n * purpose, by throwing a `QuickdrawError` with that code (a revoked session,\n * say), is the client's doing and logs at debug; any other failure at error.\n * So is a socket whose recorded session (`recordSocketSession`) expired\n * before the handshake ended: it never connects, rather than connecting and\n * being disconnected at once (the 5.1 audit's AUTH-4).\n */\nexport function authMiddleware(\n resolvePrincipal: ResolvePrincipal,\n context: Pick<SocketContext, \"logger\">,\n): (socket: QuickdrawServerSocket, next: Next) => void {\n return (socket, next) => {\n const request = {\n transport: \"socket\",\n auth: socket.handshake.auth as Readonly<Record<string, unknown>>,\n headers: socket.handshake.headers,\n socket,\n } as const;\n resolvePrincipal(request).then(\n (principal) => {\n const expiresAt = socketSessionExpiryOf(socket);\n if (expiresAt !== undefined && expiresAt <= Date.now()) {\n logExpired(context, socket, expiresAt);\n next(refusal(\"Authentication failed\", UNAUTHENTICATED));\n return;\n }\n socket.data.principal = principal;\n next();\n },\n (error: unknown) => {\n const level = isRefusal(error) ? \"debug\" : \"error\";\n context.logger[level](\"Socket authentication failed\", {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n error: describeError(error),\n });\n next(refusal(\"Authentication failed\", UNAUTHENTICATED));\n },\n );\n };\n}\n\n/** The socket rate limiter's options, as `createServer` takes them. */\nexport type SocketRateLimitOptions = Omit<RateLimitOptions, \"logger\" | \"ackPayload\">;\n\n/**\n * Events the limiter never counts: channel messages, which carry their own\n * per-socket token buckets; cancellations, since dropping one only keeps a\n * call running; entity subscriptions, which a page sends once per row it\n * mounts in batches of up to 500 ids, so a board of sixty rows would trip the\n * limiter; collection subscriptions, which a page sends once per list it\n * mounts and again to page through it, and item loads, which a board holding\n * a scope's index sends per window of up to 200 ids; topic watches, which a\n * page sends once per watching query it mounts; and stream subscriptions,\n * which a page sends once per feed it shows (RFC 0003 section 3). The ones\n * that read or authorize (`qd:sub`, `qd:col:sub`, `qd:col:items`,\n * `qd:watch`, `qd:stream:sub`) run in each socket's lane of subscription\n * work instead (`emit/lane.ts`, `limits.subscriptions`).\n */\nconst UNLIMITED_EVENTS: readonly string[] = [\n CLIENT_EVENTS.channel,\n CLIENT_EVENTS.cancel,\n CLIENT_EVENTS.sub,\n CLIENT_EVENTS.unsub,\n CLIENT_EVENTS.collectionSub,\n CLIENT_EVENTS.collectionUnsub,\n CLIENT_EVENTS.collectionItems,\n CLIENT_EVENTS.watch,\n CLIENT_EVENTS.unwatch,\n CLIENT_EVENTS.streamSub,\n CLIENT_EVENTS.streamUnsub,\n];\n\nfunction rateLimited(retryAfterMs: number): Failure {\n return {\n ok: false,\n e: { code: \"RATE_LIMITED\", message: \"Rate limit exceeded\", data: { retryAfterMs } },\n };\n}\n\nfunction isLegacy(socket: { readonly data: unknown }): boolean {\n return (socket.data as Partial<QuickdrawServerSocket[\"data\"]>).protocol === \"legacy\";\n}\n\n/** 4.1's default notice, which 4.x clients listen for; v5 clients read the acknowledgement instead. */\nfunction noticeForLegacyClients(\n limiter: RateLimiter,\n options: SocketRateLimitOptions,\n): NonNullable<RateLimitOptions[\"onRateLimitExceeded\"]> {\n const keyOf = options.keyGenerator ?? ((socket) => socket.id);\n return (socket, eventName) => {\n if (isLegacy(socket)) {\n socket.emit(\"error\", {\n code: \"RATE_LIMITED\",\n message: `Rate limit exceeded for event: ${eventName}`,\n retryAfter: limiter.getResetTime(keyOf(socket, eventName)),\n });\n }\n };\n}\n\n/** What the socket rate limiter is given: the logger, and the dispatcher's loop watch. */\nexport interface SocketLimitContext extends Pick<SocketContext, \"logger\"> {\n /** Counts each refusal, and warns in development when one socket keeps getting refused. */\n readonly loops?: Pick<LoopWatch, \"refused\">;\n}\n\n/**\n * Applies the socket rate limiter, answering a dropped call in its client's\n * reply shape. Each refusal is counted by the dispatcher's loop watch\n * (`../devWarnings.ts`).\n */\nexport function applySocketRateLimit(\n io: QuickdrawIo,\n options: SocketRateLimitOptions,\n context: SocketLimitContext,\n): void {\n const limiter = createRateLimiter({\n ...options,\n excludeEvents: [...UNLIMITED_EVENTS, ...(options.excludeEvents ?? [])],\n });\n const notice = options.onRateLimitExceeded ?? noticeForLegacyClients(limiter, options);\n applyRateLimitMiddleware(io, limiter, {\n logger: context.logger,\n keyGenerator: options.keyGenerator,\n onRateLimitExceeded: (socket, eventName) => {\n context.loops?.refused(socket.id, eventName);\n notice(socket, eventName);\n },\n ackPayload: (socket, _eventName, retryAfterMs) =>\n isLegacy(socket)\n ? legacyFailure(\"RATE_LIMITED\", \"Rate limit exceeded\")\n : rateLimited(retryAfterMs),\n });\n}\n","// The Valkey (or Redis) clients of a node's Socket.IO Redis adapter, when\n// their connection drops and comes back (the pack H finale review):\n//\n// - while the subscribing client is disconnected, nothing other nodes\n// publish reaches this node: their frames to its sockets are gone, and\n// Valkey does not keep them. So when that client is ready again, this\n// node's sockets get `qd:rotate` with a window of `RESYNC_WITHIN_MS`: each\n// client reconnects at a random moment within it and subscribes again,\n// holding its revisions, and behind a cluster a subscription always reads\n// (a collection resume reads a page), so it catches up;\n// - the adapter publishes without waiting for the result, and node-redis 5\n// and later reject a command that waited in the queue of a disconnected\n// client past their command timeout (5 seconds): an outage longer than\n// that would turn every frame published meanwhile into an unhandled\n// rejection, which ends a Node process by default. A failed publish is\n// logged once per outage instead (the other nodes miss that message; their\n// own subscriptions coming back re-sync their clients the same way).\n//\n// Both wirings are watched: an adapter given as `socket.adapter`, from\n// `createServer`, and `setupRedisAdapter`'s, once it is set. An adapter an\n// app sets later with `io.adapter(...)` itself is not.\n\nimport type { Logger } from \"../../contract/logger\";\nimport { SERVER_EVENTS } from \"../../contract/names\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { QuickdrawIo } from \"../transports/types\";\n\n/** The window this node's clients reconnect within once its Valkey subscription is back. */\nexport const RESYNC_WITHIN_MS = 2000;\n\ninterface Emitter {\n on(event: string, listener: (...args: unknown[]) => void): unknown;\n}\n\nfunction isEmitter(value: unknown): value is Emitter {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { readonly on?: unknown }).on === \"function\"\n );\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { readonly then?: unknown }).then === \"function\"\n );\n}\n\n/** Clients already watched: a server and `setupRedisAdapter` may both find one. */\nconst watched = new WeakSet<object>();\n\n/** Sends this node's sockets `qd:rotate` each time the subscribing client is ready again. */\nfunction resyncOnReady(io: QuickdrawIo, subClient: Emitter, logger: Logger): void {\n subClient.on(\"ready\", () => {\n logger.info(\n \"This node's Valkey subscription is back; its clients reconnect to catch up on what it missed\",\n { category: \"quickdraw.cluster\", withinMs: RESYNC_WITHIN_MS },\n );\n io.local.emit(SERVER_EVENTS.rotate, { withinMs: RESYNC_WITHIN_MS });\n });\n}\n\n/** Logs a publish the client failed, once per outage, instead of leaving its rejection unhandled. */\nfunction guardPublishes(pubClient: object, logger: Logger): void {\n const target = pubClient as { publish?: unknown };\n const publish = target.publish;\n if (typeof publish !== \"function\") {\n return;\n }\n let reported = false;\n target.publish = function guardedPublish(this: unknown, ...args: unknown[]): unknown {\n const sent: unknown = Reflect.apply(publish, this, args);\n if (isThenable(sent)) {\n sent.then(undefined, (error: unknown) => {\n if (!reported) {\n reported = true;\n logger.warn(\n \"Valkey did not take a message for the other nodes in time; it was dropped, and they catch up once their own subscriptions are back\",\n { category: \"quickdraw.cluster\", error: describeError(error) },\n );\n }\n });\n }\n return sent;\n };\n if (isEmitter(pubClient)) {\n pubClient.on(\"ready\", () => {\n reported = false;\n });\n }\n}\n\n/**\n * Watches the clients of `io`'s Socket.IO Redis adapter, when it has one\n * (`pubClient` and `subClient`): a subscription that comes back re-syncs\n * this node's sockets, and a failed publish is logged, not left unhandled.\n * Does nothing for another adapter, and watches a client once.\n */\nexport function watchAdapterClients(io: QuickdrawIo, logger: Logger): void {\n const adapter = io.sockets.adapter as {\n readonly pubClient?: unknown;\n readonly subClient?: unknown;\n };\n const { pubClient, subClient } = adapter;\n if (isEmitter(subClient) && !watched.has(subClient)) {\n watched.add(subClient);\n resyncOnReady(io, subClient, logger);\n }\n if (typeof pubClient === \"object\" && pubClient !== null && !watched.has(pubClient)) {\n watched.add(pubClient);\n guardPublishes(pubClient, logger);\n }\n}\n","// Answered broadcasts to the other nodes of a cluster (the pack H finale\n// review): an access change, or a user's reloaded grants, is broadcast and\n// waited for until every other node has applied it, so the flush that caused\n// it sends its frames only once no node still holds what it revoked.\n//\n// That wait is in line with the node's flushes: they run one after another\n// (`../uow/flush.ts`), so every flush behind an access change waits with it.\n// A node that does not answer (frozen, killed without its Valkey connection\n// closing yet, an old version during a rolling deploy) would put\n// `cluster.timeoutMs` on every access-changing flush, and Valkey down would\n// hold even the frames to a node's own sockets. So:\n//\n// - while the publishing client is not connected, nothing waits: the\n// broadcast is sent unanswered (it waits in the client's queue);\n// - after one broadcast was not answered in time, broadcasts stop waiting\n// (one error logged, \"degraded\"), and a probe is broadcast every second\n// until every node answers one, which ends it (one info logged).\n//\n// Broadcasts sent unanswered stay fail-open, as a timed-out wait always was:\n// a slower node may hold a revoked socket in a room until it applies the\n// change, and that socket may get the flush's frames meanwhile.\n//\n// Every broadcast and probe carries the server's deployment\n// (`deployment.ts`). A node answers every probe, whatever its deployment: a\n// probe carries nothing, and leaving one unanswered would keep a deployment\n// that shares the channels degraded.\n\nimport type { Logger } from \"../../contract/logger\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { QuickdrawIo } from \"../transports/types\";\nimport { answerOf, DEFAULT_CLUSTER_TIMEOUT_MS, within } from \"./acks\";\nimport { watchAdapterClients } from \"./adapterClients\";\nimport { clusterClientOf } from \"./counter\";\nimport { tagged } from \"./deployment\";\n\n/** The server-to-server event a degraded node probes the others with; each answers it at once. */\nexport const PROBE_EVENT = \"quickdraw:probe\";\n\n/** How often a degraded node probes the others. */\nexport const PROBE_MS = 1000;\n\n/** A node's answered broadcasts to the rest of its cluster. */\nexport interface ClusterBroadcasts {\n /**\n * Broadcasts `event` with `payload` and resolves once every other node\n * answered, at most `timeoutMs`; at once, unanswered, while the publishing\n * client is not connected or the broadcasts are degraded. The payload\n * goes out tagged with the server's deployment.\n */\n broadcast(event: string, payload: object): Promise<void>;\n /** True while broadcasts do not wait for answers. */\n degraded(): boolean;\n /** Stops probing: the server closes. */\n close(): void;\n}\n\n/** Options of {@link createClusterBroadcasts}. */\nexport interface ClusterBroadcastsOptions {\n readonly io: QuickdrawIo;\n readonly logger: Logger;\n /** How long a broadcast waits for every node's answer. Default 1,000. */\n readonly timeoutMs?: number;\n /** How often a degraded node probes. Default {@link PROBE_MS}; tests pass their own. */\n readonly probeMs?: number;\n}\n\n/** False while the adapter's publishing client says it is not connected. */\nfunction publisherReady(io: QuickdrawIo): boolean {\n const adapter = io.sockets.adapter as { readonly pubClient?: unknown };\n return clusterClientOf(adapter.pubClient)?.isReady !== false;\n}\n\n/** Creates the answered broadcasts of the server `io`. */\nexport function createClusterBroadcasts(options: ClusterBroadcastsOptions): ClusterBroadcasts {\n const { io, logger } = options;\n const timeoutMs = options.timeoutMs ?? DEFAULT_CLUSTER_TIMEOUT_MS;\n const probeMs = options.probeMs ?? PROBE_MS;\n let down = false;\n let probing = false;\n let closed = false;\n let timer: ReturnType<typeof setInterval> | undefined;\n\n const stopProbing = (): void => {\n clearInterval(timer);\n timer = undefined;\n };\n\n const probe = async (): Promise<void> => {\n if (probing || !publisherReady(io)) {\n return;\n }\n probing = true;\n try {\n await within(io.serverSideEmitWithAck(PROBE_EVENT, tagged(io, {})), timeoutMs);\n if (down) {\n down = false;\n stopProbing();\n logger.info(\"Every node answers broadcasts again; access changes wait for them again\", {\n category: \"quickdraw.cluster\",\n });\n }\n } catch {\n // Still degraded: the next probe tries again.\n } finally {\n probing = false;\n }\n };\n\n const degrade = (error: unknown): void => {\n if (down) {\n return;\n }\n down = true;\n logger.error(\n \"A node did not answer a broadcast in time; this node sends access changes without waiting for the other nodes until every node answers a probe\",\n { category: \"quickdraw.cluster\", timeoutMs, error: describeError(error) },\n );\n if (!closed) {\n timer = setInterval(() => {\n void probe();\n }, probeMs);\n timer.unref?.();\n }\n };\n\n return Object.freeze({\n async broadcast(event: string, payload: object): Promise<void> {\n const sent = tagged(io, payload);\n if (down || !publisherReady(io)) {\n io.serverSideEmit(event, sent);\n return;\n }\n try {\n await within(io.serverSideEmitWithAck(event, sent), timeoutMs);\n } catch (error) {\n degrade(error);\n }\n },\n degraded: () => down,\n close(): void {\n closed = true;\n stopProbing();\n },\n });\n}\n\n/** Answers other nodes' probes on `io`: at once, as a node that is up does, whatever their deployment. */\nexport function answerProbes(io: QuickdrawIo): void {\n io.on(PROBE_EVENT, (...rest: unknown[]) => {\n answerOf(rest)(true);\n });\n}\n\n/**\n * What a server keeps with the other nodes of its cluster: its answered\n * broadcasts, its answers to their probes, and a watch on its adapter's\n * Valkey clients (`./adapterClients.ts`).\n */\nexport function serveBroadcasts(\n io: QuickdrawIo,\n logger: Logger,\n timeoutMs: number | undefined,\n): ClusterBroadcasts {\n answerProbes(io);\n watchAdapterClients(io, logger);\n return createClusterBroadcasts({ io, logger, timeoutMs });\n}\n","// What a quickdraw server pushes on the app's request, and how the other\n// nodes of a cluster hear of it (RFC 0003 sections 4.4 and 8.3):\n//\n// - `qd:rotate`: every client reconnects within a jitter window;\n// - `server.access.refresh(userId)`: the user's grants are reloaded, put in\n// the principal of their sockets, sent to them as `qd:access`, and their\n// entity subscriptions are resolved again (a lost `Admin` grant can end\n// them). Behind a cluster adapter the reloaded grants are broadcast, so\n// every node updates its own sockets of the user;\n// - `server.access.disconnectUser(userId, { sessionId? })`: the user's\n// sockets (of one session) are disconnected, on every node.\n//\n// The adapter probe tells the live data whether rooms are local: true while\n// the server runs the in-memory adapter it was created with. Every event to\n// the other nodes carries this server's deployment, and a node applies only\n// its own deployment's (`../cluster/deployment.ts`).\n\nimport type { Logger } from \"../../contract/logger\";\nimport { SERVER_EVENTS, userRoom } from \"../../contract/names\";\nimport { emitToNodes, onNodeEvent } from \"../cluster/deployment\";\nimport type { ClusterBroadcasts } from \"../cluster/broadcasts\";\nimport type { ClusterOptions } from \"../cluster/revisions\";\nimport type { AdapterProbe } from \"../emit/hub\";\nimport { describeError } from \"../pipeline/metrics\";\nimport {\n socketSessionExpiryOf,\n socketSessionOf,\n type ServerAuth,\n type ServiceGrants,\n} from \"./auth\";\nimport type { SocketExtension } from \"./socketio\";\nimport type { QuickdrawIo, QuickdrawServerSocket } from \"./types\";\n\nexport type { ClusterOptions } from \"../cluster/revisions\";\nexport { serveBroadcasts } from \"../cluster/broadcasts\";\nexport { registerClusterDeployment } from \"../cluster/deployment\";\n\n/** The server-to-server event reloaded grants are broadcast on behind a cluster adapter. */\nexport const GRANTS_EVENT = \"quickdraw:grants\";\n\n/** The server-to-server event `server.access.disconnectUser` is broadcast on behind a cluster adapter. */\nexport const DISCONNECT_USER_EVENT = \"quickdraw:disconnect-user\";\n\n/** Options of `server.access.disconnectUser`. */\nexport interface DisconnectUserOptions {\n /** End only the sockets that authenticated with this session (`recordSocketSession`). */\n readonly sessionId?: string;\n /** Why, for the log. */\n readonly reason?: string;\n}\n\n/** What the socket server needs of its dispatcher's live data (`emit/live.ts`). */\nexport interface LiveData {\n readonly extension: SocketExtension;\n /** What a 4.x socket of the legacy shim gets instead of `extension`. */\n readonly legacyExtension: SocketExtension;\n attach(\n io: QuickdrawIo,\n probe: AdapterProbe,\n cluster?: ClusterOptions,\n broadcasts?: ClusterBroadcasts,\n ): void;\n regranted(userId: string): Promise<void>;\n}\n\n/**\n * The adapter probe of `io`: local while the server's adapter is the\n * in-memory one it was created with. An adapter given in the Socket.IO\n * options (`configured`) counts as a cluster adapter, like one an app sets\n * later with `io.adapter(...)` (`setupRedisAdapter`).\n */\nexport function adapterProbe(io: QuickdrawIo, configured: boolean): AdapterProbe {\n const initial = configured ? undefined : io.adapter();\n return Object.freeze({ local: () => initial !== undefined && io.adapter() === initial });\n}\n\n/** Sends `qd:rotate` to every client. */\nexport function rotate(io: QuickdrawIo, withinMs: number): void {\n if (typeof withinMs !== \"number\" || !Number.isFinite(withinMs) || withinMs < 0) {\n throw new TypeError(\"rotate: withinMs must be a number of milliseconds, 0 or more\");\n }\n io.emit(SERVER_EVENTS.rotate, { withinMs });\n}\n\nconst REGRANTS = new WeakMap<object, number>();\n\n/**\n * How many times this process applied new grants to a user of the server\n * `io` serves (`access.refresh`, a written grant, another node's broadcast):\n * the server's in-process callers load the grants they hold again once it\n * rises (`../caller.ts`).\n */\nexport function regrantsOf(io: object): number {\n return REGRANTS.get(io) ?? 0;\n}\n\n/** Puts `serviceAccess` in the principal of this process's sockets of `userId`. */\nfunction regrant(io: QuickdrawIo, userId: string, serviceAccess: ServiceGrants): void {\n REGRANTS.set(io, regrantsOf(io) + 1);\n for (const socketId of io.sockets.adapter.rooms.get(userRoom(userId)) ?? []) {\n const socket = io.sockets.sockets.get(socketId);\n const principal = socket?.data.principal;\n if (socket !== undefined && principal?.userId === userId) {\n socket.data.principal = { ...principal, serviceAccess };\n }\n }\n}\n\n/** Disconnects this process's sockets of `userId` (of one session, with `sessionId`); returns how many. */\nfunction disconnectHere(io: QuickdrawIo, userId: string, sessionId: string | undefined): number {\n let ended = 0;\n for (const socketId of [...(io.sockets.adapter.rooms.get(userRoom(userId)) ?? [])]) {\n const socket = io.sockets.sockets.get(socketId);\n const own = socket?.data.principal?.userId === userId;\n if (\n socket !== undefined &&\n own &&\n (sessionId === undefined || socketSessionOf(socket) === sessionId)\n ) {\n socket.disconnect(true);\n ended += 1;\n }\n }\n return ended;\n}\n\n/** The longest delay a timer keeps: `setTimeout` fires a longer one at once. */\nconst MAX_TIMER_MS = 2_147_483_647;\n\n/**\n * Disconnects `socket` when the session it authenticated with expires\n * (`recordSocketSession` with an expiry, as `socketAuth` records it; the\n * 5.1 audit's AUTH-4): the client gets `io server disconnect` and does not\n * reconnect on its own, and its next connect is authenticated afresh. An\n * expiry past the longest timer is waited out in steps; the wait ends when\n * the socket disconnects. Never in the call itself, so the connection's\n * other listeners see the socket connect, then disconnect. Nothing for a\n * socket recorded without an expiry.\n */\nexport function endAtSessionExpiry(socket: QuickdrawServerSocket, logger: Logger): void {\n const expiresAt = socketSessionExpiryOf(socket);\n if (expiresAt === undefined) {\n return;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n socket.once(\"disconnect\", () => {\n clearTimeout(timer);\n });\n const wait = (): void => {\n timer = setTimeout(arm, Math.min(Math.max(expiresAt - Date.now(), 0), MAX_TIMER_MS));\n timer.unref();\n };\n const arm = (): void => {\n if (expiresAt > Date.now()) {\n wait();\n return;\n }\n logger.debug(\"Disconnected a socket whose session expired\", {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n });\n socket.disconnect(true);\n };\n wait();\n}\n\n/** A broadcast `disconnectUser`, read; `undefined` for anything else. */\nfunction readDisconnect(\n value: unknown,\n): { readonly userId: string; readonly sessionId: string | undefined } | undefined {\n const { userId, sessionId } = (value ?? {}) as {\n readonly userId?: unknown;\n readonly sessionId?: unknown;\n };\n if (typeof userId !== \"string\" || userId.length === 0) {\n return undefined;\n }\n return { userId, sessionId: typeof sessionId === \"string\" ? sessionId : undefined };\n}\n\n/**\n * `server.access.disconnectUser(userId, options)`: disconnects every socket\n * of the user on this node (only those of one session with `sessionId`), and,\n * behind a cluster adapter, tells every other node to do the same. For a\n * session the app revoked (`createAuthRoutes`' `onRevoke`): a socket keeps\n * the principal it authenticated with until it reconnects (or until its\n * session expires, when that was recorded: `endAtSessionExpiry`), and its\n * reconnect is authenticated afresh. Returns how many sockets this node ended.\n */\nexport function disconnectUser(\n io: QuickdrawIo,\n probe: AdapterProbe,\n logger: Logger,\n userId: string,\n options: DisconnectUserOptions = {},\n): number {\n if (typeof userId !== \"string\" || userId.length === 0) {\n throw new TypeError(\"access.disconnectUser: pass the user's id\");\n }\n const { sessionId, reason } = options;\n if (!probe.local()) {\n emitToNodes(\n io,\n DISCONNECT_USER_EVENT,\n sessionId === undefined ? { userId } : { userId, sessionId },\n );\n }\n const ended = disconnectHere(io, userId, sessionId);\n logger.info(\"Disconnected a user's sockets\", {\n category: \"quickdraw.socket\",\n userId,\n sockets: ended,\n ...(sessionId === undefined ? {} : { sessionId }),\n ...(reason === undefined ? {} : { reason }),\n });\n return ended;\n}\n\n/** Listens for `disconnectUser` broadcasts from other nodes of its deployment, and ends this node's sockets they name. */\nexport function listenForDisconnects(io: QuickdrawIo, logger: Logger): void {\n onNodeEvent(io, logger, DISCONNECT_USER_EVENT, (broadcast) => {\n const request = readDisconnect(broadcast);\n if (request !== undefined) {\n disconnectHere(io, request.userId, request.sessionId);\n }\n });\n}\n\n/**\n * Listens for grants other nodes of its deployment reloaded, and applies\n * them to this node's sockets; the node that reloaded them waits for the\n * answer, sent once this node's subscriptions of the user are resolved\n * again. Another deployment's grants are answered and never applied.\n */\nexport function listenForGrants(io: QuickdrawIo, live: LiveData | undefined, logger: Logger): void {\n onNodeEvent(io, logger, GRANTS_EVENT, (broadcast, answer) => {\n const { userId, serviceAccess } = (broadcast ?? {}) as {\n readonly userId?: unknown;\n readonly serviceAccess?: unknown;\n };\n const grants = typeof serviceAccess === \"object\" && serviceAccess !== null;\n if (typeof userId !== \"string\" || userId.length === 0 || !grants) {\n answer(false);\n return;\n }\n regrant(io, userId, serviceAccess as ServiceGrants);\n (live?.regranted(userId) ?? Promise.resolve()).then(\n () => answer(true),\n (error: unknown) => {\n answer(false);\n logger.error(\"Resolving the subscriptions of a user another node regranted failed\", {\n category: \"quickdraw.access\",\n userId,\n error: describeError(error),\n });\n },\n );\n });\n}\n\n/** What `refreshGrants` works with besides the user. */\nexport interface GrantsContext {\n readonly io: QuickdrawIo;\n readonly load: ServerAuth[\"loadServiceAccess\"];\n readonly live: LiveData | undefined;\n readonly probe: AdapterProbe;\n /** Sends the reloaded grants to the other nodes, behind a cluster adapter. */\n readonly broadcasts: ClusterBroadcasts;\n}\n\n/**\n * `server.access.refresh(userId)`: reloads the user's grants, applies them on\n * every node (broadcast behind a cluster adapter, resolving once every node\n * applied them, at most `cluster.timeoutMs`, and without waiting while the\n * broadcasts are degraded: `../cluster/broadcasts.ts`), sends them to the\n * user's sockets as `qd:access`, and resolves this node's subscriptions of\n * the user again.\n */\nexport async function refreshGrants(\n context: GrantsContext,\n userId: string,\n): Promise<ServiceGrants> {\n const { io, load, live, probe } = context;\n if (load === undefined) {\n throw new TypeError(\"access.refresh needs auth.loadServiceAccess to reload a user's grants\");\n }\n const serviceAccess = (await load(userId)) ?? {};\n const others = probe.local()\n ? undefined\n : context.broadcasts.broadcast(GRANTS_EVENT, { userId, serviceAccess });\n regrant(io, userId, serviceAccess);\n io.to(userRoom(userId)).emit(SERVER_EVENTS.access, { serviceAccess });\n await Promise.all([others, live?.regranted(userId)]);\n return serviceAccess;\n}\n","// The Socket.IO transport (RFC 0003 sections 8 and 10). A v5 socket gets a\n// fixed set of listeners, whatever the number of services and methods:\n// `qd:call` and `qd:cancel` here, plus one per event from each registered\n// `SocketExtension`. 4.1 registered one listener per method, and five more per\n// service, on every socket (4.1 `src/server/ServiceRegistry.ts:118-136`).\n//\n// A call becomes one `DispatchRequest`: the connection is the socket, so its\n// queries share the socket's concurrency lane; `qd:cancel` and a disconnect\n// abort the call's signal; the reply goes out through the acknowledgement,\n// written from a shared run's encoded copy when there is one, and its size\n// comes back from the parser.\n\nimport { CLIENT_EVENTS, SERVER_EVENTS, userRoom } from \"../../contract/names\";\nimport { isCallEnvelope, isCancel, type CallId } from \"../../protocol/envelope\";\nimport { toWire } from \"../../protocol/errors\";\nimport type { HelloFrame } from \"../../protocol/version\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { Principal } from \"../types\";\nimport {\n acknowledge,\n callAcknowledgement,\n INTERNAL_FAILURE,\n unreadable,\n type Acknowledge,\n} from \"./ack\";\nimport { attachLegacyShim, type LegacyCallers, type LegacyWire } from \"./legacy\";\nimport { endAtSessionExpiry } from \"./pushes\";\nimport type { QuickdrawServerSocket, SocketContext } from \"./types\";\n\n/**\n * Adds listeners to every v5 socket, after `qd:call` and `qd:cancel`. This is\n * the registration hook for the entity, collection, watch, stream and channel\n * events that later packs serve: an extension registers one listener per\n * event, never one per method or service, and routes by the frame's fields.\n */\nexport type SocketExtension = (socket: QuickdrawServerSocket, context: SocketContext) => void;\n\n/** The part of `qd:hello` every socket of a server shares: all but who the socket acts for. */\nexport type ServerHello = Omit<HelloFrame, \"userId\" | \"serviceAccess\">;\n\n/** The connection handler's settings. */\nexport interface ConnectionSettings extends SocketContext {\n /**\n * Sent to every v5 socket once its listeners are in place, with the\n * socket's user id and service grants added.\n */\n readonly hello: ServerHello;\n readonly extensions: readonly SocketExtension[];\n /**\n * Added to every 4.x socket after the legacy shim: the live data's room\n * bookkeeping, so the app rooms its calls joined are left on disconnect.\n */\n readonly legacyExtensions: readonly SocketExtension[];\n /** The 4.x callers already logged, shared by every socket of the server. */\n readonly legacyCallers: LegacyCallers;\n /** The legacy shim's settings (its aliases); only 4.x sockets read them. */\n readonly legacyWire: LegacyWire;\n}\n\ntype Calls = Map<CallId, AbortController>;\n\nconst MALFORMED_CALL = \"A qd:call frame needs { id, s, m, i?, v? } and an acknowledgement\";\n\nfunction reply(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n ack: Acknowledge,\n message: unknown,\n): number | undefined {\n return acknowledge(context.meter, ack, message, INTERNAL_FAILURE, (error) => {\n context.logger.error(\"A call's reply could not be encoded; it was answered with INTERNAL\", {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n error: describeError(error),\n });\n });\n}\n\nfunction startCall(\n socket: QuickdrawServerSocket,\n context: SocketContext,\n calls: Calls,\n envelope: unknown,\n ack: Acknowledge,\n): void {\n if (!isCallEnvelope(envelope)) {\n reply(socket, context, ack, { ok: false, e: toWire(unreadable(MALFORMED_CALL)) });\n return;\n }\n const { id } = envelope;\n if (calls.has(id)) {\n const duplicate = unreadable(`Call ${id} is already in flight on this socket`, [\"id\"]);\n reply(socket, context, ack, { ok: false, e: toWire(duplicate) });\n return;\n }\n const controller = new AbortController();\n calls.set(id, controller);\n // Freed before the reply goes out, so the client may reuse the id at once.\n const release = (): void => {\n if (calls.get(id) === controller) {\n calls.delete(id);\n }\n };\n void context.dispatcher\n .call({\n service: envelope.s,\n method: envelope.m,\n input: envelope.i,\n principal: socket.data.principal,\n transport: \"socket\",\n connectionId: socket.id,\n signal: controller.signal,\n v: envelope.v,\n respond: (result, shared) => {\n release();\n return reply(socket, context, ack, callAcknowledgement(context.meter, result, shared));\n },\n })\n .then(release, (error: unknown) => {\n // The reply went out already; only a strict test app's warning gets here.\n release();\n context.logger.error(\"A call failed after its reply was sent\", {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n error: describeError(error),\n });\n });\n}\n\n/** Registers `qd:call` and `qd:cancel` on a v5 socket, and cancels its calls when it disconnects. */\nexport function attachCallListeners(socket: QuickdrawServerSocket, context: SocketContext): void {\n const calls: Calls = new Map();\n socket.on(CLIENT_EVENTS.call, (envelope: unknown, ack: unknown) => {\n if (typeof ack !== \"function\") {\n context.logger.debug(\"Ignored a qd:call sent without an acknowledgement\", {\n category: \"quickdraw.socket\",\n socketId: socket.id,\n });\n return;\n }\n startCall(socket, context, calls, envelope, ack as Acknowledge);\n });\n socket.on(CLIENT_EVENTS.cancel, (frame: unknown) => {\n if (isCancel(frame)) {\n calls.get(frame.id)?.abort();\n }\n });\n socket.on(\"disconnect\", () => {\n for (const controller of calls.values()) {\n controller.abort();\n }\n calls.clear();\n });\n}\n\n/**\n * The server's `connection` handler: joins the socket's user room, sets the\n * socket to end when its session expires (`endAtSessionExpiry`), then gives\n * a v5 socket its listeners and `qd:hello`, or a 4.x socket the legacy shim\n * and the legacy extensions. Only sockets the handshake middleware admitted\n * get here.\n */\nexport function onConnection(\n settings: ConnectionSettings,\n): (socket: QuickdrawServerSocket) => void {\n return (socket) => {\n const { principal } = socket.data;\n if (principal !== null) {\n void socket.join(userRoom(principal.userId));\n }\n endAtSessionExpiry(socket, settings.logger);\n if (socket.data.protocol === \"legacy\") {\n attachLegacyShim(socket, settings, settings.legacyCallers, settings.legacyWire);\n for (const extension of settings.legacyExtensions) {\n extension(socket, settings);\n }\n return;\n }\n attachCallListeners(socket, settings);\n for (const extension of settings.extensions) {\n extension(socket, settings);\n }\n socket.emit(SERVER_EVENTS.hello, helloFor(settings.hello, principal));\n };\n}\n\n/** The `qd:hello` of a socket acting for `principal`: the server's part, its user id and its grants. */\nfunction helloFor(hello: ServerHello, principal: Principal | null): HelloFrame {\n return {\n ...hello,\n userId: principal?.userId ?? null,\n serviceAccess: principal?.serviceAccess ?? {},\n };\n}\n"],"mappings":"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","names":["isIdList","where","isRecord","fail","isRecord","where","members","filtered","isRecord","members","added","where","memoized","target","where","target","reply","reply","send","target","answer","answer","settle","answer","checkName","anchorsOf","id","target","write","DEFAULT_MAX_ENTRIES","keyOf","readRows","target","answer","anchorsOf","allowed","withdrawn","entered","target","target","anchorsOf","failed","forget","answer","room","target","target","revoke","target","forbidden","where","serviceOf","count","fail","target","where","write","WHOLE","WHOLE","NONE","readRows","write","before","where","changed","allowed","target","target","write","write","failure","answer","isRecord","isName","where","filtered","readRows","members","forbidden","anchorsOf","allowed","isOwn","join","releaseTaken","sameAnchors","accessMoved","recheckAccess","settleRaces","changed","allowedScopes","reauthorize","allowed","reauthorizeAll","isRecord","logFailure","checkRoom","run","leave","target","checkRoom","answer","join","checkRoom","target","run","refuse","target","target","run","changed","write","watched","isName","groupOf","NONE","next","targetOf","anchorsNow","target","withdrawn","target","targetOf","WHOLE","targetOf","target","send","isRecord","readSubscribe","target","fail","registerInterest","write","add","resolveAccess","target","target","idsOf","resolveAccess","fail","allowed","isThenable","run","target","target","run","lookup","target","target","release","run","lookup","send","fail","targetOf","forbidden","target","fail","add","expire","target","targetOf","serve","release","keyOf","isThenable","target","answer","reply","startCall","release","notFound"]}
|