@fitzzero/quickdraw-core 5.1.2 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +793 -57
- package/dist/{admin-DWWrT1h6.d.ts → admin-CS7JB_UH.d.ts} +2 -2
- package/dist/{adminSchemas-D4bFKsrb.d.ts → adminSchemas-29cGgrg5.d.ts} +1 -1
- package/dist/{auth-DXiSJZaf.d.ts → auth-DtdYjrZ9.d.ts} +11 -7
- package/dist/{caller-BT-Mv4bD.d.ts → caller-BTwGl7vm.d.ts} +183 -15
- package/dist/chunk-2FDSKLBO.js +82 -0
- package/dist/chunk-2FDSKLBO.js.map +1 -0
- package/dist/{chunk-GSIPUNJL.js → chunk-64I6MYBC.js} +139 -792
- package/dist/chunk-64I6MYBC.js.map +1 -0
- package/dist/chunk-7473HK24.js +17 -0
- package/dist/chunk-7473HK24.js.map +1 -0
- package/dist/chunk-7Y5ROPXL.js +33 -0
- package/dist/chunk-7Y5ROPXL.js.map +1 -0
- package/dist/chunk-A2RBQD66.js +7 -0
- package/dist/chunk-A2RBQD66.js.map +1 -0
- package/dist/chunk-ASAMUGHG.js +651 -0
- package/dist/chunk-ASAMUGHG.js.map +1 -0
- package/dist/{chunk-B2P7AZ25.js → chunk-CYE4UBOB.js} +6 -4
- package/dist/chunk-CYE4UBOB.js.map +1 -0
- package/dist/chunk-DNP65TD5.js +832 -0
- package/dist/chunk-DNP65TD5.js.map +1 -0
- package/dist/{chunk-5CGO426C.js → chunk-GYLWEJHW.js} +5 -1
- package/dist/chunk-GYLWEJHW.js.map +1 -0
- package/dist/{chunk-AONAFOYU.js → chunk-I3JCFS7H.js} +25 -13
- package/dist/chunk-I3JCFS7H.js.map +1 -0
- package/dist/{chunk-X5CWPX7H.js → chunk-IIQ3WMJK.js} +13 -2
- package/dist/chunk-IIQ3WMJK.js.map +1 -0
- package/dist/{chunk-6K5BY47X.js → chunk-JVTONQFI.js} +1277 -277
- package/dist/chunk-JVTONQFI.js.map +1 -0
- package/dist/{chunk-RL4VKLBX.js → chunk-KKQANRLG.js} +2 -2
- package/dist/{chunk-RL4VKLBX.js.map → chunk-KKQANRLG.js.map} +1 -1
- package/dist/{chunk-GKH3LJ7N.js → chunk-MPQAT55F.js} +38 -205
- package/dist/chunk-MPQAT55F.js.map +1 -0
- package/dist/chunk-NX2V6SIL.js +202 -0
- package/dist/chunk-NX2V6SIL.js.map +1 -0
- package/dist/{chunk-7QCUX4TK.js → chunk-NZHA4TZD.js} +72 -175
- package/dist/chunk-NZHA4TZD.js.map +1 -0
- package/dist/{chunk-MBH6IDSM.js → chunk-OCZJ4EYV.js} +40 -17
- package/dist/chunk-OCZJ4EYV.js.map +1 -0
- package/dist/{chunk-RJ5I2VO3.js → chunk-PHCURHC7.js} +6 -6
- package/dist/chunk-PHCURHC7.js.map +1 -0
- package/dist/{chunk-4YO5H5ON.js → chunk-Q4OGQM5I.js} +4 -10
- package/dist/chunk-Q4OGQM5I.js.map +1 -0
- package/dist/chunk-QSU47XEX.js +13 -0
- package/dist/chunk-QSU47XEX.js.map +1 -0
- package/dist/{chunk-LCC7HNFP.js → chunk-RZXJTDH5.js} +2 -2
- package/dist/{chunk-Z2LZ7IZ7.js → chunk-SN3OZVEQ.js} +5 -31
- package/dist/chunk-SN3OZVEQ.js.map +1 -0
- package/dist/{chunk-Z5ILULF2.js → chunk-SQ5VUG77.js} +4 -3
- package/dist/{chunk-Z5ILULF2.js.map → chunk-SQ5VUG77.js.map} +1 -1
- package/dist/chunk-STH5DLQP.js +1192 -0
- package/dist/chunk-STH5DLQP.js.map +1 -0
- package/dist/{chunk-NMXYENH4.js → chunk-VZFJTKIW.js} +6 -6
- package/dist/{chunk-753VJIUP.js → chunk-X4ZU4QH5.js} +43 -9
- package/dist/chunk-X4ZU4QH5.js.map +1 -0
- package/dist/chunk-XD7SRDUY.js +188 -0
- package/dist/chunk-XD7SRDUY.js.map +1 -0
- package/dist/chunk-Z7I6SONO.js +825 -0
- package/dist/chunk-Z7I6SONO.js.map +1 -0
- package/dist/cli/quickdraw-docs.js +131 -113
- package/dist/cli/quickdraw-docs.js.map +1 -1
- package/dist/client/core.d.ts +387 -0
- package/dist/client/core.js +109 -0
- package/dist/client/core.js.map +1 -0
- package/dist/client/index.d.ts +30 -193
- package/dist/client/index.js +56 -217
- package/dist/client/index.js.map +1 -1
- package/dist/{clientTypes-hWcPUVS9.d.ts → clientTypes-CUUNJwWs.d.ts} +3 -3
- package/dist/{connection-CgijdGpT.d.ts → connection-2EeQ_Et0.d.ts} +16 -9
- package/dist/{createServer-Cp-Wk500.d.ts → createServer-Bx5HOcYK.d.ts} +37 -9
- package/dist/{createTestApp-BB_PkqQ7.d.ts → createTestApp-DAMANT79.d.ts} +36 -9
- package/dist/{envelope-DzWyIXjj.d.ts → envelope-BMBaxppV.d.ts} +200 -8
- package/dist/{http-DotQ5bj8.d.ts → http-YzLAar3w.d.ts} +15 -50
- package/dist/index.d.ts +7 -6
- package/dist/index.js +61 -28
- package/dist/index.js.map +1 -1
- package/dist/{infer-BmoZsL9a.d.ts → infer-Br62cnyW.d.ts} +39 -1
- package/dist/{metrics-DW80Exve.d.ts → metrics-CTVpw0gu.d.ts} +2 -2
- package/dist/parser.js +2 -1
- package/dist/prisma/index.d.ts +13 -6
- package/dist/prisma/index.js +155 -9
- package/dist/prisma/index.js.map +1 -1
- package/dist/remote-N7OUAGOW.js +15 -0
- package/dist/remote-N7OUAGOW.js.map +1 -0
- package/dist/server/auth/index.d.ts +3 -3
- package/dist/server/auth/index.js +5 -3
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/index.d.ts +140 -36
- package/dist/server/index.js +162 -55
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/index.d.ts +34 -18
- package/dist/server/mcp/index.js +29 -12
- package/dist/server/mcp/index.js.map +1 -1
- package/dist/server/otel.d.ts +3 -3
- package/dist/{sharing-UDLn1049.d.ts → sharing-BrsmlDv_.d.ts} +3 -3
- package/dist/testing/client.d.ts +13 -13
- package/dist/testing/client.js +17 -10
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts +49 -12
- package/dist/testing/index.js +102 -19
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock.d.ts +5 -5
- package/dist/testing/mock.js +15 -9
- package/dist/tracked-BR5b2O-U.d.ts +43 -0
- package/dist/{types-CYliTP65.d.ts → types-CLRCQGnO.d.ts} +4 -3
- package/dist/types-tMagHbjy.d.ts +151 -0
- package/dist/utils/index.d.ts +16 -4
- package/dist/utils/index.js +6 -3
- package/package.json +5 -1
- package/dist/chunk-4YO5H5ON.js.map +0 -1
- package/dist/chunk-5CGO426C.js.map +0 -1
- package/dist/chunk-6K5BY47X.js.map +0 -1
- package/dist/chunk-753VJIUP.js.map +0 -1
- package/dist/chunk-7QCUX4TK.js.map +0 -1
- package/dist/chunk-AONAFOYU.js.map +0 -1
- package/dist/chunk-B2P7AZ25.js.map +0 -1
- package/dist/chunk-GKH3LJ7N.js.map +0 -1
- package/dist/chunk-GSIPUNJL.js.map +0 -1
- package/dist/chunk-MBH6IDSM.js.map +0 -1
- package/dist/chunk-RJ5I2VO3.js.map +0 -1
- package/dist/chunk-X5CWPX7H.js.map +0 -1
- package/dist/chunk-Z2LZ7IZ7.js.map +0 -1
- /package/dist/{chunk-LCC7HNFP.js.map → chunk-RZXJTDH5.js.map} +0 -0
- /package/dist/{chunk-NMXYENH4.js.map → chunk-VZFJTKIW.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { e as StandardSchemaWithJSON, d as StandardSchemaV1, I as InferInput, c as InferOutput, X as RowSchema, Q as QueryDef, P as ProjectionList, p as MutationDef, J as AnyContract, ap as MethodName } from './infer-
|
|
2
|
-
import { d as ListSort, c as ListQuery, b as ListPage, D as AdminWritable, u as AdminListInput, v as AdminListQuery, y as AdminPage, r as AdminCreateInput, s as AdminCreateQuery, B as AdminUpdateInput, C as AdminUpdateQuery, w as AdminMetaInput, n as AdminServiceMeta, z as AdminSubscribers } from './adminSchemas-
|
|
1
|
+
import { e as StandardSchemaWithJSON, d as StandardSchemaV1, I as InferInput, c as InferOutput, X as RowSchema, Q as QueryDef, P as ProjectionList, p as MutationDef, J as AnyContract, ap as MethodName } from './infer-Br62cnyW.js';
|
|
2
|
+
import { d as ListSort, c as ListQuery, b as ListPage, D as AdminWritable, u as AdminListInput, v as AdminListQuery, y as AdminPage, r as AdminCreateInput, s as AdminCreateQuery, B as AdminUpdateInput, C as AdminUpdateQuery, w as AdminMetaInput, n as AdminServiceMeta, z as AdminSubscribers } from './adminSchemas-29cGgrg5.js';
|
|
3
3
|
|
|
4
4
|
/** A schema a kit generates: validation, and its JSON Schema. */
|
|
5
5
|
type KitSchema<Input, Output = Input> = StandardSchemaWithJSON<Input, Output>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IncomingMessage, IncomingHttpHeaders } from 'node:http';
|
|
2
2
|
import { Socket } from 'socket.io';
|
|
3
|
-
import { A as AccessLevel } from './infer-
|
|
4
|
-
import { P as Principal, M as MaybePromise } from './types-
|
|
3
|
+
import { A as AccessLevel } from './infer-Br62cnyW.js';
|
|
4
|
+
import { P as Principal, M as MaybePromise } from './types-CLRCQGnO.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A request as Express leaves it: maybe with `body` from `express.json()`,
|
|
@@ -80,11 +80,15 @@ type AuthenticateResult<P extends Principal> = P | ({
|
|
|
80
80
|
interface ServerAuth<P extends Principal = Principal> {
|
|
81
81
|
/**
|
|
82
82
|
* Says who is calling. Throwing refuses the socket connection ("Authentication
|
|
83
|
-
* failed"
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
83
|
+
* failed") or answers the HTTP call with `UNAUTHENTICATED`; returning
|
|
84
|
+
* nothing lets the caller in anonymously, so only `"public"` methods pass.
|
|
85
|
+
* Throw a `QuickdrawError("UNAUTHENTICATED", ...)` (or `"FORBIDDEN"`) for a
|
|
86
|
+
* refusal that is the caller's doing: it logs at debug, and a socket's
|
|
87
|
+
* `connect_error` data is `{ code: "UNAUTHENTICATED" }`, which signs a
|
|
88
|
+
* client out. Anything else thrown is the server's failure (its session
|
|
89
|
+
* store down, say): it logs at error, and the data is `{ code: "INTERNAL" }`,
|
|
90
|
+
* which a client retries, keeping the user, so never throw a plain `Error`
|
|
91
|
+
* for bad credentials.
|
|
88
92
|
* On an HTTP call a thrown `QuickdrawError("FORBIDDEN", ...)` is answered
|
|
89
93
|
* as it is, with 403 (logged at debug): a credential the request may not
|
|
90
94
|
* use from where it came, as `socketAuth` answers a session cookie sent
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as AccessLevel, J as AnyContract, y as CollectionWhere, O as OrderBy, k as MethodKind, d as StandardSchemaV1, ag as EventName, ah as EventPayloadOf, aB as ServerChannelName, ab as ChannelPayloadOf, aa as ChannelName, aC as ServerStreamName, az as StreamName, am as IsScopedStream, ay as StreamItemOf, ae as ContractMap, ap as MethodName, al as InputOf, ar as OutputOf } from './infer-Br62cnyW.js';
|
|
2
|
+
import { P as Principal, Q as QuickdrawTypes, M as MaybePromise, b as PrincipalOf, a as McpContext, T as Transport, C as ContextExtensionOf, c as McpContextOf, D as DbOf } from './types-CLRCQGnO.js';
|
|
2
3
|
import { L as Logger } from './logger-Yz93KzdV.js';
|
|
3
|
-
import {
|
|
4
|
-
import { P as Principal, Q as QuickdrawTypes, M as MaybePromise, c as PrincipalOf, a as McpContext, T as Transport, C as ContextExtensionOf, b as McpContextOf, D as DbOf } from './types-CYliTP65.js';
|
|
4
|
+
import { aA as Version, as as Revision } from './envelope-BMBaxppV.js';
|
|
5
5
|
|
|
6
6
|
/** What a development warning is about. */
|
|
7
7
|
type DevWarningKind = "n-plus-one" | "unbounded-read" | "oversized-response" | "nested-write" | "ambient-write" | "batch-read" | "batch-create-many" | "repeated-call" | "tiered-field-in-output" | "resolver-without-reads" | "untracked-access-model" | "shared-principal" | "channel-without-requires";
|
|
@@ -368,6 +368,14 @@ interface ServiceCollection {
|
|
|
368
368
|
readonly access: AccessLevel;
|
|
369
369
|
/** The contract of the rows scope values are ids of; `undefined` for a `"self"` scope. */
|
|
370
370
|
readonly anchor: AnyContract | undefined;
|
|
371
|
+
/**
|
|
372
|
+
* The service-wide grant on the collection's service every subscriber needs
|
|
373
|
+
* besides the anchor or self check (`requires: { service: L }`);
|
|
374
|
+
* `undefined` for none.
|
|
375
|
+
*/
|
|
376
|
+
readonly requires: {
|
|
377
|
+
readonly service: AccessLevel;
|
|
378
|
+
} | undefined;
|
|
371
379
|
/** More changed rows than this for one scope in one flush go out as one `reset`. */
|
|
372
380
|
readonly bulkThreshold: number;
|
|
373
381
|
/**
|
|
@@ -523,6 +531,8 @@ interface Service<T extends QuickdrawTypes = QuickdrawTypes, C extends AnyContra
|
|
|
523
531
|
* rooms. `undefined` when the service declares none.
|
|
524
532
|
*/
|
|
525
533
|
readonly onRoomLeave: RoomLeaveHandler | undefined;
|
|
534
|
+
/** The service's own `onHostLeave`: `createServer` runs it, beside the server's own, when a room's host leaves. */
|
|
535
|
+
readonly onHostLeave?: HostLeaveHandler | undefined;
|
|
526
536
|
/** Type-only: the app types the service was defined with. Never set. */
|
|
527
537
|
readonly "~types"?: T;
|
|
528
538
|
}
|
|
@@ -660,6 +670,21 @@ interface RowAccess {
|
|
|
660
670
|
allows(form: EntryAccess | ScopeAccess, request: AccessRequest): MaybePromise<boolean>;
|
|
661
671
|
}
|
|
662
672
|
|
|
673
|
+
/**
|
|
674
|
+
* A row whose access may have changed: who may now see more or less of it.
|
|
675
|
+
* `id` is the row (the anchor subscriptions record); without it, any row of
|
|
676
|
+
* the service. `userId` is the user whose level may have changed; without it,
|
|
677
|
+
* anyone's.
|
|
678
|
+
*/
|
|
679
|
+
interface AccessChange {
|
|
680
|
+
/** The service name. */
|
|
681
|
+
readonly service: string;
|
|
682
|
+
readonly id?: string;
|
|
683
|
+
readonly userId?: string;
|
|
684
|
+
}
|
|
685
|
+
/** Receives access changes; a promise it returns is awaited before the flush moves on. */
|
|
686
|
+
type AccessChangeListener = (change: AccessChange) => void | PromiseLike<void>;
|
|
687
|
+
|
|
663
688
|
/**
|
|
664
689
|
* Who is online and who is in a room (RFC 0003 section 12.5): `ctx.presence`,
|
|
665
690
|
* `server.presence`, `qd.presence`. Every answer is a promise: on a server
|
|
@@ -739,6 +764,19 @@ interface ServerRooms {
|
|
|
739
764
|
* it is 0.
|
|
740
765
|
*/
|
|
741
766
|
size(room: string): number;
|
|
767
|
+
/**
|
|
768
|
+
* The host of app room `room` (host mode, RFC 0003 section 12.5): the id
|
|
769
|
+
* of the socket that serves the room's host-served channels and streams,
|
|
770
|
+
* or `null` when it has none. This node's record, which every node of a
|
|
771
|
+
* cluster keeps. Room names are checked as `join` checks them.
|
|
772
|
+
*/
|
|
773
|
+
hostOf(room: string): string | null;
|
|
774
|
+
/**
|
|
775
|
+
* Leaves app room `room` without a host, on every node: its sockets hear
|
|
776
|
+
* `qd:host [room, null]`. Nothing happens for a room without one, and
|
|
777
|
+
* `onHostLeave` does not run (the host did not leave).
|
|
778
|
+
*/
|
|
779
|
+
clearHost(room: string): void;
|
|
742
780
|
}
|
|
743
781
|
/**
|
|
744
782
|
* `ctx.rooms` (RFC 0003 sections 3, 12.5 and 15): app-defined rooms the
|
|
@@ -762,6 +800,20 @@ interface ContextRooms extends ServerRooms {
|
|
|
762
800
|
join(room: string): boolean;
|
|
763
801
|
/** Takes the calling socket out of an app room; `false` when it was not in it, or the call has no socket. */
|
|
764
802
|
leave(room: string): boolean;
|
|
803
|
+
/**
|
|
804
|
+
* Makes the calling socket the host of app room `room` (host mode, RFC
|
|
805
|
+
* 0003 section 12.5): the room's sockets hear `qd:host [room, socketId]`
|
|
806
|
+
* on every node, and so does every socket that joins it later, until the
|
|
807
|
+
* host leaves the room (`onHostLeave` runs), another socket is made its
|
|
808
|
+
* host, or `clearHost` runs. Its peers then send the room's host-served
|
|
809
|
+
* channels to it and subscribe to its host-served streams over peer links.
|
|
810
|
+
* Returns `false`, doing nothing, for a call that did not arrive over a
|
|
811
|
+
* socket. The socket must be in the room (`FORBIDDEN`) and signed in
|
|
812
|
+
* (`UNAUTHENTICATED`), and the server must serve peer links
|
|
813
|
+
* (`createServer({ peers: true })`, else `INTERNAL`). Room names are
|
|
814
|
+
* checked as `join` checks them.
|
|
815
|
+
*/
|
|
816
|
+
setHost(room: string): boolean;
|
|
765
817
|
/** See {@link ServerRooms.leave}: every socket of the user, on every node, from any call. */
|
|
766
818
|
leave(room: string, target: RoomTarget): Promise<void>;
|
|
767
819
|
}
|
|
@@ -805,10 +857,31 @@ interface RoomLeave<P = Principal> {
|
|
|
805
857
|
* error it throws is logged; a server's `close()` waits for it.
|
|
806
858
|
*/
|
|
807
859
|
type RoomLeaveHandler<P = Principal> = (leave: RoomLeave<P>, ctx: RunContext) => void | PromiseLike<void>;
|
|
860
|
+
/** The host of an app room left it (host mode): what `onHostLeave` hears. */
|
|
861
|
+
interface HostLeave<P = Principal> {
|
|
862
|
+
readonly room: string;
|
|
863
|
+
/** The host socket that left. */
|
|
864
|
+
readonly socketId: string;
|
|
865
|
+
/** Its principal. */
|
|
866
|
+
readonly principal: P | null;
|
|
867
|
+
/** Its own leave, a removal, or a disconnect. */
|
|
868
|
+
readonly reason: RoomLeaveReason;
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* `onHostLeave` (a service's, beside `onRoomLeave`, and `createServer`'s):
|
|
872
|
+
* called once when the host of an app room leaves it, is taken out of it or
|
|
873
|
+
* disconnects, on the node that held it, after the room heard
|
|
874
|
+
* `qd:host [room, null]`, in a unit of work of its own. The room has no
|
|
875
|
+
* host until a method sets one again: the app decides what follows (another
|
|
876
|
+
* host, the end of the game).
|
|
877
|
+
*/
|
|
878
|
+
type HostLeaveHandler<P = Principal> = (leave: HostLeave<P>, ctx: RunContext) => void | PromiseLike<void>;
|
|
808
879
|
/** The arguments of a stream's `push`: `(scope, item)` for a scoped stream, `(item)` for a global one. */
|
|
809
880
|
type StreamPushArgs<C extends AnyContract, K extends StreamName<C>> = IsScopedStream<C, K> extends true ? [scope: string, item: StreamItemOf<C, K>] : [item: StreamItemOf<C, K>];
|
|
810
881
|
/** The arguments of a stream's `pushMany`: `(scope, items)` for a scoped stream, `(items)` for a global one. */
|
|
811
882
|
type StreamPushManyArgs<C extends AnyContract, K extends StreamName<C>> = IsScopedStream<C, K> extends true ? [scope: string, items: readonly StreamItemOf<C, K>[]] : [items: readonly StreamItemOf<C, K>[]];
|
|
883
|
+
/** The arguments of a stream's `subscribers`: `(scope)` for a scoped stream, `()` for a global one. */
|
|
884
|
+
type StreamSubscribersArgs<C extends AnyContract, K extends StreamName<C>> = IsScopedStream<C, K> extends true ? [scope: string] : [];
|
|
812
885
|
/** What `qd.stream(contract, name)` returns. */
|
|
813
886
|
interface StreamHandle<C extends AnyContract, K extends StreamName<C>> {
|
|
814
887
|
/**
|
|
@@ -825,6 +898,19 @@ interface StreamHandle<C extends AnyContract, K extends StreamName<C>> {
|
|
|
825
898
|
* with nothing kept or sent. The batch form of a `push` in a loop.
|
|
826
899
|
*/
|
|
827
900
|
pushMany(...args: StreamPushManyArgs<C, K>): void;
|
|
901
|
+
/**
|
|
902
|
+
* How many sockets subscribe to the feed (`subscribers(scope)`, or
|
|
903
|
+
* `subscribers()` for a global stream), on every node, anonymous ones
|
|
904
|
+
* included: a job skips the work nobody watches. These are the sockets in
|
|
905
|
+
* the feed's room, the ones a push reaches: a subscribe counts from when it
|
|
906
|
+
* joins the feed, once it is authorized. Behind a cluster adapter the
|
|
907
|
+
* other nodes answer one request with a count each: an answer that does
|
|
908
|
+
* not arrive within `cluster.timeoutMs` counts as 0, and so does a node
|
|
909
|
+
* of an earlier version, which does not know the request. A host-served stream (`serve: "host"`) has no feed on
|
|
910
|
+
* the server, so, as for `push`, its handle refuses this with a
|
|
911
|
+
* `TypeError`: only the host's client knows who subscribes.
|
|
912
|
+
*/
|
|
913
|
+
subscribers(...args: StreamSubscribersArgs<C, K>): Promise<number>;
|
|
828
914
|
}
|
|
829
915
|
/**
|
|
830
916
|
* What a stream's `seed` function receives besides the scope: who is
|
|
@@ -886,7 +972,7 @@ type StreamValidation = "always" | "development";
|
|
|
886
972
|
* subset): a seed computed at subscribe time, and when items are checked.
|
|
887
973
|
*/
|
|
888
974
|
type StreamOptions<T extends QuickdrawTypes, C extends AnyContract> = {
|
|
889
|
-
readonly [K in
|
|
975
|
+
readonly [K in ServerStreamName<C>]?: StreamImplementation<T, C, K>;
|
|
890
976
|
};
|
|
891
977
|
/** A stream's `seed` function as the subscribe path calls it, whatever its declared types. */
|
|
892
978
|
type AnyStreamSeed = (scope: string | undefined, ctx: StreamSeedContext) => unknown;
|
|
@@ -936,12 +1022,15 @@ type ChannelRoomOf<C extends AnyContract, K extends ChannelName<C>> = C["channel
|
|
|
936
1022
|
readonly room: string | object;
|
|
937
1023
|
};
|
|
938
1024
|
} ? string : undefined;
|
|
939
|
-
/**
|
|
1025
|
+
/**
|
|
1026
|
+
* `defineService`'s `channels`: one implementation per channel of the
|
|
1027
|
+
* contract the server handles (a host-served one takes none).
|
|
1028
|
+
*/
|
|
940
1029
|
type ChannelOptions<T extends QuickdrawTypes, C extends AnyContract> = {
|
|
941
|
-
readonly [K in
|
|
1030
|
+
readonly [K in ServerChannelName<C>]: ChannelImplementation<T, ChannelPayloadOf<C, K>, ChannelRoomOf<C, K>>;
|
|
942
1031
|
};
|
|
943
1032
|
/** `{ channels }` is required when the contract declares channels: every message needs a handler. */
|
|
944
|
-
type ChannelsRequired<C extends AnyContract> = [
|
|
1033
|
+
type ChannelsRequired<C extends AnyContract> = [ServerChannelName<C>] extends [never] ? unknown : {
|
|
945
1034
|
readonly channels: unknown;
|
|
946
1035
|
};
|
|
947
1036
|
/**
|
|
@@ -1032,6 +1121,8 @@ interface ServiceStream {
|
|
|
1032
1121
|
readonly access: AccessForm | undefined;
|
|
1033
1122
|
/** The contract's `access: { room }`: the app room a subscriber's socket must be in. */
|
|
1034
1123
|
readonly room: StreamRoomAccess | undefined;
|
|
1124
|
+
/** True for a stream the room's host pushes (`serve: "host"`): the server neither pushes nor subscribes it. */
|
|
1125
|
+
readonly host: boolean;
|
|
1035
1126
|
}
|
|
1036
1127
|
/** A stream's `access: { room }`, compiled: the app room a subscriber's socket must be in. */
|
|
1037
1128
|
type StreamRoomAccess = {
|
|
@@ -1054,10 +1145,10 @@ interface TouchOptions {
|
|
|
1054
1145
|
* `ctx.services`: in-process callers for the app's services (RFC 0003
|
|
1055
1146
|
* sections 3 and 10), by service name: `ctx.services.projectService.get(input)`.
|
|
1056
1147
|
* A call runs the whole pipeline (input check, access, handler, output
|
|
1057
|
-
* check) as the calling principal with transport `"internal"
|
|
1058
|
-
*
|
|
1059
|
-
* cancelled with `ctx.signal`. Typed by
|
|
1060
|
-
* like `qd.caller`; untyped without them.
|
|
1148
|
+
* check) as the calling principal with transport `"internal"` and the
|
|
1149
|
+
* calling method's `ctx.mcp`, its writes join the calling method's unit of
|
|
1150
|
+
* work (one flush for both), and it is cancelled with `ctx.signal`. Typed by
|
|
1151
|
+
* the `contracts` of the app's types, like `qd.caller`; untyped without them.
|
|
1061
1152
|
*/
|
|
1062
1153
|
type ContextServices<T extends QuickdrawTypes = QuickdrawTypes> = CallerFor<T>;
|
|
1063
1154
|
|
|
@@ -1094,7 +1185,10 @@ interface BaseContext<P = Principal, M = McpContext> {
|
|
|
1094
1185
|
/**
|
|
1095
1186
|
* The fields the MCP bridge's `context` option produced for this call, such
|
|
1096
1187
|
* as the scopes of the agent's token; typed by `QuickdrawTypes["mcp"]`.
|
|
1097
|
-
* `undefined` unless the call arrived over MCP
|
|
1188
|
+
* `undefined` unless the call arrived over MCP or was made through the
|
|
1189
|
+
* `ctx.services` of a call that has it (nested calls too), which passes
|
|
1190
|
+
* the same object on. Such a call's `transport` is `"internal"`: to tell a
|
|
1191
|
+
* token's call apart, read `ctx.mcp`, not `ctx.transport`.
|
|
1098
1192
|
*/
|
|
1099
1193
|
readonly mcp?: M;
|
|
1100
1194
|
/**
|
|
@@ -1106,10 +1200,20 @@ interface BaseContext<P = Principal, M = McpContext> {
|
|
|
1106
1200
|
*/
|
|
1107
1201
|
touch(target: string | AnyContract, ids: string | readonly string[], options?: TouchOptions): void;
|
|
1108
1202
|
/**
|
|
1109
|
-
* In-process callers for the app's services, as this call's principal
|
|
1110
|
-
* `await ctx.services.projectService.get({ id })`. See
|
|
1203
|
+
* In-process callers for the app's services, as this call's principal and
|
|
1204
|
+
* with its `ctx.mcp`: `await ctx.services.projectService.get({ id })`. See
|
|
1205
|
+
* {@link ContextServices}.
|
|
1111
1206
|
*/
|
|
1112
1207
|
readonly services: ContextServices;
|
|
1208
|
+
/**
|
|
1209
|
+
* The caller's levels on rows of the app's services, as the access forms
|
|
1210
|
+
* count them (RFC 0003 section 4.3): `dispatcher.access` bound to
|
|
1211
|
+
* `ctx.principal`, with the grants this call runs with. For a `custom`
|
|
1212
|
+
* form that checks a row its key names only sometimes, or a parent its
|
|
1213
|
+
* input names: `await ctx.access.can(project, input.projectId, "Moderate")`.
|
|
1214
|
+
* See {@link ContextAccess}.
|
|
1215
|
+
*/
|
|
1216
|
+
readonly access: ContextAccess;
|
|
1113
1217
|
/**
|
|
1114
1218
|
* App-defined rooms the calling socket joins and leaves (`join` answers
|
|
1115
1219
|
* `false` for a call without a socket), and typed room events: `emit` and
|
|
@@ -1317,6 +1421,70 @@ interface FlushSink {
|
|
|
1317
1421
|
onFlushError?(writes: readonly WriteRecord[], info: FlushInfo, error: unknown): void | Promise<void>;
|
|
1318
1422
|
}
|
|
1319
1423
|
|
|
1424
|
+
/** The dispatcher's view of its services' access policies: `dispatcher.access`. */
|
|
1425
|
+
interface DispatcherAccess {
|
|
1426
|
+
/**
|
|
1427
|
+
* The principal's level on each of `ids` of `service`, as an `{ entry }`
|
|
1428
|
+
* check counts it: the service's policy, or `Admin` on every row when the
|
|
1429
|
+
* principal holds a service-wide `Admin` grant and the service keeps
|
|
1430
|
+
* `adminBypass` on. A grant below `Admin` does not count. A row that is
|
|
1431
|
+
* not found has no level. One batched lookup per policy.
|
|
1432
|
+
*/
|
|
1433
|
+
levelsFor(service: AnyContract | string, principal: Principal, ids: readonly string[]): Promise<RowLevels>;
|
|
1434
|
+
/**
|
|
1435
|
+
* A filter for `db.<model>.findMany({ where })` matching exactly the rows of
|
|
1436
|
+
* `service` on which `levelsFor` gives the principal at least `level`:
|
|
1437
|
+
* `{}` (every row) for a service-wide `Admin` with `adminBypass`, or
|
|
1438
|
+
* `"none"` when no row matches.
|
|
1439
|
+
*/
|
|
1440
|
+
accessWhere(service: AnyContract | string, principal: Principal, level: AccessLevel): Promise<AccessFilter>;
|
|
1441
|
+
/**
|
|
1442
|
+
* Calls `listener` after each flush whose tracked writes may have changed
|
|
1443
|
+
* someone's access to a row (`AccessChange`), once the cache no longer
|
|
1444
|
+
* holds what they changed. A promise it returns is awaited before the
|
|
1445
|
+
* dispatcher's other flush sinks run. Returns a function that removes it.
|
|
1446
|
+
*/
|
|
1447
|
+
onAccessChanged(listener: AccessChangeListener): () => void;
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* `ctx.access` (RFC 0003 section 4.3): `dispatcher.access` bound to the
|
|
1451
|
+
* call's caller, `ctx.principal`, with the grants that call runs with (its
|
|
1452
|
+
* socket's, or those `qd.caller` loaded). For a `custom(...)` form or a
|
|
1453
|
+
* handler that asks about a row its method's own form does not name: a
|
|
1454
|
+
* payment's loan, a parent named by an optional key. `service` is a
|
|
1455
|
+
* contract or a service name with an access policy on the dispatcher;
|
|
1456
|
+
* another is a `TypeError`. An anonymous caller (a `"public"` method called
|
|
1457
|
+
* without credentials) has no level on any row.
|
|
1458
|
+
*
|
|
1459
|
+
* @example
|
|
1460
|
+
* access: custom(async (ctx, input) => await ctx.access.can(loan, input.loanId, "Moderate")),
|
|
1461
|
+
*/
|
|
1462
|
+
interface ContextAccess {
|
|
1463
|
+
/**
|
|
1464
|
+
* The caller's level on each of `ids` of `service`, as an `{ entry }`
|
|
1465
|
+
* check counts it (`dispatcher.access.levelsFor` with `ctx.principal`): a
|
|
1466
|
+
* service-wide `Admin` grant gives `Admin` on every id while the service
|
|
1467
|
+
* keeps `adminBypass` on, and a row that is not found has no level. One
|
|
1468
|
+
* batched lookup per policy. An empty map for an anonymous caller.
|
|
1469
|
+
*/
|
|
1470
|
+
levelsFor(service: AnyContract | string, ids: readonly string[]): Promise<RowLevels>;
|
|
1471
|
+
/**
|
|
1472
|
+
* Whether the caller's level on row `id` of `service` is at least `level`,
|
|
1473
|
+
* as `{ entry: level }` decides it on that row: `false` for a row that is
|
|
1474
|
+
* not found (but for a service-wide `Admin` grant, which reaches every id
|
|
1475
|
+
* without reading it, as for `{ entry }`) and for an anonymous caller.
|
|
1476
|
+
*/
|
|
1477
|
+
can(service: AnyContract | string, id: string, level: AccessLevel): Promise<boolean>;
|
|
1478
|
+
/**
|
|
1479
|
+
* A filter for `db.<model>.findMany({ where })` matching exactly the rows
|
|
1480
|
+
* of `service` on which `can` gives the caller `level`, for a hand-written
|
|
1481
|
+
* list (`dispatcher.access.accessWhere` with `ctx.principal`): `{}` for a
|
|
1482
|
+
* service-wide `Admin` with `adminBypass`, `"none"` when no row matches
|
|
1483
|
+
* and for an anonymous caller.
|
|
1484
|
+
*/
|
|
1485
|
+
where(service: AnyContract | string, level: AccessLevel): Promise<AccessFilter>;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1320
1488
|
/** Options of one in-process call. */
|
|
1321
1489
|
interface CallOptions {
|
|
1322
1490
|
/** Cancels the call (queries only), like a client's `qd:cancel`. */
|
|
@@ -1343,4 +1511,4 @@ type CallerFor<T extends QuickdrawTypes> = T extends {
|
|
|
1343
1511
|
readonly contracts: infer Contracts extends ContractMap;
|
|
1344
1512
|
} ? Caller<Contracts[keyof Contracts]> : Caller<AnyContract>;
|
|
1345
1513
|
|
|
1346
|
-
export { type
|
|
1514
|
+
export { type AffectsLink as $, type AnyService as A, type PublicAccess as B, type CountArgs as C, DevWarningError as D, type HandlerArgs as E, type FindManyArgs as F, type CustomAccess as G, type HostLeaveHandler as H, type ShareMode as I, type ChannelOptions as J, type StreamOptions as K, type ChannelsRequired as L, type ModelName as M, type BaseContext as N, type CallerFor as O, type Presence as P, type AccessPolicy as Q, type RunContext as R, type StorageAdapter as S, type AnyAccessPolicy as T, type UnitOfWorkFactory as U, type PolicyColumns as V, type WriteRecord as W, type PolicyForeign as X, type PolicyTools as Y, type AccessFilter as Z, type RowAccess as _, type StorageRow as a, type ProjectedOutput as a0, type Projection as a1, type TierGroup as a2, type Tiers as a3, DEFAULT_BULK_THRESHOLD as a4, type CollectionScope as a5, type ServiceCollection as a6, type ContextAccess as a7, type ContextRooms as a8, type ContextServices as a9, type ParentLink as aA, type PolicyKind as aB, type PolicyReads as aC, type RowLevel as aD, type RowLevels as aE, type AccessChange as aF, type AccessChangeListener as aG, type AccessForm as aH, type AccessRequest as aI, type AuthenticatedAccess as aJ, type EntryAccess as aK, type IdKeyOf as aL, type IdSelector as aM, type ScopeAccess as aN, type ServiceAccess as aO, ANY_FIELD as aP, type UnitOfWork as aQ, type UnitOfWorkScope as aR, type LinkInterest as aS, formatDevWarning as aT, N_PLUS_ONE_STATEMENTS as aU, type TouchOptions as aa, type ChannelAccess as ab, type ChannelContext as ac, type ChannelHandler as ad, type ChannelImplementation as ae, type ChannelRoomOf as af, type HostLeave as ag, type RoomLeave as ah, type RoomLeaveReason as ai, type RoomLeft as aj, type RoomTarget as ak, type ServiceChannel as al, type ServiceStream as am, type StreamImplementation as an, type StreamPushArgs as ao, type StreamPushManyArgs as ap, type StreamSeed as aq, type StreamSeedContext as ar, type StreamSubscribersArgs as as, type StreamValidation as at, type CallOptions as au, type MethodCaller as av, type ServiceCaller as aw, type ForeignColumns as ax, type ForeignColumnsOf as ay, type MembershipRead as az, type StorageWhere as b, type StatementCount as c, type Caller as d, type FlushSink as e, type FlushInfo as f, type ServiceMethod as g, type Service as h, type DevWarning as i, type DevWarningKind as j, type RunOptions as k, type DispatcherAccess as l, type ServerRooms as m, type StreamHandle as n, type AnyContext as o, type AccessEngine as p, type AppRooms as q, type StreamSubscriptions as r, storageOf as s, type RoomLeaveHandler as t, type PolicyFor as u, type RowForms as v, type AccessFor as w, type HandlerContext as x, type ModelColumn as y, type WatchAccess as z };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_PEER_CANDIDATE_LENGTH,
|
|
3
|
+
MAX_PEER_SIGNAL_LENGTH,
|
|
4
|
+
MAX_SCOPE_LENGTH
|
|
5
|
+
} from "./chunk-X4ZU4QH5.js";
|
|
6
|
+
import {
|
|
7
|
+
isRecord
|
|
8
|
+
} from "./chunk-QSU47XEX.js";
|
|
9
|
+
|
|
10
|
+
// src/protocol/peer.ts
|
|
11
|
+
var MAX_SOCKET_ID_LENGTH = 64;
|
|
12
|
+
function isText(value) {
|
|
13
|
+
return typeof value === "string" && value.length <= MAX_PEER_SIGNAL_LENGTH;
|
|
14
|
+
}
|
|
15
|
+
function isCandidateText(value) {
|
|
16
|
+
return typeof value === "string" && value.length <= MAX_PEER_CANDIDATE_LENGTH;
|
|
17
|
+
}
|
|
18
|
+
function isRoomName(value) {
|
|
19
|
+
return typeof value === "string" && value !== "" && value.length <= MAX_SCOPE_LENGTH;
|
|
20
|
+
}
|
|
21
|
+
function isSocketId(value) {
|
|
22
|
+
return typeof value === "string" && value !== "" && value.length <= MAX_SOCKET_ID_LENGTH;
|
|
23
|
+
}
|
|
24
|
+
function isPeerLabel(value) {
|
|
25
|
+
return value === "rel" || value === "fast";
|
|
26
|
+
}
|
|
27
|
+
function nullable(value, check) {
|
|
28
|
+
return value === void 0 || value === null || check(value);
|
|
29
|
+
}
|
|
30
|
+
function isLineIndex(value) {
|
|
31
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
32
|
+
}
|
|
33
|
+
function readDescription(value) {
|
|
34
|
+
if (!isRecord(value) || value.type !== "offer" && value.type !== "answer") {
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
return isText(value.sdp) ? { type: value.type, sdp: value.sdp } : void 0;
|
|
38
|
+
}
|
|
39
|
+
function readCandidate(value) {
|
|
40
|
+
if (!isRecord(value) || !isCandidateText(value.candidate)) {
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
const { sdpMid, sdpMLineIndex, usernameFragment } = value;
|
|
44
|
+
if (!nullable(sdpMid, isCandidateText) || !nullable(sdpMLineIndex, isLineIndex) || !nullable(usernameFragment, isCandidateText)) {
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
candidate: value.candidate,
|
|
49
|
+
...sdpMid === void 0 ? {} : { sdpMid },
|
|
50
|
+
...sdpMLineIndex === void 0 ? {} : { sdpMLineIndex },
|
|
51
|
+
...usernameFragment === void 0 ? {} : { usernameFragment }
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function readSignal(value) {
|
|
55
|
+
if (!isRecord(value)) {
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
const { sdp, ice, relay, bye } = value;
|
|
59
|
+
if ([sdp, ice, relay, bye].filter((member) => member !== void 0).length !== 1) {
|
|
60
|
+
return void 0;
|
|
61
|
+
}
|
|
62
|
+
if (sdp !== void 0) {
|
|
63
|
+
const description = readDescription(sdp);
|
|
64
|
+
return description === void 0 ? void 0 : { sdp: description };
|
|
65
|
+
}
|
|
66
|
+
if (ice !== void 0) {
|
|
67
|
+
const candidate = readCandidate(ice);
|
|
68
|
+
return candidate === void 0 ? void 0 : { ice: candidate };
|
|
69
|
+
}
|
|
70
|
+
if (relay === true) {
|
|
71
|
+
return { relay: true };
|
|
72
|
+
}
|
|
73
|
+
return bye === true ? { bye: true } : void 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
isRoomName,
|
|
78
|
+
isSocketId,
|
|
79
|
+
isPeerLabel,
|
|
80
|
+
readSignal
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=chunk-2FDSKLBO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/protocol/peer.ts"],"sourcesContent":["// Reading peer link signals (RFC 0003 section 12.5), for the server that\n// forwards them and the client that applies them. A signal is copied member\n// by member, so what goes on is only what was read: a session description\n// of at most `MAX_PEER_SIGNAL_LENGTH` characters, an ICE candidate whose\n// strings hold at most `MAX_PEER_CANDIDATE_LENGTH`, `relay` or `bye`.\n// Internal: neither the package root nor `./client` exports these.\n\nimport type { PeerCandidate, PeerDescription, PeerLabel, PeerSignal } from \"./envelope\";\nimport { isRecord } from \"./guards\";\nimport { MAX_PEER_CANDIDATE_LENGTH, MAX_PEER_SIGNAL_LENGTH, MAX_SCOPE_LENGTH } from \"./version\";\n\n/** The longest socket id a peer frame may name. Socket.IO's are 20 characters. */\nexport const MAX_SOCKET_ID_LENGTH = 64;\n\n/** True for a string of at most `MAX_PEER_SIGNAL_LENGTH` characters, empty included. */\nfunction isText(value: unknown): value is string {\n return typeof value === \"string\" && value.length <= MAX_PEER_SIGNAL_LENGTH;\n}\n\n/** True for a string of at most `MAX_PEER_CANDIDATE_LENGTH` characters, empty included. */\nfunction isCandidateText(value: unknown): value is string {\n return typeof value === \"string\" && value.length <= MAX_PEER_CANDIDATE_LENGTH;\n}\n\n/** True for what may name an app room: 1 to `MAX_SCOPE_LENGTH` characters. */\nexport function isRoomName(value: unknown): value is string {\n return typeof value === \"string\" && value !== \"\" && value.length <= MAX_SCOPE_LENGTH;\n}\n\n/** True for what may name a socket: 1 to `MAX_SOCKET_ID_LENGTH` characters. */\nexport function isSocketId(value: unknown): value is string {\n return typeof value === \"string\" && value !== \"\" && value.length <= MAX_SOCKET_ID_LENGTH;\n}\n\n/** True for `rel` and `fast`. */\nexport function isPeerLabel(value: unknown): value is PeerLabel {\n return value === \"rel\" || value === \"fast\";\n}\n\n/** True when `value` is absent, `null`, or passes `check`. */\nfunction nullable(value: unknown, check: (inner: unknown) => boolean): boolean {\n return value === undefined || value === null || check(value);\n}\n\nfunction isLineIndex(value: unknown): boolean {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction readDescription(value: unknown): PeerDescription | undefined {\n if (!isRecord(value) || (value.type !== \"offer\" && value.type !== \"answer\")) {\n return undefined;\n }\n return isText(value.sdp) ? { type: value.type, sdp: value.sdp } : undefined;\n}\n\nfunction readCandidate(value: unknown): PeerCandidate | undefined {\n if (!isRecord(value) || !isCandidateText(value.candidate)) {\n return undefined;\n }\n const { sdpMid, sdpMLineIndex, usernameFragment } = value;\n if (\n !nullable(sdpMid, isCandidateText) ||\n !nullable(sdpMLineIndex, isLineIndex) ||\n !nullable(usernameFragment, isCandidateText)\n ) {\n return undefined;\n }\n return {\n candidate: value.candidate,\n ...(sdpMid === undefined ? {} : { sdpMid: sdpMid as string | null }),\n ...(sdpMLineIndex === undefined ? {} : { sdpMLineIndex: sdpMLineIndex as number | null }),\n ...(usernameFragment === undefined\n ? {}\n : { usernameFragment: usernameFragment as string | null }),\n };\n}\n\n/**\n * The signal `value` holds, copied, or `undefined` unless it holds exactly\n * one of `sdp`, `ice`, `relay: true` and `bye: true`, well formed. Fields\n * it does not know are left behind.\n */\nexport function readSignal(value: unknown): PeerSignal | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n const { sdp, ice, relay, bye } = value;\n if ([sdp, ice, relay, bye].filter((member) => member !== undefined).length !== 1) {\n return undefined;\n }\n if (sdp !== undefined) {\n const description = readDescription(sdp);\n return description === undefined ? undefined : { sdp: description };\n }\n if (ice !== undefined) {\n const candidate = readCandidate(ice);\n return candidate === undefined ? undefined : { ice: candidate };\n }\n if (relay === true) {\n return { relay: true };\n }\n return bye === true ? { bye: true } : undefined;\n}\n"],"mappings":";;;;;;;;;;AAYO,IAAM,uBAAuB;AAGpC,SAAS,OAAO,OAAiC;AAC/C,SAAO,OAAO,UAAU,YAAY,MAAM,UAAU;AACtD;AAGA,SAAS,gBAAgB,OAAiC;AACxD,SAAO,OAAO,UAAU,YAAY,MAAM,UAAU;AACtD;AAGO,SAAS,WAAW,OAAiC;AAC1D,SAAO,OAAO,UAAU,YAAY,UAAU,MAAM,MAAM,UAAU;AACtE;AAGO,SAAS,WAAW,OAAiC;AAC1D,SAAO,OAAO,UAAU,YAAY,UAAU,MAAM,MAAM,UAAU;AACtE;AAGO,SAAS,YAAY,OAAoC;AAC9D,SAAO,UAAU,SAAS,UAAU;AACtC;AAGA,SAAS,SAAS,OAAgB,OAA6C;AAC7E,SAAO,UAAU,UAAa,UAAU,QAAQ,MAAM,KAAK;AAC7D;AAEA,SAAS,YAAY,OAAyB;AAC5C,SAAO,OAAO,UAAU,YAAY,OAAO,cAAc,KAAK,KAAK,SAAS;AAC9E;AAEA,SAAS,gBAAgB,OAA6C;AACpE,MAAI,CAAC,SAAS,KAAK,KAAM,MAAM,SAAS,WAAW,MAAM,SAAS,UAAW;AAC3E,WAAO;AAAA,EACT;AACA,SAAO,OAAO,MAAM,GAAG,IAAI,EAAE,MAAM,MAAM,MAAM,KAAK,MAAM,IAAI,IAAI;AACpE;AAEA,SAAS,cAAc,OAA2C;AAChE,MAAI,CAAC,SAAS,KAAK,KAAK,CAAC,gBAAgB,MAAM,SAAS,GAAG;AACzD,WAAO;AAAA,EACT;AACA,QAAM,EAAE,QAAQ,eAAe,iBAAiB,IAAI;AACpD,MACE,CAAC,SAAS,QAAQ,eAAe,KACjC,CAAC,SAAS,eAAe,WAAW,KACpC,CAAC,SAAS,kBAAkB,eAAe,GAC3C;AACA,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAgC;AAAA,IAClE,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,cAA8C;AAAA,IACvF,GAAI,qBAAqB,SACrB,CAAC,IACD,EAAE,iBAAoD;AAAA,EAC5D;AACF;AAOO,SAAS,WAAW,OAAwC;AACjE,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO;AAAA,EACT;AACA,QAAM,EAAE,KAAK,KAAK,OAAO,IAAI,IAAI;AACjC,MAAI,CAAC,KAAK,KAAK,OAAO,GAAG,EAAE,OAAO,CAAC,WAAW,WAAW,MAAS,EAAE,WAAW,GAAG;AAChF,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,QAAW;AACrB,UAAM,cAAc,gBAAgB,GAAG;AACvC,WAAO,gBAAgB,SAAY,SAAY,EAAE,KAAK,YAAY;AAAA,EACpE;AACA,MAAI,QAAQ,QAAW;AACrB,UAAM,YAAY,cAAc,GAAG;AACnC,WAAO,cAAc,SAAY,SAAY,EAAE,KAAK,UAAU;AAAA,EAChE;AACA,MAAI,UAAU,MAAM;AAClB,WAAO,EAAE,OAAO,KAAK;AAAA,EACvB;AACA,SAAO,QAAQ,OAAO,EAAE,KAAK,KAAK,IAAI;AACxC;","names":[]}
|