@fitzzero/quickdraw-core 5.1.0 → 5.1.1

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.
@@ -11,7 +11,7 @@ import {
11
11
  SERVER_EVENTS,
12
12
  isAuthenticationRefused,
13
13
  isProtocolMismatch
14
- } from "./chunk-VJTFXHOK.js";
14
+ } from "./chunk-VSQBHPWH.js";
15
15
  import {
16
16
  DEFAULT_COLLECTION_MAX_LIMIT
17
17
  } from "./chunk-RT6OILOI.js";
@@ -4284,4 +4284,4 @@ export {
4284
4284
  viewPredicate,
4285
4285
  showCollection
4286
4286
  };
4287
- //# sourceMappingURL=chunk-KNDDCVQJ.js.map
4287
+ //# sourceMappingURL=chunk-OECZPRPW.js.map
@@ -26,7 +26,7 @@ import {
26
26
  import {
27
27
  ACCESS_LEVELS,
28
28
  isAccessLevel
29
- } from "./chunk-VJTFXHOK.js";
29
+ } from "./chunk-VSQBHPWH.js";
30
30
  import {
31
31
  isStandardSchema
32
32
  } from "./chunk-47AEXVDM.js";
@@ -513,4 +513,4 @@ export {
513
513
  sharingSpecOf,
514
514
  sharing
515
515
  };
516
- //# sourceMappingURL=chunk-2UELNHDD.js.map
516
+ //# sourceMappingURL=chunk-QCHKWIRS.js.map
@@ -77,7 +77,7 @@ import {
77
77
  streamRoom,
78
78
  topicRoom,
79
79
  userRoom
80
- } from "./chunk-VJTFXHOK.js";
80
+ } from "./chunk-VSQBHPWH.js";
81
81
  import {
82
82
  hasJsonSchema
83
83
  } from "./chunk-47AEXVDM.js";
@@ -9206,4 +9206,4 @@ export {
9206
9206
  watchAdapterClients,
9207
9207
  createServer
9208
9208
  };
9209
- //# sourceMappingURL=chunk-A6DJBGOG.js.map
9209
+ //# sourceMappingURL=chunk-RZTP4IEW.js.map
@@ -13,12 +13,12 @@ import {
13
13
  searchTargetOf,
14
14
  streamMaxOf,
15
15
  viewPredicate
16
- } from "./chunk-KNDDCVQJ.js";
16
+ } from "./chunk-OECZPRPW.js";
17
17
  import {
18
18
  MAX_SUBSCRIBE_IDS,
19
19
  PROTOCOL_VERSION,
20
20
  QUICKDRAW_VERSION
21
- } from "./chunk-VJTFXHOK.js";
21
+ } from "./chunk-VSQBHPWH.js";
22
22
  import {
23
23
  isScopedStream
24
24
  } from "./chunk-RT6OILOI.js";
@@ -849,4 +849,4 @@ function createMockClient(contracts, options = {}) {
849
849
  export {
850
850
  createMockClient
851
851
  };
852
- //# sourceMappingURL=chunk-3674EIRT.js.map
852
+ //# sourceMappingURL=chunk-SHEGLZEP.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-4YO5H5ON.js";
4
4
 
5
5
  // src/version.ts
6
- var QUICKDRAW_VERSION = "5.1.0";
6
+ var QUICKDRAW_VERSION = "5.1.1";
7
7
 
8
8
  // src/contract/names.ts
9
9
  function entityRoom(service, id, level) {
@@ -127,4 +127,4 @@ export {
127
127
  MAX_SUBSCRIBE_IDS,
128
128
  MAX_SCOPE_LENGTH
129
129
  };
130
- //# sourceMappingURL=chunk-VJTFXHOK.js.map
130
+ //# sourceMappingURL=chunk-VSQBHPWH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts","../src/contract/names.ts","../src/protocol/version.ts","../src/contract/access.ts"],"sourcesContent":["/** The published version of `@fitzzero/quickdraw-core`. Kept in step with package.json. */\nexport const QUICKDRAW_VERSION = \"5.1.0\";\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\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 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), as `qd:hello` announces it.\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}\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","// Access levels and access-control lists, unchanged from 4.1\n// (4.1 `src/shared/types.ts:7-14`). The level names are stored in app data\n// (`User.serviceAccess`, JSON access lists), so they never change.\n\nexport type AccessLevel = \"Public\" | \"Read\" | \"Moderate\" | \"Admin\";\n\n/** Every access level, lowest first. */\nexport const ACCESS_LEVELS: readonly AccessLevel[] = Object.freeze([\n \"Public\",\n \"Read\",\n \"Moderate\",\n \"Admin\",\n]);\n\n/** True when `value` is one of the four access level names. */\nexport function isAccessLevel(value: unknown): value is AccessLevel {\n return typeof value === \"string\" && (ACCESS_LEVELS as readonly string[]).includes(value);\n}\n\nexport type ACE = {\n userId: string;\n level: AccessLevel;\n};\n\nexport type ACL = ACE[];\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;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;;;ACzGH,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,mBAAmB;;;ACpEzB,IAAM,gBAAwC,OAAO,OAAO;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,SAAS,cAAc,OAAsC;AAClE,SAAO,OAAO,UAAU,YAAa,cAAoC,SAAS,KAAK;AACzF;","names":[]}
1
+ {"version":3,"sources":["../src/version.ts","../src/contract/names.ts","../src/protocol/version.ts","../src/contract/access.ts"],"sourcesContent":["/** The published version of `@fitzzero/quickdraw-core`. Kept in step with package.json. */\nexport const QUICKDRAW_VERSION = \"5.1.1\";\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\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 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), as `qd:hello` announces it.\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}\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","// Access levels and access-control lists, unchanged from 4.1\n// (4.1 `src/shared/types.ts:7-14`). The level names are stored in app data\n// (`User.serviceAccess`, JSON access lists), so they never change.\n\nexport type AccessLevel = \"Public\" | \"Read\" | \"Moderate\" | \"Admin\";\n\n/** Every access level, lowest first. */\nexport const ACCESS_LEVELS: readonly AccessLevel[] = Object.freeze([\n \"Public\",\n \"Read\",\n \"Moderate\",\n \"Admin\",\n]);\n\n/** True when `value` is one of the four access level names. */\nexport function isAccessLevel(value: unknown): value is AccessLevel {\n return typeof value === \"string\" && (ACCESS_LEVELS as readonly string[]).includes(value);\n}\n\nexport type ACE = {\n userId: string;\n level: AccessLevel;\n};\n\nexport type ACL = ACE[];\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;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;;;ACzGH,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,mBAAmB;;;ACpEzB,IAAM,gBAAwC,OAAO,OAAO;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,SAAS,cAAc,OAAsC;AAClE,SAAO,OAAO,UAAU,YAAa,cAAoC,SAAS,KAAK;AACzF;","names":[]}
@@ -43,12 +43,12 @@ import {
43
43
  useQuickdrawContext,
44
44
  userOf,
45
45
  viewPredicate
46
- } from "./chunk-KNDDCVQJ.js";
46
+ } from "./chunk-OECZPRPW.js";
47
47
  import {
48
48
  CLIENT_EVENTS,
49
49
  SERVICE_TOPIC,
50
50
  collectionTopic
51
- } from "./chunk-VJTFXHOK.js";
51
+ } from "./chunk-VSQBHPWH.js";
52
52
  import {
53
53
  isScopedStream
54
54
  } from "./chunk-RT6OILOI.js";
@@ -1410,4 +1410,4 @@ export {
1410
1410
  QuickdrawProvider,
1411
1411
  useQuickdraw
1412
1412
  };
1413
- //# sourceMappingURL=chunk-JZBCLNDU.js.map
1413
+ //# sourceMappingURL=chunk-ZIVPHYRG.js.map
@@ -10,7 +10,7 @@ import {
10
10
  shouldRetry,
11
11
  useLiveData,
12
12
  useQuickdraw
13
- } from "../chunk-JZBCLNDU.js";
13
+ } from "../chunk-ZIVPHYRG.js";
14
14
  import {
15
15
  DEFAULT_BACKOFF_MS,
16
16
  DEFAULT_INVALIDATION_WINDOW_MS,
@@ -40,9 +40,9 @@ import {
40
40
  useAdminServices,
41
41
  useConnectionState,
42
42
  useQuickdrawContext
43
- } from "../chunk-KNDDCVQJ.js";
43
+ } from "../chunk-OECZPRPW.js";
44
44
  import "../chunk-CDKG4TFA.js";
45
- import "../chunk-VJTFXHOK.js";
45
+ import "../chunk-VSQBHPWH.js";
46
46
  import "../chunk-RT6OILOI.js";
47
47
  import "../chunk-47AEXVDM.js";
48
48
  import "../chunk-Z2LZ7IZ7.js";
package/dist/index.d.ts CHANGED
@@ -7,6 +7,6 @@ export { q as AccessFrame, A as AuthenticationRefused, C as CLIENT_EVENTS, r as
7
7
  export { E as ERROR_CODES, a as ErrorCode, Q as QuickdrawError, R as RateLimitedErrorData, V as ValidationErrorData, W as WireError, b as WireIssue, f as fromWire, h as httpStatus, i as isErrorCode, t as toWire } from './errors-S-bxEIBC.js';
8
8
 
9
9
  /** The published version of `@fitzzero/quickdraw-core`. Kept in step with package.json. */
10
- declare const QUICKDRAW_VERSION = "5.1.0";
10
+ declare const QUICKDRAW_VERSION = "5.1.1";
11
11
 
12
12
  export { QUICKDRAW_VERSION };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  SHARING_METHODS,
5
5
  crud,
6
6
  sharing
7
- } from "./chunk-2UELNHDD.js";
7
+ } from "./chunk-QCHKWIRS.js";
8
8
  import {
9
9
  isCallEnvelope,
10
10
  isCancel
@@ -50,7 +50,7 @@ import {
50
50
  streamRoom,
51
51
  topicRoom,
52
52
  userRoom
53
- } from "./chunk-VJTFXHOK.js";
53
+ } from "./chunk-VSQBHPWH.js";
54
54
  import {
55
55
  CHANNEL_DEFAULT_RATE,
56
56
  DEFAULT_COLLECTION_LIMIT,
@@ -61,7 +61,7 @@ import {
61
61
  serviceGrant,
62
62
  strip,
63
63
  watchAdapterClients
64
- } from "../chunk-A6DJBGOG.js";
64
+ } from "../chunk-RZTP4IEW.js";
65
65
  import {
66
66
  DevWarningError,
67
67
  N_PLUS_ONE_STATEMENTS,
@@ -75,7 +75,7 @@ import {
75
75
  crudSpecOf,
76
76
  sharing,
77
77
  sharingSpecOf
78
- } from "../chunk-2UELNHDD.js";
78
+ } from "../chunk-QCHKWIRS.js";
79
79
  import "../chunk-QEKVYG5F.js";
80
80
  import {
81
81
  abortError,
@@ -109,7 +109,7 @@ import {
109
109
  entityRoom,
110
110
  isAccessLevel,
111
111
  reservedRoomPrefix
112
- } from "../chunk-VJTFXHOK.js";
112
+ } from "../chunk-VSQBHPWH.js";
113
113
  import {
114
114
  CHANNEL_DEFAULT_RATE,
115
115
  DEFAULT_COLLECTION_LIMIT,
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createMockClient
3
- } from "../chunk-3674EIRT.js";
3
+ } from "../chunk-SHEGLZEP.js";
4
4
  import {
5
5
  QuickdrawProvider
6
- } from "../chunk-JZBCLNDU.js";
6
+ } from "../chunk-ZIVPHYRG.js";
7
7
  import {
8
8
  QuickdrawContext
9
- } from "../chunk-KNDDCVQJ.js";
9
+ } from "../chunk-OECZPRPW.js";
10
10
  import "../chunk-CDKG4TFA.js";
11
- import "../chunk-VJTFXHOK.js";
11
+ import "../chunk-VSQBHPWH.js";
12
12
  import "../chunk-RT6OILOI.js";
13
13
  import "../chunk-47AEXVDM.js";
14
14
  import "../chunk-Z2LZ7IZ7.js";
@@ -4,7 +4,7 @@ import {
4
4
  inputKeys,
5
5
  isCustomAccess,
6
6
  runtimeOf
7
- } from "../chunk-A6DJBGOG.js";
7
+ } from "../chunk-RZTP4IEW.js";
8
8
  import {
9
9
  DevWarningError,
10
10
  STRICT_WARNINGS,
@@ -27,7 +27,7 @@ import {
27
27
  PROTOCOL_VERSION,
28
28
  QUICKDRAW_VERSION,
29
29
  SERVER_EVENTS
30
- } from "../chunk-VJTFXHOK.js";
30
+ } from "../chunk-VSQBHPWH.js";
31
31
  import {
32
32
  hasJsonSchema,
33
33
  validate
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  createMockClient
3
- } from "../chunk-3674EIRT.js";
4
- import "../chunk-KNDDCVQJ.js";
3
+ } from "../chunk-SHEGLZEP.js";
4
+ import "../chunk-OECZPRPW.js";
5
5
  import "../chunk-CDKG4TFA.js";
6
- import "../chunk-VJTFXHOK.js";
6
+ import "../chunk-VSQBHPWH.js";
7
7
  import "../chunk-RT6OILOI.js";
8
8
  import "../chunk-47AEXVDM.js";
9
9
  import "../chunk-Z2LZ7IZ7.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fitzzero/quickdraw-core",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
4
4
  "description": "Fast fullstack patterns for real-time applications with Socket.io and TanStack Query",
5
5
  "keywords": [
6
6
  "fullstack",