@fitzzero/quickdraw-core 5.1.0 → 5.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +533 -180
  2. package/dist/{admin-DKwkIh5i.d.ts → admin-DWWrT1h6.d.ts} +2 -2
  3. package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-D4bFKsrb.d.ts} +6 -4
  4. package/dist/{auth-BhWqdyb-.d.ts → auth-DXiSJZaf.d.ts} +42 -16
  5. package/dist/{caller-CXTFswBO.d.ts → caller-BT-Mv4bD.d.ts} +117 -22
  6. package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
  7. package/dist/chunk-4D2DOGAW.js.map +1 -0
  8. package/dist/chunk-5CGO426C.js +15 -0
  9. package/dist/chunk-5CGO426C.js.map +1 -0
  10. package/dist/{chunk-A6DJBGOG.js → chunk-6K5BY47X.js} +4594 -3481
  11. package/dist/chunk-6K5BY47X.js.map +1 -0
  12. package/dist/{chunk-VJTFXHOK.js → chunk-753VJIUP.js} +13 -15
  13. package/dist/chunk-753VJIUP.js.map +1 -0
  14. package/dist/{chunk-JZBCLNDU.js → chunk-7QCUX4TK.js} +4 -4
  15. package/dist/chunk-7QCUX4TK.js.map +1 -0
  16. package/dist/chunk-AK23XSWD.js +16 -0
  17. package/dist/chunk-AK23XSWD.js.map +1 -0
  18. package/dist/{chunk-3674EIRT.js → chunk-AONAFOYU.js} +14 -5
  19. package/dist/{chunk-3674EIRT.js.map → chunk-AONAFOYU.js.map} +1 -1
  20. package/dist/chunk-DKE6QO26.js +136 -0
  21. package/dist/chunk-DKE6QO26.js.map +1 -0
  22. package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
  23. package/dist/chunk-DUBU3BB3.js.map +1 -0
  24. package/dist/{chunk-CDKG4TFA.js → chunk-GKH3LJ7N.js} +1 -1
  25. package/dist/chunk-GKH3LJ7N.js.map +1 -0
  26. package/dist/{chunk-KNDDCVQJ.js → chunk-GSIPUNJL.js} +49 -9
  27. package/dist/chunk-GSIPUNJL.js.map +1 -0
  28. package/dist/{chunk-DD4SKCNO.js → chunk-LCC7HNFP.js} +12 -1
  29. package/dist/chunk-LCC7HNFP.js.map +1 -0
  30. package/dist/{chunk-2PWMUVC7.js → chunk-MBH6IDSM.js} +480 -12
  31. package/dist/chunk-MBH6IDSM.js.map +1 -0
  32. package/dist/{chunk-2UELNHDD.js → chunk-NMXYENH4.js} +10 -10
  33. package/dist/{chunk-2UELNHDD.js.map → chunk-NMXYENH4.js.map} +1 -1
  34. package/dist/chunk-NO4M6PO5.js +101 -0
  35. package/dist/chunk-NO4M6PO5.js.map +1 -0
  36. package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
  37. package/dist/chunk-NW6U45HX.js.map +1 -0
  38. package/dist/{chunk-REX5YPHX.js → chunk-RJ5I2VO3.js} +74 -19
  39. package/dist/chunk-RJ5I2VO3.js.map +1 -0
  40. package/dist/{chunk-QEKVYG5F.js → chunk-RL4VKLBX.js} +1 -1
  41. package/dist/{chunk-QEKVYG5F.js.map → chunk-RL4VKLBX.js.map} +1 -1
  42. package/dist/chunk-XH2IZVLT.js +62 -0
  43. package/dist/chunk-XH2IZVLT.js.map +1 -0
  44. package/dist/{chunk-4DIQHASK.js → chunk-Z5ILULF2.js} +26 -7
  45. package/dist/chunk-Z5ILULF2.js.map +1 -0
  46. package/dist/cli/quickdraw-docs.js +5 -3
  47. package/dist/cli/quickdraw-docs.js.map +1 -1
  48. package/dist/client/index.d.ts +30 -18
  49. package/dist/client/index.js +8 -6
  50. package/dist/client/index.js.map +1 -1
  51. package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-hWcPUVS9.d.ts} +3 -3
  52. package/dist/{connection-Cr1BU07W.d.ts → connection-CgijdGpT.d.ts} +8 -4
  53. package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Cp-Wk500.d.ts} +36 -14
  54. package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-BB_PkqQ7.d.ts} +16 -10
  55. package/dist/{envelope-Cp3YcVxC.d.ts → envelope-DzWyIXjj.d.ts} +18 -4
  56. package/dist/{http-Djj2Inuu.d.ts → http-DotQ5bj8.d.ts} +68 -17
  57. package/dist/index.d.ts +7 -7
  58. package/dist/index.js +37 -13
  59. package/dist/index.js.map +1 -1
  60. package/dist/{infer-Teo1xpsd.d.ts → infer-BmoZsL9a.d.ts} +43 -10
  61. package/dist/logger-Yz93KzdV.d.ts +30 -0
  62. package/dist/{metrics-BdBu5o8G.d.ts → metrics-DW80Exve.d.ts} +2 -2
  63. package/dist/origins-kvpxnVcW.d.ts +8 -0
  64. package/dist/prisma/index.d.ts +5 -5
  65. package/dist/prisma/index.js +130 -67
  66. package/dist/prisma/index.js.map +1 -1
  67. package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
  68. package/dist/server/auth/index.d.ts +82 -33
  69. package/dist/server/auth/index.js +273 -268
  70. package/dist/server/auth/index.js.map +1 -1
  71. package/dist/server/express/index.d.ts +9 -2
  72. package/dist/server/express/index.js +1 -1
  73. package/dist/server/index.d.ts +147 -67
  74. package/dist/server/index.js +520 -381
  75. package/dist/server/index.js.map +1 -1
  76. package/dist/server/mcp/index.d.ts +63 -17
  77. package/dist/server/mcp/index.js +256 -54
  78. package/dist/server/mcp/index.js.map +1 -1
  79. package/dist/server/otel.d.ts +3 -3
  80. package/dist/{sharing-DVa8W-yR.d.ts → sharing-UDLn1049.d.ts} +3 -3
  81. package/dist/testing/client.d.ts +14 -14
  82. package/dist/testing/client.js +9 -7
  83. package/dist/testing/client.js.map +1 -1
  84. package/dist/testing/index.d.ts +12 -12
  85. package/dist/testing/index.js +21 -12
  86. package/dist/testing/index.js.map +1 -1
  87. package/dist/testing/mock.d.ts +5 -5
  88. package/dist/testing/mock.js +8 -6
  89. package/dist/{types-Cu0vmx7c.d.ts → types-CYliTP65.d.ts} +1 -1
  90. package/dist/utils/index.d.ts +1 -1
  91. package/package.json +1 -1
  92. package/dist/chunk-2PWMUVC7.js.map +0 -1
  93. package/dist/chunk-4DIQHASK.js.map +0 -1
  94. package/dist/chunk-A6DJBGOG.js.map +0 -1
  95. package/dist/chunk-CDKG4TFA.js.map +0 -1
  96. package/dist/chunk-DD4SKCNO.js.map +0 -1
  97. package/dist/chunk-H23KEFBA.js.map +0 -1
  98. package/dist/chunk-JZBCLNDU.js.map +0 -1
  99. package/dist/chunk-KNDDCVQJ.js.map +0 -1
  100. package/dist/chunk-REX5YPHX.js.map +0 -1
  101. package/dist/chunk-RT6OILOI.js.map +0 -1
  102. package/dist/chunk-TBMKJ26R.js.map +0 -1
  103. package/dist/chunk-VJTFXHOK.js.map +0 -1
  104. package/dist/chunk-YSWH776Y.js +0 -13
  105. package/dist/chunk-YSWH776Y.js.map +0 -1
  106. package/dist/logger-BY28acW-.d.ts +0 -16
  107. /package/dist/{rateLimit-ZMIZJUZF.js.map → rateLimit-5RKBFLUR.js.map} +0 -0
@@ -18,7 +18,13 @@ declare function stripIp(raw: string | undefined): string;
18
18
  /**
19
19
  * Key by Bearer token when present, falling back to client IP. Lets
20
20
  * token-authenticated clients get their own bucket instead of sharing
21
- * a NAT'd IP.
21
+ * a NAT'd IP. Nothing here checks the token (the 5.1 audit's
22
+ * TRANSPORT-4): a caller that sends a new made-up token on each request
23
+ * gets a fresh bucket each time, even behind `requireSession`, which signs
24
+ * a request in by its cookie first and never reads the bearer token then.
25
+ * Key a limiter mounted behind `requireSession` by the user it verified
26
+ * instead (`keyGenerator: (req) => sessionOf(req).userId`), and anonymous
27
+ * traffic by IP, as `createPublicApiLimiter` does.
22
28
  */
23
29
  declare function bearerOrIp(req: Request): string;
24
30
  /**
@@ -39,7 +45,8 @@ declare function createPublicApiLimiter(overrides?: PartialOptions): RateLimitRe
39
45
  * minute per IP, refused with `429 { ok: false, e: { code: "RATE_LIMITED",
40
46
  * message, data: { retryAfterMs } } }`. Server-side prefetch reaches the API
41
47
  * from the web server's address, so key it some other way (`keyGenerator`)
42
- * or raise `max` when the web server prefetches for many users.
48
+ * or raise `max` when the web server prefetches for many users; never by
49
+ * an unverified bearer token (`bearerOrIp`).
43
50
  */
44
51
  declare function createCallLimiter(overrides?: PartialOptions): RateLimitRequestHandler;
45
52
 
@@ -7,7 +7,7 @@ import {
7
7
  createPublicApiLimiter,
8
8
  createWebhookLimiter,
9
9
  stripIp
10
- } from "../../chunk-TBMKJ26R.js";
10
+ } from "../../chunk-NW6U45HX.js";
11
11
  export {
12
12
  bearerOrIp,
13
13
  createAuthLimiter,
@@ -1,20 +1,21 @@
1
- import { J as AnyContract, at as ProjectionName, ai as FullProjectionOf, ac as CollectionName, ap as MethodName, d as StandardSchemaV1, c as InferOutput, N as NullableProjection, P as ProjectionList, aq as MethodOf, as as ParsedInputOf, ao as KindOf, A as AccessLevel, af as EntityOf, ar as OutputOf } from '../infer-Teo1xpsd.js';
2
- import { M as ModelName, v as PolicyFor, w as RowForms, x as AccessFor, H as HandlerContext, y as ModelColumn, z as WatchAccess, B as PublicAccess, E as HandlerArgs, G as CustomAccess, I as ShareMode, J as ChannelOptions, K as StreamOptions, u as RoomLeaveHandler, L as ChannelsRequired, h as Service, N as BaseContext, O as CallerFor, l as RunContext, m as RunOptions, o as StreamHandle, P as Presence, n as ServerRooms, Q as AccessPolicy, T as AnyAccessPolicy, V as PolicyColumns, X as PolicyForeign, Y as PolicyTools, k as AccessFilter, Z as RowAccess, q as AccessEngine, b as StorageWhere } from '../caller-CXTFswBO.js';
3
- export { aI as ANY_FIELD, aA as AccessForm, aB as AccessRequest, _ as AffectsLink, p as AnyContext, A as AnyService, r as AppRooms, aC as AuthenticatedAccess, aq as CallOptions, d as Caller, a9 as ChannelAccess, aa as ChannelContext, ab as ChannelHandler, ac as ChannelImplementation, ad as ChannelRoomOf, a4 as CollectionScope, a6 as ContextRooms, a7 as ContextServices, C as CountArgs, a3 as DEFAULT_BULK_THRESHOLD, i as DevWarning, D as DevWarningError, j as DevWarningKind, aD as EntryAccess, F as FindManyArgs, f as FlushInfo, e as FlushSink, at as ForeignColumns, au as ForeignColumnsOf, aE as IdKeyOf, aF as IdSelector, av as MembershipRead, ar as MethodCaller, aM as N_PLUS_ONE_STATEMENTS, aw as ParentLink, ax as PolicyKind, ay as PolicyReads, $ as ProjectedOutput, a0 as Projection, ae as RoomLeave, af as RoomLeaveReason, ag as RoomLeft, ah as RoomTarget, az as RowLevel, R as RowLevels, aG as ScopeAccess, aH as ServiceAccess, as as ServiceCaller, ai as ServiceChannel, a5 as ServiceCollection, g as ServiceMethod, aj as ServiceStream, c as StatementCount, S as StorageAdapter, a as StorageRow, ak as StreamImplementation, al as StreamPushArgs, am as StreamPushManyArgs, an as StreamSeed, ao as StreamSeedContext, t as StreamSubscriptions, ap as StreamValidation, a1 as TierGroup, a2 as Tiers, a8 as TouchOptions, aJ as UnitOfWork, U as UnitOfWorkFactory, aK as UnitOfWorkScope, W as WriteRecord, aL as formatDevWarning, s as storageOf } from '../caller-CXTFswBO.js';
4
- import { S as ServerOptions, Q as QuickdrawServer } from '../createServer-CP9eDHZZ.js';
5
- export { C as ClusterClient, u as ClusterOptions, D as DEFAULT_STALL_INTERVAL_MS, e as DEFAULT_STALL_MAX_MS, f as DEFAULT_STALL_THRESHOLD_MS, p as DisconnectUserOptions, E as EntitySubscription, a as EntitySubscriptions, H as HttpApp, I as IoRedisLike, L as LegacyReply, t as LegacyWireOptions, M as MIN_STALL_INTERVAL_MS, m as QuickdrawIo, n as QuickdrawServerSocket, o as QuickdrawSocketData, y as RateLimitOptions, z as RateLimiter, R as RotateOptions, g as STALL_RESOLUTION_MS, b as ScopeSubscription, c as ScopeSubscriptions, l as ServerOnlyOptions, h as SlowMethod, q as SocketCors, r as SocketOptions, s as SocketRateLimitOptions, i as StallReport, j as StallWatchdogOptions, T as TopicWatch, d as TopicWatches, w as applyRateLimitMiddleware, v as createRateLimiter, k as createServer, x as createTieredRateLimiter } from '../createServer-CP9eDHZZ.js';
6
- import { ad as Version } from '../envelope-Cp3YcVxC.js';
7
- import { Q as QuickdrawTypes, D as DbOf, d as PrincipalKindOf, c as PrincipalOf, M as MaybePromise, b as McpContextOf, C as ContextExtensionOf, P as Principal } from '../types-Cu0vmx7c.js';
8
- export { a as McpContext, T as Transport } from '../types-Cu0vmx7c.js';
9
- import { a as DispatcherOptions, D as Dispatcher, c as DispatcherCollections } from '../http-Djj2Inuu.js';
10
- export { o as AccessChange, p as AccessChangeListener, A as AccessOptions, d as ChangeLogOptions, C as ContractOfServices, j as DEFAULT_LIMITS, f as DbOfServices, h as DispatchRequest, i as DispatchResult, n as DispatcherAccess, k as DispatcherLimits, s as HttpMiddleware, H as HttpRouter, u as HttpRouterOptions, b as HttpTransportOptions, L as LimitsOptions, l as PipelineOptions, P as PrincipalOfServices, R as RegisteredMethod, g as Registry, S as SharedData, m as SubscriptionLimits, T as TrackingOptions, V as VersionRequest, q as VersionSource, e as createDispatcher, r as createHttpRouter, t as toCallReply } from '../http-Djj2Inuu.js';
11
- import { l as CrudMethodName, d as CrudContractOptions, S as ScalarFieldOf, N as NumberFieldOf, m as CrudMethods, H as AdminMethodsOf, w as AdminContractOptions, G as AdminMethods } from '../admin-DKwkIh5i.js';
12
- import { S as SearchContractOptions, T as TextFieldOf, b as SearchMethods, n as SharingMethodName, f as SharingByNameMethod, g as SharingContractOptions, o as SharingMethods } from '../sharing-DVa8W-yR.js';
13
- import { x as AdminNeverWritable, l as AdminFieldConfig } from '../adminSchemas-2DUA_hZ8.js';
14
- export { a as CallOutcome, C as CallRecord } from '../metrics-BdBu5o8G.js';
15
- export { b as AuthenticateRequest, A as AuthenticateResult, c as HttpAuthenticateRequest, d as HttpCredentialSource, S as ServerAuth, e as ServiceAccessSource, a as ServiceGrants, f as SocketAuthenticateRequest, r as recordSocketSession } from '../auth-BhWqdyb-.js';
1
+ import { J as AnyContract, at as ProjectionName, ai as FullProjectionOf, ac as CollectionName, ap as MethodName, d as StandardSchemaV1, c as InferOutput, N as NullableProjection, P as ProjectionList, aq as MethodOf, as as ParsedInputOf, ao as KindOf, A as AccessLevel, af as EntityOf, ar as OutputOf } from '../infer-BmoZsL9a.js';
2
+ import { M as ModelName, v as PolicyFor, w as RowForms, x as AccessFor, H as HandlerContext, y as ModelColumn, z as WatchAccess, B as PublicAccess, E as HandlerArgs, G as CustomAccess, I as ShareMode, J as ChannelOptions, K as StreamOptions, u as RoomLeaveHandler, L as ChannelsRequired, h as Service, N as BaseContext, O as CallerFor, l as RunContext, m as RunOptions, o as StreamHandle, P as Presence, n as ServerRooms, Q as AccessPolicy, T as AnyAccessPolicy, V as PolicyColumns, X as PolicyForeign, Y as PolicyTools, k as AccessFilter, Z as RowAccess, q as AccessEngine, b as StorageWhere } from '../caller-BT-Mv4bD.js';
3
+ export { aI as ANY_FIELD, aA as AccessForm, aB as AccessRequest, _ as AffectsLink, p as AnyContext, A as AnyService, r as AppRooms, aC as AuthenticatedAccess, aq as CallOptions, d as Caller, a9 as ChannelAccess, aa as ChannelContext, ab as ChannelHandler, ac as ChannelImplementation, ad as ChannelRoomOf, a4 as CollectionScope, a6 as ContextRooms, a7 as ContextServices, C as CountArgs, a3 as DEFAULT_BULK_THRESHOLD, i as DevWarning, D as DevWarningError, j as DevWarningKind, aD as EntryAccess, F as FindManyArgs, f as FlushInfo, e as FlushSink, at as ForeignColumns, au as ForeignColumnsOf, aE as IdKeyOf, aF as IdSelector, aL as LinkInterest, av as MembershipRead, ar as MethodCaller, aN as N_PLUS_ONE_STATEMENTS, aw as ParentLink, ax as PolicyKind, ay as PolicyReads, $ as ProjectedOutput, a0 as Projection, ae as RoomLeave, af as RoomLeaveReason, ag as RoomLeft, ah as RoomTarget, az as RowLevel, R as RowLevels, aG as ScopeAccess, aH as ServiceAccess, as as ServiceCaller, ai as ServiceChannel, a5 as ServiceCollection, g as ServiceMethod, aj as ServiceStream, c as StatementCount, S as StorageAdapter, a as StorageRow, ak as StreamImplementation, al as StreamPushArgs, am as StreamPushManyArgs, an as StreamSeed, ao as StreamSeedContext, t as StreamSubscriptions, ap as StreamValidation, a1 as TierGroup, a2 as Tiers, a8 as TouchOptions, aJ as UnitOfWork, U as UnitOfWorkFactory, aK as UnitOfWorkScope, W as WriteRecord, aM as formatDevWarning, s as storageOf } from '../caller-BT-Mv4bD.js';
4
+ import { S as ServerOptions, Q as QuickdrawServer } from '../createServer-Cp-Wk500.js';
5
+ export { C as ClusterClient, u as ClusterOptions, D as DEFAULT_STALL_INTERVAL_MS, e as DEFAULT_STALL_MAX_MS, f as DEFAULT_STALL_THRESHOLD_MS, p as DisconnectUserOptions, E as EntitySubscription, a as EntitySubscriptions, H as HttpApp, I as IoRedisLike, L as LegacyReply, t as LegacyWireOptions, M as MIN_STALL_INTERVAL_MS, m as QuickdrawIo, n as QuickdrawServerSocket, o as QuickdrawSocketData, y as RateLimitOptions, z as RateLimiter, R as RotateOptions, g as STALL_RESOLUTION_MS, b as ScopeSubscription, c as ScopeSubscriptions, l as ServerOnlyOptions, h as SlowMethod, q as SocketCors, r as SocketOptions, s as SocketRateLimitOptions, i as StallReport, j as StallWatchdogOptions, T as TopicWatch, d as TopicWatches, w as applyRateLimitMiddleware, v as createRateLimiter, k as createServer, x as createTieredRateLimiter } from '../createServer-Cp-Wk500.js';
6
+ import { ad as Version } from '../envelope-DzWyIXjj.js';
7
+ export { ag as MAX_ENTITY_IDS_PER_SOCKET, ah as MAX_SCOPES_PER_SOCKET, ai as MAX_TOPICS_PER_SOCKET } from '../envelope-DzWyIXjj.js';
8
+ import { Q as QuickdrawTypes, D as DbOf, d as PrincipalKindOf, c as PrincipalOf, M as MaybePromise, b as McpContextOf, C as ContextExtensionOf, P as Principal } from '../types-CYliTP65.js';
9
+ export { a as McpContext, T as Transport } from '../types-CYliTP65.js';
10
+ import { c as DispatcherOptions, D as Dispatcher, d as DispatcherCollections } from '../http-DotQ5bj8.js';
11
+ export { p as AccessChange, q as AccessChangeListener, A as AccessOptions, e as ChangeLogOptions, C as ContractOfServices, k as DEFAULT_LIMITS, g as DbOfServices, i as DispatchRequest, j as DispatchResult, o as DispatcherAccess, a as DispatcherBaseOptions, l as DispatcherLimits, u as HttpMiddleware, H as HttpRouter, v as HttpRouterOptions, b as HttpTransportOptions, L as LimitsOptions, m as PipelineOptions, P as PrincipalOfServices, R as RegisteredMethod, h as Registry, S as SharedData, n as SubscriptionLimits, T as TrackingOptions, V as VersionRequest, r as VersionSource, f as createDispatcher, s as createHttpRouter, t as toCallReply } from '../http-DotQ5bj8.js';
12
+ import { l as CrudMethodName, d as CrudContractOptions, S as ScalarFieldOf, N as NumberFieldOf, m as CrudMethods, H as AdminMethodsOf, w as AdminContractOptions, G as AdminMethods } from '../admin-DWWrT1h6.js';
13
+ import { S as SearchContractOptions, T as TextFieldOf, b as SearchMethods, n as SharingMethodName, f as SharingByNameMethod, g as SharingContractOptions, o as SharingMethods } from '../sharing-UDLn1049.js';
14
+ import { x as AdminNeverWritable, l as AdminFieldConfig } from '../adminSchemas-D4bFKsrb.js';
15
+ export { a as CallOutcome, C as CallRecord } from '../metrics-DW80Exve.js';
16
+ export { b as AuthenticateRequest, A as AuthenticateResult, c as HttpAuthenticateRequest, d as HttpCredentialSource, S as ServerAuth, e as ServiceAccessSource, a as ServiceGrants, f as SocketAuthenticateRequest, r as recordSocketSession } from '../auth-DXiSJZaf.js';
16
17
  import { Server } from 'socket.io';
17
- import { L as Logger } from '../logger-BY28acW-.js';
18
+ import { L as Logger } from '../logger-Yz93KzdV.js';
18
19
  import 'node:http';
19
20
  import '../errors-S-bxEIBC.js';
20
21
 
@@ -31,9 +32,6 @@ declare const MAX_APP_ROOMS = 100;
31
32
  /** The most scopes one stream keeps a seed for; the scope pushed to least recently goes first. */
32
33
  declare const STREAM_MAX_SCOPES = 10000;
33
34
 
34
- /** The most stream feeds one socket may subscribe to at once. */
35
- declare const MAX_STREAMS_PER_SOCKET = 500;
36
-
37
35
  /**
38
36
  * A JSON column's value as a database client types it: structurally
39
37
  * Prisma's `JsonValue` (and its `InputJsonValue` objects and arrays). A row
@@ -113,6 +111,9 @@ type HandlerOutputOf<C extends AnyContract, M extends MethodName<C>, Proj = Reco
113
111
  * that row, through its service's policy. Deleting the row closes its
114
112
  * scopes (`qd:revoked` with reason `"anchor-deleted"`).
115
113
  * - `scopeAccess: "self"`: the scope value is the subscriber's own user id.
114
+ * On a service with an access policy its items still follow that policy:
115
+ * only the rows its user may read at `Read`, and a row the user loses goes
116
+ * out `removed`.
116
117
  *
117
118
  * A service-wide `Admin` grant on this service passes either check, as it
118
119
  * passes every check of the service. `bulkThreshold` (default 200) is how
@@ -208,9 +209,15 @@ type ShareOptions<A> = {
208
209
  /**
209
210
  * Run identical concurrent calls once: `"caller"` per principal, `"all"`
210
211
  * across principals. Every caller is authorized before it joins; the
211
- * handler runs with the first caller's `ctx`, so a `"all"` handler must
212
- * not depend on who asks. `"all"` is not allowed with `custom` access,
213
- * whose result may depend on who asks.
212
+ * handler runs with the first caller's `ctx`, and every caller gets its
213
+ * result, so a `"all"` result must depend on the input only: its
214
+ * handler reads nothing of the caller (in development, reading
215
+ * `ctx.principal`, `ctx.services` or `ctx.mcp` warns
216
+ * `[quickdraw:shared-principal]`, and a strict test app fails the
217
+ * call). `"all"` is not allowed with `custom` access, nor on the kit
218
+ * methods whose result depends on who asks (the read/write kit's
219
+ * `list` and `getMany`, `search`, the sharing kit's `listShares` and
220
+ * `listMembers`, the admin kit's `adminList` and `adminGet`).
214
221
  */
215
222
  readonly share: A extends CustomAccess<never, never> ? "caller" : ShareMode;
216
223
  /** Reuse a successful result for this long after its run, in milliseconds. */
@@ -252,6 +259,22 @@ type MethodImplementation<T extends QuickdrawTypes, C extends AnyContract, M ext
252
259
  * signed out. Leave it out for the service's list.
253
260
  */
254
261
  readonly kinds?: readonly PrincipalKindOf<T>[];
262
+ /**
263
+ * A requirement on the caller's verified claims (`principal.claims`, a
264
+ * token's `scope`), beside `access`: the call passes only when it returns
265
+ * `true`. It adds to the form, so `{ entry: "Moderate" }` with `claims`
266
+ * needs Moderate on the row and the claims. It runs right after `kinds`,
267
+ * outside the access engine, so no grant passes it, a service-wide
268
+ * `Admin` grant included. Without a principal the call is
269
+ * `UNAUTHENTICATED`; when it returns anything but `true`, `FORBIDDEN`. It
270
+ * is synchronous, and a `"public"` method takes none. Never write a check
271
+ * on claims as `custom`: that form replaces the row check, and an Admin
272
+ * grant skips it.
273
+ *
274
+ * @example
275
+ * claims: (claims) => claims?.scope === "triage",
276
+ */
277
+ readonly claims?: (claims: PrincipalOf<T>["claims"], input: ParsedInputOf<C, M>) => boolean;
255
278
  /**
256
279
  * Runs the method. For a projection output it returns the database row
257
280
  * (or rows, or `null`), which the framework projects: only the
@@ -263,11 +286,15 @@ type MethodImplementation<T extends QuickdrawTypes, C extends AnyContract, M ext
263
286
  /**
264
287
  * Says the access form is this method's whole check on purpose. On a
265
288
  * service with an access policy, `defineService` refuses a method whose
266
- * input has `id` while its access is `"public"`, `"authenticated"` or `{
267
- * service: L }` below `Admin`, since any caller the form admits could then
268
- * reach any row by its id: give it `{ entry: L }` so the policy decides,
269
- * or `rowless: true` when every such caller may reach any row (public
270
- * profiles, lookups by an id that tells nothing).
289
+ * input has `id` while its access checks some other row or none:
290
+ * `"public"`, `"authenticated"`, `{ service: L }` below `Admin`,
291
+ * `custom(fn)`, `{ scope, of, id }`, or `{ entry, id }` naming another
292
+ * key. Any caller the form admits could then reach any row by its id:
293
+ * give it `{ entry: L }` so the policy decides (with `claims` beside it
294
+ * for a check on the caller's claims), or `rowless: true` when every such
295
+ * caller may reach any row (public profiles, lookups by an id that tells
296
+ * nothing), or when `id` names a row the method creates (an id the client
297
+ * made).
271
298
  */
272
299
  readonly rowless?: true;
273
300
  } & (KindOf<C, M> extends "query" ? QueryOptions<T, C, M, A> : MutationOptions);
@@ -315,7 +342,8 @@ interface ServiceDefinition<T extends QuickdrawTypes, C extends AnyContract, A,
315
342
  * section 7.1): `{ anchor: contract }`, the contract whose rows the scope
316
343
  * values are ids of, or `{ scopeAccess: "self" }` for a scope that is the
317
344
  * subscriber's user id; plus `bulkThreshold`. Required when the contract
318
- * declares collections. Needs `model`.
345
+ * declares collections. Needs `model`. A self scope's items still follow
346
+ * the service's `access` policy, when it has one.
319
347
  */
320
348
  readonly collections?: CollectionOptions<C>;
321
349
  /**
@@ -535,6 +563,9 @@ declare const CHANNEL_ABUSE_WINDOW_MS = 10000;
535
563
  /** A socket is disconnected once its drops within the window exceed this many times the channel's rate. */
536
564
  declare const CHANNEL_ABUSE_MULTIPLIER = 100;
537
565
 
566
+ /** The most stream feeds one socket may subscribe to at once. */
567
+ declare const MAX_STREAMS_PER_SOCKET = 500;
568
+
538
569
  /**
539
570
  * A custom access check: the call passes when `check(ctx, input)` resolves
540
571
  * `true`. The caller must be authenticated first, so `ctx.principal` is
@@ -543,6 +574,11 @@ declare const CHANNEL_ABUSE_MULTIPLIER = 100;
543
574
  * custom access cannot `share: "all"`, because its result may depend on who
544
575
  * asks.
545
576
  *
577
+ * It replaces the row check: on a service with an access policy,
578
+ * `defineService` refuses it on a method whose input has `id` unless the
579
+ * method says `rowless: true`. A check on the caller's claims is the
580
+ * method's `claims`, beside an `entry` form: no grant skips that.
581
+ *
546
582
  * @example
547
583
  * access: custom((ctx, input) => ctx.principal.userId === input.ownerId),
548
584
  */
@@ -578,7 +614,11 @@ declare function jsonAcl<const Field extends string, const Owner extends string
578
614
 
579
615
  /** Options of {@link members}. */
580
616
  interface MembersOptions<Model extends string = string, Entry extends string = string, User extends string = string, Level extends string = string> {
581
- /** The membership model, named as the client names it: `"projectMember"`. */
617
+ /**
618
+ * The membership model, named as the client names it: `"projectMember"`.
619
+ * It needs an `id` column (keep the pair unique with `@@unique`, never a
620
+ * composite `@@id`), or its writes are not tracked and never revoke.
621
+ */
582
622
  readonly model: Model;
583
623
  /** The column holding the id of the row the membership is on: `"projectId"`. */
584
624
  readonly entry: Entry;
@@ -589,14 +629,20 @@ interface MembersOptions<Model extends string = string, Entry extends string = s
589
629
  /**
590
630
  * Maps stored roles to access levels: `{ owner: "Admin", editor: "Moderate", viewer: "Read" }`.
591
631
  * Without it a stored role must be a level name. A role that maps to no
592
- * level grants nothing.
632
+ * level grants nothing. Roles that map to one level are peers: with
633
+ * `{ owner: "Admin", admin: "Admin" }` the sharing kit lets an `admin`
634
+ * demote or remove the `owner`. To make an owner untouchable, give the
635
+ * row an owner column (`anyOf(owner("ownerId"), members(...))`, or
636
+ * `jsonAcl(..., { owner })`).
593
637
  */
594
638
  readonly levels?: Readonly<Record<string, AccessLevel>>;
595
639
  }
596
640
  /**
597
641
  * The level comes from the principal's row in a membership table: one query
598
642
  * per lookup, filtered by the entry ids and the user id. Several rows for one
599
- * user and entry give the highest level among them.
643
+ * user and entry give the highest level among them. The table needs an `id`
644
+ * column, or no write to it is tracked and a removed member keeps what they
645
+ * subscribed to; `createServer` names such a table at start.
600
646
  *
601
647
  * @example
602
648
  * access: members({ model: "projectMember", entry: "projectId", user: "userId", level: "role" }),
@@ -666,7 +712,8 @@ interface ResolverOptions<P extends Principal = Principal, Column extends string
666
712
  /**
667
713
  * A filter matching exactly the rows on which the principal has at least
668
714
  * `level`, or `"none"`. Without it, list filters through this policy match
669
- * no row.
715
+ * no row, and the read/write kit's `reorder` moves none below a
716
+ * service-wide grant.
670
717
  */
671
718
  readonly where?: (principal: P, level: AccessLevel, tools: PolicyTools) => MaybePromise<AccessFilter>;
672
719
  /**
@@ -819,22 +866,31 @@ interface CrudHandlersOptions<C extends AnyContract, A, Db = unknown> {
819
866
  * Who may call each of the kit's methods: one form per method, required.
820
867
  * `get`, `update`, `delete` and `reorder` take `{ entry: L }` to check the
821
868
  * row; the methods on many rows also keep only the rows the service's
822
- * policy gives the caller at the form's level.
869
+ * policy gives the caller at the form's level. A bulk method whose form
870
+ * names no level takes its single-row counterpart's row level (`delete`'s
871
+ * for `bulkDelete`, `update`'s for `bulkUpdate`) when it is higher than
872
+ * `Moderate`; give `{ entry: L, id: "ids" }` to refuse the whole call
873
+ * instead of skipping rows.
823
874
  */
824
875
  readonly access: A & NoInfer<NotAKitMethod<C, A>>;
825
876
  /**
826
877
  * What `create` writes, from its parsed input: set owner or scope columns
827
878
  * from `ctx.principal`, an ordinal from `nextOrdinal`. `create` writes the
828
- * input as it is without it.
879
+ * input as it is without it. An owner or access-list column (one the
880
+ * policy reads) comes only from here: the caller may not send one. The
881
+ * anchors of what it returns (each `inherit` parent and anchored
882
+ * collection's scope it sets) are checked at the method's row level, and
883
+ * it returns column values only, never a relation or a nested write.
829
884
  */
830
885
  readonly prepare?: [CrudCreateOf<C>] extends [never] ? `crud.handlers: prepare is for the kit's create, which ${C["name"]} does not have` : CrudPrepare<ParsedInputOf<C, CrudCreateOf<C>>, KitContext, Db>;
831
886
  /**
832
887
  * The kit's methods whose access form is their whole check on purpose:
833
888
  * each gets `rowless: true`. On a service with an access policy,
834
- * `defineService` refuses `get` under `"public"`, `"authenticated"` or
835
- * `{ service: L }` below `Admin` (any such caller could read any row by
836
- * its id) unless it is named here: `rowless: ["get"]` for public
837
- * profiles, say. `update`, `delete` and `reorder` check the row whatever
889
+ * `defineService` refuses `get` under a form that asks the policy nothing
890
+ * about the row its `id` names (`"public"`, `"authenticated"`,
891
+ * `{ service: L }` below `Admin`, `custom`, `{ scope }`, or `{ entry }` on
892
+ * another key: any such caller could read any row by its id) unless it is
893
+ * named here: `rowless: ["get"]` for public profiles, say. `update`, `delete` and `reorder` check the row whatever
838
894
  * their form, and need nothing.
839
895
  */
840
896
  readonly rowless?: readonly CrudMethodsOf<C>[];
@@ -963,7 +1019,8 @@ type SearchStrategy<Ctx = SearchStrategyContext> = {
963
1019
  * The filter of the rows that match `q`, in the database client's
964
1020
  * `where` shape: a Postgres full-text condition, say. The kit adds the
965
1021
  * access filter and the scope, and pages the rows by keyset cursor in
966
- * the scope collection's order (else by id).
1022
+ * the scope collection's order when the call passes a scope, else by
1023
+ * id.
967
1024
  */
968
1025
  readonly where: (q: string, ctx: Ctx) => MaybePromise<StorageWhere>;
969
1026
  readonly ids?: never;
@@ -1086,9 +1143,13 @@ interface SharingUserLookup {
1086
1143
  readonly email?: string;
1087
1144
  }
1088
1145
  /**
1089
- * Finds the user a by-name method means: their user id, or `null` (or
1146
+ * Finds the one user a by-name method means: their user id, or `null` (or
1090
1147
  * `undefined`) when there is no such user, which fails the call with
1091
- * `NOT_FOUND`.
1148
+ * `NOT_FOUND`. It must name exactly one user: look a user up by something
1149
+ * unique and verified (an email, with `findUnique`), and take a display
1150
+ * name's user only when exactly one user has that name, else `null`. A
1151
+ * `findFirst` by name hands the share to whoever registered the name first
1152
+ * (the 5.1 audit's SHARE-2).
1092
1153
  */
1093
1154
  type SharingResolveUser<Db = unknown> = (lookup: SharingUserLookup, ctx: KitContext, db: Db) => MaybePromise<string | null | undefined>;
1094
1155
  type NotASharingMethod<C extends AnyContract, A> = [Exclude<keyof A, SharingMethodsOf<C>>] extends [
@@ -1110,17 +1171,25 @@ type SharingHandlersOptions<C extends AnyContract, A, Db = unknown> = {
1110
1171
  readonly onChange?: SharingOnChange<Db>;
1111
1172
  /**
1112
1173
  * The kit's methods whose access form is their whole check on purpose:
1113
- * each gets `rowless: true`. On a service with an access policy,
1174
+ * each gets `rowless: true`. A change still never touches a user above
1175
+ * the caller's own level on the row, which under such a form is their
1176
+ * level on the row (often none): name `service` in the form for a
1177
+ * service-wide grant to count. On a service with an access policy,
1114
1178
  * `defineService` refuses an access-list method (`share`, `unshare`,
1115
1179
  * `setLevel`, `listShares`, `shareByName`: their input names the row as
1116
- * `id`) under `"public"`, `"authenticated"` or `{ service: L }` below
1117
- * `Admin` unless it is named here.
1180
+ * `id`) under a form that asks the policy nothing about that row
1181
+ * (`"public"`, `"authenticated"`, `{ service: L }` below `Admin`,
1182
+ * `custom`, `{ scope }`, or `{ entry }` on another key) unless it is named
1183
+ * here.
1118
1184
  */
1119
1185
  readonly rowless?: readonly SharingMethodsOf<C>[];
1120
1186
  } & ([SharingByNameOf<C>] extends [never] ? {
1121
1187
  readonly resolveUser?: `sharing.handlers: resolveUser is for shareByName and inviteByName, which ${C["name"]} does not have`;
1122
1188
  } : {
1123
- /** Finds the user `shareByName` and `inviteByName` mean, by name or email. */
1189
+ /**
1190
+ * Finds the one user `shareByName` and `inviteByName` mean, by name or
1191
+ * email, or `null`: never the first of several (`SharingResolveUser`).
1192
+ */
1124
1193
  readonly resolveUser: SharingResolveUser<Db>;
1125
1194
  });
1126
1195
  /** `sharing.handlers`' options argument: required when the contract has a by-name method. */
@@ -1233,26 +1302,29 @@ interface AdminHandlersOptions<C extends AnyContract, A, Db = unknown> {
1233
1302
  readonly displayName?: string;
1234
1303
  /**
1235
1304
  * Fields the kit leaves out entirely: from `adminMeta`, from the rows it
1236
- * returns and from what it writes. `acl`, `serviceAccess` and
1237
- * `service_access` are always hidden, as in 4.1, unless `grants` shows
1238
- * the last two.
1305
+ * returns and from what it writes. `acl`, `serviceAccess`,
1306
+ * `service_access` and the column the dispatcher's `serviceAccessSource`
1307
+ * names on this service's model are always hidden (the first three as in
1308
+ * 4.1), unless `grants` shows the grants field.
1239
1309
  */
1240
1310
  readonly hiddenFields?: readonly Exclude<AdminFieldOf<C>, "id">[];
1241
1311
  /**
1242
- * Show and write the entity's `serviceAccess` (or `service_access`), the
1243
- * user's service-wide grants, which the kit hides by default: an admin
1244
- * screen then edits grants through `adminUpdate` (a JSON field, checked by
1245
- * the entity's schema). Only a caller whose own service-wide grant on this
1246
- * service is `Admin` reads or writes it, whatever `access` gives a method;
1247
- * anyone else is refused a write, filter or sort naming it (`FORBIDDEN`)
1248
- * and gets rows without it. Such an Admin can grant any service,
1249
- * themself included, so give that grant only to those who may. With
1250
- * `auth.serviceAccessSource` naming the column, a change reaches the
1251
- * user's open sockets on every node at once (`qd:access`, their
1252
- * subscriptions resolved again), as any tracked write to it does. Only for
1253
- * an entity with such a field. Default `false`.
1254
- */
1255
- readonly grants?: [Extract<AdminFieldOf<C>, "serviceAccess" | "service_access">] extends [never] ? never : boolean;
1312
+ * Show and write the entity's grants field, the user's service-wide
1313
+ * grants, which the kit hides by default: `serviceAccess`,
1314
+ * `service_access`, or the column `auth.serviceAccessSource` names on this
1315
+ * service's model, whatever its name. An admin screen then edits grants
1316
+ * through `adminUpdate` (a JSON field, checked by the entity's schema).
1317
+ * Only a caller whose own service-wide grant on this service is `Admin`
1318
+ * reads or writes it, whatever `access` gives a method; anyone else is
1319
+ * refused a write, filter or sort naming it (`FORBIDDEN`) and gets rows
1320
+ * without it. Such an Admin can grant any service, themself included, so
1321
+ * give that grant only to those who may. With `auth.serviceAccessSource`
1322
+ * naming the column, a change reaches the user's open sockets on every
1323
+ * node at once (`qd:access`, their subscriptions resolved again), as any
1324
+ * tracked write to it does. The dispatcher refuses `true` for an entity
1325
+ * without a grants field, when it is made. Default `false`.
1326
+ */
1327
+ readonly grants?: boolean;
1256
1328
  /**
1257
1329
  * The only fields `adminCreate` and `adminUpdate` write (finding R1.4 of
1258
1330
  * the 5.0.0 review): `adminMeta` reports every other field `editable:
@@ -1273,9 +1345,10 @@ interface AdminHandlersOptions<C extends AnyContract, A, Db = unknown> {
1273
1345
  * The kit's methods whose access form is their whole check on purpose:
1274
1346
  * each gets `rowless: true`. On a service with an access policy,
1275
1347
  * `defineService` refuses `adminGet`, `adminUpdate` or `adminDelete`
1276
- * under a form below the default that checks no row (`{ service:
1277
- * "Moderate" }`, `"authenticated"`) unless it is named here, since any
1278
- * caller the form admits reaches any row by its id.
1348
+ * under a form below the default that asks the policy nothing about the
1349
+ * row its `id` names (`{ service: "Moderate" }`, `"authenticated"`,
1350
+ * `custom`, `{ scope }`, or `{ entry }` on another key) unless it is named
1351
+ * here, since any caller the form admits reaches any row by its id.
1279
1352
  */
1280
1353
  readonly rowless?: readonly AdminMethodsOf<C>[];
1281
1354
  /**
@@ -1411,11 +1484,18 @@ interface RedisAdapterOptions {
1411
1484
  */
1412
1485
  password?: string;
1413
1486
  /**
1414
- * Redis database number (default: 0)
1487
+ * Redis database number (default: 0). It does not separate deployments:
1488
+ * pub/sub is shared across a server's databases, so two deployments on one
1489
+ * Valkey hear each other's events whatever their `db`; give each its own
1490
+ * Valkey, or its own `cluster.keyPrefix` (docs/deploying.md).
1415
1491
  */
1416
1492
  db?: number;
1417
1493
  /**
1418
- * Key prefix for Socket.io adapter (default: 'socket.io')
1494
+ * The adapter's key, which names its pub/sub channels. Default: the
1495
+ * server's `cluster.keyPrefix` ("quickdraw" without one), so deployments
1496
+ * with their own prefixes use their own channels. 5.1.0 and earlier used
1497
+ * "socket.io": pass `keyPrefix: "socket.io"` for the deploy that moves a
1498
+ * cluster from such nodes, so old and new nodes keep hearing each other.
1419
1499
  */
1420
1500
  keyPrefix?: string;
1421
1501
  /**