@fitzzero/quickdraw-core 5.0.0 → 5.1.0

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 (68) hide show
  1. package/README.md +343 -49
  2. package/dist/{admin-BiU4LRZS.d.ts → admin-DKwkIh5i.d.ts} +25 -10
  3. package/dist/{adminSchemas-k5a1Ov7b.d.ts → adminSchemas-2DUA_hZ8.d.ts} +15 -9
  4. package/dist/{auth-CMyRkfjZ.d.ts → auth-BhWqdyb-.d.ts} +2 -2
  5. package/dist/{caller-DHzK3oiI.d.ts → caller-CXTFswBO.d.ts} +28 -6
  6. package/dist/{chunk-2XJFNVHW.js → chunk-2PWMUVC7.js} +1 -1
  7. package/dist/{chunk-2XJFNVHW.js.map → chunk-2PWMUVC7.js.map} +1 -1
  8. package/dist/{chunk-5IC5VZ7T.js → chunk-2UELNHDD.js} +3 -3
  9. package/dist/{chunk-XFDOGTMC.js → chunk-3674EIRT.js} +4 -4
  10. package/dist/{chunk-DNCAI3KY.js → chunk-4DIQHASK.js} +1 -1
  11. package/dist/chunk-4DIQHASK.js.map +1 -0
  12. package/dist/{chunk-LLLYILEP.js → chunk-A6DJBGOG.js} +411 -43
  13. package/dist/chunk-A6DJBGOG.js.map +1 -0
  14. package/dist/{chunk-B2UQ27GH.js → chunk-CDKG4TFA.js} +25 -5
  15. package/dist/{chunk-B2UQ27GH.js.map → chunk-CDKG4TFA.js.map} +1 -1
  16. package/dist/{chunk-IRGAGRVG.js → chunk-JZBCLNDU.js} +4 -4
  17. package/dist/{chunk-XUSN5WKU.js → chunk-KNDDCVQJ.js} +4 -4
  18. package/dist/{chunk-5YRQ26LF.js → chunk-RT6OILOI.js} +1 -1
  19. package/dist/chunk-RT6OILOI.js.map +1 -0
  20. package/dist/{chunk-7QIY2DDX.js → chunk-VJTFXHOK.js} +2 -2
  21. package/dist/{chunk-7QIY2DDX.js.map → chunk-VJTFXHOK.js.map} +1 -1
  22. package/dist/chunk-XNLWBZIG.js +9 -0
  23. package/dist/chunk-XNLWBZIG.js.map +1 -0
  24. package/dist/cli/quickdraw-docs.js +241 -27
  25. package/dist/cli/quickdraw-docs.js.map +1 -1
  26. package/dist/client/index.d.ts +7 -7
  27. package/dist/client/index.js +5 -5
  28. package/dist/{clientTypes-B3o_99Xq.d.ts → clientTypes-Bc-G8n-U.d.ts} +3 -3
  29. package/dist/{connection-DuN8GvcD.d.ts → connection-Cr1BU07W.d.ts} +2 -2
  30. package/dist/{createServer-DUacdfKl.d.ts → createServer-CP9eDHZZ.d.ts} +30 -9
  31. package/dist/{createTestApp-DFLXoTKm.d.ts → createTestApp-UKVGEmOf.d.ts} +6 -6
  32. package/dist/{envelope-nf5eGB-a.d.ts → envelope-Cp3YcVxC.d.ts} +1 -1
  33. package/dist/{http--uoooIH5.d.ts → http-Djj2Inuu.d.ts} +6 -6
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +27 -7
  36. package/dist/index.js.map +1 -1
  37. package/dist/{infer-Dw21kmLw.d.ts → infer-Teo1xpsd.d.ts} +17 -0
  38. package/dist/{metrics-C0WvB7-I.d.ts → metrics-BdBu5o8G.d.ts} +2 -2
  39. package/dist/prisma/index.d.ts +4 -4
  40. package/dist/prisma/index.js +1 -1
  41. package/dist/server/auth/index.d.ts +14 -5
  42. package/dist/server/auth/index.js +0 -5
  43. package/dist/server/auth/index.js.map +1 -1
  44. package/dist/server/index.d.ts +120 -33
  45. package/dist/server/index.js +146 -193
  46. package/dist/server/index.js.map +1 -1
  47. package/dist/server/mcp/index.d.ts +51 -11
  48. package/dist/server/mcp/index.js +129 -8
  49. package/dist/server/mcp/index.js.map +1 -1
  50. package/dist/server/otel.d.ts +3 -3
  51. package/dist/{sharing-n4ss-ONM.d.ts → sharing-DVa8W-yR.d.ts} +3 -3
  52. package/dist/testing/client.d.ts +13 -13
  53. package/dist/testing/client.js +6 -6
  54. package/dist/testing/index.d.ts +156 -12
  55. package/dist/testing/index.js +1037 -22
  56. package/dist/testing/index.js.map +1 -1
  57. package/dist/testing/mock.d.ts +5 -5
  58. package/dist/testing/mock.js +5 -5
  59. package/dist/{types-Bwg3kIEc.d.ts → types-Cu0vmx7c.d.ts} +8 -2
  60. package/dist/utils/index.d.ts +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-5YRQ26LF.js.map +0 -1
  63. package/dist/chunk-DNCAI3KY.js.map +0 -1
  64. package/dist/chunk-LLLYILEP.js.map +0 -1
  65. /package/dist/{chunk-5IC5VZ7T.js.map → chunk-2UELNHDD.js.map} +0 -0
  66. /package/dist/{chunk-XFDOGTMC.js.map → chunk-3674EIRT.js.map} +0 -0
  67. /package/dist/{chunk-IRGAGRVG.js.map → chunk-JZBCLNDU.js.map} +0 -0
  68. /package/dist/{chunk-XUSN5WKU.js.map → chunk-KNDDCVQJ.js.map} +0 -0
@@ -1,18 +1,18 @@
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-Dw21kmLw.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, f 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-DHzK3oiI.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, i 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, g as DevWarning, D as DevWarningError, h as DevWarningKind, aD as EntryAccess, F as FindManyArgs, e as FlushInfo, d 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, j 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-DHzK3oiI.js';
4
- import { S as ServerOptions, Q as QuickdrawServer } from '../createServer-DUacdfKl.js';
5
- export { C as ClusterClient, t 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, M as MIN_STALL_INTERVAL_MS, m as QuickdrawIo, n as QuickdrawServerSocket, o as QuickdrawSocketData, x as RateLimitOptions, y 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, v as applyRateLimitMiddleware, u as createRateLimiter, k as createServer, w as createTieredRateLimiter } from '../createServer-DUacdfKl.js';
6
- import { ad as Version } from '../envelope-nf5eGB-a.js';
7
- import { Q as QuickdrawTypes, D as DbOf, c as PrincipalOf, M as MaybePromise, b as McpContextOf, C as ContextExtensionOf, P as Principal } from '../types-Bwg3kIEc.js';
8
- export { a as McpContext, T as Transport } from '../types-Bwg3kIEc.js';
9
- import { a as DispatcherOptions, D as Dispatcher, c as DispatcherCollections } from '../http--uoooIH5.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--uoooIH5.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-BiU4LRZS.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-n4ss-ONM.js';
13
- import { l as AdminFieldConfig } from '../adminSchemas-k5a1Ov7b.js';
14
- export { a as CallOutcome, C as CallRecord } from '../metrics-C0WvB7-I.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-CMyRkfjZ.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-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';
16
16
  import { Server } from 'socket.io';
17
17
  import { L as Logger } from '../logger-BY28acW-.js';
18
18
  import 'node:http';
@@ -34,16 +34,6 @@ declare const STREAM_MAX_SCOPES = 10000;
34
34
  /** The most stream feeds one socket may subscribe to at once. */
35
35
  declare const MAX_STREAMS_PER_SOCKET = 500;
36
36
 
37
- /** 4.x's `ServiceResponse`, the shape every reply of the shim takes. */
38
- type LegacyReply = {
39
- readonly success: true;
40
- readonly data: unknown;
41
- } | {
42
- readonly success: false;
43
- readonly error: string;
44
- readonly code: number;
45
- };
46
-
47
37
  /**
48
38
  * A JSON column's value as a database client types it: structurally
49
39
  * Prisma's `JsonValue` (and its `InputJsonValue` objects and arrays). A row
@@ -252,6 +242,16 @@ interface MutationOptions {
252
242
  type MethodImplementation<T extends QuickdrawTypes, C extends AnyContract, M extends MethodName<C>, A, Rows extends RowForms = "all", Proj = Empty$2> = {
253
243
  /** Who may call: `"public"`, `"authenticated"`, `{ service }`, `{ entry }`, `{ scope, of, id }` or `custom(fn)`. */
254
244
  readonly access: AccessValue<A, MethodAccess<T, C, M, Rows>>;
245
+ /**
246
+ * The kinds of principal that may call this method (RFC 0003 section
247
+ * 4.1), within its service's `kinds` (or the app's): `kinds: ["user"]`
248
+ * keeps an agent's token out of a method that mints tokens. A principal
249
+ * of another kind, or without a `kind`, gets `FORBIDDEN` before `access`
250
+ * is asked, whatever its grants; an anonymous caller is left to `access`.
251
+ * Not on a `"public"` method, which a caller of any kind could call
252
+ * signed out. Leave it out for the service's list.
253
+ */
254
+ readonly kinds?: readonly PrincipalKindOf<T>[];
255
255
  /**
256
256
  * Runs the method. For a projection output it returns the database row
257
257
  * (or rows, or `null`), which the framework projects: only the
@@ -377,6 +377,18 @@ interface ServiceDefinition<T extends QuickdrawTypes, C extends AnyContract, A,
377
377
  * service (RFC 0003 section 4.1). Default `true`.
378
378
  */
379
379
  readonly adminBypass?: boolean;
380
+ /**
381
+ * The kinds of principal that may call the service's methods and
382
+ * subscribe to its live data (RFC 0003 section 4.1): `kinds: ["user"]`.
383
+ * Within the app's `initQuickdraw({ kinds })`, which the service takes
384
+ * when it leaves this out; a method's own `kinds` narrows it further. A
385
+ * principal of another kind, or without a `kind`, gets `FORBIDDEN` before
386
+ * any access form is asked, and a service-wide `Admin` grant does not
387
+ * pass it; an anonymous caller is left to the form. Its entity, collection,
388
+ * topic and stream subscriptions refuse such a principal the same way, and
389
+ * its channels drop its messages.
390
+ */
391
+ readonly kinds?: readonly PrincipalKindOf<T>[];
380
392
  }
381
393
  /** `qd.defineService`, typed by the app's `QuickdrawTypes`. */
382
394
  type DefineService<T extends QuickdrawTypes> = <C extends AnyContract, const Model extends ModelName<DbOf<T>> | undefined = undefined, Policy extends PolicyFor<DbOf<T>, Model> | undefined = undefined, const A extends MethodKeys<C> = AccessMap<T, C, RowFormsOf<Model, Policy>>, const Proj = Empty$2>(contract: C, definition: ServiceDefinition<T, C, A, Model, Policy, Proj> & CollectionsRequired<C> & ChannelsRequired<C>) => Service<T, C>;
@@ -390,6 +402,15 @@ type ContextFactory<T extends QuickdrawTypes> = (base: BaseContext<PrincipalOf<T
390
402
  interface InitOptions<T extends QuickdrawTypes> {
391
403
  /** Adds the app's fields to every handler's `ctx`. Required when the app's types declare `context`. */
392
404
  readonly context?: ContextFactory<T>;
405
+ /**
406
+ * The kinds of principal every service this instance defines admits
407
+ * (RFC 0003 section 4.1), so a new service starts closed to the rest:
408
+ * `kinds: ["user", "agent"]`. A service's `kinds`, and a method's, may
409
+ * only narrow it. A principal of another kind, or without a `kind`, gets
410
+ * `FORBIDDEN` before any access form or `Admin` grant is asked; an
411
+ * anonymous caller is left to the form. Leave it out to admit every kind.
412
+ */
413
+ readonly kinds?: readonly PrincipalKindOf<T>[];
393
414
  }
394
415
  /** `initQuickdraw`'s arguments: the options are required when `T` declares `context`. */
395
416
  type InitArgs<T extends QuickdrawTypes> = T extends {
@@ -616,8 +637,25 @@ declare function inherit<const Via extends string>(options: InheritOptions<Via>)
616
637
  */
617
638
  declare function anyOf<const P extends readonly AnyAccessPolicy[]>(...policies: P): AccessPolicy<PolicyColumns<P[number]>, PolicyForeign<P[number]>>;
618
639
 
640
+ /** A membership table a resolver's levels depend on: `{ model, entry, user, level, levels? }`, as `members` takes it. */
641
+ type ResolverMembership = MembersOptions;
642
+ /** What a resolver's levels depend on: `resolver({ reads })`. Name at least one column or table. */
643
+ interface ResolverReads<Column extends string = string, Membership extends ResolverMembership = ResolverMembership> {
644
+ /**
645
+ * Columns of the service's own model. A tracked write that sets one (or
646
+ * creates or deletes a row) re-checks that row, for every user. `tools.rows`
647
+ * reads them.
648
+ */
649
+ readonly columns?: readonly Column[];
650
+ /**
651
+ * Membership tables, one row per user and row of this service: `entry`
652
+ * holds the id of this service's row, as for `members`. A tracked write to
653
+ * one re-checks that user on that row.
654
+ */
655
+ readonly memberships?: readonly Membership[];
656
+ }
619
657
  /** Options of {@link resolver}. */
620
- interface ResolverOptions<P extends Principal = Principal> {
658
+ interface ResolverOptions<P extends Principal = Principal, Column extends string = string, Membership extends ResolverMembership = ResolverMembership> {
621
659
  /**
622
660
  * The principal's level on each of `ids`, as a map or a record by id. An id
623
661
  * left out, or given anything but an access level, has no level. Read
@@ -631,21 +669,52 @@ interface ResolverOptions<P extends Principal = Principal> {
631
669
  * no row.
632
670
  */
633
671
  readonly where?: (principal: P, level: AccessLevel, tools: PolicyTools) => MaybePromise<AccessFilter>;
672
+ /**
673
+ * What the levels depend on, so tracked writes re-check what they
674
+ * decided: live rows, collection scopes and change topics.
675
+ * `{ columns, memberships }` names the service's columns and the membership
676
+ * tables `levelsFor` and `where` read; `"none"` says nothing a tracked
677
+ * write changes can change a level (the levels come from the principal's
678
+ * grants alone, say). Without it nothing a write does re-checks this
679
+ * policy, and the server says so in development (`resolver-without-reads`).
680
+ */
681
+ readonly reads?: ResolverReads<Column, Membership> | "none";
634
682
  }
683
+ /** The other models and columns the membership tables `M` read: what `defineService` checks. */
684
+ type MembershipColumns<M> = M extends {
685
+ readonly model: infer Model extends string;
686
+ readonly entry: infer Entry extends string;
687
+ readonly user: infer User extends string;
688
+ readonly level: infer Level extends string;
689
+ } ? {
690
+ readonly model: Model;
691
+ readonly columns: Entry | User | Level;
692
+ } : never;
635
693
  /**
636
694
  * A policy written in app code: `levelsFor` answers the level per row and
637
695
  * `where` the list filter. A resolver's own results are memoized for the
638
- * request and never cached across requests, because the framework cannot
639
- * know which writes change them; what it reads through `tools` is cached as
640
- * usual.
696
+ * request and never cached across requests; what it reads through `tools`
697
+ * is: `tools.rows(ids)` reads `id` and the declared columns in one query,
698
+ * and `tools.memberships(table, userId, ids)` a member's levels, both kept
699
+ * with `cacheMs` and evicted by tracked writes when `reads` declares them.
700
+ *
701
+ * `reads` declares what the levels depend on, so a tracked write to it
702
+ * re-checks the live rows, collection scopes and change topics the policy
703
+ * authorized, as for the other builders: a user removed from a membership
704
+ * table stops receiving the rows it gave them. `defineService` checks the
705
+ * declared columns and tables against the app's database client.
641
706
  *
642
707
  * @example
643
708
  * access: resolver({
644
- * levelsFor: async (principal, ids) => levelsFromMyTable(principal.userId, ids),
709
+ * levelsFor: (principal, ids, tools) => levelsFromMyTables(principal.userId, ids, tools),
645
710
  * where: (principal) => ({ visibility: "public" }),
711
+ * reads: {
712
+ * columns: ["visibility"],
713
+ * memberships: [{ model: "teamMember", entry: "projectId", user: "userId", level: "role" }],
714
+ * },
646
715
  * }),
647
716
  */
648
- declare function resolver<P extends Principal = Principal>(options: ResolverOptions<P>): AccessPolicy<never, never>;
717
+ declare function resolver<P extends Principal = Principal, const Column extends string = never, const Membership extends ResolverMembership = never>(options: ResolverOptions<P, Column, Membership>): AccessPolicy<Column, MembershipColumns<Membership>>;
649
718
 
650
719
  /**
651
720
  * Every signed-in user has `level` on every row. Anonymous callers have no
@@ -1184,6 +1253,18 @@ interface AdminHandlersOptions<C extends AnyContract, A, Db = unknown> {
1184
1253
  * an entity with such a field. Default `false`.
1185
1254
  */
1186
1255
  readonly grants?: [Extract<AdminFieldOf<C>, "serviceAccess" | "service_access">] extends [never] ? never : boolean;
1256
+ /**
1257
+ * The only fields `adminCreate` and `adminUpdate` write (finding R1.4 of
1258
+ * the 5.0.0 review): `adminMeta` reports every other field `editable:
1259
+ * false`, so a generic form leaves it read-only, and a write naming one is
1260
+ * refused with `VALIDATION` ("is not editable"). Each must be a field the
1261
+ * kit shows, never `id` or a timestamp, and a `fieldOverrides` entry may
1262
+ * not say otherwise about it. When `admin.contract` was given a list, this
1263
+ * one must name the same fields, and without this one the contract's
1264
+ * applies. Without either, the kit writes every field but `id`, the
1265
+ * timestamps, the hidden ones and those an override made read-only.
1266
+ */
1267
+ readonly editable?: readonly Exclude<AdminFieldOf<C>, AdminNeverWritable>[];
1187
1268
  /** Changes to the configuration `adminMeta` derives, per field. */
1188
1269
  readonly fieldOverrides?: {
1189
1270
  readonly [Field in AdminFieldOf<C>]?: AdminFieldOverride;
@@ -1253,7 +1334,7 @@ type Empty = Record<never, never>;
1253
1334
  declare function handlers<C extends AnyContract, const A extends AdminAccess<C> = Empty, Db = unknown>(contract: C & NoInfer<AdminContract<C>>, options?: AdminHandlersOptions<C, A, Db>): AdminImplementations<C, A, Db>;
1254
1335
  /**
1255
1336
  * The admin kit: `admin.handlers(contract, { access?, displayName?,
1256
- * hiddenFields?, fieldOverrides?, rowless?, grants? })` implements the
1337
+ * hiddenFields?, editable?, fieldOverrides?, rowless?, grants? })` implements the
1257
1338
  * methods `admin.contract` made in `contract`, each open to a service-wide
1258
1339
  * `Admin` grant unless `access` gives another form. `admin.contract` is here
1259
1340
  * too, for server code; a shared package imports it from the root export.
@@ -1273,6 +1354,12 @@ declare const admin: Readonly<{
1273
1354
  readonly sort: `admin.contract: sort: "${Exclude<O extends infer T_3 ? T_3 extends O ? T_3 extends {
1274
1355
  readonly sort: readonly (infer Field extends string)[];
1275
1356
  } ? Field : never : never : never, ScalarFieldOf<Entity extends StandardSchemaV1<unknown, unknown> ? InferOutput<Entity> : never>> & string}" is not a field of the entity holding strings, numbers or booleans`;
1357
+ }) & ([Exclude<O extends infer T_4 ? T_4 extends O ? T_4 extends {
1358
+ readonly editable: readonly (infer Field extends string)[];
1359
+ } ? Field : never : never : never, Exclude<keyof (Entity extends StandardSchemaV1<unknown, unknown> ? InferOutput<Entity> : never), AdminNeverWritable>>] extends [never] ? unknown : {
1360
+ readonly editable: `admin.contract: editable: "${Exclude<O extends infer T_5 ? T_5 extends O ? T_5 extends {
1361
+ readonly editable: readonly (infer Field extends string)[];
1362
+ } ? Field : never : never : never, Exclude<keyof (Entity extends StandardSchemaV1<unknown, unknown> ? InferOutput<Entity> : never), AdminNeverWritable>> & string}" is not a field of the entity the kit may write`;
1276
1363
  }) : unknown>) => AdminMethods<O>;
1277
1364
  handlers: typeof handlers;
1278
1365
  }>;
@@ -1491,4 +1578,4 @@ declare function decryptIfEncrypted(value: string): string;
1491
1578
  /** Safe wrapper that returns `null` instead of throwing on invalid/stale ciphertext. */
1492
1579
  declare function tryDecrypt(ciphertext: string, logger?: Logger): string | null;
1493
1580
 
1494
- export { ADMIN_HIDDEN_FIELDS, AccessEngine, AccessFilter, AccessFor, type AccessMap, AccessPolicy, type AdminAccess, type AdminContract, type AdminDefaultAccess, type AdminFieldOf, type AdminFieldOverride, type AdminHandlersOptions, type AdminImplementations, type AdminOnCommitted, type AdminOnWrite, type AdminOutputOf, type AdminWrite, type AffectsOption, AnyAccessPolicy, BaseContext, type BasicAccessEngineOptions, CHANNEL_ABUSE_MULTIPLIER, CHANNEL_ABUSE_WINDOW_MS, CallerFor, ChannelOptions, ChannelsRequired, type CollectionOption, type CollectionOptions, type CollectionsRequired, ContextExtensionOf, type ContextFactory, type CrudAccess, type CrudCreateOf, type CrudHandlersOptions, type CrudImplementations, type CrudKindOf, type CrudMethodsOf, type CrudPrepare, CustomAccess, DbOf, type DefineService, Dispatcher, DispatcherCollections, DispatcherOptions, type EnvValidationResult, HandlerArgs, HandlerContext, type HandlerOutputOf, type HandlerRow, INDEX_MAX_ROWS, type InheritOptions, type InitArgs, type InitOptions, type JsonAclOptions, type JsonColumnValue, type KitContext, type KitHandler, type KitHandlerArgs, type LegacyReply, MAX_APP_ROOMS, MAX_ITEM_IDS, MAX_STREAMS_PER_SOCKET, MaybePromise, McpContextOf, type MembersOptions, type MethodAccess, type MethodImplementation, ModelColumn, ModelName, type NextOrdinalOptions, ORDINAL_STEP, PRESENCE_MAX_LAST_SEEN, PolicyFor, PolicyTools, Presence, Principal, type PrincipalFor, PrincipalOf, type ProjectCheck, type ProjectionOption, PublicAccess, type Quickdraw, QuickdrawServer, QuickdrawTypes, RESUME_MAX_AGE_MS, RESUME_MAX_DELTAS, type RedisAdapterOptions, type RedisAdapterResult, type ResolverOptions, RoomLeaveHandler, RowAccess, type RowFor, RowForms, type RowFormsOf, RunContext, RunOptions, STREAM_MAX_SCOPES, type SearchAccess, type SearchContract, type SearchHandlersOptions, type SearchIdsOptions, type SearchImplementations, type SearchMethodsOf, type SearchStrategy, type SearchStrategyContext, ServerOptions, ServerRooms, Service, type ServiceDefinition, ShareMode, type SharingAccess, type SharingByNameOf, type SharingChange, type SharingChangeKind, type SharingContract, type SharingDefaultAccess, type SharingHandlersOptions, type SharingImplementations, type SharingKindOf, type SharingMethodsOf, type SharingOnChange, type SharingOptionsArgs, type SharingResolveUser, type SharingUserLookup, StorageWhere, StreamHandle, StreamOptions, type ValidateEnvOptions, WatchAccess, admin, anyOf, checkEnv, createBasicAccessEngine, crud, custom, decrypt, decryptIfEncrypted, displayNameOf, encrypt, everyone, inherit, initQuickdraw, isEncrypted, isRedisAdapterAvailable, jsonAcl, labelOf, meetsLevel, members, nextOrdinal, owner, requireEnv, requireRow, resolver, search, serviceGrant, setupRedisAdapter, sharing, tryDecrypt, validateEnv };
1581
+ export { ADMIN_HIDDEN_FIELDS, AccessEngine, AccessFilter, AccessFor, type AccessMap, AccessPolicy, type AdminAccess, type AdminContract, type AdminDefaultAccess, type AdminFieldOf, type AdminFieldOverride, type AdminHandlersOptions, type AdminImplementations, type AdminOnCommitted, type AdminOnWrite, type AdminOutputOf, type AdminWrite, type AffectsOption, AnyAccessPolicy, BaseContext, type BasicAccessEngineOptions, CHANNEL_ABUSE_MULTIPLIER, CHANNEL_ABUSE_WINDOW_MS, CallerFor, ChannelOptions, ChannelsRequired, type CollectionOption, type CollectionOptions, type CollectionsRequired, ContextExtensionOf, type ContextFactory, type CrudAccess, type CrudCreateOf, type CrudHandlersOptions, type CrudImplementations, type CrudKindOf, type CrudMethodsOf, type CrudPrepare, CustomAccess, DbOf, type DefineService, Dispatcher, DispatcherCollections, DispatcherOptions, type EnvValidationResult, HandlerArgs, HandlerContext, type HandlerOutputOf, type HandlerRow, INDEX_MAX_ROWS, type InheritOptions, type InitArgs, type InitOptions, type JsonAclOptions, type JsonColumnValue, type KitContext, type KitHandler, type KitHandlerArgs, MAX_APP_ROOMS, MAX_ITEM_IDS, MAX_STREAMS_PER_SOCKET, MaybePromise, McpContextOf, type MembersOptions, type MethodAccess, type MethodImplementation, ModelColumn, ModelName, type NextOrdinalOptions, ORDINAL_STEP, PRESENCE_MAX_LAST_SEEN, PolicyFor, PolicyTools, Presence, Principal, type PrincipalFor, PrincipalKindOf, PrincipalOf, type ProjectCheck, type ProjectionOption, PublicAccess, type Quickdraw, QuickdrawServer, QuickdrawTypes, RESUME_MAX_AGE_MS, RESUME_MAX_DELTAS, type RedisAdapterOptions, type RedisAdapterResult, type ResolverMembership, type ResolverOptions, type ResolverReads, RoomLeaveHandler, RowAccess, type RowFor, RowForms, type RowFormsOf, RunContext, RunOptions, STREAM_MAX_SCOPES, type SearchAccess, type SearchContract, type SearchHandlersOptions, type SearchIdsOptions, type SearchImplementations, type SearchMethodsOf, type SearchStrategy, type SearchStrategyContext, ServerOptions, ServerRooms, Service, type ServiceDefinition, ShareMode, type SharingAccess, type SharingByNameOf, type SharingChange, type SharingChangeKind, type SharingContract, type SharingDefaultAccess, type SharingHandlersOptions, type SharingImplementations, type SharingKindOf, type SharingMethodsOf, type SharingOnChange, type SharingOptionsArgs, type SharingResolveUser, type SharingUserLookup, StorageWhere, StreamHandle, StreamOptions, type ValidateEnvOptions, WatchAccess, admin, anyOf, checkEnv, createBasicAccessEngine, crud, custom, decrypt, decryptIfEncrypted, displayNameOf, encrypt, everyone, inherit, initQuickdraw, isEncrypted, isRedisAdapterAvailable, jsonAcl, labelOf, meetsLevel, members, nextOrdinal, owner, requireEnv, requireRow, resolver, search, serviceGrant, setupRedisAdapter, sharing, tryDecrypt, validateEnv };