@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
package/dist/testing/mock.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { A as AccessLevel, ae as ContractMap, J as AnyContract, ap as MethodName, al as InputOf, ar as OutputOf, af as EntityOf, ac as CollectionName, aw as ScopeOf, an as ItemOf, az as StreamName, am as IsScopedStream, ay as StreamItemOf, aa as ChannelName, a9 as ChannelInputOf, ag as EventName, ah as EventPayloadOf } from '../infer-
|
|
1
|
+
import { A as AccessLevel, ae as ContractMap, J as AnyContract, ap as MethodName, al as InputOf, ar as OutputOf, af as EntityOf, ac as CollectionName, aw as ScopeOf, an as ItemOf, az as StreamName, am as IsScopedStream, ay as StreamItemOf, aa as ChannelName, a9 as ChannelInputOf, ag as EventName, ah as EventPayloadOf } from '../infer-Br62cnyW.js';
|
|
2
2
|
import { QueryClient } from '@tanstack/react-query';
|
|
3
3
|
import { ReactNode, ReactElement } from 'react';
|
|
4
|
-
import { i as MethodMember, E as EntityMembers, C as CollectionMember, y as StreamMember, u as ChannelMember, v as EventMember, n as QuickdrawInvalidate } from '../clientTypes-
|
|
5
|
-
import { H as AdminMethodsOf } from '../admin-
|
|
4
|
+
import { i as MethodMember, E as EntityMembers, C as CollectionMember, y as StreamMember, u as ChannelMember, v as EventMember, n as QuickdrawInvalidate } from '../clientTypes-CUUNJwWs.js';
|
|
5
|
+
import { H as AdminMethodsOf } from '../admin-CS7JB_UH.js';
|
|
6
6
|
import { Q as QuickdrawError } from '../errors-S-bxEIBC.js';
|
|
7
7
|
import '../keys-CqKkljVN.js';
|
|
8
|
-
import '../adminSchemas-
|
|
9
|
-
import '../envelope-
|
|
8
|
+
import '../adminSchemas-29cGgrg5.js';
|
|
9
|
+
import '../envelope-BMBaxppV.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* How a mocked method answers. Until one of the `mock*` setters runs, every
|
package/dist/testing/mock.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMockClient
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-753VJIUP.js";
|
|
7
|
-
import "../chunk-5CGO426C.js";
|
|
3
|
+
} from "../chunk-I3JCFS7H.js";
|
|
4
|
+
import "../chunk-64I6MYBC.js";
|
|
5
|
+
import "../chunk-XD7SRDUY.js";
|
|
8
6
|
import "../chunk-4D2DOGAW.js";
|
|
9
7
|
import "../chunk-AK23XSWD.js";
|
|
10
|
-
import "../chunk-47AEXVDM.js";
|
|
11
|
-
import "../chunk-Z2LZ7IZ7.js";
|
|
12
8
|
import "../chunk-DKE6QO26.js";
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
9
|
+
import "../chunk-STH5DLQP.js";
|
|
10
|
+
import "../chunk-IIQ3WMJK.js";
|
|
11
|
+
import "../chunk-2FDSKLBO.js";
|
|
12
|
+
import "../chunk-MPQAT55F.js";
|
|
13
|
+
import "../chunk-A2RBQD66.js";
|
|
14
|
+
import "../chunk-X4ZU4QH5.js";
|
|
15
|
+
import "../chunk-GYLWEJHW.js";
|
|
16
|
+
import "../chunk-47AEXVDM.js";
|
|
17
|
+
import "../chunk-SN3OZVEQ.js";
|
|
18
|
+
import "../chunk-7Y5ROPXL.js";
|
|
19
|
+
import "../chunk-Q4OGQM5I.js";
|
|
20
|
+
import "../chunk-QSU47XEX.js";
|
|
15
21
|
export {
|
|
16
22
|
createMockClient
|
|
17
23
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
declare const TRACKED: unique symbol;
|
|
2
|
+
/** What marks a client as tracked: a type only, with no property at run time. */
|
|
3
|
+
interface TrackedMark {
|
|
4
|
+
readonly [TRACKED]: true;
|
|
5
|
+
}
|
|
6
|
+
/** The client an interactive `$transaction` of `C` passes its callback, or `C` itself when it has none. */
|
|
7
|
+
type TransactionClientOf<C> = C extends {
|
|
8
|
+
$transaction(fn: (tx: infer Tx) => unknown, options?: unknown): unknown;
|
|
9
|
+
} ? Tx : C;
|
|
10
|
+
/** The interactive `$transaction` of a tracked `C`: its callback gets the tracked transaction client. */
|
|
11
|
+
interface TrackedInteractiveTransaction<C, Options> {
|
|
12
|
+
$transaction<R>(fn: (tx: TrackedTransaction<C>) => Promise<R>, options?: Options): Promise<R>;
|
|
13
|
+
}
|
|
14
|
+
/** `$transaction` declared again, with Prisma's options, for a `C` that has an interactive one; nothing for one that has none. */
|
|
15
|
+
type TrackedTransactions<C> = C extends {
|
|
16
|
+
$transaction(fn: (tx: infer _Tx) => unknown, options?: infer Options): unknown;
|
|
17
|
+
} ? TrackedInteractiveTransaction<C, Options> : unknown;
|
|
18
|
+
/**
|
|
19
|
+
* A database client whose writes the framework sees: what `trackPrisma`
|
|
20
|
+
* returns. It is still a `C` everywhere a `C` is asked for, but a plain `C`
|
|
21
|
+
* is not a `Tracked<C>`, so a helper that writes takes `db: Tracked<Db>`
|
|
22
|
+
* and the untracked client passed to it is a type error. Its interactive
|
|
23
|
+
* `$transaction` passes a {@link TrackedTransaction}; the array form is
|
|
24
|
+
* Prisma's own.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* export const db = trackPrisma(new PrismaClient({ adapter })); // Tracked<PrismaClient>
|
|
28
|
+
* export async function archive(client: Tracked<PrismaClient>, id: string): Promise<void> {
|
|
29
|
+
* await client.project.update({ where: { id }, data: { archived: true } });
|
|
30
|
+
* }
|
|
31
|
+
* await qd.run(() => archive(db, projectId)); // archive(prisma, projectId) is a type error
|
|
32
|
+
*/
|
|
33
|
+
type Tracked<C> = TrackedMark & TrackedTransactions<C> & C;
|
|
34
|
+
/**
|
|
35
|
+
* The client an interactive `db.$transaction(async (tx) => ...)` of a
|
|
36
|
+
* tracked `db` passes as `tx`, tracked too: Prisma's transaction client of
|
|
37
|
+
* `C`. `C` is the client, tracked or not; a transaction client stays itself.
|
|
38
|
+
* A helper that writes inside or outside a transaction takes
|
|
39
|
+
* `TrackedTransaction<Db>`, which both `db` and `tx` are.
|
|
40
|
+
*/
|
|
41
|
+
type TrackedTransaction<C> = Tracked<TransactionClientOf<C>>;
|
|
42
|
+
|
|
43
|
+
export type { Tracked as T, TrackedTransaction as a };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AccessLevel, ae as ContractMap } from './infer-
|
|
1
|
+
import { A as AccessLevel, ae as ContractMap } from './infer-Br62cnyW.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Who is calling. A transport authenticates the connection or request and
|
|
@@ -28,7 +28,8 @@ interface Principal {
|
|
|
28
28
|
* - `context`: the fields `initQuickdraw({ context })` adds to every handler's `ctx`.
|
|
29
29
|
* - `contracts`: the app's contracts (`{ task, project }`), which type `qd.caller`.
|
|
30
30
|
* - `mcp`: the fields the MCP bridge's `context` option gives calls that
|
|
31
|
-
* arrive over MCP,
|
|
31
|
+
* arrive over MCP, and the calls they make through `ctx.services`, which
|
|
32
|
+
* handlers read as `ctx.mcp` (token scopes, for example).
|
|
32
33
|
*
|
|
33
34
|
* @example
|
|
34
35
|
* export const qd = initQuickdraw<{ db: AppPrisma; principal: AppPrincipal }>();
|
|
@@ -69,4 +70,4 @@ type Transport = "socket" | "http" | "mcp" | "internal" | "legacy";
|
|
|
69
70
|
/** A value, or a promise of it. */
|
|
70
71
|
type MaybePromise<T> = T | PromiseLike<T>;
|
|
71
72
|
|
|
72
|
-
export type { ContextExtensionOf as C, DbOf as D, MaybePromise as M, Principal as P, QuickdrawTypes as Q, Transport as T, McpContext as a,
|
|
73
|
+
export type { ContextExtensionOf as C, DbOf as D, MaybePromise as M, Principal as P, QuickdrawTypes as Q, Transport as T, McpContext as a, PrincipalOf as b, McpContextOf as c, PrincipalKindOf as d };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { ab as PeerLabel } from './envelope-BMBaxppV.js';
|
|
2
|
+
|
|
3
|
+
/** A peer's clock, as a link estimates it. */
|
|
4
|
+
interface PeerClock {
|
|
5
|
+
/** The peer's clock now, in milliseconds: this side's `performance.now()` plus `offset`. */
|
|
6
|
+
now(): number;
|
|
7
|
+
/** The peer's clock minus this side's, in milliseconds; 0 before the first pong. */
|
|
8
|
+
readonly offset: number;
|
|
9
|
+
/** The round trip, smoothed, in milliseconds; 0 before the first pong. */
|
|
10
|
+
readonly rtt: number;
|
|
11
|
+
/** How much round trips vary, smoothed, in milliseconds. */
|
|
12
|
+
readonly jitter: number;
|
|
13
|
+
/** True once enough pongs arrived for `offset` to hold: about half a second after the link opens. */
|
|
14
|
+
readonly synced: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Where a link is: `connecting` until a path carries it, `open` while one
|
|
19
|
+
* does (`path` says which), `closed` for good (`closeReason` says why).
|
|
20
|
+
*/
|
|
21
|
+
type PeerLinkState = "connecting" | "open" | "closed";
|
|
22
|
+
/** What carries an open link: WebRTC data channels between the two clients, or the server's relay. */
|
|
23
|
+
type PeerPath = "direct" | "relay";
|
|
24
|
+
/**
|
|
25
|
+
* Why a link closed:
|
|
26
|
+
*
|
|
27
|
+
* - `closed`: this side's `close()`;
|
|
28
|
+
* - `bye`: the peer closed it, left the room or disconnected (the server
|
|
29
|
+
* says so for a peer that left);
|
|
30
|
+
* - `left`: this socket left the link's room, or was taken out of it;
|
|
31
|
+
* - `disconnected`: this side's socket disconnected (a link lives as long
|
|
32
|
+
* as the socket it started on), or the connection was closed;
|
|
33
|
+
* - `timeout`: no path opened within 15 seconds;
|
|
34
|
+
* - `lost`: nothing was heard from the peer for 8 seconds, or the direct
|
|
35
|
+
* path of a link that may not use the relay (`relay: "never"`) dropped
|
|
36
|
+
* after it opened;
|
|
37
|
+
* - `failed`: the direct path failed and the link may not use the relay
|
|
38
|
+
* (`relay: "never"`);
|
|
39
|
+
* - `refused`: the server refused a signal (the peer is not in the room,
|
|
40
|
+
* this socket signals too many peers, ...);
|
|
41
|
+
* - `unsupported`: the server serves no peer links (its hello lists no
|
|
42
|
+
* `"peer"`), or the link may use neither WebRTC (absent here) nor the
|
|
43
|
+
* relay.
|
|
44
|
+
*/
|
|
45
|
+
type PeerCloseReason = "closed" | "bye" | "left" | "disconnected" | "timeout" | "lost" | "failed" | "refused" | "unsupported";
|
|
46
|
+
/** What a link counted. */
|
|
47
|
+
interface PeerLinkStats {
|
|
48
|
+
/** App messages a path took: under a lag (`setLag`), each as it goes. */
|
|
49
|
+
readonly sent: number;
|
|
50
|
+
/** App messages received. */
|
|
51
|
+
readonly received: number;
|
|
52
|
+
/**
|
|
53
|
+
* App messages `send` dropped: sent while the link was not open, a `fast`
|
|
54
|
+
* message while the data channel was backed up, or one over the relay's
|
|
55
|
+
* limits. Under a lag, also a held `fast` message its path refused as it
|
|
56
|
+
* came due, and a `rel` one sent while a held `rel` message waits for its
|
|
57
|
+
* path.
|
|
58
|
+
*/
|
|
59
|
+
readonly dropped: number;
|
|
60
|
+
/**
|
|
61
|
+
* App messages the lag lost (`setLag`'s `loss`), sent or received: `fast`
|
|
62
|
+
* ones alone, and never counted in `dropped`.
|
|
63
|
+
*/
|
|
64
|
+
readonly simulatedLoss: number;
|
|
65
|
+
}
|
|
66
|
+
/** A link's simulated network, as `setLag` set it. */
|
|
67
|
+
interface PeerLinkLag {
|
|
68
|
+
/** How long each message waits, each way, in milliseconds. */
|
|
69
|
+
readonly ms: number;
|
|
70
|
+
/** Up to this many milliseconds more, at random, per message. */
|
|
71
|
+
readonly jitter: number;
|
|
72
|
+
/** The share of `fast` messages lost, each way, from 0 to 1. */
|
|
73
|
+
readonly loss: number;
|
|
74
|
+
}
|
|
75
|
+
/** What `setLag` takes: each part defaults to 0. */
|
|
76
|
+
interface PeerLinkLagOptions {
|
|
77
|
+
/** How long each message waits, each way, in milliseconds. */
|
|
78
|
+
readonly ms?: number;
|
|
79
|
+
/** Up to this many milliseconds more, at random, per message. */
|
|
80
|
+
readonly jitter?: number;
|
|
81
|
+
/** The share of `fast` messages lost, each way, from 0 to 1. `rel` ones never are. */
|
|
82
|
+
readonly loss?: number;
|
|
83
|
+
/** Random numbers from 0 to 1, for jitter and loss. Default `Math.random`; pass a seeded one to repeat a run. */
|
|
84
|
+
readonly random?: () => number;
|
|
85
|
+
}
|
|
86
|
+
/** A link's events and their listeners' arguments. */
|
|
87
|
+
interface PeerLinkEvents {
|
|
88
|
+
/** An app message from the peer, on `label`. */
|
|
89
|
+
message: (data: unknown, label: PeerLabel) => void;
|
|
90
|
+
/** The link opened, on `path`: once. */
|
|
91
|
+
open: (path: PeerPath) => void;
|
|
92
|
+
/** The link's state or path changed. */
|
|
93
|
+
state: (state: PeerLinkState, path: PeerPath | undefined) => void;
|
|
94
|
+
/** The link closed, for good: once. */
|
|
95
|
+
close: (reason: PeerCloseReason) => void;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A link to another socket of an app room: two channels, `rel` (ordered,
|
|
99
|
+
* reliable) and `fast` (unordered, never retransmitted), over WebRTC data
|
|
100
|
+
* channels or, when those cannot form, the server's relay, with the same
|
|
101
|
+
* behaviour either way. Messages are JSON values.
|
|
102
|
+
*/
|
|
103
|
+
interface PeerLink {
|
|
104
|
+
/** The app room the link belongs to. */
|
|
105
|
+
readonly room: string;
|
|
106
|
+
/** The peer's socket id. */
|
|
107
|
+
readonly peer: string;
|
|
108
|
+
/** The peer's user, as the server named it in the peer's first signal; `undefined` until then. */
|
|
109
|
+
readonly userId: string | undefined;
|
|
110
|
+
readonly state: PeerLinkState;
|
|
111
|
+
/** What carries the link while it is open. */
|
|
112
|
+
readonly path: PeerPath | undefined;
|
|
113
|
+
/** Why the link closed, once it has. */
|
|
114
|
+
readonly closeReason: PeerCloseReason | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Sends `data` (any JSON value) on `label`. Returns false when it was
|
|
117
|
+
* dropped: the link is not open, `fast` is backed up, or the relay's rate
|
|
118
|
+
* is spent (`stats.dropped` counts it). `rel` delivers in order while the
|
|
119
|
+
* path holds; a path change (the direct path failed, the relay took over)
|
|
120
|
+
* may lose `rel` messages in flight, and emits `state`. Under a lag
|
|
121
|
+
* (`setLag`) it returns true for a message it holds. Throws a
|
|
122
|
+
* `RangeError` for a message over `limits.peers.maxMessageBytes`.
|
|
123
|
+
*/
|
|
124
|
+
send(label: PeerLabel, data: unknown): boolean;
|
|
125
|
+
/** Calls `listener` on `event`; returns its removal. */
|
|
126
|
+
on<E extends keyof PeerLinkEvents>(event: E, listener: PeerLinkEvents[E]): () => void;
|
|
127
|
+
/** The peer's clock, read from pings the link sends on `fast`. */
|
|
128
|
+
readonly clock: PeerClock;
|
|
129
|
+
/** What the link counted. */
|
|
130
|
+
readonly stats: PeerLinkStats;
|
|
131
|
+
/**
|
|
132
|
+
* Simulates a bad network on this link, both ways and on either path, for
|
|
133
|
+
* a test, a bench or a host that gives itself its peers' lag: each
|
|
134
|
+
* message waits `ms` plus up to `jitter` milliseconds, and a `fast` one
|
|
135
|
+
* is lost with probability `loss` (`stats.simulatedLoss` counts the
|
|
136
|
+
* app's). `rel` messages are never lost and keep their order; one its
|
|
137
|
+
* path refuses as it comes due goes again a little later. The clock's
|
|
138
|
+
* pings wait too, so `clock.rtt` reads the lagged round trip. A new lag
|
|
139
|
+
* leaves what is held on its time; `null` (or all zeros) ends it, and
|
|
140
|
+
* what is held goes on the next task, in order. A link that closes drops
|
|
141
|
+
* what it holds. Throws a `TypeError` for a part out of range. Does
|
|
142
|
+
* nothing once the link is closed.
|
|
143
|
+
*/
|
|
144
|
+
setLag(lag: PeerLinkLagOptions | null): void;
|
|
145
|
+
/** The lag `setLag` set; `null` for none. */
|
|
146
|
+
readonly lag: PeerLinkLag | null;
|
|
147
|
+
/** Closes the link and tells the peer. Does nothing once it is closed. */
|
|
148
|
+
close(): void;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type { PeerPath as P, PeerLink as a, PeerClock as b, PeerCloseReason as c, PeerLinkEvents as d, PeerLinkLag as e, PeerLinkLagOptions as f, PeerLinkState as g, PeerLinkStats as h };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { M as MethodQueryKey } from '../keys-CqKkljVN.js';
|
|
2
2
|
export { C as CollectionQueryKey, E as EntityQueryKey, K as KEY_ROOT, b as MethodKeyPrefix, S as ServiceKeyPrefix, c as collectionKey, e as entityKey, m as methodKey, a as methodKeyPrefix, s as serviceKeyPrefix } from '../keys-CqKkljVN.js';
|
|
3
|
-
import {
|
|
4
|
-
import { ae as ContractMap, ap as MethodName, J as AnyContract, ao as KindOf, al as InputOf, ar as OutputOf } from '../infer-BmoZsL9a.js';
|
|
3
|
+
import { ae as ContractMap, ap as MethodName, J as AnyContract, ao as KindOf, al as InputOf, ar as OutputOf } from '../infer-Br62cnyW.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Format a currency value for display.
|
|
@@ -91,6 +90,19 @@ interface ServerCallerOptions {
|
|
|
91
90
|
/** The `fetch` to call with. Default: the global one. */
|
|
92
91
|
readonly fetch?: typeof fetch;
|
|
93
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* The part of a TanStack `QueryClient` that `prefetch` calls, which any
|
|
95
|
+
* `QueryClient` is: `prefetchQuery` with the method's key and a function
|
|
96
|
+
* that calls it.
|
|
97
|
+
*/
|
|
98
|
+
interface QueryClientLike {
|
|
99
|
+
prefetchQuery(options: {
|
|
100
|
+
readonly queryKey: MethodQueryKey;
|
|
101
|
+
readonly queryFn: (context: {
|
|
102
|
+
readonly signal: AbortSignal;
|
|
103
|
+
}) => Promise<unknown>;
|
|
104
|
+
}): Promise<void>;
|
|
105
|
+
}
|
|
94
106
|
/** Options of one HTTP call. */
|
|
95
107
|
interface ServerCallOptions {
|
|
96
108
|
/** Aborting it cancels the request; the call rejects with `CANCELLED`. */
|
|
@@ -104,7 +116,7 @@ interface ServerQuery<C extends AnyContract, M extends MethodName<C>> {
|
|
|
104
116
|
/** The key the query's result is cached under, the one the client's hooks read. */
|
|
105
117
|
key(...args: InputArgs<C, M, []>): MethodQueryKey<InputOf<C, M>>;
|
|
106
118
|
/** Calls the query into `queryClient`, as `queryClient.prefetchQuery` does: it never rejects. */
|
|
107
|
-
prefetch(queryClient:
|
|
119
|
+
prefetch(queryClient: QueryClientLike, ...args: InputArgs<C, M, []>): Promise<void>;
|
|
108
120
|
}
|
|
109
121
|
/** A mutation of the server caller. */
|
|
110
122
|
interface ServerMutation<C extends AnyContract, M extends MethodName<C>> {
|
|
@@ -137,4 +149,4 @@ type ServerCaller<Contracts extends ContractMap> = {
|
|
|
137
149
|
*/
|
|
138
150
|
declare function createServerCaller<const Contracts extends ContractMap>(contracts: Contracts, options: ServerCallerOptions): ServerCaller<Contracts>;
|
|
139
151
|
|
|
140
|
-
export { type BreadcrumbItem, type JWTPayload, MethodQueryKey, type NavItem, type ServerCallOptions, type ServerCaller, type ServerCallerHeaders, type ServerCallerOptions, type ServerMethod, type ServerMutation, type ServerQuery, buildBreadcrumbs, createServerCaller, findNavItemByHref, findParentNavItem, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, parseJWTPayload, routeRequiresAuth, truncate };
|
|
152
|
+
export { type BreadcrumbItem, type JWTPayload, MethodQueryKey, type NavItem, type QueryClientLike, type ServerCallOptions, type ServerCaller, type ServerCallerHeaders, type ServerCallerOptions, type ServerMethod, type ServerMutation, type ServerQuery, buildBreadcrumbs, createServerCaller, findNavItemByHref, findParentNavItem, formatCurrency, formatDate, formatDateTime, formatNumber, formatPercent, parseJWTPayload, routeRequiresAuth, truncate };
|
package/dist/utils/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
parseJWTPayload,
|
|
12
12
|
routeRequiresAuth,
|
|
13
13
|
truncate
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-CYE4UBOB.js";
|
|
15
15
|
import {
|
|
16
16
|
KEY_ROOT,
|
|
17
17
|
collectionKey,
|
|
@@ -19,8 +19,11 @@ import {
|
|
|
19
19
|
methodKey,
|
|
20
20
|
methodKeyPrefix,
|
|
21
21
|
serviceKeyPrefix
|
|
22
|
-
} from "../chunk-
|
|
23
|
-
import "../chunk-
|
|
22
|
+
} from "../chunk-IIQ3WMJK.js";
|
|
23
|
+
import "../chunk-MPQAT55F.js";
|
|
24
|
+
import "../chunk-47AEXVDM.js";
|
|
25
|
+
import "../chunk-Q4OGQM5I.js";
|
|
26
|
+
import "../chunk-QSU47XEX.js";
|
|
24
27
|
export {
|
|
25
28
|
KEY_ROOT,
|
|
26
29
|
buildBreadcrumbs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fitzzero/quickdraw-core",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.3",
|
|
4
4
|
"description": "Fast fullstack patterns for real-time applications with Socket.io and TanStack Query",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fullstack",
|
|
@@ -53,6 +53,10 @@
|
|
|
53
53
|
"types": "./dist/client/index.d.ts",
|
|
54
54
|
"import": "./dist/client/index.js"
|
|
55
55
|
},
|
|
56
|
+
"./client/core": {
|
|
57
|
+
"types": "./dist/client/core.d.ts",
|
|
58
|
+
"import": "./dist/client/core.js"
|
|
59
|
+
},
|
|
56
60
|
"./utils": {
|
|
57
61
|
"types": "./dist/utils/index.d.ts",
|
|
58
62
|
"import": "./dist/utils/index.js"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol/guards.ts","../src/protocol/errors.ts"],"sourcesContent":["// Shape checks shared by the protocol's hand-written guards. Internal: the\n// package root exports the guards built on these, not these.\n\n/** An object that is not an array or `null`: what a JSON object decodes to. */\nexport type UnknownRecord = { readonly [key: string]: unknown };\n\n/** True when `value` is an object that is not an array or `null`. */\nexport function isRecord(value: unknown): value is UnknownRecord {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** True when `value` is a non-empty string, as service and method names are. */\nexport function isName(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n","// Error codes and the error every failed call carries (RFC 0003 section 3).\n// In 4.1 a failed call answered `{ success: false, error, code? }`\n// (4.1 `src/shared/types.ts:88-90`), every thrown error became code 500\n// with its own message (4.1 `src/server/ServiceRegistry.ts:398-402`), and\n// the client rethrew it as `ServiceCallError` with that number\n// (4.1 `src/client/serviceError.ts:6`). In 5.0 a handler picks the code by\n// throwing `QuickdrawError`; the same code reaches the caller on every\n// transport, and the HTTP transport maps it to a status with `httpStatus`.\n\nimport { isRecord } from \"./guards\";\n\n/** Every code a call can fail with, in the order of RFC 0003 section 3. */\nexport const ERROR_CODES = Object.freeze([\n \"UNAUTHENTICATED\",\n \"FORBIDDEN\",\n \"NOT_FOUND\",\n \"CONFLICT\",\n \"VALIDATION\",\n \"RATE_LIMITED\",\n \"CANCELLED\",\n \"TIMEOUT\",\n \"INTERNAL\",\n] as const);\n\n/**\n * Why a call failed:\n *\n * - `UNAUTHENTICATED` (401): there is no principal.\n * - `FORBIDDEN` (403): access was denied.\n * - `NOT_FOUND` (404): an unknown service, method or row.\n * - `CONFLICT` (409): a unique or state conflict.\n * - `VALIDATION` (422): the input failed its schema; see {@link ValidationErrorData}.\n * - `RATE_LIMITED` (429): a limiter or a full queue; see {@link RateLimitedErrorData}.\n * - `CANCELLED` (499): the caller cancelled.\n * - `TIMEOUT` (504): the handler ran past its time limit.\n * - `INTERNAL` (500): anything else.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[number];\n\nconst HTTP_STATUS: Readonly<Record<ErrorCode, number>> = Object.freeze({\n UNAUTHENTICATED: 401,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n CONFLICT: 409,\n VALIDATION: 422,\n RATE_LIMITED: 429,\n CANCELLED: 499,\n TIMEOUT: 504,\n INTERNAL: 500,\n});\n\n/** The message every `INTERNAL` error carries on the wire, whatever was thrown. */\nexport const INTERNAL_MESSAGE = \"Internal error\";\n\n/** True when `value` is one of the error codes. */\nexport function isErrorCode(value: unknown): value is ErrorCode {\n return typeof value === \"string\" && Object.hasOwn(HTTP_STATUS, value);\n}\n\n/** The HTTP status for an error code, as the table in RFC 0003 section 3 gives it. */\nexport function httpStatus(code: ErrorCode): number {\n return HTTP_STATUS[code];\n}\n\n/** One problem with a call's input, in a `VALIDATION` error's `data.issues`. */\nexport interface WireIssue {\n /** Where the problem is, as object keys and array indexes; empty for the input itself. */\n readonly path: readonly (string | number)[];\n readonly message: string;\n}\n\n/** The `data` of a `VALIDATION` error. */\nexport interface ValidationErrorData {\n readonly issues: readonly WireIssue[];\n}\n\n/** The `data` of a `RATE_LIMITED` error. */\nexport interface RateLimitedErrorData {\n /** How long to wait before trying again, in milliseconds. */\n readonly retryAfterMs: number;\n}\n\n/**\n * The error a failed call carries. A handler throws it to choose the code the\n * caller sees; the client rejects with it. Anything else a handler throws\n * reaches the caller as `INTERNAL` with a generic message (see {@link toWire}).\n */\nexport class QuickdrawError extends Error {\n /** Why the call failed. */\n readonly code: ErrorCode;\n /**\n * Details for the caller, sent as JSON: `issues` for `VALIDATION`,\n * `retryAfterMs` for `RATE_LIMITED`. `INTERNAL` errors never send it.\n */\n readonly data: unknown;\n\n constructor(code: ErrorCode, message: string, data?: unknown) {\n super(message);\n this.name = \"QuickdrawError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/** An error as it travels: the `e` of a failed acknowledgement. */\nexport interface WireError {\n readonly code: ErrorCode;\n readonly message: string;\n readonly data?: unknown;\n}\n\n/**\n * The wire form of whatever a call failed with. A `QuickdrawError` keeps its\n * code, message and data. Anything else, and every `INTERNAL` error, becomes\n * `{ code: \"INTERNAL\", message: \"Internal error\" }`: no stack, message or data\n * of an internal failure ever reaches the caller, so log the original first.\n */\nexport function toWire(error: unknown): WireError {\n if (!(error instanceof QuickdrawError) || error.code === \"INTERNAL\" || !isErrorCode(error.code)) {\n return { code: \"INTERNAL\", message: INTERNAL_MESSAGE };\n }\n return error.data === undefined\n ? { code: error.code, message: error.message }\n : { code: error.code, message: error.message, data: error.data };\n}\n\n/**\n * The `QuickdrawError` a wire error describes. A code this version does not\n * know becomes `INTERNAL`, keeping the message and data. A payload that is not\n * a wire error (not an object, or no string `message`) becomes a generic\n * `INTERNAL`. Either way the caller can branch on `code`.\n */\nexport function fromWire(payload: unknown): QuickdrawError {\n if (!isRecord(payload) || typeof payload.message !== \"string\") {\n return new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE);\n }\n const code = isErrorCode(payload.code) ? payload.code : \"INTERNAL\";\n return new QuickdrawError(code, payload.message, payload.data);\n}\n"],"mappings":";AAOO,SAAS,SAAS,OAAwC;AAC/D,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAGO,SAAS,OAAO,OAAiC;AACtD,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS;AACrD;;;ACFO,IAAM,cAAc,OAAO,OAAO;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAU;AAiBV,IAAM,cAAmD,OAAO,OAAO;AAAA,EACrE,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AACZ,CAAC;AAGM,IAAM,mBAAmB;AAGzB,SAAS,YAAY,OAAoC;AAC9D,SAAO,OAAO,UAAU,YAAY,OAAO,OAAO,aAAa,KAAK;AACtE;AAGO,SAAS,WAAW,MAAyB;AAClD,SAAO,YAAY,IAAI;AACzB;AAyBO,IAAM,iBAAN,cAA6B,MAAM;AAAA;AAAA,EAE/B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EAET,YAAY,MAAiB,SAAiB,MAAgB;AAC5D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAeO,SAAS,OAAO,OAA2B;AAChD,MAAI,EAAE,iBAAiB,mBAAmB,MAAM,SAAS,cAAc,CAAC,YAAY,MAAM,IAAI,GAAG;AAC/F,WAAO,EAAE,MAAM,YAAY,SAAS,iBAAiB;AAAA,EACvD;AACA,SAAO,MAAM,SAAS,SAClB,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ,IAC3C,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,SAAS,MAAM,MAAM,KAAK;AACnE;AAQO,SAAS,SAAS,SAAkC;AACzD,MAAI,CAAC,SAAS,OAAO,KAAK,OAAO,QAAQ,YAAY,UAAU;AAC7D,WAAO,IAAI,eAAe,YAAY,gBAAgB;AAAA,EACxD;AACA,QAAM,OAAO,YAAY,QAAQ,IAAI,IAAI,QAAQ,OAAO;AACxD,SAAO,IAAI,eAAe,MAAM,QAAQ,SAAS,QAAQ,IAAI;AAC/D;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/contract/realtime.ts"],"sourcesContent":["// Streams, channels and typed room events in a contract (RFC 0003 section\n// 12.5). A stream is server-to-client append-only data a subscriber receives\n// with a seed of recent items; a channel is fire-and-forget client-to-server\n// input (cursors, typing) behind a per-socket token bucket; an event is a\n// typed custom frame a handler sends to a room. 4.1 declared channels on the\n// service class (4.1 `src/server/BaseService.ts:915-942`) and typed room\n// events through the augmentable `QuickdrawEventMap`; here all three live in\n// the contract, so the client is typed from it.\n//\n// Methods, collections, streams, channels and events share one namespace:\n// the client exposes each as `qd.<service>.<name>`.\n\nimport type { AccessLevel } from \"./access\";\nimport type { AnyContract } from \"./defineContract\";\nimport type { StandardSchemaV1 } from \"./standardSchema\";\n\n/** The `scope` of a stream with one feed for the whole service: the default. */\nexport const GLOBAL_STREAM = \"global\";\n\n/** The most items a stream may keep per scope as the seed for new subscribers. */\nexport const STREAM_MAX_SEED = 1000;\n\n/** A channel's sustained rate when it declares none: messages per second per socket. */\nexport const CHANNEL_DEFAULT_RATE = 30;\n\n/**\n * The app room a stream's subscriber must be in (`access: { room }`): for a\n * global stream the room's name, or `{ prefix }` for any room whose name\n * starts with it; for a scoped stream a function of the scope\n * (`(worldId) => \\`world:${worldId}\\``), since a name or a prefix would let\n * a socket in that room read every scope (`defineContract` refuses them\n * there).\n */\nexport type StreamRoom = string | RoomPrefix | ((scope: string) => string | null | undefined);\n\n/**\n * Who may subscribe to a stream (RFC 0003 section 4.1's forms, as data). A\n * scoped stream's scope value is the row an `entry` or `scope` form is about:\n * `{ entry: L }` needs level `L` on the row of this service whose id is the\n * scope, `{ scope: L, of }` level `L` on that row of `of`'s service.\n * `{ room }` opens it to the sockets in an app room a method joined them to\n * (signed in or not), as a channel's `requires: { room }` does its messages:\n * a socket that leaves the room, or is taken out of it, leaves the feed too.\n * A scoped stream computes that room from its scope; a name or `{ prefix }`\n * serves a global stream only. A stream that declares none is closed: no\n * client may subscribe.\n */\nexport type StreamAccess =\n | \"public\"\n | \"authenticated\"\n | {\n readonly service: AccessLevel;\n readonly entry?: undefined;\n readonly scope?: undefined;\n readonly of?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly entry: AccessLevel;\n readonly service?: AccessLevel;\n readonly scope?: undefined;\n readonly of?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly scope: AccessLevel;\n readonly of: AnyContract;\n readonly service?: undefined;\n readonly entry?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly room: StreamRoom;\n readonly service?: undefined;\n readonly entry?: undefined;\n readonly scope?: undefined;\n readonly of?: undefined;\n };\n\n/** A server-to-client stream of append-only items (RFC 0003 section 12.5). */\nexport interface StreamDef<Item extends StandardSchemaV1 = StandardSchemaV1> {\n /** One item's schema. Pushed items are checked against it before they are sent. */\n readonly item: Item;\n /**\n * What a scope value is (`\"taskId\"`): the stream has one feed per scope.\n * `\"global\"`, the default, makes one feed for the whole service.\n */\n readonly scope?: string;\n /**\n * How many of the latest items the server keeps per scope, in memory on\n * each process, and sends a new subscriber first. Default 0; at most 1,000.\n */\n readonly seed?: number;\n /** Send items volatile: dropped for a client whose connection is backed up. Default `false`. */\n readonly volatile?: boolean;\n /** Who may subscribe. Without it the stream is closed. */\n readonly access?: StreamAccess;\n /** What the stream carries, in a sentence or two, for the generated docs. */\n readonly describe?: string;\n}\n\n/**\n * Where a channel requirement finds its row id or scope value in the parsed\n * payload: the name of a key holding a string, or a function of the payload.\n */\nexport type PayloadSelector = string | ((payload: never) => string | null | undefined);\n\n/**\n * Any app room whose name starts with `prefix` (`{ prefix: \"world:\" }`, a\n * game of many worlds): the sending socket passes when it is in one, and\n * the channel's handler gets the one it matched as `ctx.room`, so the\n * payload need not repeat which room it is for.\n */\nexport interface RoomPrefix {\n readonly prefix: string;\n}\n\n/**\n * The app room a channel requirement names: the room itself (`\"world\"`, a\n * game's one world), a function of the parsed payload that returns it\n * (`(payload) => \\`lobby:${payload.lobbyId}\\``), or `{ prefix }`, any room\n * whose name starts with it (`{ prefix: \"world:\" }`). Unlike a\n * {@link PayloadSelector}, a string here is the room's name, not a payload\n * key. A name starting with `qd:` or `user:`, or one with the shape of a\n * Socket.IO socket id (20 letters, digits, `_` or `-`), is never an app\n * room: a literal one (or such a prefix) is refused when the contract is\n * defined, and a computed one drops the message.\n */\nexport type RoomSelector = string | ((payload: never) => string | null | undefined) | RoomPrefix;\n\n/**\n * What a channel message requires of the socket that sends it: a live\n * subscription (`qd:sub`) to the row of this service `entity` names, or\n * (`qd:col:sub`) to the scope of `collection` that `scope` names; or that\n * the socket is in the app room `room` names (or, for `{ prefix }`, in any\n * app room whose name starts with it), which a method called over that\n * same socket joined with `ctx.rooms.join` (a room another socket of the\n * user joined does not count, and a reconnected socket is in none until it\n * joins again). The handler gets the room that matched as `ctx.room`. Each\n * is checked in memory against the sending socket's own records, on the\n * node it is connected to. A message whose payload names none is dropped.\n */\nexport type ChannelRequires =\n | {\n readonly entity: PayloadSelector;\n readonly collection?: undefined;\n readonly scope?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly collection: string;\n readonly scope: PayloadSelector;\n readonly entity?: undefined;\n readonly room?: undefined;\n }\n | {\n readonly room: RoomSelector;\n readonly entity?: undefined;\n readonly collection?: undefined;\n readonly scope?: undefined;\n };\n\n/** A client-to-server fire-and-forget channel (RFC 0003 section 12.5). */\nexport interface ChannelDef<Payload extends StandardSchemaV1 = StandardSchemaV1> {\n /** One message's schema. A message that fails it is dropped. */\n readonly payload: Payload;\n /** Messages one socket may send per second, sustained. Default 30. */\n readonly ratePerSecond?: number;\n /** How many messages one socket may send at once. Default twice `ratePerSecond`. */\n readonly burst?: number;\n /**\n * What the sender must already be subscribed to, or the app room it must\n * be in. Without it every signed-in user may send the channel, about any\n * row or room its payload names, and the server warns\n * `channel-without-requires` unless the service declares the channel's\n * `access` (`\"authenticated\"` when any signed-in user may send it).\n */\n readonly requires?: ChannelRequires;\n /** What a message says, in a sentence or two, for the generated docs. */\n readonly describe?: string;\n}\n\n/** A typed custom room event, delivered as `qd:event` (RFC 0003 section 8.3). */\nexport interface EventDef<Payload extends StandardSchemaV1 = StandardSchemaV1> {\n readonly payload: Payload;\n /** What the event announces, in a sentence or two, for the generated docs. */\n readonly describe?: string;\n}\n\n/** True when a stream has one feed per scope value; false for a global stream. */\nexport function isScopedStream(def: Pick<StreamDef, \"scope\">): boolean {\n return def.scope !== undefined && def.scope !== GLOBAL_STREAM;\n}\n"],"mappings":";AAiBO,IAAM,gBAAgB;AAGtB,IAAM,kBAAkB;AAGxB,IAAM,uBAAuB;AAuK7B,SAAS,eAAe,KAAwC;AACrE,SAAO,IAAI,UAAU,UAAa,IAAI,UAAU;AAClD;","names":[]}
|