@spfn/core 0.3.0-beta.23 → 0.3.0-beta.25
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 +1 -0
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.js +2 -2
- package/dist/contract/index.js.map +1 -1
- package/dist/event/index.d.ts +3 -3
- package/dist/event/index.js +160 -2
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +2 -2
- package/dist/event/sse/client.js +20 -1
- package/dist/event/sse/client.js.map +1 -1
- package/dist/event/sse/index.d.ts +16 -4
- package/dist/event/sse/index.js +366 -109
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +2 -2
- package/dist/event/ws/index.d.ts +3 -3
- package/dist/router-D5B0cpVN.d.ts +378 -0
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.js +366 -109
- package/dist/server/index.js.map +1 -1
- package/dist/state/index.d.ts +380 -0
- package/dist/state/index.js +571 -0
- package/dist/state/index.js.map +1 -0
- package/dist/{types-W4u_S0lF.d.ts → types-CqTsDETV.d.ts} +1 -1
- package/dist/{types-B8zAxFsE.d.ts → types-DqXYtI69.d.ts} +27 -2
- package/package.json +6 -1
- package/src/contract/README.md +5 -3
- package/src/event/README.md +150 -13
- package/src/state/README.md +350 -0
- package/dist/router-CysBmgv3.d.ts +0 -232
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { TObject, TSchema, Static } from '@sinclair/typebox';
|
|
2
|
+
import { MiddlewareHandler, Context } from 'hono';
|
|
3
|
+
import { EventDef } from '@spfn/core/event';
|
|
4
|
+
import { NamedMiddleware, RouteAuthProfile, Router, RouteDef } from '@spfn/core/route';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* State Types
|
|
8
|
+
*
|
|
9
|
+
* A state's shape is tracked as one phantom record, `StateShape`, which each
|
|
10
|
+
* builder call rewrites. Every derived type — the read context, the result,
|
|
11
|
+
* the change signal's payload, the frame, the routes — is computed from it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* What a builder has declared so far, at the type level only.
|
|
16
|
+
*/
|
|
17
|
+
interface StateShape {
|
|
18
|
+
key: TObject | undefined;
|
|
19
|
+
shared: boolean;
|
|
20
|
+
value: TSchema | undefined;
|
|
21
|
+
data: TSchema | undefined;
|
|
22
|
+
input: TSchema | undefined;
|
|
23
|
+
read: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** The shape of `defineState(id)` before any call. */
|
|
26
|
+
interface EmptyStateShape extends StateShape {
|
|
27
|
+
key: undefined;
|
|
28
|
+
shared: false;
|
|
29
|
+
value: undefined;
|
|
30
|
+
data: undefined;
|
|
31
|
+
input: undefined;
|
|
32
|
+
read: false;
|
|
33
|
+
}
|
|
34
|
+
/** `T` with the fields of `U` replaced. */
|
|
35
|
+
type WithShape<T extends StateShape, U extends Partial<StateShape>> = {
|
|
36
|
+
[K in keyof StateShape]: K extends keyof U ? U[K] : T[K];
|
|
37
|
+
};
|
|
38
|
+
type Simplify<T> = {
|
|
39
|
+
[K in keyof T]: T[K];
|
|
40
|
+
} & {};
|
|
41
|
+
/** The key object of a keyed state, `undefined` for a keyless one. */
|
|
42
|
+
type StateKey<T extends StateShape> = T['key'] extends TObject ? Static<T['key']> : undefined;
|
|
43
|
+
/** The value type, `unknown` until `.value()` is declared. */
|
|
44
|
+
type StateValue<T extends StateShape> = T['value'] extends TSchema ? Static<T['value']> : unknown;
|
|
45
|
+
/**
|
|
46
|
+
* What `read()` returns: always an object, so a value can never be mistaken
|
|
47
|
+
* for `{ value, data }`. With `.data()` declared, `data` is part of every
|
|
48
|
+
* result — the router checks each one against the declaration.
|
|
49
|
+
*/
|
|
50
|
+
type StateResult<T extends StateShape> = T['data'] extends TSchema ? {
|
|
51
|
+
value: StateValue<T>;
|
|
52
|
+
data: Static<T['data']>;
|
|
53
|
+
} : {
|
|
54
|
+
value: StateValue<T>;
|
|
55
|
+
};
|
|
56
|
+
/** What the read and write routes answer: the result and the time its read started. */
|
|
57
|
+
type StateSnapshot<T extends StateShape> = Simplify<{
|
|
58
|
+
at: string;
|
|
59
|
+
} & StateResult<T>>;
|
|
60
|
+
/** What `.canRead()` / `.canWrite()` decide on. */
|
|
61
|
+
type PermissionContext<T extends StateShape> = T['key'] extends TObject ? {
|
|
62
|
+
subject: string;
|
|
63
|
+
principal: unknown;
|
|
64
|
+
key: Static<T['key']>;
|
|
65
|
+
} : {
|
|
66
|
+
subject: string;
|
|
67
|
+
principal: unknown;
|
|
68
|
+
};
|
|
69
|
+
/** What `read()` receives. A shared state's value does not depend on the subject, so it gets none. */
|
|
70
|
+
type ReadContext<T extends StateShape> = T['key'] extends TObject ? T['shared'] extends true ? {
|
|
71
|
+
principal: unknown;
|
|
72
|
+
key: Static<T['key']>;
|
|
73
|
+
} : PermissionContext<T> : PermissionContext<T>;
|
|
74
|
+
/** What `write()` receives: the read context plus the validated input. */
|
|
75
|
+
type WriteContext<T extends StateShape, I extends TSchema> = Simplify<ReadContext<T> & {
|
|
76
|
+
input: Static<I>;
|
|
77
|
+
}>;
|
|
78
|
+
/** The payload of `state.changed.emit()`: exactly what names the value to re-read. */
|
|
79
|
+
type ChangedPayload<T extends StateShape> = T['key'] extends TObject ? T['shared'] extends true ? Simplify<Static<T['key']>> : Simplify<Static<T['key']> & {
|
|
80
|
+
subject: string;
|
|
81
|
+
}> : {
|
|
82
|
+
subject: string;
|
|
83
|
+
};
|
|
84
|
+
/** The payload of the derived SSE event `state.<id>.changed`. */
|
|
85
|
+
type StateFrame<T extends StateShape> = Simplify<StateSnapshot<T> & (T['key'] extends TObject ? {
|
|
86
|
+
key: Static<T['key']>;
|
|
87
|
+
} : {}) & (T['key'] extends TObject ? (T['shared'] extends true ? {} : {
|
|
88
|
+
subject: string;
|
|
89
|
+
}) : {
|
|
90
|
+
subject: string;
|
|
91
|
+
})>;
|
|
92
|
+
/** Whom `grant()` reaches, and for a keyed state the one key it opens and sends the current value of. */
|
|
93
|
+
type GrantTarget<T extends StateShape> = T['key'] extends TObject ? {
|
|
94
|
+
subject: string;
|
|
95
|
+
key: Static<T['key']>;
|
|
96
|
+
} : {
|
|
97
|
+
subject: string;
|
|
98
|
+
};
|
|
99
|
+
/** Whom `revoke()` reaches: for a keyed state, the connections on `key`, or every one without it. */
|
|
100
|
+
type RevokeTarget<T extends StateShape> = T['key'] extends TObject ? {
|
|
101
|
+
subject: string;
|
|
102
|
+
key?: Static<T['key']>;
|
|
103
|
+
} : {
|
|
104
|
+
subject: string;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* The contract one `.contract()` declares for the read route, the write route
|
|
108
|
+
* and the derived event. The response schema is derived, never declared.
|
|
109
|
+
*/
|
|
110
|
+
interface StateContract {
|
|
111
|
+
since: string;
|
|
112
|
+
auth?: RouteAuthProfile;
|
|
113
|
+
requiresSession?: boolean;
|
|
114
|
+
deprecatedIn?: string;
|
|
115
|
+
removedIn?: string;
|
|
116
|
+
}
|
|
117
|
+
/** Version markers of a write added, deprecated or removed apart from its read. */
|
|
118
|
+
interface StateWriteOptions {
|
|
119
|
+
since?: string;
|
|
120
|
+
deprecatedIn?: string;
|
|
121
|
+
removedIn?: string;
|
|
122
|
+
}
|
|
123
|
+
/** Any read / permission / write context, as the runtime handles it. */
|
|
124
|
+
interface StateCallContext {
|
|
125
|
+
subject?: string;
|
|
126
|
+
principal: unknown;
|
|
127
|
+
key?: Record<string, string>;
|
|
128
|
+
input?: unknown;
|
|
129
|
+
}
|
|
130
|
+
type StatePredicate = (ctx: StateCallContext) => boolean | Promise<boolean>;
|
|
131
|
+
type StateReader = (ctx: StateCallContext) => unknown;
|
|
132
|
+
type StateWriter = (ctx: StateCallContext) => void | Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Everything one builder declared, as the router reads it.
|
|
135
|
+
*/
|
|
136
|
+
interface StateDefinition {
|
|
137
|
+
id: string;
|
|
138
|
+
key?: TObject;
|
|
139
|
+
shared: boolean;
|
|
140
|
+
value?: TSchema;
|
|
141
|
+
data?: TSchema;
|
|
142
|
+
middlewares: (MiddlewareHandler | NamedMiddleware<string>)[];
|
|
143
|
+
skipMiddlewares?: string[] | '*';
|
|
144
|
+
contract?: StateContract;
|
|
145
|
+
canRead?: StatePredicate;
|
|
146
|
+
canWrite?: StatePredicate;
|
|
147
|
+
read?: StateReader;
|
|
148
|
+
write?: {
|
|
149
|
+
input: TSchema;
|
|
150
|
+
fn: StateWriter;
|
|
151
|
+
options: StateWriteOptions;
|
|
152
|
+
};
|
|
153
|
+
changedBy?: EventDef<any>[];
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* What `defineStateRouter` accepts: a builder with `.value()` and `.read()`
|
|
157
|
+
* declared. A builder without either is not assignable here.
|
|
158
|
+
*/
|
|
159
|
+
interface RoutableState {
|
|
160
|
+
readonly id: string;
|
|
161
|
+
readonly _types: StateShape & {
|
|
162
|
+
value: TSchema;
|
|
163
|
+
read: true;
|
|
164
|
+
};
|
|
165
|
+
readonly _definition: Readonly<StateDefinition>;
|
|
166
|
+
readonly _event: EventDef<any>;
|
|
167
|
+
readonly changed: EventDef<any>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* State Builder
|
|
172
|
+
*
|
|
173
|
+
* `defineState(id)` starts an immutable builder: every call returns a new one,
|
|
174
|
+
* order is free and there is no terminal method. `defineStateRouter` reads
|
|
175
|
+
* what a builder declared and derives its routes and SSE event from it.
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A server-owned value declared once. See the module README.
|
|
180
|
+
*/
|
|
181
|
+
declare class StateBuilder<TId extends string, T extends StateShape> {
|
|
182
|
+
readonly id: TId;
|
|
183
|
+
readonly _definition: Readonly<StateDefinition>;
|
|
184
|
+
/** Type inference helper: what this builder declared. Never set at runtime. */
|
|
185
|
+
readonly _types: T;
|
|
186
|
+
private changedSignal?;
|
|
187
|
+
private stateEvent?;
|
|
188
|
+
constructor(id: TId, _definition: Readonly<StateDefinition>);
|
|
189
|
+
/**
|
|
190
|
+
* Declare the key: one value per key (and per subject, unless `shared`).
|
|
191
|
+
* Fields are required strings: they travel as query parameters.
|
|
192
|
+
*/
|
|
193
|
+
key<K extends TObject, S extends boolean = false>(schema: K, options?: {
|
|
194
|
+
shared?: S;
|
|
195
|
+
}): StateBuilder<TId, WithShape<T, {
|
|
196
|
+
key: K;
|
|
197
|
+
shared: S;
|
|
198
|
+
}>>;
|
|
199
|
+
/** Declare the value schema. Required. */
|
|
200
|
+
value<V extends TSchema>(schema: V): StateBuilder<TId, WithShape<T, {
|
|
201
|
+
value: V;
|
|
202
|
+
}>>;
|
|
203
|
+
/** Declare data attached to the value. Optional. */
|
|
204
|
+
data<D extends TSchema>(schema: D): StateBuilder<TId, WithShape<T, {
|
|
205
|
+
data: D;
|
|
206
|
+
}>>;
|
|
207
|
+
/**
|
|
208
|
+
* Middleware for the two per-state routes, `get<Id>State` / `put<Id>State`.
|
|
209
|
+
* Not authorization: the snapshot and the SSE stream cannot run it, so a
|
|
210
|
+
* state with `.use()` must declare `.canRead()`. Calls add up.
|
|
211
|
+
*/
|
|
212
|
+
use(middlewares: (MiddlewareHandler | NamedMiddleware<string>)[]): StateBuilder<TId, T>;
|
|
213
|
+
/** Server-level named middlewares the two per-state routes skip. Calls add up; `'*'` wins. Needs `.canRead()`, as `.use()`. */
|
|
214
|
+
skip(middlewareNames: string[] | '*'): StateBuilder<TId, T>;
|
|
215
|
+
/** Publish the read route, the write route and the event in the contract. */
|
|
216
|
+
contract(contract: StateContract): StateBuilder<TId, T>;
|
|
217
|
+
/** Who may read. Required on a keyed state; checked on HTTP and at SSE connect. */
|
|
218
|
+
canRead(predicate: (ctx: PermissionContext<T>) => boolean | Promise<boolean>): StateBuilder<TId, T>;
|
|
219
|
+
/** Who may write. Absent → `canRead` decides. */
|
|
220
|
+
canWrite(predicate: (ctx: PermissionContext<T>) => boolean | Promise<boolean>): StateBuilder<TId, T>;
|
|
221
|
+
/** The only source of a value. Required. */
|
|
222
|
+
read(fn: (ctx: ReadContext<T>) => StateResult<T> | Promise<StateResult<T>>): StateBuilder<TId, WithShape<T, {
|
|
223
|
+
read: true;
|
|
224
|
+
}>>;
|
|
225
|
+
/**
|
|
226
|
+
* Derive `PUT <path>/<id>`. `fn` runs the command; the value the route
|
|
227
|
+
* answers and broadcasts is re-read afterwards, never taken from `input`.
|
|
228
|
+
*/
|
|
229
|
+
write<I extends TSchema>(input: I, fn: (ctx: WriteContext<T, I>) => void | Promise<void>, options?: StateWriteOptions): StateBuilder<TId, WithShape<T, {
|
|
230
|
+
input: I;
|
|
231
|
+
}>>;
|
|
232
|
+
/**
|
|
233
|
+
* Domain events whose payload names a changed value of this state, treated
|
|
234
|
+
* like `changed.emit` with that payload: keyless `subject`, keyed the key
|
|
235
|
+
* fields and `subject`, shared the key fields. The router subscribes them
|
|
236
|
+
* and refuses one whose payload schema lacks a field.
|
|
237
|
+
*/
|
|
238
|
+
changedBy(events: EventDef<any>[]): StateBuilder<TId, T>;
|
|
239
|
+
/**
|
|
240
|
+
* The change signal. Emit it after the change is committed; the module
|
|
241
|
+
* re-reads the value and sends the frame. Refused on a builder no router
|
|
242
|
+
* grouped — export the instance you passed to `defineStateRouter`.
|
|
243
|
+
*/
|
|
244
|
+
get changed(): EventDef<ChangedPayload<T>>;
|
|
245
|
+
/** Internal: the SSE event `state.<id>.changed` (`defineStateRouter(...).events`). */
|
|
246
|
+
get _event(): EventDef<StateFrame<T>>;
|
|
247
|
+
/**
|
|
248
|
+
* Activate the state's event on `subject`'s open connections and send it
|
|
249
|
+
* the current value at once. On a keyed state only the connections that
|
|
250
|
+
* declared `key` are opened. Does not consult `canRead`.
|
|
251
|
+
*/
|
|
252
|
+
grant(target: GrantTarget<T>): Promise<void>;
|
|
253
|
+
/**
|
|
254
|
+
* Deactivate the state's event on `subject`'s open connections: on a keyed
|
|
255
|
+
* state those that declared `key`, or every one when no key is given.
|
|
256
|
+
*/
|
|
257
|
+
revoke(target: RevokeTarget<T>): Promise<void>;
|
|
258
|
+
/** A keyed grant opens one key: without it there is no key to open and no value to send. */
|
|
259
|
+
private assertGrantKey;
|
|
260
|
+
/**
|
|
261
|
+
* The declared key fields of `key`, checked against `.key()`: an empty or
|
|
262
|
+
* partial key would match every connection of the subject. A field the
|
|
263
|
+
* declaration does not name is dropped, never matched on — so the check
|
|
264
|
+
* runs on a fresh object of the declared fields, never `.key()` itself: a
|
|
265
|
+
* key declared `additionalProperties: false` would otherwise refuse it.
|
|
266
|
+
* The fresh object keeps `.key()`'s `required`, and a key that still picks
|
|
267
|
+
* to nothing is refused: `undefined` here would mean every connection.
|
|
268
|
+
*/
|
|
269
|
+
private declaredKey;
|
|
270
|
+
private refuseKey;
|
|
271
|
+
private with;
|
|
272
|
+
private assertOnce;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Declare a server-owned state.
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```typescript
|
|
279
|
+
* export const consent = defineState('consent')
|
|
280
|
+
* .value(Type.Union([Type.Literal('pending'), Type.Literal('agreed')]))
|
|
281
|
+
* .read(({ subject }) => consents.current(subject));
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
declare function defineState<TId extends string>(id: TId): StateBuilder<TId, EmptyStateShape>;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* State Routes
|
|
288
|
+
*
|
|
289
|
+
* The read, write and snapshot routes a state router derives. They are
|
|
290
|
+
* ordinary `RouteDef`s registered through `registerRoutes`, so a state's
|
|
291
|
+
* `.use()` middleware runs inside the route's own chain after the app's
|
|
292
|
+
* global middleware.
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
/** Who a request is for. `null` answers 401. */
|
|
296
|
+
type SubjectResolver = (c: Context) => string | null;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* State Router
|
|
300
|
+
*
|
|
301
|
+
* Groups states, derives their routes into one `Router` the app mounts with
|
|
302
|
+
* `.packages()`, collects their SSE events for the app's event router, and
|
|
303
|
+
* subscribes each state's change signal — once, here.
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
interface StateRouterOptions {
|
|
307
|
+
/**
|
|
308
|
+
* Where the routes are mounted: `GET <path>`, `GET|PUT <path>/<id>`.
|
|
309
|
+
* @default '/state'
|
|
310
|
+
*/
|
|
311
|
+
path?: string;
|
|
312
|
+
/**
|
|
313
|
+
* Who an HTTP request is for. `null` answers 401.
|
|
314
|
+
* @default (c) => c.get('auth')?.userId ?? null
|
|
315
|
+
*/
|
|
316
|
+
subject?: SubjectResolver;
|
|
317
|
+
}
|
|
318
|
+
type Shape<S extends RoutableState> = S['_types'];
|
|
319
|
+
type KeyQuery<S extends RoutableState> = Shape<S>['key'] extends TObject ? {
|
|
320
|
+
query: Shape<S>['key'];
|
|
321
|
+
} : {};
|
|
322
|
+
type ReadRoutes<S extends Record<string, RoutableState>> = {
|
|
323
|
+
[K in keyof S as `get${Capitalize<S[K]['id']>}State`]: RouteDef<KeyQuery<S[K]>, {}, StateSnapshot<Shape<S[K]>>>;
|
|
324
|
+
};
|
|
325
|
+
type WriteInput<S extends RoutableState> = KeyQuery<S> & {
|
|
326
|
+
body: Shape<S>['input'];
|
|
327
|
+
};
|
|
328
|
+
type WriteRoutes<S extends Record<string, RoutableState>> = {
|
|
329
|
+
[K in keyof S as Shape<S[K]>['input'] extends TSchema ? `put${Capitalize<S[K]['id']>}State` : never]: RouteDef<WriteInput<S[K]>, {}, StateSnapshot<Shape<S[K]>>>;
|
|
330
|
+
};
|
|
331
|
+
/** What `GET <path>` answers: every state the subject may read and whose key the query carries. */
|
|
332
|
+
type StatesSnapshot<S extends Record<string, RoutableState>> = {
|
|
333
|
+
at: string;
|
|
334
|
+
states: {
|
|
335
|
+
[K in keyof S as S[K]['id']]?: StateResult<Shape<S[K]>>;
|
|
336
|
+
};
|
|
337
|
+
};
|
|
338
|
+
/** The routes one state router derives, typed for `createApi` and the route map. */
|
|
339
|
+
type StateRoutes<S extends Record<string, RoutableState>> = ReadRoutes<S> & WriteRoutes<S> & {
|
|
340
|
+
getStates: RouteDef<{
|
|
341
|
+
query: TObject;
|
|
342
|
+
}, {}, StatesSnapshot<S>>;
|
|
343
|
+
};
|
|
344
|
+
/** The SSE events, keyed by their wire names, for the app's `defineEventRouter`. */
|
|
345
|
+
type StateEvents<S extends Record<string, RoutableState>> = {
|
|
346
|
+
[K in keyof S as `state.${S[K]['id']}.changed`]: EventDef<StateFrame<Shape<S[K]>>>;
|
|
347
|
+
};
|
|
348
|
+
interface StateRouter<S extends Record<string, RoutableState>> {
|
|
349
|
+
/** The derived routes. Mount with `appRouter.packages([states.router])`. */
|
|
350
|
+
router: Router<StateRoutes<S>>;
|
|
351
|
+
/** The derived SSE events. Spread into `defineEventRouter({ ...appEvents, ...states.events })`. */
|
|
352
|
+
events: StateEvents<S>;
|
|
353
|
+
/** The declarations, as given. */
|
|
354
|
+
states: S;
|
|
355
|
+
}
|
|
356
|
+
type StateById<R extends StateRouter<any>, TId extends string> = Extract<R['states'][keyof R['states']], {
|
|
357
|
+
id: TId;
|
|
358
|
+
}>;
|
|
359
|
+
/** The value type of state `TId` of a state router. */
|
|
360
|
+
type InferStateValue<R extends StateRouter<any>, TId extends string> = StateValue<Shape<StateById<R, TId>>>;
|
|
361
|
+
/** The key type of state `TId`, `undefined` when it is keyless. */
|
|
362
|
+
type InferStateKey<R extends StateRouter<any>, TId extends string> = StateKey<Shape<StateById<R, TId>>>;
|
|
363
|
+
/** The write input of state `TId`, `never` when it declares no `.write()`. */
|
|
364
|
+
type InferStateInput<R extends StateRouter<any>, TId extends string> = Shape<StateById<R, TId>>['input'] extends TSchema ? Static<Shape<StateById<R, TId>>['input']> : never;
|
|
365
|
+
/**
|
|
366
|
+
* Group states, derive their routes and SSE events, and subscribe their change
|
|
367
|
+
* signals.
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```typescript
|
|
371
|
+
* export const states = defineStateRouter({ consent, runtime, member });
|
|
372
|
+
*
|
|
373
|
+
* // server.config.ts
|
|
374
|
+
* // .routes(appRouter.packages([states.router]))
|
|
375
|
+
* // .events(defineEventRouter({ ...appEvents, ...states.events }), { auth: { enabled: true } })
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
declare function defineStateRouter<S extends Record<string, RoutableState>>(states: S, options?: StateRouterOptions): StateRouter<S>;
|
|
379
|
+
|
|
380
|
+
export { type ChangedPayload, type GrantTarget, type InferStateInput, type InferStateKey, type InferStateValue, type PermissionContext, type ReadContext, type RevokeTarget, type RoutableState, StateBuilder, type StateContract, type StateEvents, type StateFrame, type StateKey, type StateResult, type StateRouter, type StateRouterOptions, type StateRoutes, type StateShape, type StateSnapshot, type StateValue, type StateWriteOptions, type StatesSnapshot, type SubjectResolver, type WriteContext, defineState, defineStateRouter };
|