@fitzzero/quickdraw-core 5.1.1 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1308 -219
- package/dist/{admin-DKwkIh5i.d.ts → admin-CS7JB_UH.d.ts} +2 -2
- package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-29cGgrg5.d.ts} +6 -4
- package/dist/{auth-BhWqdyb-.d.ts → auth-DtdYjrZ9.d.ts} +51 -21
- package/dist/{caller-CXTFswBO.d.ts → caller-BTwGl7vm.d.ts} +296 -33
- package/dist/chunk-2FDSKLBO.js +82 -0
- package/dist/chunk-2FDSKLBO.js.map +1 -0
- package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
- package/dist/chunk-4D2DOGAW.js.map +1 -0
- package/dist/{chunk-OECZPRPW.js → chunk-64I6MYBC.js} +162 -775
- package/dist/chunk-64I6MYBC.js.map +1 -0
- package/dist/chunk-7473HK24.js +17 -0
- package/dist/chunk-7473HK24.js.map +1 -0
- package/dist/chunk-7Y5ROPXL.js +33 -0
- package/dist/chunk-7Y5ROPXL.js.map +1 -0
- package/dist/chunk-A2RBQD66.js +7 -0
- package/dist/chunk-A2RBQD66.js.map +1 -0
- package/dist/chunk-AK23XSWD.js +16 -0
- package/dist/chunk-AK23XSWD.js.map +1 -0
- package/dist/chunk-ASAMUGHG.js +651 -0
- package/dist/chunk-ASAMUGHG.js.map +1 -0
- package/dist/{chunk-B2P7AZ25.js → chunk-CYE4UBOB.js} +6 -4
- package/dist/chunk-CYE4UBOB.js.map +1 -0
- package/dist/chunk-DKE6QO26.js +136 -0
- package/dist/chunk-DKE6QO26.js.map +1 -0
- package/dist/chunk-DNP65TD5.js +832 -0
- package/dist/chunk-DNP65TD5.js.map +1 -0
- package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
- package/dist/chunk-DUBU3BB3.js.map +1 -0
- package/dist/chunk-GYLWEJHW.js +19 -0
- package/dist/chunk-GYLWEJHW.js.map +1 -0
- package/dist/{chunk-SHEGLZEP.js → chunk-I3JCFS7H.js} +34 -13
- package/dist/chunk-I3JCFS7H.js.map +1 -0
- package/dist/{chunk-X5CWPX7H.js → chunk-IIQ3WMJK.js} +13 -2
- package/dist/chunk-IIQ3WMJK.js.map +1 -0
- package/dist/{chunk-RZTP4IEW.js → chunk-JVTONQFI.js} +6339 -4226
- package/dist/chunk-JVTONQFI.js.map +1 -0
- package/dist/{chunk-QEKVYG5F.js → chunk-KKQANRLG.js} +2 -2
- package/dist/chunk-KKQANRLG.js.map +1 -0
- package/dist/{chunk-CDKG4TFA.js → chunk-MPQAT55F.js} +38 -205
- package/dist/chunk-MPQAT55F.js.map +1 -0
- package/dist/chunk-NO4M6PO5.js +101 -0
- package/dist/chunk-NO4M6PO5.js.map +1 -0
- package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
- package/dist/chunk-NW6U45HX.js.map +1 -0
- package/dist/chunk-NX2V6SIL.js +202 -0
- package/dist/chunk-NX2V6SIL.js.map +1 -0
- package/dist/{chunk-ZIVPHYRG.js → chunk-NZHA4TZD.js} +72 -175
- package/dist/chunk-NZHA4TZD.js.map +1 -0
- package/dist/{chunk-2PWMUVC7.js → chunk-OCZJ4EYV.js} +518 -27
- package/dist/chunk-OCZJ4EYV.js.map +1 -0
- package/dist/{chunk-REX5YPHX.js → chunk-PHCURHC7.js} +76 -21
- package/dist/chunk-PHCURHC7.js.map +1 -0
- package/dist/{chunk-4YO5H5ON.js → chunk-Q4OGQM5I.js} +4 -10
- package/dist/chunk-Q4OGQM5I.js.map +1 -0
- package/dist/chunk-QSU47XEX.js +13 -0
- package/dist/chunk-QSU47XEX.js.map +1 -0
- package/dist/{chunk-DD4SKCNO.js → chunk-RZXJTDH5.js} +13 -2
- package/dist/chunk-RZXJTDH5.js.map +1 -0
- package/dist/{chunk-Z2LZ7IZ7.js → chunk-SN3OZVEQ.js} +5 -31
- package/dist/chunk-SN3OZVEQ.js.map +1 -0
- package/dist/{chunk-4DIQHASK.js → chunk-SQ5VUG77.js} +28 -8
- package/dist/chunk-SQ5VUG77.js.map +1 -0
- package/dist/chunk-STH5DLQP.js +1192 -0
- package/dist/chunk-STH5DLQP.js.map +1 -0
- package/dist/{chunk-QCHKWIRS.js → chunk-VZFJTKIW.js} +13 -13
- package/dist/{chunk-QCHKWIRS.js.map → chunk-VZFJTKIW.js.map} +1 -1
- package/dist/{chunk-VSQBHPWH.js → chunk-X4ZU4QH5.js} +54 -22
- package/dist/chunk-X4ZU4QH5.js.map +1 -0
- package/dist/chunk-XD7SRDUY.js +188 -0
- package/dist/chunk-XD7SRDUY.js.map +1 -0
- package/dist/chunk-XH2IZVLT.js +62 -0
- package/dist/chunk-XH2IZVLT.js.map +1 -0
- package/dist/chunk-Z7I6SONO.js +825 -0
- package/dist/chunk-Z7I6SONO.js.map +1 -0
- package/dist/cli/quickdraw-docs.js +132 -112
- package/dist/cli/quickdraw-docs.js.map +1 -1
- package/dist/client/core.d.ts +387 -0
- package/dist/client/core.js +109 -0
- package/dist/client/index.d.ts +52 -203
- package/dist/client/index.js +59 -218
- package/dist/client/index.js.map +1 -1
- package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-CUUNJwWs.d.ts} +3 -3
- package/dist/{connection-Cr1BU07W.d.ts → connection-2EeQ_Et0.d.ts} +22 -11
- package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Bx5HOcYK.d.ts} +67 -17
- package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-DAMANT79.d.ts} +46 -13
- package/dist/{envelope-Cp3YcVxC.d.ts → envelope-BMBaxppV.d.ts} +216 -10
- package/dist/{http-Djj2Inuu.d.ts → http-YzLAar3w.d.ts} +76 -60
- package/dist/index.d.ts +8 -7
- package/dist/index.js +82 -25
- package/dist/index.js.map +1 -1
- package/dist/{infer-Teo1xpsd.d.ts → infer-Br62cnyW.d.ts} +82 -11
- package/dist/logger-Yz93KzdV.d.ts +30 -0
- package/dist/{metrics-BdBu5o8G.d.ts → metrics-CTVpw0gu.d.ts} +2 -2
- package/dist/origins-kvpxnVcW.d.ts +8 -0
- package/dist/parser.js +2 -1
- package/dist/prisma/index.d.ts +14 -7
- package/dist/prisma/index.js +279 -70
- package/dist/prisma/index.js.map +1 -1
- package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
- package/dist/rateLimit-5RKBFLUR.js.map +1 -0
- package/dist/remote-N7OUAGOW.js +15 -0
- package/dist/remote-N7OUAGOW.js.map +1 -0
- package/dist/server/auth/index.d.ts +82 -33
- package/dist/server/auth/index.js +277 -270
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/express/index.d.ts +9 -2
- package/dist/server/express/index.js +1 -1
- package/dist/server/index.d.ts +268 -84
- package/dist/server/index.js +664 -418
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/index.d.ts +89 -27
- package/dist/server/mcp/index.js +281 -62
- package/dist/server/mcp/index.js.map +1 -1
- package/dist/server/otel.d.ts +3 -3
- package/dist/{sharing-DVa8W-yR.d.ts → sharing-BrsmlDv_.d.ts} +3 -3
- package/dist/testing/client.d.ts +14 -14
- package/dist/testing/client.js +19 -10
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts +50 -13
- package/dist/testing/index.js +113 -21
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock.d.ts +5 -5
- package/dist/testing/mock.js +17 -9
- package/dist/tracked-BR5b2O-U.d.ts +43 -0
- package/dist/{types-Cu0vmx7c.d.ts → types-CLRCQGnO.d.ts} +4 -3
- package/dist/types-tMagHbjy.d.ts +151 -0
- package/dist/utils/index.d.ts +16 -4
- package/dist/utils/index.js +6 -3
- package/package.json +5 -1
- package/dist/chunk-2PWMUVC7.js.map +0 -1
- package/dist/chunk-4DIQHASK.js.map +0 -1
- package/dist/chunk-4YO5H5ON.js.map +0 -1
- package/dist/chunk-B2P7AZ25.js.map +0 -1
- package/dist/chunk-CDKG4TFA.js.map +0 -1
- package/dist/chunk-DD4SKCNO.js.map +0 -1
- package/dist/chunk-H23KEFBA.js.map +0 -1
- package/dist/chunk-OECZPRPW.js.map +0 -1
- package/dist/chunk-QEKVYG5F.js.map +0 -1
- package/dist/chunk-REX5YPHX.js.map +0 -1
- package/dist/chunk-RT6OILOI.js.map +0 -1
- package/dist/chunk-RZTP4IEW.js.map +0 -1
- package/dist/chunk-SHEGLZEP.js.map +0 -1
- package/dist/chunk-TBMKJ26R.js.map +0 -1
- package/dist/chunk-VSQBHPWH.js.map +0 -1
- package/dist/chunk-X5CWPX7H.js.map +0 -1
- package/dist/chunk-YSWH776Y.js +0 -13
- package/dist/chunk-YSWH776Y.js.map +0 -1
- package/dist/chunk-Z2LZ7IZ7.js.map +0 -1
- package/dist/chunk-ZIVPHYRG.js.map +0 -1
- package/dist/logger-BY28acW-.d.ts +0 -16
- /package/dist/{rateLimit-ZMIZJUZF.js.map → client/core.js.map} +0 -0
package/dist/server/index.d.ts
CHANGED
|
@@ -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,
|
|
2
|
-
import { M as ModelName,
|
|
3
|
-
export {
|
|
4
|
-
import { S as ServerOptions, Q as QuickdrawServer } from '../createServer-
|
|
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-
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
export {
|
|
1
|
+
import { J as AnyContract, at as ProjectionName, ai as FullProjectionOf, ac as CollectionName, A as AccessLevel, ap as MethodName, d as StandardSchemaV1, c as InferOutput, N as NullableProjection, P as ProjectionList, aq as MethodOf, as as ParsedInputOf, ao as KindOf, af as EntityOf, ar as OutputOf } from '../infer-Br62cnyW.js';
|
|
2
|
+
import { M as ModelName, u as PolicyFor, v as RowForms, w as AccessFor, x 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, t as RoomLeaveHandler, H as HostLeaveHandler, L as ChannelsRequired, h as Service, N as BaseContext, O as CallerFor, R as RunContext, k as RunOptions, n as StreamHandle, P as Presence, m as ServerRooms, Q as AccessPolicy, T as AnyAccessPolicy, V as PolicyColumns, X as PolicyForeign, Y as PolicyTools, Z as AccessFilter, _ as RowAccess, p as AccessEngine, b as StorageWhere } from '../caller-BTwGl7vm.js';
|
|
3
|
+
export { aP as ANY_FIELD, aF as AccessChange, aG as AccessChangeListener, aH as AccessForm, aI as AccessRequest, $ as AffectsLink, o as AnyContext, A as AnyService, q as AppRooms, aJ as AuthenticatedAccess, au as CallOptions, d as Caller, ab as ChannelAccess, ac as ChannelContext, ad as ChannelHandler, ae as ChannelImplementation, af as ChannelRoomOf, a5 as CollectionScope, a7 as ContextAccess, a8 as ContextRooms, a9 as ContextServices, C as CountArgs, a4 as DEFAULT_BULK_THRESHOLD, i as DevWarning, D as DevWarningError, j as DevWarningKind, l as DispatcherAccess, aK as EntryAccess, F as FindManyArgs, f as FlushInfo, e as FlushSink, ax as ForeignColumns, ay as ForeignColumnsOf, ag as HostLeave, aL as IdKeyOf, aM as IdSelector, aS as LinkInterest, az as MembershipRead, av as MethodCaller, aU as N_PLUS_ONE_STATEMENTS, aA as ParentLink, aB as PolicyKind, aC as PolicyReads, a0 as ProjectedOutput, a1 as Projection, ah as RoomLeave, ai as RoomLeaveReason, aj as RoomLeft, ak as RoomTarget, aD as RowLevel, aE as RowLevels, aN as ScopeAccess, aO as ServiceAccess, aw as ServiceCaller, al as ServiceChannel, a6 as ServiceCollection, g as ServiceMethod, am as ServiceStream, c as StatementCount, S as StorageAdapter, a as StorageRow, an as StreamImplementation, ao as StreamPushArgs, ap as StreamPushManyArgs, aq as StreamSeed, ar as StreamSeedContext, as as StreamSubscribersArgs, r as StreamSubscriptions, at as StreamValidation, a2 as TierGroup, a3 as Tiers, aa as TouchOptions, aQ as UnitOfWork, U as UnitOfWorkFactory, aR as UnitOfWorkScope, W as WriteRecord, aT as formatDevWarning, s as storageOf } from '../caller-BTwGl7vm.js';
|
|
4
|
+
import { S as ServerOptions, Q as QuickdrawServer } from '../createServer-Bx5HOcYK.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-Bx5HOcYK.js';
|
|
6
|
+
import { aA as Version } from '../envelope-BMBaxppV.js';
|
|
7
|
+
export { aD as MAX_ENTITY_IDS_PER_SOCKET, aE as MAX_SCOPES_PER_SOCKET, aF as MAX_TOPICS_PER_SOCKET } from '../envelope-BMBaxppV.js';
|
|
8
|
+
import { Q as QuickdrawTypes, D as DbOf, d as PrincipalKindOf, b as PrincipalOf, M as MaybePromise, c as McpContextOf, C as ContextExtensionOf, P as Principal } from '../types-CLRCQGnO.js';
|
|
9
|
+
export { a as McpContext, T as Transport } from '../types-CLRCQGnO.js';
|
|
10
|
+
import { c as DispatcherOptions, D as Dispatcher, d as DispatcherCollections } from '../http-YzLAar3w.js';
|
|
11
|
+
export { A as AccessOptions, e as ChangeLogOptions, C as ContractOfServices, k as DEFAULT_LIMITS, g as DbOfServices, i as DispatchRequest, j as DispatchResult, a as DispatcherBaseOptions, l as DispatcherLimits, q as HttpMiddleware, H as HttpRouter, r 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, o as VersionSource, f as createDispatcher, p as createHttpRouter, t as toCallReply } from '../http-YzLAar3w.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-CS7JB_UH.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-BrsmlDv_.js';
|
|
14
|
+
import { x as AdminNeverWritable, l as AdminFieldConfig, t as AdminData } from '../adminSchemas-29cGgrg5.js';
|
|
15
|
+
export { a as CallOutcome, C as CallRecord } from '../metrics-CTVpw0gu.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-DtdYjrZ9.js';
|
|
16
17
|
import { Server } from 'socket.io';
|
|
17
|
-
import { L as Logger } from '../logger-
|
|
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
|
|
@@ -103,6 +101,14 @@ type HandlerResult<C extends AnyContract, Output, Proj> = Output extends Standar
|
|
|
103
101
|
* wrapped by `nullable` and `listOf`.
|
|
104
102
|
*/
|
|
105
103
|
type HandlerOutputOf<C extends AnyContract, M extends MethodName<C>, Proj = Record<never, never>> = HandlerResult<C, MethodOf<C, M>["output"], Proj>;
|
|
104
|
+
/**
|
|
105
|
+
* A service-wide grant a collection's subscribers need besides the anchor or
|
|
106
|
+
* self check: `{ service: L }`, the caller's grant on the collection's own
|
|
107
|
+
* service at least `L`, as a method's `{ service: L }` form counts it.
|
|
108
|
+
*/
|
|
109
|
+
interface CollectionRequires {
|
|
110
|
+
readonly service: AccessLevel;
|
|
111
|
+
}
|
|
106
112
|
/**
|
|
107
113
|
* How one collection's scopes are authorized (RFC 0003 section 7.1), in
|
|
108
114
|
* `defineService`'s `collections` option.
|
|
@@ -113,8 +119,17 @@ type HandlerOutputOf<C extends AnyContract, M extends MethodName<C>, Proj = Reco
|
|
|
113
119
|
* that row, through its service's policy. Deleting the row closes its
|
|
114
120
|
* scopes (`qd:revoked` with reason `"anchor-deleted"`).
|
|
115
121
|
* - `scopeAccess: "self"`: the scope value is the subscriber's own user id.
|
|
122
|
+
* On a service with an access policy its items still follow that policy:
|
|
123
|
+
* only the rows its user may read at `Read`, and a row the user loses goes
|
|
124
|
+
* out `removed`.
|
|
125
|
+
* - `requires: { service: L }`, beside either: the subscriber also needs a
|
|
126
|
+
* service-wide grant of at least `L` on this service, as the service's
|
|
127
|
+
* methods under `{ service: L }` do (`{ scopeAccess: "self", requires:
|
|
128
|
+
* { service: "Read" } }`: the user's own rows, for holders of the Read
|
|
129
|
+
* grant). Without it the scope is `FORBIDDEN`, and a socket whose grants
|
|
130
|
+
* reload below it leaves the scope (`qd:revoked`, reason `"access"`).
|
|
116
131
|
*
|
|
117
|
-
* A service-wide `Admin` grant on this service passes
|
|
132
|
+
* A service-wide `Admin` grant on this service passes every check, as it
|
|
118
133
|
* passes every check of the service. `bulkThreshold` (default 200) is how
|
|
119
134
|
* many changed rows of one scope one flush may send as deltas; past it the
|
|
120
135
|
* scope gets one `reset` and its clients load it again.
|
|
@@ -122,10 +137,12 @@ type HandlerOutputOf<C extends AnyContract, M extends MethodName<C>, Proj = Reco
|
|
|
122
137
|
type CollectionOption = {
|
|
123
138
|
readonly anchor: AnyContract;
|
|
124
139
|
readonly scopeAccess?: undefined;
|
|
140
|
+
readonly requires?: CollectionRequires;
|
|
125
141
|
readonly bulkThreshold?: number;
|
|
126
142
|
} | {
|
|
127
143
|
readonly scopeAccess: "self";
|
|
128
144
|
readonly anchor?: undefined;
|
|
145
|
+
readonly requires?: CollectionRequires;
|
|
129
146
|
readonly bulkThreshold?: number;
|
|
130
147
|
};
|
|
131
148
|
/** `defineService`'s `collections` option: one entry per collection of the contract. */
|
|
@@ -208,9 +225,15 @@ type ShareOptions<A> = {
|
|
|
208
225
|
/**
|
|
209
226
|
* Run identical concurrent calls once: `"caller"` per principal, `"all"`
|
|
210
227
|
* across principals. Every caller is authorized before it joins; the
|
|
211
|
-
* handler runs with the first caller's `ctx`,
|
|
212
|
-
*
|
|
213
|
-
*
|
|
228
|
+
* handler runs with the first caller's `ctx`, and every caller gets its
|
|
229
|
+
* result, so a `"all"` result must depend on the input only: its
|
|
230
|
+
* handler reads nothing of the caller (in development, reading
|
|
231
|
+
* `ctx.principal`, `ctx.services`, `ctx.mcp` or `ctx.access` warns
|
|
232
|
+
* `[quickdraw:shared-principal]`, and a strict test app fails the
|
|
233
|
+
* call). `"all"` is not allowed with `custom` access, nor on the kit
|
|
234
|
+
* methods whose result depends on who asks (the read/write kit's
|
|
235
|
+
* `list` and `getMany`, `search`, the sharing kit's `listShares` and
|
|
236
|
+
* `listMembers`, the admin kit's `adminList` and `adminGet`).
|
|
214
237
|
*/
|
|
215
238
|
readonly share: A extends CustomAccess<never, never> ? "caller" : ShareMode;
|
|
216
239
|
/** Reuse a successful result for this long after its run, in milliseconds. */
|
|
@@ -252,6 +275,22 @@ type MethodImplementation<T extends QuickdrawTypes, C extends AnyContract, M ext
|
|
|
252
275
|
* signed out. Leave it out for the service's list.
|
|
253
276
|
*/
|
|
254
277
|
readonly kinds?: readonly PrincipalKindOf<T>[];
|
|
278
|
+
/**
|
|
279
|
+
* A requirement on the caller's verified claims (`principal.claims`, a
|
|
280
|
+
* token's `scope`), beside `access`: the call passes only when it returns
|
|
281
|
+
* `true`. It adds to the form, so `{ entry: "Moderate" }` with `claims`
|
|
282
|
+
* needs Moderate on the row and the claims. It runs right after `kinds`,
|
|
283
|
+
* outside the access engine, so no grant passes it, a service-wide
|
|
284
|
+
* `Admin` grant included. Without a principal the call is
|
|
285
|
+
* `UNAUTHENTICATED`; when it returns anything but `true`, `FORBIDDEN`. It
|
|
286
|
+
* is synchronous, and a `"public"` method takes none. Never write a check
|
|
287
|
+
* on claims as `custom`: that form replaces the row check, and an Admin
|
|
288
|
+
* grant skips it.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* claims: (claims) => claims?.scope === "triage",
|
|
292
|
+
*/
|
|
293
|
+
readonly claims?: (claims: PrincipalOf<T>["claims"], input: ParsedInputOf<C, M>) => boolean;
|
|
255
294
|
/**
|
|
256
295
|
* Runs the method. For a projection output it returns the database row
|
|
257
296
|
* (or rows, or `null`), which the framework projects: only the
|
|
@@ -263,11 +302,15 @@ type MethodImplementation<T extends QuickdrawTypes, C extends AnyContract, M ext
|
|
|
263
302
|
/**
|
|
264
303
|
* Says the access form is this method's whole check on purpose. On a
|
|
265
304
|
* service with an access policy, `defineService` refuses a method whose
|
|
266
|
-
* input has `id` while its access
|
|
267
|
-
* service: L }` below `Admin`,
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
305
|
+
* input has `id` while its access checks some other row or none:
|
|
306
|
+
* `"public"`, `"authenticated"`, `{ service: L }` below `Admin`,
|
|
307
|
+
* `custom(fn)`, `{ scope, of, id }`, or `{ entry, id }` naming another
|
|
308
|
+
* key. Any caller the form admits could then reach any row by its id:
|
|
309
|
+
* give it `{ entry: L }` so the policy decides (with `claims` beside it
|
|
310
|
+
* for a check on the caller's claims), or `rowless: true` when every such
|
|
311
|
+
* caller may reach any row (public profiles, lookups by an id that tells
|
|
312
|
+
* nothing), or when `id` names a row the method creates (an id the client
|
|
313
|
+
* made).
|
|
271
314
|
*/
|
|
272
315
|
readonly rowless?: true;
|
|
273
316
|
} & (KindOf<C, M> extends "query" ? QueryOptions<T, C, M, A> : MutationOptions);
|
|
@@ -314,8 +357,10 @@ interface ServiceDefinition<T extends QuickdrawTypes, C extends AnyContract, A,
|
|
|
314
357
|
* How each collection of the contract authorizes its scopes (RFC 0003
|
|
315
358
|
* section 7.1): `{ anchor: contract }`, the contract whose rows the scope
|
|
316
359
|
* values are ids of, or `{ scopeAccess: "self" }` for a scope that is the
|
|
317
|
-
* subscriber's user id; plus `
|
|
318
|
-
*
|
|
360
|
+
* subscriber's user id; plus `requires: { service: L }`, a service-wide
|
|
361
|
+
* grant every subscriber needs besides, and `bulkThreshold`. Required
|
|
362
|
+
* when the contract declares collections. Needs `model`. A self scope's
|
|
363
|
+
* items still follow the service's `access` policy, when it has one.
|
|
319
364
|
*/
|
|
320
365
|
readonly collections?: CollectionOptions<C>;
|
|
321
366
|
/**
|
|
@@ -372,6 +417,20 @@ interface ServiceDefinition<T extends QuickdrawTypes, C extends AnyContract, A,
|
|
|
372
417
|
* },
|
|
373
418
|
*/
|
|
374
419
|
readonly onRoomLeave?: RoomLeaveHandler<PrincipalOf<T>>;
|
|
420
|
+
/**
|
|
421
|
+
* Called once when the host of an app room leaves it (host mode, RFC 0003
|
|
422
|
+
* section 12.5): its own leave, a removal, or a disconnect, with the room,
|
|
423
|
+
* the host's socket and principal and the reason. The room has no host
|
|
424
|
+
* then, and its sockets heard `qd:host [room, null]`; the app decides
|
|
425
|
+
* what follows (another host, the game's end). Run as `onRoomLeave` is,
|
|
426
|
+
* beside `createServer`'s own, in a unit of work of its own.
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* onHostLeave: ({ room }) => {
|
|
430
|
+
* qd.rooms.emit(room, game, "hostLeft", { room });
|
|
431
|
+
* },
|
|
432
|
+
*/
|
|
433
|
+
readonly onHostLeave?: HostLeaveHandler<PrincipalOf<T>>;
|
|
375
434
|
/**
|
|
376
435
|
* Whether a service-wide `Admin` grant passes every access check of this
|
|
377
436
|
* service (RFC 0003 section 4.1). Default `true`.
|
|
@@ -485,10 +544,12 @@ interface Quickdraw<T extends QuickdrawTypes> {
|
|
|
485
544
|
/**
|
|
486
545
|
* The handle of a stream (RFC 0003 section 12.5), for handlers, jobs and
|
|
487
546
|
* timers: `qd.stream(task, "logs").push(taskId, line)` (`push(item)` for a
|
|
488
|
-
* global stream; `pushMany(taskId, lines)` for several at once)
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
* a
|
|
547
|
+
* global stream; `pushMany(taskId, lines)` for several at once), and
|
|
548
|
+
* `await qd.stream(task, "logs").subscribers(taskId)`, how many sockets
|
|
549
|
+
* watch the feed on every node. Each use goes through the dispatcher this
|
|
550
|
+
* instance created last, so a handle can be made when a module loads;
|
|
551
|
+
* pushing before any dispatcher exists, or to a stream it does not serve,
|
|
552
|
+
* throws (`subscribers` rejects).
|
|
492
553
|
* Throws a `TypeError` at once for a stream the contract does not declare.
|
|
493
554
|
*/
|
|
494
555
|
stream<C extends AnyContract, K extends keyof C["streams"] & string>(contract: C, name: K): StreamHandle<C, K>;
|
|
@@ -535,6 +596,9 @@ declare const CHANNEL_ABUSE_WINDOW_MS = 10000;
|
|
|
535
596
|
/** A socket is disconnected once its drops within the window exceed this many times the channel's rate. */
|
|
536
597
|
declare const CHANNEL_ABUSE_MULTIPLIER = 100;
|
|
537
598
|
|
|
599
|
+
/** The most stream feeds one socket may subscribe to at once. */
|
|
600
|
+
declare const MAX_STREAMS_PER_SOCKET = 500;
|
|
601
|
+
|
|
538
602
|
/**
|
|
539
603
|
* A custom access check: the call passes when `check(ctx, input)` resolves
|
|
540
604
|
* `true`. The caller must be authenticated first, so `ctx.principal` is
|
|
@@ -543,6 +607,11 @@ declare const CHANNEL_ABUSE_MULTIPLIER = 100;
|
|
|
543
607
|
* custom access cannot `share: "all"`, because its result may depend on who
|
|
544
608
|
* asks.
|
|
545
609
|
*
|
|
610
|
+
* It replaces the row check: on a service with an access policy,
|
|
611
|
+
* `defineService` refuses it on a method whose input has `id` unless the
|
|
612
|
+
* method says `rowless: true`. A check on the caller's claims is the
|
|
613
|
+
* method's `claims`, beside an `entry` form: no grant skips that.
|
|
614
|
+
*
|
|
546
615
|
* @example
|
|
547
616
|
* access: custom((ctx, input) => ctx.principal.userId === input.ownerId),
|
|
548
617
|
*/
|
|
@@ -578,7 +647,11 @@ declare function jsonAcl<const Field extends string, const Owner extends string
|
|
|
578
647
|
|
|
579
648
|
/** Options of {@link members}. */
|
|
580
649
|
interface MembersOptions<Model extends string = string, Entry extends string = string, User extends string = string, Level extends string = string> {
|
|
581
|
-
/**
|
|
650
|
+
/**
|
|
651
|
+
* The membership model, named as the client names it: `"projectMember"`.
|
|
652
|
+
* It needs an `id` column (keep the pair unique with `@@unique`, never a
|
|
653
|
+
* composite `@@id`), or its writes are not tracked and never revoke.
|
|
654
|
+
*/
|
|
582
655
|
readonly model: Model;
|
|
583
656
|
/** The column holding the id of the row the membership is on: `"projectId"`. */
|
|
584
657
|
readonly entry: Entry;
|
|
@@ -589,14 +662,20 @@ interface MembersOptions<Model extends string = string, Entry extends string = s
|
|
|
589
662
|
/**
|
|
590
663
|
* Maps stored roles to access levels: `{ owner: "Admin", editor: "Moderate", viewer: "Read" }`.
|
|
591
664
|
* Without it a stored role must be a level name. A role that maps to no
|
|
592
|
-
* level grants nothing.
|
|
665
|
+
* level grants nothing. Roles that map to one level are peers: with
|
|
666
|
+
* `{ owner: "Admin", admin: "Admin" }` the sharing kit lets an `admin`
|
|
667
|
+
* demote or remove the `owner`. To make an owner untouchable, give the
|
|
668
|
+
* row an owner column (`anyOf(owner("ownerId"), members(...))`, or
|
|
669
|
+
* `jsonAcl(..., { owner })`).
|
|
593
670
|
*/
|
|
594
671
|
readonly levels?: Readonly<Record<string, AccessLevel>>;
|
|
595
672
|
}
|
|
596
673
|
/**
|
|
597
674
|
* The level comes from the principal's row in a membership table: one query
|
|
598
675
|
* 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.
|
|
676
|
+
* user and entry give the highest level among them. The table needs an `id`
|
|
677
|
+
* column, or no write to it is tracked and a removed member keeps what they
|
|
678
|
+
* subscribed to; `createServer` names such a table at start.
|
|
600
679
|
*
|
|
601
680
|
* @example
|
|
602
681
|
* access: members({ model: "projectMember", entry: "projectId", user: "userId", level: "role" }),
|
|
@@ -666,7 +745,8 @@ interface ResolverOptions<P extends Principal = Principal, Column extends string
|
|
|
666
745
|
/**
|
|
667
746
|
* A filter matching exactly the rows on which the principal has at least
|
|
668
747
|
* `level`, or `"none"`. Without it, list filters through this policy match
|
|
669
|
-
* no row
|
|
748
|
+
* no row, and the read/write kit's `reorder` moves none below a
|
|
749
|
+
* service-wide grant.
|
|
670
750
|
*/
|
|
671
751
|
readonly where?: (principal: P, level: AccessLevel, tools: PolicyTools) => MaybePromise<AccessFilter>;
|
|
672
752
|
/**
|
|
@@ -797,8 +877,12 @@ type CrudMethodsOf<C extends AnyContract> = {
|
|
|
797
877
|
type CrudKindOf<C extends AnyContract, M extends MethodName<C>> = C["methods"][M] extends {
|
|
798
878
|
readonly "~crud"?: infer Kind;
|
|
799
879
|
} ? Extract<Kind, CrudMethodName> : never;
|
|
800
|
-
/**
|
|
801
|
-
|
|
880
|
+
/**
|
|
881
|
+
* What a `custom` access check of a kit method, and the app's callbacks a
|
|
882
|
+
* kit calls (`prepare`, `onWrite`, `onChange`, ...), read from `ctx`:
|
|
883
|
+
* `ctx.access` asks the caller's level on another row.
|
|
884
|
+
*/
|
|
885
|
+
type KitContext = Pick<BaseContext<Principal>, "principal" | "signal" | "log" | "requestId" | "transport" | "access">;
|
|
802
886
|
/** One access form per kit method of `C`: what `crud.handlers`' `access` must give. */
|
|
803
887
|
type CrudAccess<C extends AnyContract> = {
|
|
804
888
|
readonly [M in CrudMethodsOf<C>]: AccessFor<ParsedInputOf<C, M>, KitContext>;
|
|
@@ -819,22 +903,31 @@ interface CrudHandlersOptions<C extends AnyContract, A, Db = unknown> {
|
|
|
819
903
|
* Who may call each of the kit's methods: one form per method, required.
|
|
820
904
|
* `get`, `update`, `delete` and `reorder` take `{ entry: L }` to check the
|
|
821
905
|
* row; the methods on many rows also keep only the rows the service's
|
|
822
|
-
* policy gives the caller at the form's level.
|
|
906
|
+
* policy gives the caller at the form's level. A bulk method whose form
|
|
907
|
+
* names no level takes its single-row counterpart's row level (`delete`'s
|
|
908
|
+
* for `bulkDelete`, `update`'s for `bulkUpdate`) when it is higher than
|
|
909
|
+
* `Moderate`; give `{ entry: L, id: "ids" }` to refuse the whole call
|
|
910
|
+
* instead of skipping rows.
|
|
823
911
|
*/
|
|
824
912
|
readonly access: A & NoInfer<NotAKitMethod<C, A>>;
|
|
825
913
|
/**
|
|
826
914
|
* What `create` writes, from its parsed input: set owner or scope columns
|
|
827
915
|
* from `ctx.principal`, an ordinal from `nextOrdinal`. `create` writes the
|
|
828
|
-
* input as it is without it.
|
|
916
|
+
* input as it is without it. An owner or access-list column (one the
|
|
917
|
+
* policy reads) comes only from here: the caller may not send one. The
|
|
918
|
+
* anchors of what it returns (each `inherit` parent and anchored
|
|
919
|
+
* collection's scope it sets) are checked at the method's row level, and
|
|
920
|
+
* it returns column values only, never a relation or a nested write.
|
|
829
921
|
*/
|
|
830
922
|
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
923
|
/**
|
|
832
924
|
* The kit's methods whose access form is their whole check on purpose:
|
|
833
925
|
* each gets `rowless: true`. On a service with an access policy,
|
|
834
|
-
* `defineService` refuses `get` under
|
|
835
|
-
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
926
|
+
* `defineService` refuses `get` under a form that asks the policy nothing
|
|
927
|
+
* about the row its `id` names (`"public"`, `"authenticated"`,
|
|
928
|
+
* `{ service: L }` below `Admin`, `custom`, `{ scope }`, or `{ entry }` on
|
|
929
|
+
* another key: any such caller could read any row by its id) unless it is
|
|
930
|
+
* named here: `rowless: ["get"]` for public profiles, say. `update`, `delete` and `reorder` check the row whatever
|
|
838
931
|
* their form, and need nothing.
|
|
839
932
|
*/
|
|
840
933
|
readonly rowless?: readonly CrudMethodsOf<C>[];
|
|
@@ -963,7 +1056,8 @@ type SearchStrategy<Ctx = SearchStrategyContext> = {
|
|
|
963
1056
|
* The filter of the rows that match `q`, in the database client's
|
|
964
1057
|
* `where` shape: a Postgres full-text condition, say. The kit adds the
|
|
965
1058
|
* access filter and the scope, and pages the rows by keyset cursor in
|
|
966
|
-
* the scope collection's order
|
|
1059
|
+
* the scope collection's order when the call passes a scope, else by
|
|
1060
|
+
* id.
|
|
967
1061
|
*/
|
|
968
1062
|
readonly where: (q: string, ctx: Ctx) => MaybePromise<StorageWhere>;
|
|
969
1063
|
readonly ids?: never;
|
|
@@ -1086,9 +1180,13 @@ interface SharingUserLookup {
|
|
|
1086
1180
|
readonly email?: string;
|
|
1087
1181
|
}
|
|
1088
1182
|
/**
|
|
1089
|
-
* Finds the user a by-name method means: their user id, or `null` (or
|
|
1183
|
+
* Finds the one user a by-name method means: their user id, or `null` (or
|
|
1090
1184
|
* `undefined`) when there is no such user, which fails the call with
|
|
1091
|
-
* `NOT_FOUND`.
|
|
1185
|
+
* `NOT_FOUND`. It must name exactly one user: look a user up by something
|
|
1186
|
+
* unique and verified (an email, with `findUnique`), and take a display
|
|
1187
|
+
* name's user only when exactly one user has that name, else `null`. A
|
|
1188
|
+
* `findFirst` by name hands the share to whoever registered the name first
|
|
1189
|
+
* (the 5.1 audit's SHARE-2).
|
|
1092
1190
|
*/
|
|
1093
1191
|
type SharingResolveUser<Db = unknown> = (lookup: SharingUserLookup, ctx: KitContext, db: Db) => MaybePromise<string | null | undefined>;
|
|
1094
1192
|
type NotASharingMethod<C extends AnyContract, A> = [Exclude<keyof A, SharingMethodsOf<C>>] extends [
|
|
@@ -1110,17 +1208,25 @@ type SharingHandlersOptions<C extends AnyContract, A, Db = unknown> = {
|
|
|
1110
1208
|
readonly onChange?: SharingOnChange<Db>;
|
|
1111
1209
|
/**
|
|
1112
1210
|
* The kit's methods whose access form is their whole check on purpose:
|
|
1113
|
-
* each gets `rowless: true`.
|
|
1211
|
+
* each gets `rowless: true`. A change still never touches a user above
|
|
1212
|
+
* the caller's own level on the row, which under such a form is their
|
|
1213
|
+
* level on the row (often none): name `service` in the form for a
|
|
1214
|
+
* service-wide grant to count. On a service with an access policy,
|
|
1114
1215
|
* `defineService` refuses an access-list method (`share`, `unshare`,
|
|
1115
1216
|
* `setLevel`, `listShares`, `shareByName`: their input names the row as
|
|
1116
|
-
* `id`) under
|
|
1117
|
-
* `
|
|
1217
|
+
* `id`) under a form that asks the policy nothing about that row
|
|
1218
|
+
* (`"public"`, `"authenticated"`, `{ service: L }` below `Admin`,
|
|
1219
|
+
* `custom`, `{ scope }`, or `{ entry }` on another key) unless it is named
|
|
1220
|
+
* here.
|
|
1118
1221
|
*/
|
|
1119
1222
|
readonly rowless?: readonly SharingMethodsOf<C>[];
|
|
1120
1223
|
} & ([SharingByNameOf<C>] extends [never] ? {
|
|
1121
1224
|
readonly resolveUser?: `sharing.handlers: resolveUser is for shareByName and inviteByName, which ${C["name"]} does not have`;
|
|
1122
1225
|
} : {
|
|
1123
|
-
/**
|
|
1226
|
+
/**
|
|
1227
|
+
* Finds the one user `shareByName` and `inviteByName` mean, by name or
|
|
1228
|
+
* email, or `null`: never the first of several (`SharingResolveUser`).
|
|
1229
|
+
*/
|
|
1124
1230
|
readonly resolveUser: SharingResolveUser<Db>;
|
|
1125
1231
|
});
|
|
1126
1232
|
/** `sharing.handlers`' options argument: required when the contract has a by-name method. */
|
|
@@ -1163,6 +1269,35 @@ declare function labelOf(name: string): string;
|
|
|
1163
1269
|
/** A service's name for people: "taskService" is "Tasks" (4.1's `toDisplayName`). */
|
|
1164
1270
|
declare function displayNameOf(serviceName: string): string;
|
|
1165
1271
|
|
|
1272
|
+
/**
|
|
1273
|
+
* A write the admin kit is about to make, as `prepare` hears it: `data` is
|
|
1274
|
+
* the caller's data, checked; `before` is the row before the write, every
|
|
1275
|
+
* field, read in the write's transaction (as `onWrite` hears it).
|
|
1276
|
+
*/
|
|
1277
|
+
type AdminPrepareCall<Row = unknown> = {
|
|
1278
|
+
readonly method: "adminCreate";
|
|
1279
|
+
readonly data: AdminData<Row>;
|
|
1280
|
+
} | {
|
|
1281
|
+
readonly method: "adminUpdate";
|
|
1282
|
+
readonly id: string;
|
|
1283
|
+
readonly data: AdminData<Row>;
|
|
1284
|
+
readonly before: Row;
|
|
1285
|
+
} | {
|
|
1286
|
+
readonly method: "adminDelete";
|
|
1287
|
+
readonly id: string;
|
|
1288
|
+
readonly before: Row;
|
|
1289
|
+
};
|
|
1290
|
+
/**
|
|
1291
|
+
* `admin.handlers`' `prepare`: runs before each write the kit makes, inside
|
|
1292
|
+
* one transaction with it, after the caller's access and data were checked,
|
|
1293
|
+
* with that transaction's tracked client as `db` (the app's client type
|
|
1294
|
+
* `Db`, when `db` is annotated): its own writes commit with the edit, and a
|
|
1295
|
+
* throw undoes them and the edit and fails the call. Before `adminCreate`
|
|
1296
|
+
* and `adminUpdate` it may return column values, merged over the caller's
|
|
1297
|
+
* data (each anchor column among them checked at the method's row level);
|
|
1298
|
+
* what it returns before `adminDelete` is ignored.
|
|
1299
|
+
*/
|
|
1300
|
+
type AdminPrepare<Row = unknown, Db = unknown> = (call: AdminPrepareCall<Row>, ctx: KitContext, db: Db) => MaybePromise<Readonly<Record<string, unknown>> | void>;
|
|
1166
1301
|
/** A write the admin kit made, as `onWrite` hears it. */
|
|
1167
1302
|
interface AdminWrite<Row = unknown> {
|
|
1168
1303
|
/** The method that wrote. */
|
|
@@ -1220,7 +1355,7 @@ type AdminFieldOverride = Partial<Pick<AdminFieldConfig, "type" | "label" | "req
|
|
|
1220
1355
|
type NotAnAdminMethod<C extends AnyContract, A> = [Exclude<keyof A, AdminMethodsOf<C>>] extends [
|
|
1221
1356
|
never
|
|
1222
1357
|
] ? unknown : `admin.handlers: ${Exclude<keyof A, AdminMethodsOf<C>> & string} is not a method admin.contract made for ${C["name"]}`;
|
|
1223
|
-
/** The options of `admin.handlers(contract, options)`. `Db` comes from an annotated `
|
|
1358
|
+
/** The options of `admin.handlers(contract, options)`. `Db` comes from an annotated `db` of `prepare` or `onWrite`. */
|
|
1224
1359
|
interface AdminHandlersOptions<C extends AnyContract, A, Db = unknown> {
|
|
1225
1360
|
/**
|
|
1226
1361
|
* Forms that replace the kit's default, `{ service: "Admin" }`, per method.
|
|
@@ -1233,26 +1368,29 @@ interface AdminHandlersOptions<C extends AnyContract, A, Db = unknown> {
|
|
|
1233
1368
|
readonly displayName?: string;
|
|
1234
1369
|
/**
|
|
1235
1370
|
* Fields the kit leaves out entirely: from `adminMeta`, from the rows it
|
|
1236
|
-
* returns and from what it writes. `acl`, `serviceAccess
|
|
1237
|
-
* `service_access`
|
|
1238
|
-
* the
|
|
1371
|
+
* returns and from what it writes. `acl`, `serviceAccess`,
|
|
1372
|
+
* `service_access` and the column the dispatcher's `serviceAccessSource`
|
|
1373
|
+
* names on this service's model are always hidden (the first three as in
|
|
1374
|
+
* 4.1), unless `grants` shows the grants field.
|
|
1239
1375
|
*/
|
|
1240
1376
|
readonly hiddenFields?: readonly Exclude<AdminFieldOf<C>, "id">[];
|
|
1241
1377
|
/**
|
|
1242
|
-
* Show and write the entity's
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1248
|
-
*
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
|
|
1255
|
-
|
|
1378
|
+
* Show and write the entity's grants field, the user's service-wide
|
|
1379
|
+
* grants, which the kit hides by default: `serviceAccess`,
|
|
1380
|
+
* `service_access`, or the column `auth.serviceAccessSource` names on this
|
|
1381
|
+
* service's model, whatever its name. An admin screen then edits grants
|
|
1382
|
+
* through `adminUpdate` (a JSON field, checked by the entity's schema).
|
|
1383
|
+
* Only a caller whose own service-wide grant on this service is `Admin`
|
|
1384
|
+
* reads or writes it, whatever `access` gives a method; anyone else is
|
|
1385
|
+
* refused a write, filter or sort naming it (`FORBIDDEN`) and gets rows
|
|
1386
|
+
* without it. Such an Admin can grant any service, themself included, so
|
|
1387
|
+
* give that grant only to those who may. With `auth.serviceAccessSource`
|
|
1388
|
+
* naming the column, a change reaches the user's open sockets on every
|
|
1389
|
+
* node at once (`qd:access`, their subscriptions resolved again), as any
|
|
1390
|
+
* tracked write to it does. The dispatcher refuses `true` for an entity
|
|
1391
|
+
* without a grants field, when it is made. Default `false`.
|
|
1392
|
+
*/
|
|
1393
|
+
readonly grants?: boolean;
|
|
1256
1394
|
/**
|
|
1257
1395
|
* The only fields `adminCreate` and `adminUpdate` write (finding R1.4 of
|
|
1258
1396
|
* the 5.0.0 review): `adminMeta` reports every other field `editable:
|
|
@@ -1273,19 +1411,55 @@ interface AdminHandlersOptions<C extends AnyContract, A, Db = unknown> {
|
|
|
1273
1411
|
* The kit's methods whose access form is their whole check on purpose:
|
|
1274
1412
|
* each gets `rowless: true`. On a service with an access policy,
|
|
1275
1413
|
* `defineService` refuses `adminGet`, `adminUpdate` or `adminDelete`
|
|
1276
|
-
* under a form below the default that
|
|
1277
|
-
* "Moderate" }`, `"authenticated"
|
|
1278
|
-
*
|
|
1414
|
+
* under a form below the default that asks the policy nothing about the
|
|
1415
|
+
* row its `id` names (`{ service: "Moderate" }`, `"authenticated"`,
|
|
1416
|
+
* `custom`, `{ scope }`, or `{ entry }` on another key) unless it is named
|
|
1417
|
+
* here, since any caller the form admits reaches any row by its id.
|
|
1279
1418
|
*/
|
|
1280
1419
|
readonly rowless?: readonly AdminMethodsOf<C>[];
|
|
1420
|
+
/**
|
|
1421
|
+
* Runs before each write `adminCreate`, `adminUpdate` or `adminDelete`
|
|
1422
|
+
* makes, in one transaction with it and `onWrite`, once the caller's
|
|
1423
|
+
* access and data were checked: `{ method: "adminCreate", data }`,
|
|
1424
|
+
* `{ method: "adminUpdate", id, data, before }` or
|
|
1425
|
+
* `{ method: "adminDelete", id, before }` (`data` the caller's, `before`
|
|
1426
|
+
* the row, every field), the call's `ctx`, and the transaction's tracked
|
|
1427
|
+
* client as `db`. A throw fails the call and undoes everything.
|
|
1428
|
+
*
|
|
1429
|
+
* Before `adminCreate` and `adminUpdate` it may return column values,
|
|
1430
|
+
* merged over the caller's data and written: a column the server computes
|
|
1431
|
+
* (a hash, a slug), even one the caller may not write (hidden, not
|
|
1432
|
+
* editable, above the caller's level, an owner column the policy reads),
|
|
1433
|
+
* but never `id`, a timestamp, a relation or a nested write (`VALIDATION`).
|
|
1434
|
+
* An anchor column it sets (an `inherit` parent, an anchored collection's
|
|
1435
|
+
* scope) must name a row on which the caller has the method's row level
|
|
1436
|
+
* (`FORBIDDEN`), as for the caller's data and the read/write kit's
|
|
1437
|
+
* `prepare`: a lowered form never moves a row into a parent its caller
|
|
1438
|
+
* cannot reach. Returning nothing, or `undefined` for a key, keeps the
|
|
1439
|
+
* caller's data. What it returns before `adminDelete` is ignored.
|
|
1440
|
+
*
|
|
1441
|
+
* Its writes through `db` are tracked like any other: before a delete,
|
|
1442
|
+
* delete or clear there the rows the database would delete or clear with
|
|
1443
|
+
* the row (a cascade, `SET NULL`), which the tracked client never sees,
|
|
1444
|
+
* so the rows and lists open on them are told.
|
|
1445
|
+
*
|
|
1446
|
+
* @example
|
|
1447
|
+
* prepare: async (call, ctx, db: PrismaClient) => {
|
|
1448
|
+
* if (call.method === "adminDelete") {
|
|
1449
|
+
* // the database deletes a project's tasks with it: delete them first, tracked
|
|
1450
|
+
* await db.task.deleteMany({ where: { projectId: call.id } });
|
|
1451
|
+
* }
|
|
1452
|
+
* },
|
|
1453
|
+
*/
|
|
1454
|
+
readonly prepare?: AdminPrepare<EntityOf<C>, Db>;
|
|
1281
1455
|
/**
|
|
1282
1456
|
* Runs after each write `adminCreate`, `adminUpdate` or `adminDelete`
|
|
1283
1457
|
* makes, in one transaction with it: `{ method, id, before?, after }` and
|
|
1284
1458
|
* the call's `ctx`, with the transaction's tracked client as `db`. A
|
|
1285
1459
|
* throw undoes the write and fails the call. For what an admin edit must
|
|
1286
1460
|
* set off (a game reloading its tunables, an audit row) without wrapping
|
|
1287
|
-
* the kit's handlers. Without it
|
|
1288
|
-
* no `before`.
|
|
1461
|
+
* the kit's handlers. Without it, `prepare` or `onCommitted`, the kit
|
|
1462
|
+
* opens no transaction and reads no `before`.
|
|
1289
1463
|
*
|
|
1290
1464
|
* @example
|
|
1291
1465
|
* onWrite: ({ method, after }) => {
|
|
@@ -1334,10 +1508,11 @@ type Empty = Record<never, never>;
|
|
|
1334
1508
|
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>;
|
|
1335
1509
|
/**
|
|
1336
1510
|
* The admin kit: `admin.handlers(contract, { access?, displayName?,
|
|
1337
|
-
* hiddenFields?, editable?, fieldOverrides?, rowless?, grants
|
|
1338
|
-
* methods `admin.contract` made in
|
|
1339
|
-
* `Admin` grant unless `access` gives
|
|
1340
|
-
* too, for server code; a shared
|
|
1511
|
+
* hiddenFields?, editable?, fieldOverrides?, rowless?, grants?, prepare?,
|
|
1512
|
+
* onWrite?, onCommitted? })` implements the methods `admin.contract` made in
|
|
1513
|
+
* `contract`, each open to a service-wide `Admin` grant unless `access` gives
|
|
1514
|
+
* another form. `admin.contract` is here too, for server code; a shared
|
|
1515
|
+
* package imports it from the root export.
|
|
1341
1516
|
*/
|
|
1342
1517
|
declare const admin: Readonly<{
|
|
1343
1518
|
contract: <const O extends AdminContractOptions>(options: O & NoInfer<O extends {
|
|
@@ -1374,7 +1549,9 @@ declare const admin: Readonly<{
|
|
|
1374
1549
|
* option; docs/deploying.md). When the subscribing connection comes back
|
|
1375
1550
|
* after a drop, the node's clients are told to reconnect within 2 seconds,
|
|
1376
1551
|
* so they catch up on what the node missed; a publish Valkey did not take
|
|
1377
|
-
* is logged rather than left unhandled (`cluster/adapterClients.ts`).
|
|
1552
|
+
* is logged rather than left unhandled (`cluster/adapterClients.ts`). Once
|
|
1553
|
+
* the adapter is set, the node asks the others for the hosts of their app
|
|
1554
|
+
* rooms, as a node started with a cluster adapter does (`realtime/hosts.ts`).
|
|
1378
1555
|
*
|
|
1379
1556
|
* @example
|
|
1380
1557
|
* ```typescript
|
|
@@ -1411,11 +1588,18 @@ interface RedisAdapterOptions {
|
|
|
1411
1588
|
*/
|
|
1412
1589
|
password?: string;
|
|
1413
1590
|
/**
|
|
1414
|
-
* Redis database number (default: 0)
|
|
1591
|
+
* Redis database number (default: 0). It does not separate deployments:
|
|
1592
|
+
* pub/sub is shared across a server's databases, so two deployments on one
|
|
1593
|
+
* Valkey hear each other's events whatever their `db`; give each its own
|
|
1594
|
+
* Valkey, or its own `cluster.keyPrefix` (docs/deploying.md).
|
|
1415
1595
|
*/
|
|
1416
1596
|
db?: number;
|
|
1417
1597
|
/**
|
|
1418
|
-
*
|
|
1598
|
+
* The adapter's key, which names its pub/sub channels. Default: the
|
|
1599
|
+
* server's `cluster.keyPrefix` ("quickdraw" without one), so deployments
|
|
1600
|
+
* with their own prefixes use their own channels. 5.1.0 and earlier used
|
|
1601
|
+
* "socket.io": pass `keyPrefix: "socket.io"` for the deploy that moves a
|
|
1602
|
+
* cluster from such nodes, so old and new nodes keep hearing each other.
|
|
1419
1603
|
*/
|
|
1420
1604
|
keyPrefix?: string;
|
|
1421
1605
|
/**
|
|
@@ -1578,4 +1762,4 @@ declare function decryptIfEncrypted(value: string): string;
|
|
|
1578
1762
|
/** Safe wrapper that returns `null` instead of throwing on invalid/stale ciphertext. */
|
|
1579
1763
|
declare function tryDecrypt(ciphertext: string, logger?: Logger): string | null;
|
|
1580
1764
|
|
|
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 };
|
|
1765
|
+
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 AdminPrepare, type AdminPrepareCall, type AdminWrite, type AffectsOption, AnyAccessPolicy, BaseContext, type BasicAccessEngineOptions, CHANNEL_ABUSE_MULTIPLIER, CHANNEL_ABUSE_WINDOW_MS, CallerFor, ChannelOptions, ChannelsRequired, type CollectionOption, type CollectionOptions, type CollectionRequires, 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, HostLeaveHandler, 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 };
|