@fitzzero/quickdraw-core 5.1.2 → 5.1.3
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 +793 -57
- package/dist/{admin-DWWrT1h6.d.ts → admin-CS7JB_UH.d.ts} +2 -2
- package/dist/{adminSchemas-D4bFKsrb.d.ts → adminSchemas-29cGgrg5.d.ts} +1 -1
- package/dist/{auth-DXiSJZaf.d.ts → auth-DtdYjrZ9.d.ts} +11 -7
- package/dist/{caller-BT-Mv4bD.d.ts → caller-BTwGl7vm.d.ts} +183 -15
- package/dist/chunk-2FDSKLBO.js +82 -0
- package/dist/chunk-2FDSKLBO.js.map +1 -0
- package/dist/{chunk-GSIPUNJL.js → chunk-64I6MYBC.js} +139 -792
- package/dist/chunk-64I6MYBC.js.map +1 -0
- package/dist/chunk-7473HK24.js +17 -0
- package/dist/chunk-7473HK24.js.map +1 -0
- package/dist/chunk-7Y5ROPXL.js +33 -0
- package/dist/chunk-7Y5ROPXL.js.map +1 -0
- package/dist/chunk-A2RBQD66.js +7 -0
- package/dist/chunk-A2RBQD66.js.map +1 -0
- package/dist/chunk-ASAMUGHG.js +651 -0
- package/dist/chunk-ASAMUGHG.js.map +1 -0
- package/dist/{chunk-B2P7AZ25.js → chunk-CYE4UBOB.js} +6 -4
- package/dist/chunk-CYE4UBOB.js.map +1 -0
- package/dist/chunk-DNP65TD5.js +832 -0
- package/dist/chunk-DNP65TD5.js.map +1 -0
- package/dist/{chunk-5CGO426C.js → chunk-GYLWEJHW.js} +5 -1
- package/dist/chunk-GYLWEJHW.js.map +1 -0
- package/dist/{chunk-AONAFOYU.js → chunk-I3JCFS7H.js} +25 -13
- package/dist/chunk-I3JCFS7H.js.map +1 -0
- package/dist/{chunk-X5CWPX7H.js → chunk-IIQ3WMJK.js} +13 -2
- package/dist/chunk-IIQ3WMJK.js.map +1 -0
- package/dist/{chunk-6K5BY47X.js → chunk-JVTONQFI.js} +1277 -277
- package/dist/chunk-JVTONQFI.js.map +1 -0
- package/dist/{chunk-RL4VKLBX.js → chunk-KKQANRLG.js} +2 -2
- package/dist/{chunk-RL4VKLBX.js.map → chunk-KKQANRLG.js.map} +1 -1
- package/dist/{chunk-GKH3LJ7N.js → chunk-MPQAT55F.js} +38 -205
- package/dist/chunk-MPQAT55F.js.map +1 -0
- package/dist/chunk-NX2V6SIL.js +202 -0
- package/dist/chunk-NX2V6SIL.js.map +1 -0
- package/dist/{chunk-7QCUX4TK.js → chunk-NZHA4TZD.js} +72 -175
- package/dist/chunk-NZHA4TZD.js.map +1 -0
- package/dist/{chunk-MBH6IDSM.js → chunk-OCZJ4EYV.js} +40 -17
- package/dist/chunk-OCZJ4EYV.js.map +1 -0
- package/dist/{chunk-RJ5I2VO3.js → chunk-PHCURHC7.js} +6 -6
- package/dist/chunk-PHCURHC7.js.map +1 -0
- package/dist/{chunk-4YO5H5ON.js → chunk-Q4OGQM5I.js} +4 -10
- package/dist/chunk-Q4OGQM5I.js.map +1 -0
- package/dist/chunk-QSU47XEX.js +13 -0
- package/dist/chunk-QSU47XEX.js.map +1 -0
- package/dist/{chunk-LCC7HNFP.js → chunk-RZXJTDH5.js} +2 -2
- package/dist/{chunk-Z2LZ7IZ7.js → chunk-SN3OZVEQ.js} +5 -31
- package/dist/chunk-SN3OZVEQ.js.map +1 -0
- package/dist/{chunk-Z5ILULF2.js → chunk-SQ5VUG77.js} +4 -3
- package/dist/{chunk-Z5ILULF2.js.map → chunk-SQ5VUG77.js.map} +1 -1
- package/dist/chunk-STH5DLQP.js +1192 -0
- package/dist/chunk-STH5DLQP.js.map +1 -0
- package/dist/{chunk-NMXYENH4.js → chunk-VZFJTKIW.js} +6 -6
- package/dist/{chunk-753VJIUP.js → chunk-X4ZU4QH5.js} +43 -9
- package/dist/chunk-X4ZU4QH5.js.map +1 -0
- package/dist/chunk-XD7SRDUY.js +188 -0
- package/dist/chunk-XD7SRDUY.js.map +1 -0
- package/dist/chunk-Z7I6SONO.js +825 -0
- package/dist/chunk-Z7I6SONO.js.map +1 -0
- package/dist/cli/quickdraw-docs.js +131 -113
- package/dist/cli/quickdraw-docs.js.map +1 -1
- package/dist/client/core.d.ts +387 -0
- package/dist/client/core.js +109 -0
- package/dist/client/core.js.map +1 -0
- package/dist/client/index.d.ts +30 -193
- package/dist/client/index.js +56 -217
- package/dist/client/index.js.map +1 -1
- package/dist/{clientTypes-hWcPUVS9.d.ts → clientTypes-CUUNJwWs.d.ts} +3 -3
- package/dist/{connection-CgijdGpT.d.ts → connection-2EeQ_Et0.d.ts} +16 -9
- package/dist/{createServer-Cp-Wk500.d.ts → createServer-Bx5HOcYK.d.ts} +37 -9
- package/dist/{createTestApp-BB_PkqQ7.d.ts → createTestApp-DAMANT79.d.ts} +36 -9
- package/dist/{envelope-DzWyIXjj.d.ts → envelope-BMBaxppV.d.ts} +200 -8
- package/dist/{http-DotQ5bj8.d.ts → http-YzLAar3w.d.ts} +15 -50
- package/dist/index.d.ts +7 -6
- package/dist/index.js +61 -28
- package/dist/index.js.map +1 -1
- package/dist/{infer-BmoZsL9a.d.ts → infer-Br62cnyW.d.ts} +39 -1
- package/dist/{metrics-DW80Exve.d.ts → metrics-CTVpw0gu.d.ts} +2 -2
- package/dist/parser.js +2 -1
- package/dist/prisma/index.d.ts +13 -6
- package/dist/prisma/index.js +155 -9
- package/dist/prisma/index.js.map +1 -1
- package/dist/remote-N7OUAGOW.js +15 -0
- package/dist/remote-N7OUAGOW.js.map +1 -0
- package/dist/server/auth/index.d.ts +3 -3
- package/dist/server/auth/index.js +5 -3
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/index.d.ts +140 -36
- package/dist/server/index.js +162 -55
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/index.d.ts +34 -18
- package/dist/server/mcp/index.js +29 -12
- package/dist/server/mcp/index.js.map +1 -1
- package/dist/server/otel.d.ts +3 -3
- package/dist/{sharing-UDLn1049.d.ts → sharing-BrsmlDv_.d.ts} +3 -3
- package/dist/testing/client.d.ts +13 -13
- package/dist/testing/client.js +17 -10
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts +49 -12
- package/dist/testing/index.js +102 -19
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock.d.ts +5 -5
- package/dist/testing/mock.js +15 -9
- package/dist/tracked-BR5b2O-U.d.ts +43 -0
- package/dist/{types-CYliTP65.d.ts → types-CLRCQGnO.d.ts} +4 -3
- package/dist/types-tMagHbjy.d.ts +151 -0
- package/dist/utils/index.d.ts +16 -4
- package/dist/utils/index.js +6 -3
- package/package.json +5 -1
- package/dist/chunk-4YO5H5ON.js.map +0 -1
- package/dist/chunk-5CGO426C.js.map +0 -1
- package/dist/chunk-6K5BY47X.js.map +0 -1
- package/dist/chunk-753VJIUP.js.map +0 -1
- package/dist/chunk-7QCUX4TK.js.map +0 -1
- package/dist/chunk-AONAFOYU.js.map +0 -1
- package/dist/chunk-B2P7AZ25.js.map +0 -1
- package/dist/chunk-GKH3LJ7N.js.map +0 -1
- package/dist/chunk-GSIPUNJL.js.map +0 -1
- package/dist/chunk-MBH6IDSM.js.map +0 -1
- package/dist/chunk-RJ5I2VO3.js.map +0 -1
- package/dist/chunk-X5CWPX7H.js.map +0 -1
- package/dist/chunk-Z2LZ7IZ7.js.map +0 -1
- /package/dist/{chunk-LCC7HNFP.js.map → chunk-RZXJTDH5.js.map} +0 -0
- /package/dist/{chunk-NMXYENH4.js.map → chunk-VZFJTKIW.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts","../src/contract/names.ts","../src/protocol/version.ts"],"sourcesContent":["/** The published version of `@fitzzero/quickdraw-core`. Kept in step with package.json. */\nexport const QUICKDRAW_VERSION = \"5.1.2\";\n","// Room and event names for protocol v5 (RFC 0003 sections 6, 7 and 8). Ported\n// from the 4.1 room helpers (4.1 `src/shared/types.ts:364-405`), which were\n// plain template strings so shared code could name a room without holding a\n// service instance. The 5.0 rooms live under a `qd:` prefix so they never\n// collide with an app's own rooms; the per-user room keeps its 4.1 name.\n\nimport type { AccessLevel } from \"./access\";\n\n/**\n * The room for one entity at one access tier: `qd:e:{service}:{id}@{level}`.\n * A subscriber joins the room for its own level, so a frame is built once and\n * stripped once per occupied tier.\n */\nexport function entityRoom(service: string, id: string, level: AccessLevel): string {\n return `qd:e:${service}:${id}@${level}`;\n}\n\n/** The room for one scope of a collection: `qd:c:{service}:{collection}:{scope}`. */\nexport function collectionRoom(service: string, collection: string, scope: string): string {\n return `qd:c:${service}:${collection}:${scope}`;\n}\n\n/** The room for a watched topic of a service: `qd:t:{service}:{topic}`. */\nexport function topicRoom(service: string, topic: string): string {\n return `qd:t:${service}:${topic}`;\n}\n\n/**\n * The change topic of a whole service (RFC 0003 section 11.3): every flush\n * that changes one of its rows or collection scopes signals it.\n */\nexport const SERVICE_TOPIC = \"service\";\n\n/** The change topic of one scope of a collection: `{collection}:{scope}` (RFC 0003 section 11.3). */\nexport function collectionTopic(collection: string, scope: string): string {\n return `${collection}:${scope}`;\n}\n\n/**\n * The room of a stream's feed (RFC 0003 section 12.5):\n * `qd:s:{service}:{stream}:{scope}` for one scope of a scoped stream, and\n * `qd:s:{service}:{stream}` for a global stream. Stream names hold no colon.\n */\nexport function streamRoom(service: string, stream: string, scope?: string): string {\n return scope === undefined ? `qd:s:${service}:${stream}` : `qd:s:${service}:${stream}:${scope}`;\n}\n\n/** The room every authenticated socket of a user joins: `user:{userId}`, as in 4.1. */\nexport function userRoom(userId: string): string {\n return `user:${userId}`;\n}\n\n/**\n * The prefixes of the rooms the framework manages: entity, collection, topic\n * and stream rooms (`qd:`) and user rooms (`user:`). `ctx.rooms.join` refuses\n * them; a socket enters those rooms only through their authorized paths.\n */\nexport const RESERVED_ROOM_PREFIXES: readonly string[] = Object.freeze([\"qd:\", \"user:\"]);\n\n/**\n * The reserved prefix `room` starts with (`qd:` or `user:`), or `undefined`\n * when an app room may have that name.\n */\nexport function reservedRoomPrefix(room: string): string | undefined {\n return RESERVED_ROOM_PREFIXES.find((prefix) => room.startsWith(prefix));\n}\n\nconst SOCKET_ID = /^[\\w-]{20}$/u;\n\n/**\n * True when `room` has the shape of a Socket.IO socket id: 20 letters,\n * digits, `_` or `-`. Socket.IO puts every socket alone in a room named by\n * its id, 15 random bytes as base64url (the `base64id` package), so an app\n * room of that shape could be one socket's own room: `ctx.rooms.join`,\n * `rooms.size`, `rooms.leave` and presence refuse such names (the 5.1\n * audit's RT-I1), and no app room has that shape.\n */\nexport function socketIdShaped(room: string): boolean {\n return SOCKET_ID.test(room);\n}\n\n/** Events a client sends to the server (RFC 0003 section 8.2). */\nexport const CLIENT_EVENTS = Object.freeze({\n /** A method call: `{ id, s, m, i, v? }`, answered by ack. */\n call: \"qd:call\",\n /** Cancels an in-flight call: `{ id }`. */\n cancel: \"qd:cancel\",\n /** Subscribes to entities by id, with the revisions held. */\n sub: \"qd:sub\",\n /** Unsubscribes from entities. */\n unsub: \"qd:unsub\",\n /** Subscribes to a collection scope, or resumes it from a revision. */\n collectionSub: \"qd:col:sub\",\n /** Unsubscribes from a collection scope. */\n collectionUnsub: \"qd:col:unsub\",\n /** Loads collection items by id. */\n collectionItems: \"qd:col:items\",\n /** Joins a watched topic: `{ s, topic }`. */\n watch: \"qd:watch\",\n /** Leaves a watched topic. */\n unwatch: \"qd:unwatch\",\n /** Subscribes to a stream and receives its seed. */\n streamSub: \"qd:stream:sub\",\n /** Unsubscribes from a stream. */\n streamUnsub: \"qd:stream:unsub\",\n /** A fire-and-forget channel message, sent volatile: `[s, channel, payload]`. */\n channel: \"qd:ch\",\n} as const);\n\n/** Events the server sends to a client (RFC 0003 section 8.3). */\nexport const SERVER_EVENTS = Object.freeze({\n /** The handshake reply: `{ protocol, server, limits, features, userId, serviceAccess }`. */\n hello: \"qd:hello\",\n /** Entity frames: full update, patch or removal. */\n entity: \"qd:e\",\n /** Collection deltas, batched per flush. */\n collection: \"qd:c\",\n /** A watched topic changed; the client invalidates its queries. */\n changed: \"qd:changed\",\n /** Access to a subscription was revoked. */\n revoked: \"qd:revoked\",\n /** Stream items. */\n stream: \"qd:stream\",\n /** Typed custom room events declared in a contract's `events`. */\n event: \"qd:event\",\n /** Who is in an app room the socket is in: the list on joining, then each user who joins or leaves. */\n presence: \"qd:presence\",\n /** Reconnect within a jitter window. */\n rotate: \"qd:rotate\",\n /** The user's service grants changed. */\n access: \"qd:access\",\n} as const);\n\n/** The name of an event a client sends. */\nexport type ClientEventName = (typeof CLIENT_EVENTS)[keyof typeof CLIENT_EVENTS];\n\n/** The name of an event the server sends. */\nexport type ServerEventName = (typeof SERVER_EVENTS)[keyof typeof SERVER_EVENTS];\n","// The protocol version and the connection handshake (RFC 0003 section 8.1).\n// A v5 client connects with `auth: { token, qd: { protocol: 5, client } }`.\n// The server answers with `qd:hello`, or refuses a client that names another\n// protocol with `PROTOCOL_MISMATCH` in the `connect_error` data, and one whose\n// authentication failed with `UNAUTHENTICATED` there. A client that sends no\n// `auth.qd` is a 4.x client, which only the legacy shim serves (section 8.5).\n// There is no capability negotiation: the version decides.\n\nimport type { AccessLevel } from \"../contract/access\";\nimport { isRecord } from \"./guards\";\n\n/** The wire protocol this package speaks. */\nexport const PROTOCOL_VERSION = 5;\n\n/** `auth.qd`: what a v5 client sends when it connects. */\nexport interface QdHandshake {\n /** The protocol the client speaks. The server refuses any but its own. */\n readonly protocol: number;\n /** The client package's version, for logs. */\n readonly client: string;\n}\n\n/** The Socket.IO `auth` a v5 client connects with. */\nexport interface HandshakeAuth {\n /** The session token the server's `authenticate` reads. */\n readonly token?: string;\n /** The protocol the client speaks. A client without it is a 4.x client (RFC 0003 section 8.5). */\n readonly qd: QdHandshake;\n}\n\n/**\n * True when `value` has the shape of `auth.qd`, whatever protocol it names.\n * Compare `protocol` with {@link PROTOCOL_VERSION} to decide whether to serve it.\n */\nexport function isQdHandshake(value: unknown): value is QdHandshake {\n return isRecord(value) && Number.isInteger(value.protocol) && typeof value.client === \"string\";\n}\n\n/** The code in the `connect_error` data of a connection refused for its protocol. */\nexport const PROTOCOL_MISMATCH = \"PROTOCOL_MISMATCH\";\n\n/**\n * The `data` of the error a server refuses a connection with when the client\n * speaks another protocol, or none. It is not an `ErrorCode`: no call failed.\n */\nexport interface ProtocolMismatch {\n readonly code: typeof PROTOCOL_MISMATCH;\n /** The protocol the server speaks. */\n readonly expected: number;\n}\n\n/** True when a `connect_error`'s `data` says the server speaks another protocol. */\nexport function isProtocolMismatch(value: unknown): value is ProtocolMismatch {\n return isRecord(value) && value.code === PROTOCOL_MISMATCH && Number.isInteger(value.expected);\n}\n\n/**\n * The `data` of the error a server refuses a connection with when\n * authenticating it failed: the app's `authenticate` threw, so the\n * credentials are bad or could not be checked. A client tells it apart from\n * {@link ProtocolMismatch} by `code`; reconnecting needs other credentials.\n */\nexport interface AuthenticationRefused {\n readonly code: \"UNAUTHENTICATED\";\n}\n\n/** True when a `connect_error`'s `data` says authenticating the connection failed. */\nexport function isAuthenticationRefused(value: unknown): value is AuthenticationRefused {\n return isRecord(value) && value.code === \"UNAUTHENTICATED\";\n}\n\n/** The most ids one `qd:sub` may name (RFC 0003 section 6), as `qd:hello` announces it. */\nexport const MAX_SUBSCRIBE_IDS = 500;\n\n/** The most rows one socket may hold entity subscriptions to at once, as `qd:hello` announces it. */\nexport const MAX_ENTITY_IDS_PER_SOCKET = 10_000;\n\n/** The most collection scopes one socket may hold at once, as `qd:hello` announces it. */\nexport const MAX_SCOPES_PER_SOCKET = 1_000;\n\n/** The most change topics one socket may watch at once, as `qd:hello` announces it. */\nexport const MAX_TOPICS_PER_SOCKET = 1_000;\n\n/** The longest collection scope value or change topic a frame may name, in characters. */\nexport const MAX_SCOPE_LENGTH = 256;\n\n/**\n * Each socket's lane of subscription events (`qd:sub`, `qd:col:sub`,\n * `qd:col:items`, `qd:watch`; RFC 0003 section 8.2), and how much one\n * socket may hold at once, as `qd:hello` announces them.\n */\nexport interface HelloSubscriptionLimits {\n /** Subscription events one socket may have running at once. */\n readonly maxInFlight: number;\n /** Subscription events one socket may have waiting; past that one fails with `RATE_LIMITED`. */\n readonly maxQueued: number;\n /** Rows one socket may hold entity subscriptions to at once; one more is `CONFLICT`. Absent from servers up to 5.1.0, which have no such cap. */\n readonly maxEntityIds?: number;\n /** Collection scopes one socket may hold at once; one more is `CONFLICT`. Absent from servers up to 5.1.0, which have no such cap. */\n readonly maxScopes?: number;\n /** Change topics one socket may watch at once; one more is `CONFLICT`. Absent from servers up to 5.1.0, which have no such cap. */\n readonly maxTopics?: number;\n}\n\n/** The limits a server announces in `qd:hello`, so a client can stay inside them. */\nexport interface HelloLimits {\n /** Queries one socket may have running at once; more wait in a queue (RFC 0003 section 9). */\n readonly maxInFlightQueries: number;\n /** Queries one socket may have waiting; past that a query fails with `RATE_LIMITED`. */\n readonly maxQueuedQueries: number;\n /** Ids one `qd:sub` may name (RFC 0003 section 6). */\n readonly maxSubscribeIds: number;\n /**\n * A call's default time limit in milliseconds, after which it fails with\n * `TIMEOUT`. A v5 client waits this long plus 2 s for an answer, so a slow\n * call ends with the server's `TIMEOUT` rather than its own.\n */\n readonly callTimeoutMs: number;\n /** The socket's lane of subscription events. */\n readonly subscriptions: HelloSubscriptionLimits;\n}\n\n/**\n * `qd:hello`: the server's answer to a v5 handshake, sent once per\n * connection, after the socket's listeners are in place. It says who the\n * socket acts for, so a client knows its user without another call.\n */\nexport interface HelloFrame {\n /** The protocol the server speaks. */\n readonly protocol: typeof PROTOCOL_VERSION;\n /** The server package's version. */\n readonly server: string;\n /**\n * This server's id: random, new each time a server starts. A client that\n * reconnects to the same id came back after a blip, to another id to a\n * restarted server (a game's world and clock start over) or, behind a\n * cluster, to another node, each of which has its own.\n */\n readonly serverId: string;\n /** What a client must stay within. */\n readonly limits: HelloLimits;\n /** Names of optional server features that are on. Informational only. */\n readonly features: readonly string[];\n /** The user the socket acts for, or `null` when it is anonymous. */\n readonly userId: string | null;\n /**\n * The principal's service-wide grants when the socket connected, by\n * service name: `{ taskService: \"Admin\" }`. Empty for an anonymous socket\n * or a principal without grants. Later changes arrive as `qd:access`.\n */\n readonly serviceAccess: Readonly<Record<string, AccessLevel>>;\n}\n"],"mappings":";;;;;AACO,IAAM,oBAAoB;;;ACY1B,SAAS,WAAW,SAAiB,IAAY,OAA4B;AAClF,SAAO,QAAQ,OAAO,IAAI,EAAE,IAAI,KAAK;AACvC;AAGO,SAAS,eAAe,SAAiB,YAAoB,OAAuB;AACzF,SAAO,QAAQ,OAAO,IAAI,UAAU,IAAI,KAAK;AAC/C;AAGO,SAAS,UAAU,SAAiB,OAAuB;AAChE,SAAO,QAAQ,OAAO,IAAI,KAAK;AACjC;AAMO,IAAM,gBAAgB;AAGtB,SAAS,gBAAgB,YAAoB,OAAuB;AACzE,SAAO,GAAG,UAAU,IAAI,KAAK;AAC/B;AAOO,SAAS,WAAW,SAAiB,QAAgB,OAAwB;AAClF,SAAO,UAAU,SAAY,QAAQ,OAAO,IAAI,MAAM,KAAK,QAAQ,OAAO,IAAI,MAAM,IAAI,KAAK;AAC/F;AAGO,SAAS,SAAS,QAAwB;AAC/C,SAAO,QAAQ,MAAM;AACvB;AAOO,IAAM,yBAA4C,OAAO,OAAO,CAAC,OAAO,OAAO,CAAC;AAMhF,SAAS,mBAAmB,MAAkC;AACnE,SAAO,uBAAuB,KAAK,CAAC,WAAW,KAAK,WAAW,MAAM,CAAC;AACxE;AAEA,IAAM,YAAY;AAUX,SAAS,eAAe,MAAuB;AACpD,SAAO,UAAU,KAAK,IAAI;AAC5B;AAGO,IAAM,gBAAgB,OAAO,OAAO;AAAA;AAAA,EAEzC,MAAM;AAAA;AAAA,EAEN,QAAQ;AAAA;AAAA,EAER,KAAK;AAAA;AAAA,EAEL,OAAO;AAAA;AAAA,EAEP,eAAe;AAAA;AAAA,EAEf,iBAAiB;AAAA;AAAA,EAEjB,iBAAiB;AAAA;AAAA,EAEjB,OAAO;AAAA;AAAA,EAEP,SAAS;AAAA;AAAA,EAET,WAAW;AAAA;AAAA,EAEX,aAAa;AAAA;AAAA,EAEb,SAAS;AACX,CAAU;AAGH,IAAM,gBAAgB,OAAO,OAAO;AAAA;AAAA,EAEzC,OAAO;AAAA;AAAA,EAEP,QAAQ;AAAA;AAAA,EAER,YAAY;AAAA;AAAA,EAEZ,SAAS;AAAA;AAAA,EAET,SAAS;AAAA;AAAA,EAET,QAAQ;AAAA;AAAA,EAER,OAAO;AAAA;AAAA,EAEP,UAAU;AAAA;AAAA,EAEV,QAAQ;AAAA;AAAA,EAER,QAAQ;AACV,CAAU;;;ACvHH,IAAM,mBAAmB;AAsBzB,SAAS,cAAc,OAAsC;AAClE,SAAO,SAAS,KAAK,KAAK,OAAO,UAAU,MAAM,QAAQ,KAAK,OAAO,MAAM,WAAW;AACxF;AAGO,IAAM,oBAAoB;AAa1B,SAAS,mBAAmB,OAA2C;AAC5E,SAAO,SAAS,KAAK,KAAK,MAAM,SAAS,qBAAqB,OAAO,UAAU,MAAM,QAAQ;AAC/F;AAaO,SAAS,wBAAwB,OAAgD;AACtF,SAAO,SAAS,KAAK,KAAK,MAAM,SAAS;AAC3C;AAGO,IAAM,oBAAoB;AAG1B,IAAM,4BAA4B;AAGlC,IAAM,wBAAwB;AAG9B,IAAM,wBAAwB;AAG9B,IAAM,mBAAmB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/call.ts","../src/client/live/useSearch.ts","../src/client/hooks.ts","../src/client/overlayRows.ts","../src/client/versions.ts","../src/client/query.ts","../src/client/queryHooks.ts","../src/client/mutation.ts","../src/client/optimisticCall.ts","../src/client/live/liveHooks.ts","../src/client/adminMeta.ts","../src/client/adminGrants.ts","../src/client/live/useChannel.ts","../src/client/live/useEvent.ts","../src/client/live/useStream.ts","../src/client/live/realtimeMembers.ts","../src/client/live/useCollection.ts","../src/client/live/useEntity.ts","../src/client/live/members.ts","../src/client/createClient.ts","../src/client/provider.tsx"],"sourcesContent":["// One method call over a client connection (RFC 0003 sections 8.2, 9 and\n// 11.2): a `qd:call` envelope with a fresh id, answered through Socket.IO's\n// acknowledgement. 4.1 sent one event per method and resolved the\n// `{ success, data }` reply (4.1 `src/client/useServiceQuery.ts:94-121`).\n//\n// - A failed call rejects with the `QuickdrawError` the reply carries.\n// `RATE_LIMITED` also starts the connection's backoff for the call's kind,\n// and while it lasts a call of that kind fails at once, without being\n// sent, so a client that is being limited stops spending the budget.\n// - Aborting the signal rejects with `CANCELLED` and sends `qd:cancel`; a\n// call still waiting in Socket.IO's send buffer is dropped instead, so it\n// never reaches the server.\n// - No answer within the time limit rejects with `TIMEOUT`. It is never\n// retried here: the server may still be running the call.\n// - A connection that drops before the answer, or is not open at all,\n// rejects with `INTERNAL`. A call made while the socket reconnects waits in\n// Socket.IO's send buffer, within its time limit; new credentials meanwhile\n// fail it with `CANCELLED` instead of sending it as them (`connection.ts`).\n// - A `TIMEOUT`, and the `INTERNAL` of a call whose connection dropped after\n// it was sent, leave its outcome unknown: the server may have run it, and\n// may still be running it. `isUnknownOutcome` tells them from refusals, so\n// an optimistic addition waits for its scope's next load instead of being\n// refused (`optimisticCall.ts`).\n// - A reply `{ ok: true, nm: true, v }` resolves as it is: the version the\n// caller sent is current, and the caller keeps its copy.\n//\n// React-free: the hooks call through here, and so can any other client.\n\nimport type { MethodKind } from \"../contract/methods\";\nimport { CLIENT_EVENTS } from \"../contract/names\";\nimport type {\n CallEnvelope,\n CallId,\n CallNotModified,\n CallSuccess,\n Version,\n} from \"../protocol/envelope\";\nimport { QuickdrawError, fromWire } from \"../protocol/errors\";\nimport { isRecord } from \"../protocol/guards\";\nimport { retryAfterOf } from \"./backoff\";\nimport { isTimeLimit, type QuickdrawConnection, type QuickdrawSocket } from \"./connection\";\nimport { notifyEach } from \"./watch\";\n\n/**\n * What Socket.IO's client fails an acknowledgement with when its time limit\n * passes; with the socket down, the packet was still in its send buffer,\n * which drops it. Any other failure while the socket is down (it says \"socket\n * has been disconnected\") came after the packet was sent.\n */\nconst UNSENT_TIMEOUT = \"operation has timed out\";\n\n/** One call, as {@link call} takes it. */\nexport interface CallRequest {\n /** The service's name on the wire: the contract's `name`. */\n readonly service: string;\n readonly method: string;\n /** The input; left out of the envelope when `undefined`. */\n readonly input?: unknown;\n /** The method's kind, which picks the backoff a `RATE_LIMITED` answer starts. Default `\"query\"`. */\n readonly kind?: MethodKind;\n /** Aborting it cancels the call. */\n readonly signal?: AbortSignal;\n /** How long to wait for the answer. Default: the connection's `timeoutMs`. */\n readonly timeoutMs?: number;\n /** The version of the result the caller holds; the server answers \"not modified\" while it is current. */\n readonly v?: Version;\n /**\n * Called with the result the moment the reply arrives, before any frame\n * the server sent after it is handled; the returned promise settles only\n * after more microtasks, and a client on Node can handle several frames in\n * between. What must follow reply order goes here: an optimistic layer\n * ends at the first newer frame after its call's reply.\n */\n readonly onReply?: (result: CallResult) => void;\n}\n\n/** What a call resolves with: the data, or \"not modified\" when the `v` it sent is current. */\nexport type CallResult<Output = unknown> = CallSuccess<Output> | CallNotModified;\n\n/** True when the server answered that the caller's version is current. */\nexport function isNotModified(result: CallResult): result is CallNotModified {\n return result.nm === true;\n}\n\n/** The error a cancelled call rejects with. */\nfunction cancelledError(): QuickdrawError {\n return new QuickdrawError(\"CANCELLED\", \"The call was cancelled\");\n}\n\nfunction internalError(message: string): QuickdrawError {\n return new QuickdrawError(\"INTERNAL\", message);\n}\n\n/** The errors of calls whose connection dropped after they were sent: their outcome is unknown. */\nconst lostInFlight = new WeakSet<QuickdrawError>();\n\n/**\n * True when `error` leaves a call's outcome unknown: a `TIMEOUT` (the\n * server may still be running it, or ran it and the answer was lost), or the\n * `INTERNAL` of a call whose connection dropped after it was sent. The write\n * may have been made: before sending it again, make sure the call is\n * idempotent (a create that carries an id the client made, which the server\n * keeps, fails `CONFLICT` the second time instead of writing a second row).\n * False for a refusal, and for a call that was never sent.\n *\n * @example\n * onError: (error) => setStatus(isUnknownOutcome(error) ? \"checking\" : \"failed\")\n */\nexport function isUnknownOutcome(error: unknown): boolean {\n return error instanceof QuickdrawError && (error.code === \"TIMEOUT\" || lostInFlight.has(error));\n}\n\n/** The error of a call whose connection dropped after it was sent. */\nfunction lostError(): QuickdrawError {\n const error = internalError(\"No answer: the connection to the server is down\");\n lostInFlight.add(error);\n return error;\n}\n\n/** Why a call fails before it is sent, if it does. */\nfunction refusedBeforeSending(\n connection: QuickdrawConnection,\n kind: MethodKind,\n signal: AbortSignal | undefined,\n): QuickdrawError | undefined {\n if (signal?.aborted === true) {\n return cancelledError();\n }\n const { socket } = connection;\n if (!socket.connected && !socket.active) {\n return internalError(\"Not connected to the server\");\n }\n const remaining = connection.backoffRemaining(kind);\n if (remaining > 0) {\n return new QuickdrawError(\n \"RATE_LIMITED\",\n `Waiting before more ${kind} calls: the server answered RATE_LIMITED`,\n { retryAfterMs: Math.ceil(remaining) },\n );\n }\n return undefined;\n}\n\nfunction envelopeOf(id: CallId, request: CallRequest): CallEnvelope {\n return {\n id,\n s: request.service,\n m: request.method,\n ...(request.input === undefined ? {} : { i: request.input }),\n ...(request.v === undefined ? {} : { v: request.v }),\n };\n}\n\n/** The result or error a reply stands for; `RATE_LIMITED` starts the kind's backoff. */\nfunction readReply(\n connection: QuickdrawConnection,\n kind: MethodKind,\n reply: unknown,\n): CallResult | QuickdrawError {\n if (isRecord(reply) && reply.ok === true) {\n const versioned = typeof reply.v === \"string\" || typeof reply.v === \"number\";\n if (reply.nm === true && !versioned) {\n return internalError(\"The server answered not modified without a version\");\n }\n return reply as unknown as CallResult;\n }\n if (isRecord(reply) && reply.ok === false) {\n const error = fromWire(reply.e);\n if (error.code === \"RATE_LIMITED\") {\n connection.reportRateLimited(kind, retryAfterOf(error));\n }\n return error;\n }\n return internalError(\"The server's reply is not a call reply\");\n}\n\n/** True when a send-buffer packet is the `qd:call` frame of call `id`. */\nfunction isQueuedCall(data: unknown, id: CallId): boolean {\n return (\n Array.isArray(data) && data[0] === CLIENT_EVENTS.call && isRecord(data[1]) && data[1].id === id\n );\n}\n\n/** Drops the call from Socket.IO's send buffer, or else asks the server to cancel it. */\nfunction cancelCall(socket: QuickdrawSocket, id: CallId): void {\n const queued = socket.sendBuffer.findIndex((packet) => isQueuedCall(packet.data, id));\n if (queued >= 0) {\n socket.sendBuffer.splice(queued, 1);\n } else if (socket.connected) {\n socket.emit(CLIENT_EVENTS.cancel, { id });\n }\n}\n\n/**\n * Calls `request.method` of `request.service` over `connection`. Resolves\n * with `{ ok: true, d, v? }`, or `{ ok: true, nm: true, v }` when the `v` it\n * sent is current; rejects with a `QuickdrawError` (see the top of this file\n * for which code when).\n *\n * @example\n * const reply = await call(connection, { service: \"taskService\", method: \"get\", input: { id } });\n * const task = isNotModified(reply) ? cached : reply.d;\n */\nexport function call<Output = unknown>(\n connection: QuickdrawConnection,\n request: CallRequest,\n): Promise<CallResult<Output>> {\n const kind = request.kind ?? \"query\";\n const { signal } = request;\n const refused = refusedBeforeSending(connection, kind, signal);\n if (refused !== undefined) {\n return Promise.reject(refused);\n }\n const { socket } = connection;\n const timeoutMs = request.timeoutMs ?? connection.timeoutMs;\n if (!isTimeLimit(timeoutMs)) {\n return Promise.reject(\n new TypeError(\n \"call: timeoutMs must be a number of milliseconds, above 0 and at most 2^31 - 1\",\n ),\n );\n }\n const id = connection.nextCallId();\n return new Promise<CallResult<Output>>((resolve, reject) => {\n let settled = false;\n const settle = (outcome: CallResult | QuickdrawError): void => {\n if (settled) {\n return;\n }\n settled = true;\n signal?.removeEventListener(\"abort\", onAbort);\n if (outcome instanceof QuickdrawError) {\n reject(outcome);\n } else {\n notifyEach([request.onReply], (onReply) => {\n onReply?.(outcome);\n });\n resolve(outcome as CallResult<Output>);\n }\n };\n function onAbort(): void {\n cancelCall(socket, id);\n settle(cancelledError());\n }\n socket\n .timeout(timeoutMs)\n .emit(CLIENT_EVENTS.call, envelopeOf(id, request), (error: Error | null, reply: unknown) => {\n if (error === null) {\n settle(readReply(connection, kind, reply));\n } else if (error instanceof QuickdrawError) {\n // Failed by the connection before it was sent (new credentials).\n settle(error);\n } else if (socket.connected) {\n settle(new QuickdrawError(\"TIMEOUT\", `No answer within ${timeoutMs} ms`));\n } else if (error.message === UNSENT_TIMEOUT) {\n // Still in the send buffer when its time ran out: Socket.IO drops it unsent.\n settle(internalError(\"No answer: the connection to the server is down\"));\n } else {\n // Sent, then the connection dropped: Socket.IO fails the acknowledgements it waits for.\n settle(lostError());\n }\n });\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * Calls a method and resolves with its data. For a caller that sends no\n * version, which is never answered \"not modified\".\n */\nexport async function callData<Output = unknown>(\n connection: QuickdrawConnection,\n request: Omit<CallRequest, \"v\">,\n): Promise<Output> {\n const result = await call<Output>(connection, request);\n if (isNotModified(result)) {\n throw internalError(\"The server answered not modified to a call that sent no version\");\n }\n return result.d;\n}\n\n/**\n * The default `retry` of query hooks: one more attempt after an `INTERNAL`\n * error, which includes a dropped connection, or an error that is not a\n * `QuickdrawError`; none for any other code. A `TIMEOUT` is not retried,\n * because the server may still be running the call, and `RATE_LIMITED`\n * waits for the backoff instead.\n */\nexport function shouldRetry(failureCount: number, error: unknown): boolean {\n return failureCount < 1 && (!(error instanceof QuickdrawError) || error.code === \"INTERNAL\");\n}\n","\"use client\";\n\n// `qd.<service>.<search>.useSearch(q, options)` (RFC 0003 section 12.2): the\n// search kit's method, as the user types.\n//\n// - `q` is trimmed, and sent once it has stayed the same for `debounceMs`\n// (200 by default); a query shorter than the method's `minLength` sends\n// nothing and shows nothing.\n// - The search is the method's own `useQuery` (`../hooks.ts`), keyed by\n// `{ q, scope?, limit? }`: TanStack's signal reaches the call, so when the\n// next query replaces one still on its way, that call is cancelled\n// (`qd:cancel`) and the server stops it.\n// - While a newer search is on its way, the last results in the same scope\n// stay shown.\n// - A search kept to a scope of its collection returns that collection's\n// items. While a `useCollection` holds the scope, they are kept in its\n// state and shown as it holds them, so the scope's deltas (another user\n// renaming a result) show in the results too (`searchResults.ts`). There\n// is no subscription of the search's own.\n\nimport { useQuery, type QueryKey } from \"@tanstack/react-query\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { SearchPage } from \"../../contract/kits/searchSchemas\";\nimport { useMethodQuery } from \"../hooks\";\nimport { collectionKey } from \"../keys\";\nimport type { CollectionEntry } from \"./collectionLoads\";\nimport { entryQuery } from \"./host\";\nimport { useLiveData, useOverlayView } from \"./liveHooks\";\nimport { searchCall, shownResults, type SearchCall, type SearchTarget } from \"./searchResults\";\nimport type { UseSearchOptions, UseSearchResult } from \"./searchTypes\";\n\ntype LiveData = ReturnType<typeof useLiveData>[\"live\"];\n\n/** How long typing must pause before `useSearch` sends a query, by default. */\nexport const SEARCH_DEBOUNCE_MS = 200;\n\n/** `value` once it has stayed the same for `delayMs`; the first value at once. */\nfunction useDebounced(value: string, delayMs: number): string {\n const [settled, setSettled] = useState(value);\n useEffect(() => {\n if (settled === value) {\n return undefined;\n }\n const timer = setTimeout(() => {\n setSettled(value);\n }, delayMs);\n return () => {\n clearTimeout(timer);\n };\n }, [value, delayMs, settled]);\n return settled;\n}\n\n/** The scope a search's cache key holds, or `\"\"`. */\nfunction scopeOfKey(queryKey: QueryKey | undefined): string {\n const input = queryKey?.[4] as SearchCall | undefined;\n return typeof input?.scope === \"string\" ? input.scope : \"\";\n}\n\n/** TanStack's `placeholderData`: the last results while a newer search loads, in the same scope only. */\nfunction sameScopeResults(scope: string) {\n return <Page>(\n previous: Page | undefined,\n previousQuery?: { readonly queryKey: QueryKey },\n ): Page | undefined => (scopeOfKey(previousQuery?.queryKey) === scope ? previous : undefined);\n}\n\n/**\n * The state of the scope the results are items of, while a hook holds it;\n * `null` otherwise. Observing the entry renders the search again when the\n * scope's deltas change it.\n */\nfunction useHeldScope(live: LiveData, target: SearchTarget, scope: string) {\n const collection = target.collection ?? \"\";\n const key = collectionKey(target.service, collection, collection === \"\" ? \"\" : scope);\n const { data: entry } = useQuery(entryQuery<CollectionEntry>(key));\n const held =\n collection !== \"\" && scope !== \"\" && live.collections.holds(target.service, collection, scope);\n return held ? (entry?.state ?? null) : null;\n}\n\n/** `qd.<service>.<search>.useSearch(q, options)`. */\nexport function useSearch<Item>(\n target: SearchTarget,\n q: string,\n options: UseSearchOptions = {},\n): UseSearchResult<Item> {\n const { queryClient, live } = useLiveData(`${target.service}.${target.method}.useSearch`);\n const typed = typeof q === \"string\" ? q.trim() : \"\";\n const debounced = useDebounced(typed, options.debounceMs ?? SEARCH_DEBOUNCE_MS);\n const scope = typeof options.scope === \"string\" ? options.scope : \"\";\n const wanted = options.enabled !== false && typed.length >= target.minLength;\n const active = wanted && debounced.length >= target.minLength;\n const { limit } = options;\n const input = useMemo(() => searchCall(debounced, scope, limit), [debounced, scope, limit]);\n const placeholderData = useMemo(() => sameScopeResults(scope), [scope]);\n const result = useMethodQuery<SearchPage<Item>, SearchPage<Item>, SearchCall>(target, input, {\n enabled: active,\n placeholderData,\n });\n const page = active ? result.data : undefined;\n const fresh = result.isPlaceholderData ? undefined : page;\n const state = useHeldScope(live, target, scope);\n const loaded = state !== null;\n useEffect(() => {\n if (fresh?.rev !== undefined && loaded && target.collection !== undefined) {\n live.collections.keep(target.service, target.collection, scope, fresh.items, fresh.rev);\n }\n }, [live, target, scope, fresh, loaded]);\n const view = useOverlayView(queryClient, target.service);\n const items = useMemo(\n () => shownResults(page, state, view, target.collection),\n [page, state, view, target.collection],\n );\n const isSearching = wanted && (debounced !== typed || result.isFetching);\n const hasMore = (page?.nextCursor ?? null) !== null;\n const error = active ? result.error : null;\n return useMemo(\n () => ({ items, hasMore, isSearching, isLoading: isSearching && page === undefined, error }),\n [items, hasMore, isSearching, page, error],\n );\n}\n","\"use client\";\n\n// The query and mutation hooks behind `qd.<service>.<method>.useQuery` and\n// `.useMutation` (RFC 0003 sections 11, 11.2, 11.3 and 11.4). They are\n// TanStack Query's own hooks, keyed by `keys.ts` and fetching through\n// `call.ts`. 4.1's `useServiceQuery` and `useService` wrapped them by service\n// and method name strings and returned a reshaped result\n// (4.1 `src/client/useServiceQuery.ts:54-229`, `useService.ts:39-112`).\n//\n// A query:\n// - runs only while the connection is connected (or reconnecting with the\n// same credentials), the server's hello has named the user, and queries\n// are not backing off after `RATE_LIMITED`, besides its own `enabled`;\n// after another user's hello, or once the server ended the session, it\n// renders again over the emptied cache (`session.ts`);\n// - passes TanStack's abort signal to the call, so unmounting the last\n// component that reads it, or `cancelQueries`, sends `qd:cancel`;\n// - sends the cached result's version and keeps the cached result when the\n// server answers \"not modified\" (`query.ts`);\n// - retries once after `INTERNAL` (a dropped connection included) and never\n// after any other code (`shouldRetry`), unless `retry` says otherwise;\n// - joins the change topic its contract method `watch`es while it is\n// mounted and enabled, and is invalidated through the coordinator when the\n// topic changes: never a read cancelled, at most one queued behind it. A\n// read that starts while the join is in flight on a connected socket\n// waits for the server's answer, so the first mount reads once;\n// - shows the overlays of optimistic mutations over the rows it returns.\n// There are no effect-based `onSuccess`/`onError` callbacks (4.1 had them at\n// 4.1 `src/client/useServiceQuery.ts:185-198`).\n//\n// The mutation hook is `mutation.ts`'s, exported from here too.\n\nimport {\n replaceEqualDeep,\n useQuery,\n type UseQueryOptions,\n type UseQueryResult,\n} from \"@tanstack/react-query\";\nimport type { QuickdrawError } from \"../protocol/errors\";\nimport { shouldRetry } from \"./call\";\nimport { useAwaitingHello, useQueriesHello, useQuickdrawContext } from \"./context\";\nimport { methodKey, type MethodQueryKey } from \"./keys\";\nimport type { MethodTarget } from \"./members\";\nimport { fetchMethodQuery } from \"./query\";\nimport {\n hiddenResult,\n readAfterJoin,\n topicOf,\n watchedModelsOf,\n useOverlaySelect,\n useTopicWatch,\n} from \"./queryHooks\";\nimport { carryVersion } from \"./versions\";\n\nexport { useMethodMutation, type MethodMutationOptions } from \"./mutation\";\n\n/** Options of a query hook: TanStack's `useQuery` options, without the key and the query function. */\nexport type MethodQueryOptions<Output, Data = Output, Input = unknown> = Omit<\n UseQueryOptions<Output, QuickdrawError, Data, MethodQueryKey<Input>>,\n \"queryKey\" | \"queryFn\"\n>;\n\ntype StructuralSharing = boolean | ((oldData: unknown, newData: unknown) => unknown);\n\n/**\n * TanStack's structural sharing, which keeps the cached object when a new\n * result is deeply equal to it, moving the new result's version onto the\n * object the cache keeps. `false` turns sharing off as it does in TanStack.\n */\nexport function shareKeepingVersion(option: StructuralSharing | undefined): StructuralSharing {\n if (option === false) {\n return false;\n }\n return (oldData, newData) => {\n const kept =\n typeof option === \"function\" ? option(oldData, newData) : replaceEqualDeep(oldData, newData);\n carryVersion(newData, kept);\n return kept;\n };\n}\n\n/** `qd.<service>.<method>.useQuery(input, options)`. */\nexport function useMethodQuery<Output, Data = Output, Input = unknown>(\n target: MethodTarget,\n input: Input,\n options: MethodQueryOptions<Output, Data, Input> = {},\n): UseQueryResult<Data, QuickdrawError> {\n const { connection, queryClient, coordinator } = useQuickdrawContext(\n `${target.service}.${target.method}.useQuery`,\n );\n const live = useQueriesHello(connection) !== null;\n const awaiting = useAwaitingHello(connection, queryClient);\n const { enabled, retry, structuralSharing, select, ...rest } = options;\n const queryKey = methodKey(target.service, target.method, input);\n const topic = enabled === false ? undefined : topicOf(target, input);\n useTopicWatch({\n connection,\n coordinator,\n service: target.service,\n queryKey,\n topic,\n models: watchedModelsOf(target),\n });\n const shown = useOverlaySelect<Output, Data>(queryClient, target, select);\n const result = useQuery<Output, QuickdrawError, Data, MethodQueryKey<Input>>({\n ...rest,\n queryKey,\n queryFn: async ({ signal }) => {\n await readAfterJoin(connection, target.service, topic, queryKey, signal);\n return await fetchMethodQuery<Output>(\n connection,\n queryClient,\n {\n service: target.service,\n method: target.method,\n input,\n key: queryKey,\n output: target.output,\n },\n signal,\n );\n },\n enabled: live ? (enabled ?? true) : false,\n retry: retry ?? shouldRetry,\n structuralSharing: shareKeepingVersion(structuralSharing),\n ...(shown === undefined ? {} : { select: shown }),\n });\n // While new credentials await their hello, what is cached may be the last user's.\n return awaiting ? hiddenResult(result) : result;\n}\n","// What the query hooks show of a method's result (RFC 0003 section 11.4):\n// the overlays of optimistic mutations over the rows it holds, by the shape\n// of the method's output. Split from `optimistic.ts`, the overlay store.\n//\n// React-free.\n\nimport type { MethodOutput } from \"../contract/methods\";\nimport { isRecord } from \"../protocol/guards\";\nimport type { OverlayView } from \"./optimistic\";\n\n/**\n * How a method's output holds rows of its service: one row (`\"entity\"` or a\n * projection name), one row or `null` (`nullable(...)`), or a list of rows\n * (`listOf(...)`). A schema output holds none.\n */\nexport type RowShape = \"one\" | \"nullable\" | \"list\";\n\n/** The row shape of a method's output, or `undefined` for a schema output. */\nexport function rowShapeOf(output: MethodOutput | undefined): RowShape | undefined {\n if (typeof output === \"string\") {\n return \"one\";\n }\n if (!isRecord(output) || \"~standard\" in output) {\n return undefined;\n }\n if (output.kind === \"nullable\") {\n return \"nullable\";\n }\n return output.kind === \"list\" ? \"list\" : undefined;\n}\n\n/**\n * A result of shape `shape`, read at `readAt` (`OverlayOptions`), as `view`\n * shows it. A hidden row leaves a list and makes a `nullable` result `null`;\n * a result that must be a row keeps it. Returns `data` itself when no\n * overlay changes it.\n */\nexport function showRows<T>(\n view: OverlayView,\n shape: RowShape,\n data: T,\n readAt: number | undefined,\n): T {\n const options = { readAt };\n if (shape !== \"list\") {\n const shown = view.apply(data, options);\n if (shown === undefined) {\n return (shape === \"nullable\" ? null : data) as T;\n }\n return shown;\n }\n if (!Array.isArray(data)) {\n return data;\n }\n const rows: unknown[] = [];\n let same = true;\n for (const row of data as unknown[]) {\n const shown = view.apply(row, options);\n same &&= shown === row;\n if (shown !== undefined) {\n rows.push(shown);\n }\n }\n return (same ? data : rows) as T;\n}\n","// What the client knows about each cached query result: the version it was\n// answered with (RFC 0003 section 9, step 5), so the next fetch of that query\n// can send it back as `v` and be answered \"not modified\"; and when its read\n// was sent, on the overlay store's clock (`optimistic.ts`), so the overlays\n// of mutations that had finished by then are not shown over it again. Both\n// belong to the data object they came with, not to the query key: data\n// written into the cache some other way (`setQueryData`, a live frame) is a\n// new object with neither, so the client never claims to hold a version of\n// data it does not hold. Weak maps forget them with the data.\n//\n// Results that are not objects (a count, a string) carry neither; their\n// queries simply always run.\n//\n// React-free.\n\nimport type { Version } from \"../protocol/envelope\";\n\nconst versions = new WeakMap<object, Version>();\nconst reads = new WeakMap<object, number>();\n\nfunction isObject(value: unknown): value is object {\n return (typeof value === \"object\" && value !== null) || typeof value === \"function\";\n}\n\n/** The version `data` was answered with, if it was answered with one. */\nexport function versionOf(data: unknown): Version | undefined {\n return isObject(data) ? versions.get(data) : undefined;\n}\n\n/** Records that `data` was answered with `version`. */\nexport function rememberVersion(data: unknown, version: Version | undefined): void {\n if (isObject(data) && version !== undefined) {\n versions.set(data, version);\n }\n}\n\n/** When the newest read that returned `data` was sent, on the overlay store's clock. */\nexport function readAtOf(data: unknown): number | undefined {\n return isObject(data) ? reads.get(data) : undefined;\n}\n\n/** Records that a read sent at `readAt` returned `data`; a later read of the same object wins. */\nexport function rememberReadAt(data: unknown, readAt: number | undefined): void {\n if (isObject(data) && readAt !== undefined) {\n reads.set(data, Math.max(readAt, reads.get(data) ?? readAt));\n }\n}\n\n/**\n * Gives `kept` the version and read time of `received` when the cache keeps\n * another object for it: TanStack's structural sharing keeps the old object\n * when the new data is deeply equal to it, or a copy that reuses its\n * unchanged parts.\n */\nexport function carryVersion(received: unknown, kept: unknown): void {\n if (kept !== received) {\n rememberVersion(kept, versionOf(received));\n rememberReadAt(kept, readAtOf(received));\n }\n}\n","// How a query hook (and a prefetch) fetches: send the version of the cached\n// result, keep the cached result when the server answers \"not modified\", and\n// remember the version of a new result (`versions.ts`).\n//\n// \"Not modified\" says the copy the caller holds is current. If that copy is\n// no longer in the cache when the answer arrives (it was removed, reset or\n// replaced meanwhile), there is nothing to keep, so the call is made once\n// more without a version; a query never resolves to `undefined` that way.\n//\n// A result that holds rows of its service remembers when its read was sent,\n// on the overlay store's clock (`optimistic.ts`): it holds every mutation\n// that had finished by then, so their overlays are not shown over it.\n//\n// Nothing is read before the server's hello on the connection's current\n// credentials has arrived: the hello says which user the cache may hold data\n// for, and empties it when that is another user than it was loaded for\n// (`session.ts`). A version read from the cache before then could belong to\n// the last user's data, which the server would answer \"not modified\" for.\n//\n// A read refused with `FORBIDDEN`, `UNAUTHENTICATED` or `NOT_FOUND` takes the\n// cached result out of the query, so `data` never holds what the user may no\n// longer read beside the error (TanStack keeps the last data on an error).\n//\n// React-free: it reads the cache through the `QueryClient` it is given.\n\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport type { MethodOutput } from \"../contract/methods\";\nimport { QuickdrawError } from \"../protocol/errors\";\nimport { call, isNotModified, type CallRequest } from \"./call\";\nimport type { QuickdrawConnection } from \"./connection\";\nimport type { MethodQueryKey } from \"./keys\";\nimport { overlaysOf } from \"./optimistic\";\nimport { rowShapeOf } from \"./overlayRows\";\nimport { rememberReadAt, rememberVersion, versionOf } from \"./versions\";\n\n/** A query to fetch: the call, the key its result is cached under, and the method's output. */\nexport interface MethodQuery extends Omit<CallRequest, \"v\" | \"signal\" | \"kind\"> {\n readonly key: MethodQueryKey;\n /** The contract's `output`, which says whether the result holds rows of the service. */\n readonly output?: MethodOutput;\n}\n\nasync function fetchFresh<Output>(\n connection: QuickdrawConnection,\n query: MethodQuery,\n signal: AbortSignal | undefined,\n): Promise<Output> {\n const result = await call<Output>(connection, { ...query, kind: \"query\", signal });\n if (isNotModified(result)) {\n throw new QuickdrawError(\n \"INTERNAL\",\n `${query.service}.${query.method} answered not modified to a call that sent no version`,\n );\n }\n rememberVersion(result.d, result.v);\n return result.d;\n}\n\nasync function fetchVersioned<Output>(\n connection: QuickdrawConnection,\n queryClient: QueryClient,\n query: MethodQuery,\n signal: AbortSignal | undefined,\n): Promise<Output> {\n const v = versionOf(queryClient.getQueryData(query.key));\n if (v === undefined) {\n return fetchFresh(connection, query, signal);\n }\n const result = await call<Output>(connection, { ...query, kind: \"query\", signal, v });\n if (!isNotModified(result)) {\n rememberVersion(result.d, result.v);\n return result.d;\n }\n const cached = queryClient.getQueryData<Output>(query.key);\n if (cached !== undefined && versionOf(cached) === v) {\n return cached;\n }\n return fetchFresh(connection, query, signal);\n}\n\n/**\n * Resolves once the connection holds the server's hello on its current\n * credentials, once its socket stops trying to connect (the call then fails\n * as it would), or as soon as `signal` aborts. Resolving takes a microtask,\n * so whatever the hello does to the cache (`session.ts`) is done before the\n * read looks at the cache.\n */\nasync function helloKnown(\n connection: QuickdrawConnection,\n signal: AbortSignal | undefined,\n): Promise<void> {\n const ready = (): boolean =>\n connection.getState().hello !== null || !connection.socket.active || signal?.aborted === true;\n if (ready()) {\n return;\n }\n await new Promise<void>((resolve) => {\n let stop = (): void => undefined;\n const check = (): void => {\n if (ready()) {\n stop();\n signal?.removeEventListener(\"abort\", check);\n resolve();\n }\n };\n stop = connection.subscribe(check);\n signal?.addEventListener(\"abort\", check, { once: true });\n });\n}\n\n/** The codes that say the caller may not have the result, or there is none: its cached data goes. */\nconst REFUSALS: ReadonlySet<string> = new Set([\"FORBIDDEN\", \"UNAUTHENTICATED\", \"NOT_FOUND\"]);\n\n/** Takes the cached result out of the query of `key`: its read was refused. */\nfunction forgetResult(queryClient: QueryClient, key: MethodQueryKey): void {\n const cached = queryClient.getQueryCache().find({ queryKey: key, exact: true });\n if (cached !== undefined && cached.state.data !== undefined) {\n cached.setState({ ...cached.state, data: undefined });\n }\n}\n\nasync function fetchShown<Output>(\n connection: QuickdrawConnection,\n queryClient: QueryClient,\n query: MethodQuery,\n signal: AbortSignal | undefined,\n): Promise<Output> {\n if (rowShapeOf(query.output) === undefined) {\n return await fetchVersioned(connection, queryClient, query, signal);\n }\n const sentAt = overlaysOf(queryClient).now();\n const data = await fetchVersioned<Output>(connection, queryClient, query, signal);\n rememberReadAt(data, sentAt);\n return data;\n}\n\n/**\n * Fetches a query's result for `queryClient`'s cache, once the server's\n * hello has named the user: sends the version of the cached result as `v`,\n * resolves with the cached result itself when the server answers \"not\n * modified\", and calls once more without a version when that result left\n * the cache meanwhile. A refusal (`FORBIDDEN`, `UNAUTHENTICATED`,\n * `NOT_FOUND`) also takes the cached result out of the query.\n */\nexport async function fetchMethodQuery<Output>(\n connection: QuickdrawConnection,\n queryClient: QueryClient,\n query: MethodQuery,\n signal?: AbortSignal,\n): Promise<Output> {\n await helloKnown(connection, signal);\n try {\n return await fetchShown<Output>(connection, queryClient, query, signal);\n } catch (error) {\n if (error instanceof QuickdrawError && REFUSALS.has(error.code)) {\n forgetResult(queryClient, query.key);\n }\n throw error;\n }\n}\n","\"use client\";\n\n// The parts of `qd.<service>.<method>.useQuery` beyond TanStack's own\n// (RFC 0003 sections 11.3 and 11.4): joining the change topic the query\n// watches (and holding its read until the join is answered), showing the\n// overlays of optimistic mutations over the rows it returns, and showing\n// nothing while new credentials await their hello.\n\nimport { hashKey, type QueryClient, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useEffect, useMemo, useRef, useSyncExternalStore } from \"react\";\nimport { collectionTopic, SERVICE_TOPIC } from \"../contract/names\";\nimport type { QuickdrawConnection } from \"./connection\";\nimport type { InvalidationCoordinator } from \"./coordinator\";\nimport type { MethodQueryKey } from \"./keys\";\nimport type { MethodTarget } from \"./members\";\nimport { NO_OVERLAYS, overlaysOf, type OverlayView } from \"./optimistic\";\nimport { rowShapeOf, showRows } from \"./overlayRows\";\nimport { readAtOf } from \"./versions\";\n\n/**\n * The models a query of `target` watches on its service's topic (`watch: {\n * service: [models] }`), or `undefined` when it watches every change there,\n * or another topic.\n */\nexport function watchedModelsOf(target: MethodTarget): readonly string[] | undefined {\n const { watch } = target;\n return typeof watch === \"object\" && \"service\" in watch ? watch.service : undefined;\n}\n\n/**\n * The change topic a query of `target` with `input` watches: the service's\n * own (`watch: \"service\"`, or `{ service: [models] }`, which narrows it), or\n * `{collection}:{scope}`, with the scope from the contract's\n * `watch.scope(input)`. `undefined` when the method watches nothing, or the\n * scope function throws or returns no scope.\n */\nexport function topicOf(target: MethodTarget, input: unknown): string | undefined {\n const { watch } = target;\n if (watch === undefined) {\n return undefined;\n }\n if (watch === SERVICE_TOPIC || \"service\" in watch) {\n return SERVICE_TOPIC;\n }\n let scope: unknown;\n try {\n scope = (watch.scope as (input: unknown) => unknown)(input);\n } catch {\n return undefined;\n }\n return typeof scope === \"string\" && scope !== \"\"\n ? collectionTopic(watch.collection, scope)\n : undefined;\n}\n\n/** What {@link useTopicWatch} watches, and how it invalidates. */\nexport interface QueryWatch {\n readonly connection: QuickdrawConnection;\n readonly coordinator: InvalidationCoordinator;\n readonly service: string;\n readonly queryKey: MethodQueryKey;\n /** The topic, or `undefined` to watch nothing. */\n readonly topic: string | undefined;\n /** On the service topic, the models the query watches (`watchedModelsOf`); `undefined` for all. */\n readonly models?: readonly string[] | undefined;\n}\n\n/** True when a read of the cached query `queryKey` was sent: it holds a result or an error, or is reading. */\nfunction wasRead(coordinator: InvalidationCoordinator, queryKey: MethodQueryKey): boolean {\n const query = coordinator.queryClient.getQueryCache().find({ queryKey, exact: true });\n if (query === undefined) {\n return false;\n }\n const { dataUpdatedAt, errorUpdatedAt, fetchStatus } = query.state;\n return dataUpdatedAt > 0 || errorUpdatedAt > 0 || fetchStatus !== \"idle\";\n}\n\n/** Resolves when `joined` does, or as soon as `signal` aborts. */\nfunction untilJoinedOrAborted(\n joined: Promise<void>,\n signal: AbortSignal | undefined,\n): Promise<void> {\n if (signal === undefined) {\n return joined;\n }\n return new Promise<void>((resolve) => {\n const done = (): void => {\n signal.removeEventListener(\"abort\", done);\n resolve();\n };\n if (signal.aborted) {\n done();\n return;\n }\n signal.addEventListener(\"abort\", done, { once: true });\n void joined.then(done);\n });\n}\n\n/**\n * Holds a watching query's read while its change topic is being joined on a\n * connected socket, until the server answers the join (RFC 0003 section 17):\n * joined, the read then sees every change made before the join, so the\n * query is read once on its first mount, not once and again when the join\n * lands; refused, it reads anyway. Returns at once when there is nothing to\n * wait for, and as soon as `signal` aborts (the call then fails `CANCELLED`\n * without being sent).\n */\nexport async function readAfterJoin(\n connection: QuickdrawConnection,\n service: string,\n topic: string | undefined,\n queryKey: MethodQueryKey,\n signal: AbortSignal | undefined,\n): Promise<void> {\n const joined =\n topic === undefined\n ? undefined\n : connection.waitForJoin({ service, topic, key: hashKey(queryKey) });\n if (joined !== undefined) {\n await untilJoinedOrAborted(joined, signal);\n }\n}\n\n/**\n * Joins the change topic of a watching query while the component is\n * mounted, and invalidates the query through the coordinator on each\n * `qd:changed`. Components reading the same query cause one invalidation per\n * frame between them: their watches share the query key's hash. A read that\n * starts while the join is in flight waits for it (`readAfterJoin`). When\n * the server acknowledges the join after a read of the query was sent\n * instead (on a socket that was not connected yet, a result prefetched\n * before the watch, or a read that waited in the send buffer through an\n * outage and went out before the topic was joined again), a change made\n * between that read and the join sent no `qd:changed` here, so the query is\n * invalidated once (RFC 0003 section 17).\n */\nexport function useTopicWatch({\n connection,\n coordinator,\n service,\n queryKey,\n topic,\n models,\n}: QueryWatch): void {\n const latest = useRef(queryKey);\n useEffect(() => {\n latest.current = queryKey;\n });\n const key = hashKey(queryKey);\n // The contract's list, the same on every render; compared by its names all the same.\n const modelNames = models?.join(\"\\u0000\");\n useEffect(() => {\n if (topic === undefined) {\n return undefined;\n }\n return connection.watch({\n service,\n topic,\n key,\n ...(modelNames === undefined ? {} : { models: modelNames.split(\"\\u0000\") }),\n onChanged: () => {\n coordinator.invalidate(latest.current, { exact: true });\n },\n onJoined: () => {\n if (wasRead(coordinator, latest.current)) {\n coordinator.invalidate(latest.current, { exact: true });\n }\n },\n });\n }, [connection, coordinator, service, topic, key, modelNames]);\n}\n\nconst ignoreChanges = (): (() => void) => () => undefined;\n\nconst noOverlays = (): OverlayView => NO_OVERLAYS;\n\n/**\n * The `select` a query of `target` runs: the overlays of optimistic\n * mutations shown over the rows it returns, then the caller's own `select`.\n * It changes when an overlay of the service does, which makes TanStack run it\n * again. `select` itself for a method whose output holds no rows.\n */\nexport function useOverlaySelect<Output, Data>(\n queryClient: QueryClient,\n target: MethodTarget,\n select: ((data: Output) => Data) | undefined,\n): ((data: Output) => Data) | undefined {\n const overlays = overlaysOf(queryClient);\n const shape = rowShapeOf(target.output);\n const { service } = target;\n const snapshot = (): OverlayView => (shape === undefined ? NO_OVERLAYS : overlays.view(service));\n // No mutation runs on a server: its render, and the hydration, show none.\n const view = useSyncExternalStore(\n shape === undefined ? ignoreChanges : overlays.subscribe,\n snapshot,\n noOverlays,\n );\n return useMemo(() => {\n if (shape === undefined) {\n return select;\n }\n return (data: Output): Data => {\n const shown = showRows(view, shape, data, readAtOf(data));\n return select === undefined ? (shown as unknown as Data) : select(shown);\n };\n }, [shape, view, select]);\n}\n\n/**\n * `result` as a query that has read nothing yet: what `useQuery` shows while\n * new credentials await their hello (`./session.ts`), since what is cached\n * may be the last user's. The cache keeps it; the hello decides.\n */\nexport function hiddenResult<Data, Failure>(\n result: UseQueryResult<Data, Failure>,\n): UseQueryResult<Data, Failure> {\n return {\n ...result,\n data: undefined,\n error: null,\n status: \"pending\",\n isPending: true,\n isSuccess: false,\n isError: false,\n isLoading: result.isFetching,\n isLoadingError: false,\n isRefetchError: false,\n isRefetching: false,\n isPlaceholderData: false,\n isFetched: false,\n isFetchedAfterMount: false,\n dataUpdatedAt: 0,\n errorUpdatedAt: 0,\n failureCount: 0,\n failureReason: null,\n errorUpdateCount: 0,\n } as UseQueryResult<Data, Failure>;\n}\n","\"use client\";\n\n// The mutation hook behind `qd.<service>.<method>.useMutation` (RFC 0003\n// sections 11.2 and 11.4), TanStack Query's own `useMutation` keyed by\n// `keys.ts` and calling through `call.ts`; `hooks.ts` exports it with the\n// query hook. It returns TanStack's mutation result as it is, typed with\n// `QuickdrawError`, and is optimistic by default when its input has `id` and\n// its output is `\"entity\"` (`optimistic.ts`). A failed call's refused items\n// show in the render that shows the mutation's error, and their `retry()`\n// sends the call again through this hook's mutation, so its `isPending` and\n// callbacks follow it (finding F8.3). In development, one hook instance\n// issuing its mutation more than 5 times within a second is named as a\n// loop, with its component (`loopGuard.ts`).\n\nimport {\n useMutation,\n type UseMutationOptions,\n type UseMutationResult,\n} from \"@tanstack/react-query\";\nimport { useRef } from \"react\";\nimport type { QuickdrawError } from \"../protocol/errors\";\nimport { callData, isNotModified } from \"./call\";\nimport { useQuickdrawContext } from \"./context\";\nimport { methodKeyPrefix } from \"./keys\";\nimport { createMutationTrace, loopGuardOf, type MutationTrace } from \"./loopGuard\";\nimport type { MethodTarget } from \"./members\";\nimport type { OptimisticCache, OptimisticUpdate } from \"./optimistic\";\nimport { applyWhenMutationFails, mutateOptimistically } from \"./optimisticCall\";\n\n/**\n * Options of a mutation hook: TanStack's `useMutation` options, without the\n * mutation function, and `optimistic`.\n */\nexport type MethodMutationOptions<\n Output,\n Variables,\n Context = unknown,\n Cache = OptimisticCache,\n> = Omit<UseMutationOptions<Output, QuickdrawError, Variables, Context>, \"mutationFn\"> & {\n /**\n * The mutation's optimistic update (RFC 0003 section 11.4): `false` for\n * none, or a function that writes its own layers through `cache`. Left\n * out, a mutation whose input has `id` and whose output is `\"entity\"`\n * shows its input's other fields over that row from the moment it is sent:\n * dropped if the call fails, kept after it succeeds until the server's\n * data for the row catches up.\n */\n readonly optimistic?: false | OptimisticUpdate<Variables, Cache>;\n};\n\n/**\n * `qd.<service>.<method>.useMutation(options)`. `mutate` returns nothing (a\n * failure lands in the result's `error`); `mutateAsync` returns the promise\n * of the output, which rejects with the `QuickdrawError`.\n */\nexport function useMethodMutation<Output, Variables, Context = unknown, Cache = OptimisticCache>(\n target: MethodTarget,\n options: MethodMutationOptions<Output, Variables, Context, Cache> = {},\n): UseMutationResult<Output, QuickdrawError, Variables, Context> {\n const { connection, queryClient } = useQuickdrawContext(\n `${target.service}.${target.method}.useMutation`,\n );\n // where this hook instance was first rendered, for a loop warning (development only)\n const traced = useRef<MutationTrace>(undefined);\n traced.current ??= createMutationTrace();\n const trace = traced.current;\n const { optimistic, ...rest } = options;\n const optimisticTarget = {\n service: target.service,\n entityOutput: target.output === \"entity\",\n collections: target.collections,\n };\n // The hook's own mutate, so a refused item's retry() goes through it (finding F8.3).\n const resend = useRef<((input: Variables) => Promise<Output>) | undefined>(undefined);\n const mutation = useMutation<Output, QuickdrawError, Variables, Context>({\n mutationKey: methodKeyPrefix(target.service, target.method),\n ...rest,\n mutationFn: (input: Variables) => {\n loopGuardOf(queryClient).mutated(trace, target.service, target.method);\n return mutateOptimistically<Output>(\n queryClient,\n optimisticTarget,\n optimistic as false | OptimisticUpdate<unknown> | undefined,\n input,\n (replied) =>\n callData<Output>(connection, {\n service: target.service,\n method: target.method,\n input,\n kind: \"mutation\",\n onReply: (result) => {\n if (!isNotModified(result)) {\n replied(result.d as Output);\n }\n },\n }),\n {\n resend: async () => await resend.current?.(input),\n onFailed: (apply) => {\n applyWhenMutationFails(queryClient, input, apply);\n },\n },\n );\n },\n });\n resend.current = mutation.mutateAsync;\n return mutation;\n}\n","// One mutation call's optimistic update (RFC 0003 section 11.4): the layers\n// and additions it opens in the overlay store (`optimistic.ts`) when it is\n// sent, finished with its reply or dropped when it fails (an addition made\n// with `onRefused: \"keep\"` stays, refused, with a `retry` that sends the\n// same call again; finding F6.4). A failure that leaves the outcome unknown\n// (`isUnknownOutcome`) refuses no addition yet: each waits for its scope's\n// next load (`additions.ts`). The default\n// update of a mutation whose input has `id` and whose output is `\"entity\"`\n// overlays the input's other fields on that row; a custom one writes\n// through the `OptimisticCache` it is given (`patchEntity`, `removeEntity`,\n// `patchItem`, `addItem`, `addEntity`).\n//\n// React-free.\n\nimport { notifyManager, type QueryClient } from \"@tanstack/react-query\";\nimport type { CollectionDef } from \"../contract/collections\";\nimport { QuickdrawError } from \"../protocol/errors\";\nimport { isRecord } from \"../protocol/guards\";\nimport { entityScopes, newItem, type AddedRow, type AddItemOptions } from \"./additions\";\nimport { isUnknownOutcome } from \"./call\";\nimport {\n storeOf,\n type OptimisticCache,\n type OptimisticUpdate,\n type Opened,\n type StoreInternals,\n} from \"./optimistic\";\n\n/** A row as an update finds its input: any object with a string `id`. */\nfunction isRow(value: unknown): value is AddedRow {\n return isRecord(value) && typeof value.id === \"string\";\n}\n\n/** The method a mutation calls, as its default optimistic update needs it. */\nexport interface OptimisticTarget {\n /** The service's name on the wire. */\n readonly service: string;\n /** True when the method's output is `\"entity\"`: its calls are optimistic by default. */\n readonly entityOutput: boolean;\n /** The collections of the service's contract, for `addEntity`. */\n readonly collections?: Readonly<Record<string, CollectionDef>>;\n}\n\n/** `options.onRefused`, checked: true for `\"keep\"`. */\nfunction keepsRefused(owner: string, options: AddItemOptions | undefined): boolean {\n const onRefused = options?.onRefused;\n if (onRefused !== undefined && onRefused !== \"keep\" && onRefused !== \"drop\") {\n throw new TypeError(`${owner}: onRefused is \"keep\" or \"drop\"`);\n }\n return onRefused === \"keep\";\n}\n\n/** A call's failure as the refused item shows it. */\nfunction refusalError(error: unknown): QuickdrawError {\n return error instanceof QuickdrawError\n ? error\n : new QuickdrawError(\"INTERNAL\", error instanceof Error ? error.message : String(error));\n}\n\nfunction cacheFor(\n store: StoreInternals,\n target: OptimisticTarget,\n opened: Opened,\n): OptimisticCache {\n const { service } = target;\n const fieldsOf = (fields: unknown): Readonly<Record<string, unknown>> =>\n isRecord(fields) ? { ...fields } : {};\n const addTo = (collection: string, scope: unknown, item: AddedRow, keep: boolean): void => {\n if (typeof scope !== \"string\" || scope === \"\") {\n throw new TypeError(\"addItem: the scope must be the scope's value, a non-empty string\");\n }\n opened.additions.push(store.addItem(service, collection, scope, item, keep));\n };\n return Object.freeze({\n patchEntity(id: string, fields: Partial<Record<string, unknown>>): void {\n opened.layers.push(\n store.add(service, id, { collection: undefined, removed: false, fields: fieldsOf(fields) }),\n );\n },\n removeEntity(id: string): void {\n opened.layers.push(\n store.add(service, id, { collection: undefined, removed: true, fields: {} }),\n );\n },\n patchItem(collection: string, id: string, fields: Partial<Record<string, unknown>>): void {\n opened.layers.push(\n store.add(service, id, { collection, removed: false, fields: fieldsOf(fields) }),\n );\n },\n addItem(collection: string, scope: unknown, item: unknown, options?: AddItemOptions): void {\n addTo(collection, scope, newItem(\"addItem\", item), keepsRefused(\"addItem\", options));\n },\n addEntity(row: unknown, options?: AddItemOptions): void {\n const item = newItem(\"addEntity\", row);\n const keep = keepsRefused(\"addEntity\", options);\n for (const [collection, scope] of entityScopes(target.collections ?? {}, item)) {\n addTo(collection, scope, item, keep);\n }\n },\n });\n}\n\n/** The layers and additions a call opens: the custom update's, or the default's. */\nfunction openLayers(\n store: StoreInternals,\n target: OptimisticTarget,\n optimistic: OptimisticUpdate<unknown> | undefined,\n input: unknown,\n): Opened {\n const opened: Opened = { layers: [], additions: [] };\n const cache = cacheFor(store, target, opened);\n try {\n if (optimistic !== undefined) {\n optimistic(input, cache);\n } else if (target.entityOutput && isRow(input)) {\n const { id, ...fields } = input;\n cache.patchEntity(id, fields);\n }\n } catch (error) {\n store.discard(opened);\n throw error;\n }\n return opened;\n}\n\n/** How a mutation hook runs its calls' optimistic updates (`mutation.ts`). */\nexport interface MutationRun {\n /**\n * Sends the call again through the hook's own mutation, for a refused\n * item's `retry()`, so the hook's `isPending` and its callbacks follow it.\n * Default: the call is sent again directly.\n */\n readonly resend?: () => Promise<unknown>;\n /**\n * Runs what a failure does to the overlays (a refusal, or an unknown\n * outcome) when the mutation's own state turns to error, so a refused\n * item shows in the same render as the hook's error. Default: at once.\n */\n readonly onFailed?: (apply: () => void) => void;\n}\n\n/**\n * Runs one mutation call with its optimistic layers: opens them, sends the\n * call with `send`, then finishes them with the reply or drops them when the\n * call fails. `send` is given `replied`, to call with the reply's data the\n * moment it arrives (`CallRequest.onReply`): a frame handled after that is\n * after the reply, even when the call's promise has not settled yet, as on\n * Node, where one read of the socket can hand over the reply and the\n * flush's frames together. A `send` that never calls it has its layers\n * finished when its promise resolves.\n */\nexport async function mutateOptimistically<T>(\n queryClient: QueryClient,\n target: OptimisticTarget,\n optimistic: false | OptimisticUpdate<unknown> | undefined,\n input: unknown,\n send: (replied: (data: T) => void) => Promise<T>,\n run: MutationRun = {},\n): Promise<T> {\n const ignore = (): void => undefined;\n if (optimistic === false) {\n return await send(ignore);\n }\n const store = storeOf(queryClient);\n const opened = openLayers(store, target, optimistic, input);\n if (opened.layers.length === 0 && opened.additions.length === 0) {\n return await send(ignore);\n }\n let finished = false;\n const replied = (data: T): void => {\n if (!finished) {\n finished = true;\n store.finish(opened, data);\n }\n };\n try {\n const data = await send(replied);\n replied(data);\n return data;\n } catch (error) {\n // Kept additions stay, refused; `retry` sends the same call again, its update adding them anew.\n const refusal = {\n error: refusalError(error),\n retry:\n run.resend ?? (() => mutateOptimistically(queryClient, target, optimistic, input, send)),\n };\n const apply = (): void => {\n if (isUnknownOutcome(error)) {\n // The server may have made the write: the scopes' next loads say (`additions.ts`).\n store.unknown(opened, refusal);\n } else {\n store.refuse(opened, refusal);\n }\n };\n if (run.onFailed === undefined) {\n apply();\n } else {\n run.onFailed(apply);\n }\n throw error;\n }\n}\n\n/** What each `QueryClient`'s mutations hold back until their state turns to error, by their variables. */\nconst heldFailures = new WeakMap<QueryClient, Map<unknown, (() => void)[]>>();\n\n/**\n * Runs `apply` when the mutation of `queryClient` called with `variables`\n * (that very value) turns to error, inside TanStack's notify batch of that\n * change: what the failure does to the overlays then shows in the render\n * that shows the mutation's error and `isPending` false (finding F8.3 of the\n * quickdraw-chat migration). The mutation function's call fails before\n * TanStack runs its `onError` and `onSettled` and then sets the state.\n */\nexport function applyWhenMutationFails(\n queryClient: QueryClient,\n variables: unknown,\n apply: () => void,\n): void {\n let held = heldFailures.get(queryClient);\n if (held === undefined) {\n const byVariables = new Map<unknown, (() => void)[]>();\n held = byVariables;\n heldFailures.set(queryClient, byVariables);\n queryClient.getMutationCache().subscribe((event) => {\n if (event.type !== \"updated\" || event.action.type !== \"error\") {\n return;\n }\n const { variables: failed } = event.mutation.state;\n const waiting = byVariables.get(failed);\n byVariables.delete(failed);\n for (const run of waiting ?? []) {\n // Queued in the batch the mutation's observers are told in: one render shows both.\n notifyManager.schedule(run);\n }\n });\n }\n held.set(variables, [...(held.get(variables) ?? []), apply]);\n}\n","\"use client\";\n\n// What the live-data hooks share: the provider's live data, the overlays of\n// optimistic mutations for one service, and the user the connection acts for.\n\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport { useMemo, useSyncExternalStore } from \"react\";\nimport type { QuickdrawConnection } from \"../connection\";\nimport { serverStateOf, useAwaitingHello, useHello, useQuickdrawContext } from \"../context\";\nimport type { QuickdrawError } from \"../../protocol/errors\";\nimport {\n NO_OVERLAYS,\n overlaysOf,\n storeOf,\n type OverlayView,\n type RefusedAddition,\n} from \"../optimistic\";\nimport { userOf } from \"../session\";\nimport { liveDataOf, type LiveData } from \"./liveData\";\n\n/**\n * The provider's connection and `QueryClient`, and their live data; `hook`\n * names the caller in errors. The hook renders again on each new hello, so\n * after another user's hello emptied the cache it shows the new entries\n * (`../session.ts`).\n */\nexport function useLiveData(hook: string): {\n readonly connection: QuickdrawConnection;\n readonly queryClient: QueryClient;\n readonly live: LiveData;\n /**\n * True while new credentials await their hello on a cache loaded under the\n * last ones: the hook shows nothing of what is cached (`../session.ts`).\n */\n readonly awaiting: boolean;\n} {\n const { connection, queryClient } = useQuickdrawContext(hook);\n useHello(connection);\n const awaiting = useAwaitingHello(connection, queryClient);\n return { connection, queryClient, live: liveDataOf(connection, queryClient), awaiting };\n}\n\nconst noOverlays = (): OverlayView => NO_OVERLAYS;\n\n/** The overlays of `service`, re-rendering when one of them changes; none on a server and while hydrating. */\nexport function useOverlayView(queryClient: QueryClient, service: string): OverlayView {\n const overlays = overlaysOf(queryClient);\n const snapshot = (): OverlayView => overlays.view(service);\n return useSyncExternalStore(overlays.subscribe, snapshot, noOverlays);\n}\n\n/**\n * The user the connection acts for, from its `qd:hello`: `null` while\n * anonymous or before the hello; on a server and while hydrating, the one\n * its server state names (`../context.ts`).\n */\nexport function useUserId(connection: QuickdrawConnection): string | null {\n return useSyncExternalStore(\n connection.subscribe,\n () => userOf(connection.getState().hello),\n () => userOf(serverStateOf(connection).hello),\n );\n}\n\n/**\n * An item an optimistic update added with `onRefused: \"keep\"` whose call\n * the server refused (`useCollection().refused`).\n */\nexport interface RefusedItem<Item> {\n /** The fields the update gave the item, with its own id or a provisional one. */\n readonly item: Item;\n /** Why the server refused the call. */\n readonly error: QuickdrawError;\n /** Forgets it: it leaves `refused`. */\n dismiss(): void;\n /**\n * Sends the same call again, through the mutation hook that sent it (its\n * `isPending`, `onSuccess`, `onError` and `onSettled` follow the retry): it\n * leaves `refused`, and the update adds the item anew, `pending` while the\n * call is in flight. Resolves once the call settles, and never rejects: a\n * refusal shows in `refused` again. Send it only when the call is\n * idempotent (an id the client made, which the server keeps) if its error\n * left the outcome unknown (`isUnknownOutcome`).\n */\n retry(): Promise<void>;\n}\n\nconst NONE_REFUSED: readonly RefusedItem<never>[] = Object.freeze([]);\n\n/** The refused items of a scope, as the hook returns them: each with `dismiss` and `retry`. */\nfunction refusedItems(\n queryClient: QueryClient,\n refused: readonly RefusedAddition[],\n): readonly RefusedItem<unknown>[] {\n if (refused.length === 0) {\n return NONE_REFUSED;\n }\n const store = storeOf(queryClient);\n return refused.map(({ item, error, addition }) => ({\n item,\n error,\n dismiss: () => {\n store.dismiss(addition);\n },\n retry: async () => {\n store.dismiss(addition);\n try {\n await addition.refusal?.retry();\n } catch {\n // Refused again: shown in `refused` again, with the new error.\n }\n },\n }));\n}\n\n/**\n * The items added to scope `scope` of `collection` with `onRefused: \"keep\"`\n * whose call was refused (`useCollection().refused`); none for an empty\n * scope (a hook that shows nothing).\n */\nexport function useRefusedItems(\n queryClient: QueryClient,\n overlays: OverlayView,\n collection: string,\n scope: string,\n): readonly RefusedItem<unknown>[] {\n return useMemo(\n () =>\n scope === \"\" ? NONE_REFUSED : refusedItems(queryClient, overlays.refused(collection, scope)),\n [queryClient, overlays, collection, scope],\n );\n}\n","\"use client\";\n\n// How the typed client runs its services' `adminMeta` for `useAdminServices`\n// (`admin.ts`): one TanStack query per service, made as\n// `qd.<service>.admin.adminMeta.useQuery()` makes it (`hooks.ts`), under the\n// same key, so the two share one cached result. It runs once the server's\n// hello on the current credentials has arrived, and retries as every query\n// does. A service whose `adminMeta` refused the user (`FORBIDDEN`,\n// `UNAUTHENTICATED`) is not asked again (not on a remount, not after a\n// reconnect) until the user's grant on that service changes: its access is\n// the service grant, which the hello and `qd:access` carry.\n\nimport { useQueries, type UseQueryResult } from \"@tanstack/react-query\";\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { AdminServiceMeta } from \"../contract/kits/admin\";\nimport { adminNamespace, type AdminMetaQuery, type AdminMetaState } from \"./admin\";\nimport { grantOn, isRefusal, refusalsOf, useClientAdminGrants } from \"./adminGrants\";\nimport { shouldRetry } from \"./call\";\nimport { useAwaitingHello, useQueriesHello, useQuickdrawContext } from \"./context\";\nimport { shareKeepingVersion } from \"./hooks\";\nimport { methodKey } from \"./keys\";\nimport { fetchMethodQuery } from \"./query\";\n\n/** The states of the queries: a stable function, so TanStack keeps the result while they do not change. */\nfunction statesOf(results: UseQueryResult<AdminServiceMeta>[]): AdminMetaState[] {\n return results.map((result) => ({ data: result.data, error: result.error }));\n}\n\n/** The typed client's `adminMeta` queries, under the provider it renders in. */\nfunction useClientAdminMeta(\n queries: readonly AdminMetaQuery[],\n enabled: boolean,\n): readonly AdminMetaState[] {\n const { connection, queryClient } = useQuickdrawContext(\"useAdminServices\");\n const live = useQueriesHello(connection) !== null;\n const awaiting = useAwaitingHello(connection, queryClient);\n const refused = refusalsOf(queryClient);\n const states = useQueries(\n {\n queries: queries.map((query) => {\n const queryKey = methodKey(query.serviceName, query.method, undefined);\n const standing = refused.get(query.serviceName);\n return {\n queryKey,\n queryFn: async ({ signal }: { readonly signal: AbortSignal }) => {\n const grant = grantOn(connection, query.serviceName);\n try {\n const meta = await fetchMethodQuery<AdminServiceMeta>(\n connection,\n queryClient,\n {\n service: query.serviceName,\n method: query.method,\n input: undefined,\n key: queryKey,\n },\n signal,\n );\n refused.delete(query.serviceName);\n return meta;\n } catch (error) {\n if (isRefusal(error)) {\n refused.set(query.serviceName, grant);\n }\n throw error;\n }\n },\n // Refused under the grant the user still holds: not asked again.\n enabled:\n live &&\n enabled &&\n (standing === undefined || standing !== grantOn(connection, query.serviceName)),\n retry: shouldRetry,\n structuralSharing: shareKeepingVersion(undefined),\n };\n }),\n combine: statesOf,\n },\n queryClient,\n );\n // While new credentials await their hello, what is cached may be the last user's.\n return awaiting ? states.map(() => NOTHING_YET) : states;\n}\n\nconst NOTHING_YET: AdminMetaState = Object.freeze({ data: undefined, error: null });\n\n/** The typed client's `admin` member of a contract's service (`adminNamespace`). */\nexport function clientAdminNamespace(\n contract: AnyContract,\n methods: Readonly<Record<string, object>>,\n): Readonly<Record<string, object>> {\n return adminNamespace(contract, methods, {\n useMeta: useClientAdminMeta,\n useGrants: useClientAdminGrants,\n });\n}\n","\"use client\";\n\n// The user's grants as the admin kit's client half reads them\n// (`adminMeta.ts`): the service-wide grants the server's hello and\n// `qd:access` give, and the grant each service's `adminMeta` was refused\n// under, so a refusal stands until that grant changes (finding F3.6).\n\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport { useSyncExternalStore } from \"react\";\nimport type { AccessLevel } from \"../contract/access\";\nimport { QuickdrawError } from \"../protocol/errors\";\nimport type { QuickdrawConnection } from \"./connection\";\nimport { serverStateOf, useQuickdrawContext } from \"./context\";\n\n/** No grant at all: what a service the user holds no grant on is refused under. */\nconst NO_GRANT = \"none\";\n\n/**\n * The grant each service's `adminMeta` was refused under, per cache: asked\n * again only once the user's grant on the service differs.\n */\nconst refusals = new WeakMap<QueryClient, Map<string, AccessLevel | typeof NO_GRANT>>();\n\nexport function refusalsOf(queryClient: QueryClient): Map<string, AccessLevel | typeof NO_GRANT> {\n let held = refusals.get(queryClient);\n if (held === undefined) {\n held = new Map();\n refusals.set(queryClient, held);\n }\n return held;\n}\n\n/** The user's grant on `service` now, as the connection's state holds it. */\nexport function grantOn(\n connection: QuickdrawConnection,\n service: string,\n): AccessLevel | typeof NO_GRANT {\n const grants = connection.getState().serviceAccess;\n return grants !== null && Object.hasOwn(grants, service)\n ? (grants[service] ?? NO_GRANT)\n : NO_GRANT;\n}\n\n/** True for a refusal that stands until the user's grant changes. */\nexport function isRefusal(error: unknown): boolean {\n return (\n error instanceof QuickdrawError &&\n (error.code === \"FORBIDDEN\" || error.code === \"UNAUTHENTICATED\")\n );\n}\n\n/** The user's service-wide grants under the provider, `null` before the hello; none on a server. */\nexport function useClientAdminGrants(): Readonly<Record<string, AccessLevel>> | null {\n const { connection } = useQuickdrawContext(\"useAdminServices\");\n return useSyncExternalStore(\n connection.subscribe,\n () => connection.getState().serviceAccess,\n () => serverStateOf(connection).serviceAccess,\n );\n}\n","\"use client\";\n\n// `qd.<service>.<channel>.useChannel()` (RFC 0003 section 12.5): fast\n// one-way input such as cursors or typing. `send(payload)` emits `qd:ch\n// [service, channel, payload]` volatile: when the connection is backed up\n// the message is dropped rather than queued, which is what input superseded\n// by the next message wants. There is no answer; the server drops a message\n// over its rate, with an invalid payload or without access, silently. Ported\n// from 4.1's `useChannelSend` (4.1 `src/client/useChannelSend.ts:36`).\n\nimport { useCallback, useMemo } from \"react\";\nimport { CLIENT_EVENTS } from \"../../contract/names\";\nimport { useConnectionState, useQuickdrawContext } from \"../context\";\n\n/** What `useChannel` returns. */\nexport interface UseChannelResult<Payload> {\n /** Sends one message; does nothing while the socket is not connected. Stable across renders. */\n send(payload: Payload): void;\n /** True while the socket is connected and the server has said hello on it. */\n readonly isReady: boolean;\n}\n\n/** One channel of a service, as its member sends on it. */\nexport function useChannel<Payload>(service: string, channel: string): UseChannelResult<Payload> {\n const { connection } = useQuickdrawContext(`${service}.${channel}.useChannel`);\n const state = useConnectionState(connection);\n const send = useCallback(\n (payload: Payload) => {\n const { socket } = connection;\n if (socket.connected) {\n socket.volatile.emit(CLIENT_EVENTS.channel, [service, channel, payload]);\n }\n },\n [connection, service, channel],\n );\n const isReady = state.status === \"connected\" && state.hello !== null;\n return useMemo(() => ({ send, isReady }), [send, isReady]);\n}\n","\"use client\";\n\n// `qd.<service>.<event>.useEvent(handler)` (RFC 0003 sections 8.3 and\n// 12.5): calls `handler` with the payload of each of the contract's typed\n// room events the server sends this socket (`ctx.rooms.emit`), while the\n// component is mounted. The handler may change on every render without\n// re-registering. Replaces 4.1's `useRoomEvents` with its hand-written event\n// names (4.1 `src/client/useRoomEvents.ts:46`); the socket gets the\n// events of the rooms a method joined it to, so pair it with that method.\n\nimport { useEffect, useRef } from \"react\";\nimport { useLiveData } from \"./liveHooks\";\n\n/** Options of `useEvent`. */\nexport interface UseEventOptions {\n /** `false` calls nothing. Default `true`. */\n readonly enabled?: boolean;\n}\n\n/** Calls `handler` with each `event` of `service` the socket receives. */\nexport function useEvent<Payload>(\n service: string,\n event: string,\n handler: (payload: Payload) => void,\n options: UseEventOptions = {},\n): void {\n const { live } = useLiveData(`${service}.${event}.useEvent`);\n const latest = useRef(handler);\n useEffect(() => {\n latest.current = handler;\n });\n const enabled = options.enabled !== false;\n useEffect(() => {\n if (!enabled) {\n return undefined;\n }\n return live.events.on(service, event, (payload) => {\n latest.current(payload as Payload);\n });\n }, [live, service, event, enabled]);\n}\n","\"use client\";\n\n// `qd.<service>.<stream>.useStream(scope, { max })` (RFC 0003 section 12.5):\n// a feed that starts with recent history and then appends, such as logs or\n// metrics. The first answer is the server's seed (the latest items it kept\n// for the scope), then every item pushed after it arrives in order; the hook\n// shows the latest `max` (default 500). A global stream takes no scope:\n// `useStream({ max })`. Two components holding one feed share one\n// subscription (`streams.ts`).\n\nimport { useCallback, useEffect, useMemo, useSyncExternalStore } from \"react\";\nimport type { QuickdrawError } from \"../../protocol/errors\";\nimport { useLiveData } from \"./liveHooks\";\nimport {\n feedKey,\n PENDING_STREAM,\n streamMaxOf,\n type StreamState,\n type StreamTarget,\n} from \"./streams\";\n\n/** Options of `useStream`. */\nexport interface UseStreamOptions {\n /** How many of the latest items to show. Default 500; at most 10,000. */\n readonly max?: number;\n /** `false` holds no subscription and shows nothing. Default `true`. */\n readonly enabled?: boolean;\n}\n\n/** What `useStream` returns. */\nexport interface UseStreamResult<Item> {\n /** The latest items, oldest first: the seed, then what was pushed after it. */\n readonly items: readonly Item[];\n /** True until the server answers the subscribe with the seed. */\n readonly isLoading: boolean;\n /** Why the subscribe was refused: `FORBIDDEN` for a feed the user may not read. */\n readonly error: QuickdrawError | null;\n}\n\nconst IDLE: StreamState = Object.freeze({\n items: Object.freeze([]),\n isLoading: false,\n error: null,\n});\n\n/**\n * One feed of a stream, live. `scope` is the scope of a scoped stream (a\n * `null` or empty one holds nothing) and `undefined` for a global stream.\n */\nexport function useStream<Item>(\n target: StreamTarget,\n scope: string | null | undefined,\n options: UseStreamOptions = {},\n): UseStreamResult<Item> {\n const { live, awaiting } = useLiveData(`${target.service}.${target.stream}.useStream`);\n const feed = target.scoped ? (typeof scope === \"string\" ? scope : \"\") : undefined;\n const active = options.enabled !== false && feed !== \"\";\n const max = streamMaxOf(options.max);\n const key = feedKey(target.service, target.stream, feed);\n useEffect(\n () => (active ? live.streams.hold(target, feed, max) : undefined),\n [live, target, feed, max, active],\n );\n const listen = useCallback(\n (listener: () => void) => live.streams.listen(key, listener),\n [live, key],\n );\n // Awaiting new credentials' hello, it shows none of the last user's items.\n const read = (): StreamState =>\n active ? (awaiting ? PENDING_STREAM : live.streams.state(key)) : IDLE;\n // A server holds no feed: loading, as the browser hydrates it too.\n const onServer = (): StreamState => (active ? PENDING_STREAM : IDLE);\n const state = useSyncExternalStore(listen, read, onServer);\n return useMemo(() => {\n const items =\n state.items.length > max ? state.items.slice(state.items.length - max) : state.items;\n return { items: items as readonly Item[], isLoading: state.isLoading, error: state.error };\n }, [state, max]);\n}\n","\"use client\";\n\n// The realtime members of `qd.<service>` (RFC 0003 section 12.5), built once\n// per contract with the rest of the client (`members.ts`): one per stream\n// (`useStream`), per channel (`useChannel`) and per event (`useEvent`). They\n// sit beside the methods and collections, which share their namespace.\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport { isScopedStream } from \"../../contract/realtime\";\nimport type { StreamTarget } from \"./streams\";\nimport { useChannel } from \"./useChannel\";\nimport { useEvent, type UseEventOptions } from \"./useEvent\";\nimport { useStream, type UseStreamOptions } from \"./useStream\";\n\n/**\n * `qd.<service>.<stream>.useStream`: `(scope, options)` for a scoped stream,\n * `(options)` for a global one.\n */\nfunction streamMember(target: StreamTarget): object {\n return Object.freeze({\n useStream: (first?: unknown, second?: UseStreamOptions) => {\n const scope = target.scoped ? (first as string | null | undefined) : undefined;\n const options = target.scoped ? second : (first as UseStreamOptions | undefined);\n return useStream(target, scope, options);\n },\n });\n}\n\n/** The stream, channel and event members of one contract's service, keyed as they sit on `qd.<service>`. */\nexport function realtimeMembers(contract: AnyContract): [string, object][] {\n const service = contract.name;\n const streams = Object.entries(contract.streams).map(([stream, def]): [string, object] => [\n stream,\n streamMember(Object.freeze({ service, stream, scoped: isScopedStream(def) })),\n ]);\n const channels = Object.keys(contract.channels).map((channel): [string, object] => [\n channel,\n Object.freeze({ useChannel: () => useChannel(service, channel) }),\n ]);\n const events = Object.keys(contract.events).map((event): [string, object] => [\n event,\n Object.freeze({\n useEvent: (handler: (payload: unknown) => void, options?: UseEventOptions) => {\n useEvent(service, event, handler, options);\n },\n }),\n ]);\n return [...streams, ...channels, ...events];\n}\n","\"use client\";\n\n// `qd.<service>.<collection>.useCollection(scope, options)` (RFC 0003\n// sections 7, 11 and 11.5): one scope of a collection, live. Replaces 4.1's\n// `useCollection(serviceName, collection, scopeId)`\n// (4.1 `src/client/useCollection.ts:65-369`).\n//\n// Every component showing a scope shares its pipeline\n// (`collectionController.ts`): one load, one page in flight, deltas applied\n// by revision, a resume from the revision held after a reconnect, when the\n// tab shows again after 30 s, and every 5 minutes. The hook shows the state\n// cached under `[\"qd\", service, \"c\", collection, scope]`:\n//\n// - `index`: the scope's members in order, one small row each (`id` and the\n// index fields), for a collection that declares `index`; with `view`, the\n// members the contract's view selects for the connection's user;\n// - `items`: the items loaded among those members, in order. The first page\n// loads with the scope, `loadMore` loads the next, `loadItems(ids)` loads\n// chosen members, and `load: \"all\"` loads every page;\n// - both with the overlays of optimistic mutations laid over them, and the\n// items they added (`cache.addItem`) in their place; `pending` names those\n// whose call is in flight, and `checking` those among them whose call's\n// outcome is unknown until the scope's next load says;\n// - `refused`: the items added with `onRefused: \"keep\"` whose call the\n// server refused, with the error, until the app dismisses one or sends its\n// call again (finding F6.4 of the quickdraw-chat migration).\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useEffect, useMemo, useRef } from \"react\";\nimport type { QuickdrawError } from \"../../protocol/errors\";\nimport { collectionKey } from \"../keys\";\nimport type { CollectionController } from \"./collectionController\";\nimport type { IndexRow } from \"./collectionIndex\";\nimport type { CollectionEntry, CollectionTarget } from \"./collectionLoads\";\nimport { entryQuery } from \"./host\";\nimport {\n useLiveData,\n useOverlayView,\n useRefusedItems,\n useUserId,\n type RefusedItem,\n} from \"./liveHooks\";\nimport { showCollection, viewPredicate, type CollectionView } from \"./views\";\n\nexport type { RefusedItem };\n\n/** Options of `useCollection`. */\nexport interface UseCollectionOptions<View extends string = string> {\n /** A view the collection's contract declares: only the members it selects for the connection's user are shown. */\n readonly view?: View;\n /** `\"all\"` loads every page of the scope, and keeps every item loaded as it changes. */\n readonly load?: \"all\";\n /**\n * The page size to ask for; above the collection's `maxLimit` it is\n * lowered (`clamped`). The first component to show a scope sets it.\n * Default: the collection's `limit`, or its `maxLimit` with `load: \"all\"`.\n */\n readonly limit?: number;\n /**\n * `false` holds no subscription and shows nothing: no items, no index, no\n * count (and `isLoading` false), even while the scope is cached. Default\n * `true`.\n */\n readonly enabled?: boolean;\n}\n\n/** What `useCollection` returns. */\nexport interface UseCollectionResult<Item, Row> {\n /**\n * The items loaded among the members shown, in order, with the items\n * optimistic updates added (`cache.addItem`) in their place until the\n * scope's own copies arrive.\n */\n readonly items: readonly Item[];\n /**\n * The ids of the items shown that an optimistic update added and whose\n * call is in flight: style them as sending. Empty when there are none.\n */\n readonly pending: ReadonlySet<string>;\n /**\n * The ids among `pending` whose call's outcome is unknown: its connection\n * dropped after it was sent, or it timed out, so the server may have made\n * the write. Show them as checking. Each ends with the scope's next load:\n * its own copy shows when the scope holds its id, and a load that answers\n * without it refuses it (into `refused` with `onRefused: \"keep\"`). Only an\n * id the client made, which the server keeps, can be found: give an item\n * one (`newId()`) when the app may send its call again. Empty when there\n * are none.\n */\n readonly checking: ReadonlySet<string>;\n /**\n * The items an optimistic update added with `onRefused: \"keep\"` whose call\n * was refused, oldest first, each with its error, `dismiss()` and\n * `retry()`: not among `items`, so show them where the app shows a failed\n * send. `retry()` sends the same call again; send it only when the call is\n * idempotent (an id the client made, which the server keeps), since a\n * refusal after an unknown outcome may follow a write the server made.\n * Empty when there are none.\n */\n readonly refused: readonly RefusedItem<Item>[];\n /**\n * The members shown, in order: one row each, `id` and the index fields.\n * `undefined` for a collection without an index, and for a scope too large\n * for one (`indexTruncated`), whose view then runs over the items loaded.\n */\n readonly index: readonly Row[] | undefined;\n /** `items` by id. */\n readonly byId: ReadonlyMap<string, Item>;\n /** How many members the scope has, whatever the view; `null` before the first load. */\n readonly totalCount: number | null;\n /** True while a page follows the items loaded (`loadMore`). */\n readonly hasMore: boolean;\n /** True when the page size asked for was above the collection's `maxLimit`, and was lowered to it. */\n readonly clamped: boolean;\n /** True when the scope has more members than an index holds (50,000), so `index` is `undefined`. */\n readonly indexTruncated: boolean;\n /** True until the scope's first load answers. */\n readonly isLoading: boolean;\n /** True while a page is being loaded. */\n readonly isLoadingMore: boolean;\n /** Why the last request failed, or why the server ended the subscription (`FORBIDDEN`, `NOT_FOUND`). */\n readonly error: QuickdrawError | null;\n /** Loads the next page; a load of the whole scope that starts meanwhile cancels it. */\n loadMore(): Promise<void>;\n /** Loads the items of members `ids` (at most 200 per request). Rejects with the server's refusal. */\n loadItems(ids: readonly string[]): Promise<void>;\n /** Loads the scope again from scratch. */\n refresh(): Promise<void>;\n}\n\nconst NOTHING: CollectionView<never> = Object.freeze({\n items: [],\n index: undefined,\n byId: new Map<string, never>(),\n});\n\nconst NONE_PENDING: ReadonlySet<string> = new Set();\n\n/** What the hook shows, and the ids among it of additions whose call is in flight, or of unknown outcome. */\ninterface Shown extends CollectionView<{ readonly id: string }> {\n readonly pending: ReadonlySet<string>;\n readonly checking: ReadonlySet<string>;\n}\n\n/** What the hook returns besides what it shows. */\ntype Actions = Pick<UseCollectionResult<unknown, unknown>, \"loadMore\" | \"loadItems\" | \"refresh\">;\n\n/** The actions of the controller held by `held`; they do nothing while none is held. */\nfunction actionsOf(held: { readonly current: CollectionController | null }): Actions {\n return {\n loadMore: async () => {\n await held.current?.loadMore();\n },\n loadItems: async (ids: readonly string[]) => {\n await held.current?.loadItems(ids);\n },\n refresh: async () => {\n await held.current?.refresh();\n },\n };\n}\n\n/** What the hook returns, from the entry, what it shows of it and the actions. */\nfunction resultOf<Item, Row>(\n entry: CollectionEntry | null | undefined,\n view: Shown,\n refused: readonly RefusedItem<unknown>[],\n active: boolean,\n actions: Actions,\n): UseCollectionResult<Item, Row> {\n const state = entry?.state ?? null;\n const error = entry?.error ?? null;\n return {\n items: view.items as readonly Item[],\n pending: view.pending,\n checking: view.checking,\n refused: refused as readonly RefusedItem<Item>[],\n index: view.index as readonly Row[] | undefined,\n byId: view.byId as ReadonlyMap<string, Item>,\n totalCount: state?.totalCount ?? null,\n hasMore: (state?.nextCursor ?? null) !== null,\n clamped: state?.clamped ?? false,\n indexTruncated: state?.indexTruncated ?? false,\n isLoading: active && state === null && error === null,\n isLoadingMore: entry?.loadingMore ?? false,\n error,\n ...actions,\n };\n}\n\n/** `qd.<service>.<collection>.useCollection(scope, options)`. A `null` or empty scope holds nothing. */\nexport function useCollection<Item, Row = IndexRow>(\n target: CollectionTarget,\n scope: string | null | undefined,\n options: UseCollectionOptions = {},\n): UseCollectionResult<Item, Row> {\n const { connection, queryClient, live, awaiting } = useLiveData(\n `${target.service}.${target.collection}.useCollection`,\n );\n const scopeValue = typeof scope === \"string\" ? scope : \"\";\n const active = options.enabled !== false && scopeValue !== \"\";\n const loadAll = options.load === \"all\";\n const { limit } = options;\n const held = useRef<CollectionController | null>(null);\n useEffect(() => {\n if (!active) {\n return undefined;\n }\n const holding = live.collections.subscribe(target, scopeValue, { limit, loadAll });\n held.current = holding.controller;\n return () => {\n held.current = null;\n holding.release();\n };\n }, [live, target, scopeValue, active, limit, loadAll]);\n const overlays = useOverlayView(queryClient, target.service);\n const userId = useUserId(connection);\n const { data: cached } = useQuery(\n entryQuery<CollectionEntry>(collectionKey(target.service, target.collection, scopeValue)),\n );\n // Disabled, or awaiting new credentials' hello, it shows nothing of what is cached.\n const entry = active && !awaiting ? cached : undefined;\n const predicate = viewPredicate(target.def, options.view);\n const state = entry?.state ?? null;\n const shown = useMemo((): Shown => {\n if (state === null) {\n return { ...NOTHING, pending: NONE_PENDING, checking: NONE_PENDING };\n }\n const added = overlays.added(target.collection, scopeValue);\n const view = showCollection(state, {\n view: predicate,\n who: { userId: userId ?? \"\" },\n overlay: (row) => overlays.apply(row, { collection: target.collection }),\n added: added.map((addition) => addition.item),\n shape: target.def,\n });\n const sending = added.filter((addition) => addition.pending && view.byId.has(addition.item.id));\n const unknown = sending.filter((addition) => addition.unknown);\n return {\n ...view,\n pending:\n sending.length === 0 ? NONE_PENDING : new Set(sending.map((addition) => addition.item.id)),\n checking:\n unknown.length === 0 ? NONE_PENDING : new Set(unknown.map((addition) => addition.item.id)),\n };\n }, [state, predicate, userId, overlays, target.collection, target.def, scopeValue]);\n const refused = useRefusedItems(\n queryClient,\n overlays,\n target.collection,\n active && !awaiting ? scopeValue : \"\",\n );\n const actions = useMemo(() => actionsOf(held), []);\n return useMemo(\n () => resultOf<Item, Row>(entry, shown, refused, active, actions),\n [entry, shown, refused, active, actions],\n );\n}\n","\"use client\";\n\n// `qd.<service>.useEntity(id)` and `qd.<service>.useEntities(ids)` (RFC 0003\n// sections 6, 11 and 11.5): rows of a service, live. Replaces 4.1's\n// `useSubscription(serviceName, entryId)`\n// (4.1 `src/client/useSubscription.ts:42-246`), which put a socket\n// listener per row on the socket, merged updates in arrival order and loaded\n// everything again after a reconnect.\n//\n// A row is subscribed while a mounted component holds it (`entityStore.ts`):\n// ids asked for in one tick share one `qd:sub`, frames apply by revision, and\n// a reconnect asks for each row again with the revision held, so an\n// unchanged row is answered \"not modified\". The hooks show the row cached\n// under `[\"qd\", service, \"e\", id]`, as the subscriber's access tier sees it,\n// with the overlays of optimistic mutations laid over it.\n\nimport { useQueries, useQuery, type QueryObserverResult } from \"@tanstack/react-query\";\nimport { useEffect, useMemo } from \"react\";\nimport type { QuickdrawError } from \"../../protocol/errors\";\nimport { entityKey } from \"../keys\";\nimport type { OverlayView } from \"../optimistic\";\nimport { EMPTY_ENTITY, type EntityEntry } from \"./entities\";\nimport { entryQuery } from \"./host\";\nimport { useLiveData, useOverlayView } from \"./liveHooks\";\n\n/** Options of `useEntity` and `useEntities`. */\nexport interface UseEntityOptions {\n /**\n * `false` holds no subscription and shows nothing: `data` is `undefined`\n * (and `isLoading` false) even while the row is cached. Default `true`.\n */\n readonly enabled?: boolean;\n}\n\n/** What `qd.<service>.useEntity(id)` returns. */\nexport interface UseEntityResult<Row> {\n /**\n * The row as the subscriber's access tier sees it (fields above that tier\n * are absent), with optimistic edits laid over it; `undefined` while\n * loading, once removed, or after an error.\n */\n readonly data: Row | undefined;\n /** True until the first answer for the row. */\n readonly isLoading: boolean;\n /** True when the server says the row does not exist (deleted, or never there), or an optimistic removal hides it. */\n readonly isRemoved: boolean;\n /** Why the subscription failed or ended: `FORBIDDEN` when access is refused or revoked. */\n readonly error: QuickdrawError | null;\n}\n\n/** What `qd.<service>.useEntities(ids)` returns. */\nexport interface UseEntitiesResult<Row> {\n /** One entry per id, in the order of `ids`: the row, or `undefined` while loading, once removed, or after an error. */\n readonly data: readonly (Row | undefined)[];\n /** The rows shown, by id. */\n readonly byId: ReadonlyMap<string, Row>;\n /** True while any of the rows waits for its first answer. */\n readonly isLoading: boolean;\n /** The first error among the rows, or `null`. */\n readonly error: QuickdrawError | null;\n /** Each failed row's error, by id. */\n readonly errors: ReadonlyMap<string, QuickdrawError>;\n}\n\n/** What the hooks show of an entry. */\nfunction shown<Row>(\n entry: EntityEntry<Row> | null | undefined,\n view: OverlayView,\n active: boolean,\n): UseEntityResult<Row> {\n const held = entry ?? (EMPTY_ENTITY as EntityEntry<Row>);\n const data = held.data === undefined ? undefined : view.apply(held.data, { readAt: held.readAt });\n return {\n data,\n isLoading: active && held.data === undefined && !held.removed && held.error === null,\n isRemoved: held.removed || (held.data !== undefined && data === undefined),\n error: held.error,\n };\n}\n\n/** `qd.<service>.useEntity(id, options)`: row `id` of `service`, live. A `null` or empty id holds nothing. */\nexport function useEntity<Row>(\n service: string,\n id: string | null | undefined,\n options: UseEntityOptions = {},\n): UseEntityResult<Row> {\n const { queryClient, live, awaiting } = useLiveData(`${service}.useEntity`);\n const rowId = typeof id === \"string\" ? id : \"\";\n const active = options.enabled !== false && rowId !== \"\";\n useEffect(\n () => (active ? live.entities.subscribe(service, [rowId]) : undefined),\n [live, service, rowId, active],\n );\n const view = useOverlayView(queryClient, service);\n const { data: entry } = useQuery(entryQuery<EntityEntry<Row>>(entityKey(service, rowId)));\n // Disabled, or awaiting new credentials' hello, it shows nothing of what is cached.\n const held = active && !awaiting ? entry : undefined;\n return useMemo(() => shown(held, view, active), [held, view, active]);\n}\n\nconst NO_ENTRIES: readonly undefined[] = Object.freeze([]);\n\n/** The entries of `useQueries`' results: a stable function, so TanStack keeps its combined result while they do not change. */\nfunction entriesOf<Row>(\n results: readonly QueryObserverResult<EntityEntry<Row> | null>[],\n): (EntityEntry<Row> | null | undefined)[] {\n return results.map((result) => result.data);\n}\n\n/** What `useEntities` shows of the entries of `ids`. */\nfunction combined<Row>(\n ids: readonly string[],\n entries: readonly (EntityEntry<Row> | null | undefined)[],\n view: OverlayView,\n active: boolean,\n): UseEntitiesResult<Row> {\n const data: (Row | undefined)[] = [];\n const byId = new Map<string, Row>();\n const errors = new Map<string, QuickdrawError>();\n let isLoading = false;\n for (const [position, id] of ids.entries()) {\n const row = shown(entries[position], view, active && id !== \"\");\n data.push(row.data);\n if (row.data !== undefined) {\n byId.set(id, row.data);\n }\n if (row.error !== null) {\n errors.set(id, row.error);\n }\n isLoading ||= row.isLoading;\n }\n return { data, byId, isLoading, error: errors.values().next().value ?? null, errors };\n}\n\n/**\n * `qd.<service>.useEntities(ids, options)`: rows `ids` of `service`, live,\n * subscribed together (one `qd:sub` per 500 ids).\n */\nexport function useEntities<Row>(\n service: string,\n ids: readonly string[],\n options: UseEntityOptions = {},\n): UseEntitiesResult<Row> {\n const { queryClient, live, awaiting } = useLiveData(`${service}.useEntities`);\n const joined = ids.map((id) => (typeof id === \"string\" ? id : \"\")).join(\"\\u0000\");\n const count = ids.length;\n const rowIds = useMemo(() => (count === 0 ? [] : joined.split(\"\\u0000\")), [joined, count]);\n const active = options.enabled !== false;\n useEffect(() => {\n const held = rowIds.filter((id) => id !== \"\");\n return active && held.length > 0 ? live.entities.subscribe(service, held) : undefined;\n }, [live, service, rowIds, active]);\n const view = useOverlayView(queryClient, service);\n const entries = useQueries({\n queries: rowIds.map((id) => entryQuery<EntityEntry<Row>>(entityKey(service, id))),\n combine: entriesOf<Row>,\n });\n // Disabled, or awaiting new credentials' hello, it shows nothing of what is cached.\n const held = active && !awaiting ? entries : NO_ENTRIES;\n return useMemo(() => combined(rowIds, held, view, active), [rowIds, held, view, active]);\n}\n","\"use client\";\n\n// The live members of `qd.<service>` (RFC 0003 sections 11, 11.5, 12.2 and\n// 12.5), built once per contract with the rest of the client\n// (`../members.ts`): `useEntity` and `useEntities` for a contract with an\n// entity, one member per collection,\n// `qd.<service>.<collection>.useCollection`, and one per stream, channel and\n// event (`realtimeMembers.ts`). A collection's member lives beside the\n// methods, not on the service, because methods, collections, streams,\n// channels and events share one namespace. For the same reason a search kit\n// method's `useSearch` lives on that method's member,\n// `qd.<service>.<search>.useSearch`. A contract with the admin kit also gets\n// `qd.<service>.admin`, its admin methods' members together (`../admin.ts`).\n\nimport type { AnyContract } from \"../../contract/defineContract\";\nimport type { MethodDef } from \"../../contract/methods\";\nimport { clientAdminNamespace } from \"../adminMeta\";\nimport type { MethodTarget } from \"../members\";\nimport type { CollectionTarget } from \"./collectionLoads\";\nimport { realtimeMembers } from \"./realtimeMembers\";\nimport { searchTargetOf } from \"./searchResults\";\nimport { useCollection, type UseCollectionOptions } from \"./useCollection\";\nimport { useEntities, useEntity, type UseEntityOptions } from \"./useEntity\";\nimport { useSearch } from \"./useSearch\";\n\ntype UseSearchOptions = Parameters<typeof useSearch>[2];\n\n/**\n * The live members of one contract's service, keyed as they sit on\n * `qd.<service>`, and its `admin` member when the contract has the admin\n * kit (`methods` are the service's method members). Built with\n * `Object.fromEntries`, so a collection named `__proto__` is an ordinary\n * member, never a prototype.\n */\nexport function liveMembers(\n contract: AnyContract,\n methods: Readonly<Record<string, object>> = {},\n): Readonly<Record<string, object>> {\n const service = contract.name;\n const entities: [string, object][] =\n contract.entity === undefined\n ? []\n : [\n [\n \"useEntity\",\n (id: string | null | undefined, options?: UseEntityOptions) =>\n useEntity(service, id, options),\n ],\n [\n \"useEntities\",\n (ids: readonly string[], options?: UseEntityOptions) =>\n useEntities(service, ids, options),\n ],\n ];\n const collections = Object.entries(contract.collections).map(([collection, def]) => {\n const target: CollectionTarget = Object.freeze({ service, collection, def });\n const member = Object.freeze({\n useCollection: (scope: string | null | undefined, options?: UseCollectionOptions) =>\n useCollection(target, scope, options),\n });\n return [collection, member] as [string, object];\n });\n const admin = Object.entries(clientAdminNamespace(contract, methods));\n return Object.freeze(\n Object.fromEntries([...entities, ...collections, ...realtimeMembers(contract), ...admin]),\n );\n}\n\n/**\n * What a query member gets besides its own hooks: `useSearch` when the\n * search kit made its method (RFC 0003 section 12.2), found by what the\n * contract half marked it with, never by its name; nothing otherwise.\n */\nexport function searchMember(\n target: MethodTarget,\n definition: MethodDef,\n contract: AnyContract,\n): Readonly<Record<string, unknown>> {\n const search = searchTargetOf(target, definition, contract);\n if (search === undefined) {\n return {};\n }\n return {\n useSearch: (q: string, options?: UseSearchOptions) => useSearch(search, q, options),\n };\n}\n","\"use client\";\n\n// `createQuickdrawClient(contracts)` (RFC 0003 section 11): the client object\n// built at runtime from the app's contracts (`members.ts`), with no code\n// generation and no per-app wrapper file. Each member is made once, so its\n// hooks keep their identity across renders.\n//\n// The hooks read the connection of the provider they render under. `call`,\n// `prefetch` and `qd.invalidate` run outside React, so they use the\n// connection and the invalidation coordinator of the `QuickdrawProvider` this\n// client was given to (`binding.ts`), and fail with `INTERNAL` while none is\n// mounted.\n\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport type { ContractMap } from \"../contract/infer\";\nimport {\n attachBinding,\n connectionOf,\n createBinding,\n invalidateWith,\n registerQuery,\n setDataWith,\n type Binding,\n} from \"./binding\";\nimport { callData } from \"./call\";\nimport type { MutationCallOptions, QueryCallOptions, QuickdrawClient } from \"./clientTypes\";\nimport {\n shareKeepingVersion,\n useMethodMutation,\n useMethodQuery,\n type MethodMutationOptions,\n type MethodQueryOptions,\n} from \"./hooks\";\nimport { methodKey, type MethodQueryKey } from \"./keys\";\nimport { liveMembers, searchMember } from \"./live/members\";\nimport { buildCaller, type MethodTarget } from \"./members\";\nimport { fetchMethodQuery } from \"./query\";\n\nexport { bindConnection, isWatchedQuery } from \"./binding\";\n\n/** The members of the client object besides its services. */\nconst RESERVED_KEYS = [\"invalidate\"] as const;\n\nfunction queryMember(\n binding: Binding,\n target: MethodTarget,\n extra: Readonly<Record<string, unknown>>,\n): object {\n const key = (input?: unknown): MethodQueryKey => methodKey(target.service, target.method, input);\n const member = Object.freeze({\n ...extra,\n useQuery: (input?: unknown, options?: MethodQueryOptions<unknown>) =>\n useMethodQuery(target, input, options),\n call: async (input?: unknown, options?: QueryCallOptions): Promise<unknown> =>\n await callData(connectionOf(binding, target, \"call\"), {\n ...target,\n input,\n signal: options?.signal,\n timeoutMs: options?.timeoutMs,\n }),\n key,\n setData: setDataWith(binding, target),\n async prefetch(queryClient: QueryClient, input?: unknown): Promise<void> {\n const connection = connectionOf(binding, target, \"prefetch\");\n const queryKey = key(input);\n await queryClient.prefetchQuery({\n queryKey,\n queryFn: ({ signal }) =>\n fetchMethodQuery(\n connection,\n queryClient,\n {\n service: target.service,\n method: target.method,\n input,\n key: queryKey,\n output: target.output,\n },\n signal,\n ),\n structuralSharing: shareKeepingVersion(undefined),\n });\n },\n });\n registerQuery(binding, member, target);\n return member;\n}\n\nfunction mutationMember(binding: Binding, target: MethodTarget): object {\n return Object.freeze({\n useMutation: (options?: MethodMutationOptions<unknown, unknown>) =>\n useMethodMutation(target, options),\n call: async (input?: unknown, options?: MutationCallOptions): Promise<unknown> =>\n await callData(connectionOf(binding, target, \"call\"), {\n ...target,\n input,\n timeoutMs: options?.timeoutMs,\n }),\n });\n}\n\n/**\n * Creates the typed client of `contracts`: `qd.<key>.<method>` for every\n * contract in the map, with `useQuery`, `call`, `key`, `setData` and `prefetch` on a\n * query (and `useSearch` on one the search kit made) and `useMutation` and\n * `call` on a mutation; `qd.<key>.useEntity` and `useEntities` for a\n * contract with an entity; `qd.<key>.<collection>` with `useCollection` for\n * each collection; `qd.<key>.admin` for a contract with the admin kit; plus\n * `qd.invalidate`. Render a `QuickdrawProvider` with\n * `client={qd}` above the components that use it. No contract may be keyed\n * `invalidate`.\n *\n * @example\n * export const qd = createQuickdrawClient({ task, project });\n * const { data } = qd.task.get.useQuery({ id });\n * const rename = qd.task.rename.useMutation();\n * const { data: row } = qd.task.useEntity(id);\n * const { items, index } = qd.task.byProject.useCollection(projectId, { view: \"mine\" });\n * const { items: found } = qd.task.search.useSearch(text, { scope: projectId });\n * qd.invalidate(qd.task.list);\n */\nexport function createQuickdrawClient<const Contracts extends ContractMap>(\n contracts: Contracts & { readonly invalidate?: never },\n): QuickdrawClient<Contracts> {\n const binding = createBinding();\n const client = buildCaller(\n \"createQuickdrawClient\",\n contracts,\n (target, definition, contract) =>\n target.kind === \"query\"\n ? queryMember(binding, target, searchMember(target, definition, contract))\n : mutationMember(binding, target),\n RESERVED_KEYS,\n liveMembers,\n );\n // Not enumerable: the client's own keys stay its services.\n Object.defineProperty(client, \"invalidate\", { value: invalidateWith(binding) });\n Object.freeze(client);\n attachBinding(client, binding);\n return client as QuickdrawClient<Contracts>;\n}\n","\"use client\";\n\n// `QuickdrawProvider` and `useQuickdraw` (RFC 0003 sections 11.1 and 11.3).\n// The provider owns one connection (`connection.ts`), the TanStack\n// `QueryClient` the hooks cache in and that client's invalidation\n// coordinator (`coordinator.ts`), and binds the connection and the\n// coordinator to the client it is given, so the client's `call`, `prefetch`\n// and `invalidate` use them too. Ported from 4.1's provider\n// (4.1 `src/client/QuickdrawProvider.tsx:223-437`), which held the socket\n// in React state and recreated it on every token change.\n//\n// React's strict mode mounts effects twice. 4.1 guarded the socket with a ref\n// (4.1 `src/client/QuickdrawProvider.tsx:297-298`); here the connection is\n// retained by the mounted provider and closed a tick after its last release,\n// so a strict-mode remount keeps the same socket instead of reconnecting.\n// A dropped connection clears nothing: cached data stays. A session the\n// server ends (its disconnect, or a reconnect refused with `UNAUTHENTICATED`\n// or `FORBIDDEN`) is signed out: the hello, the grants and everything\n// quickdraw cached are gone (`session.ts`). After a reconnect\n// with the same credentials, the coordinator refetches only the queries that\n// watch a topic (they missed its changes) or are stale, each after a random\n// delay of up to 2 s by default (`reconnectJitterMs`), where 4.1 invalidated\n// every query at once (4.1 `src/client/QuickdrawProvider.tsx:320-321`).\n// The cache follows the user the server's hello names (`session.ts`):\n// another user's hello empties it, and new credentials for the same user\n// refetch it. New grants (`qd:access`) refetch every query, and a revoked row\n// or scope (`qd:revoked`) the method queries of its service.\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport type { AccessLevel } from \"../contract/access\";\nimport type { ContractMap } from \"../contract/infer\";\nimport type { HelloFrame, ProtocolMismatch } from \"../protocol/version\";\nimport type { QuickdrawClient } from \"./clientTypes\";\nimport {\n createQuickdrawConnection,\n type ConnectionAuth,\n type ConnectionRefusal,\n type ConnectionStatus,\n type QuickdrawConnection,\n type QuickdrawConnectionOptions,\n} from \"./connection\";\nimport { QuickdrawContext, useConnectionState, useQuickdrawContext } from \"./context\";\nimport { createInvalidationCoordinator, reconnectJitter } from \"./coordinator\";\nimport { bindConnection, isWatchedQuery } from \"./createClient\";\nimport { liveDataOf } from \"./live/liveData\";\nimport { reloadOncePerSession } from \"./reload\";\nimport { refetchOnAccessChanges, sessionOf } from \"./session\";\n\n/** Props of {@link QuickdrawProvider}. */\nexport interface QuickdrawProviderProps<Contracts extends ContractMap> extends Omit<\n QuickdrawConnectionOptions,\n \"auth\"\n> {\n /** The client from `createQuickdrawClient`; its `call` and `prefetch` use this provider's connection. */\n readonly client: QuickdrawClient<Contracts>;\n /**\n * The credentials to connect with: a token (sent as `auth.token`), handshake\n * fields, or nothing for an anonymous or cookie-authenticated connection.\n * When they change (by value), the connection reconnects with them. When\n * the server's hello then names another user, everything quickdraw cached\n * is removed, since it was read as the last user; when it names the same\n * user, it is refetched as the new credentials.\n */\n readonly auth?: ConnectionAuth;\n /** The cache the hooks use. Default: a `QueryClient` the provider creates (5-minute stale time). */\n readonly queryClient?: QueryClient;\n /**\n * After a reconnect, the longest random delay before each watched or stale\n * query is refetched, so a fleet of clients that reconnect together (a\n * server restart) does not refetch in one burst; `0` refetches them at\n * once. Default 2,000 ms. Entity rows and collections resume by revision\n * at once either way.\n */\n readonly reconnectJitterMs?: number;\n readonly children?: React.ReactNode;\n}\n\n/** What {@link useQuickdraw} returns. */\nexport interface QuickdrawStatus {\n /** The provider's connection, for non-hook code such as `call`. */\n readonly connection: QuickdrawConnection;\n readonly status: ConnectionStatus;\n /**\n * True while the connection is connected. It turns true before the\n * server's hello names the user (see `isKnown`) and false while it\n * reconnects (see `reconnecting`).\n */\n readonly isConnected: boolean;\n /**\n * True once the server's hello on the current credentials has arrived:\n * `userId` is then final, `null` meaning anonymous. False before it, again\n * from new credentials (`auth` changed) until their hello, and again once\n * the server ended the session or refused a connect for it (`status`\n * `\"disconnected\"`, or `\"refused\"` after the handshake's error code\n * `UNAUTHENTICATED` or `FORBIDDEN`): the hello, the grants and everything\n * quickdraw cached are gone. Another protocol (`refusal.code`\n * `\"PROTOCOL_MISMATCH\"`) keeps them. It stays true while the connection\n * reconnects with the same credentials. Gate on it, not on `isConnected`;\n * while it is false, a stopped `status` tells \"signed out\" from \"not\n * known yet\".\n */\n readonly isKnown: boolean;\n /**\n * True while the connection is connecting again after it was connected\n * with its current credentials (the network dropped, or the server asked\n * it to rotate). What it showed stays meanwhile, and `userId` is kept.\n */\n readonly reconnecting: boolean;\n /** The server's `qd:hello` on the current credentials: its version, limits and who the socket acts for. */\n readonly hello: HelloFrame | null;\n /**\n * The user the connection acts for, from the server's hello: `null` while\n * anonymous, before the hello on the current credentials arrives, and\n * once the server ended the session (`isKnown` and `status` tell them\n * apart).\n */\n readonly userId: string | null;\n /**\n * The user's service grants: from the server's hello, then from each\n * `qd:access` push; `null` before the hello on the current credentials,\n * and once the server ended the session.\n */\n readonly serviceAccess: Readonly<Record<string, AccessLevel>> | null;\n /** Why the server refused the connection, while `status` is `refused`. */\n readonly refusal: ConnectionRefusal | null;\n /** True while any kind of work backs off after a `RATE_LIMITED` answer. */\n readonly isRateLimited: boolean;\n}\n\nfunction createDefaultQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: { queries: { staleTime: 5 * 60 * 1000, refetchOnWindowFocus: false } },\n });\n}\n\n/** The connection for one mounted provider: made on first render, with the props it had then. */\nfunction useProviderConnection(\n props: Omit<QuickdrawConnectionOptions, \"onProtocolMismatch\">,\n onProtocolMismatch: ((mismatch: ProtocolMismatch) => void) | undefined,\n): QuickdrawConnection {\n const mismatch = React.useRef(onProtocolMismatch);\n React.useEffect(() => {\n mismatch.current = onProtocolMismatch;\n }, [onProtocolMismatch]);\n const [connection] = React.useState(() =>\n createQuickdrawConnection({\n ...props,\n onProtocolMismatch: (refused) => {\n (mismatch.current ?? reloadOncePerSession)(refused);\n },\n }),\n );\n return connection;\n}\n\nfunction ConnectedProvider<Contracts extends ContractMap>(\n props: QuickdrawProviderProps<Contracts>,\n): React.ReactElement {\n const {\n client,\n auth,\n queryClient: given,\n reconnectJitterMs,\n children,\n onProtocolMismatch,\n ...options\n } = props;\n const jitterMs = reconnectJitter(\"QuickdrawProvider: reconnectJitterMs\", reconnectJitterMs);\n const [ownQueryClient] = React.useState(createDefaultQueryClient);\n const queryClient = given ?? ownQueryClient;\n const coordinator = React.useMemo(\n () => createInvalidationCoordinator(queryClient),\n [queryClient],\n );\n const connection = useProviderConnection({ ...options, auth }, onProtocolMismatch);\n React.useEffect(() => {\n // From now on each hello settles the cache for the user it names.\n sessionOf(connection, queryClient);\n // Before the socket connects: `qd:presence` frames can arrive before any hook asks.\n liveDataOf(connection, queryClient);\n }, [connection, queryClient]);\n React.useEffect(() => connection.retain(), [connection]);\n // Disposed a tick after the provider unmounts or takes another `QueryClient`.\n React.useEffect(() => coordinator.retain(), [coordinator]);\n React.useEffect(() => {\n // New credentials reconnect; the hello that follows decides what the cache keeps.\n connection.setAuth(auth);\n }, [connection, auth]);\n React.useEffect(\n () =>\n connection.onReconnect(() => {\n coordinator.refetchAfterReconnect({\n watched: (query) => isWatchedQuery(client, query.queryKey),\n jitterMs,\n });\n }),\n [connection, coordinator, client, jitterMs],\n );\n React.useEffect(() => refetchOnAccessChanges(connection, coordinator), [connection, coordinator]);\n React.useEffect(\n () => bindConnection(client, connection, coordinator),\n [client, connection, coordinator],\n );\n const value = React.useMemo(\n () => ({ connection, queryClient, coordinator }),\n [connection, queryClient, coordinator],\n );\n return (\n <QueryClientProvider client={queryClient}>\n <QuickdrawContext.Provider value={value}>{children}</QuickdrawContext.Provider>\n </QueryClientProvider>\n );\n}\n\n/**\n * Connects to the quickdraw server at `url` and provides the connection and\n * the `QueryClient` to the hooks of `client` below it. It renders TanStack's\n * `QueryClientProvider` itself.\n *\n * The socket options (`socketOptions`, `transports`, `binary`, `timeoutMs`)\n * are read when the provider mounts; a new `url` makes a new connection.\n * Changing `auth` reconnects with the new credentials.\n *\n * @example\n * <QuickdrawProvider client={qd} url=\"http://localhost:4000\" auth={token}>\n * <App />\n * </QuickdrawProvider>\n */\nexport function QuickdrawProvider<Contracts extends ContractMap>(\n props: QuickdrawProviderProps<Contracts>,\n): React.ReactElement {\n return <ConnectedProvider key={props.url} {...props} />;\n}\n\n/**\n * The provider's connection state: whether it is connected, whether the\n * server's hello has named the user (`isKnown`) and whether it is\n * reconnecting, the hello, who the connection acts for and their grants, why\n * the server refused the connection, and whether calls are backing off after\n * `RATE_LIMITED`.\n *\n * @example\n * const { status, isKnown, userId } = useQuickdraw();\n * // stopped with nobody known: the server ended or refused the session\n * if (!isKnown) return status === \"disconnected\" || status === \"refused\" ? <SignIn /> : <Spinner />;\n * return userId === null ? <SignIn /> : <App />;\n */\nexport function useQuickdraw(): QuickdrawStatus {\n const { connection } = useQuickdrawContext(\"useQuickdraw\");\n const state = useConnectionState(connection);\n return React.useMemo(\n () => ({\n connection,\n status: state.status,\n isConnected: state.status === \"connected\",\n isKnown: state.hello !== null,\n reconnecting: state.reconnecting,\n hello: state.hello,\n userId: state.hello?.userId ?? null,\n serviceAccess: state.serviceAccess,\n refusal: state.refusal,\n isRateLimited: Object.keys(state.backoff).length > 0,\n }),\n [connection, state],\n );\n}\n"],"mappings":"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","names":["useQuery","useEffect","useMemo","shown","shown","useRef","useRef","shown","useMemo","useSyncExternalStore","noOverlays","useSyncExternalStore","useMemo","useEffect","useQuery","useMemo","useSyncExternalStore","useSyncExternalStore","useMemo","useMemo","useEffect","useRef","useRef","useEffect","useCallback","useEffect","useMemo","useSyncExternalStore","useEffect","useCallback","useSyncExternalStore","useMemo","useQuery","useEffect","useMemo","useRef","useRef","useEffect","useQuery","shown","useMemo","useQueries","useQuery","useEffect","useMemo","useEffect","useQuery","useMemo","held","useQueries"]}
|