@live-state/sync 0.0.7 → 1.0.0-canary-2

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/dist/server.d.ts CHANGED
@@ -1,14 +1,20 @@
1
1
  import { z } from 'zod';
2
- import { L as LiveObjectAny, I as IncludeClause, a as InferLiveObject, W as WhereClause, S as Simplify, b as InferInsert, c as InferUpdate, M as MaterializedLiveType, d as Schema, e as LiveCollectionAny, f as InferLiveCollection, g as InferLiveObjectWithRelationalIds, h as Logger, i as LogLevel } from './index-hO1iQ-VU.js';
2
+ import { L as LiveObjectAny, I as IncludeClause, W as WhereClause, S as Simplify, a as InferLiveObject, b as InferInsert, c as InferUpdate, d as Schema, e as LiveCollectionAny, f as InferLiveCollection, g as InferLiveObjectWithRelationalIds, M as MaterializedLiveType, h as Logger, i as LogLevel } from './index-hO1iQ-VU.js';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
4
  import { PostgresPool, Kysely } from 'kysely';
5
5
  import { Application } from 'express-ws';
6
6
 
7
+ /**
8
+ * Internal Tracked Query representation. A Custom Query handler returns an
9
+ * unresolved query builder; the server mints a `RawQueryRequest` from it via
10
+ * `buildQueryRequest()`, which the query engine subscribes and resolves against
11
+ * storage. This is **not** an inbound client→server message — clients can only
12
+ * invoke named Custom Query procedures (see ADR-0002).
13
+ */
7
14
  declare const querySchema: z.ZodObject<{
8
15
  resource: z.ZodString;
9
16
  where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
10
17
  include: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
11
- lastSyncedAt: z.ZodOptional<z.ZodString>;
12
18
  limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
13
19
  sort: z.ZodOptional<z.ZodArray<z.ZodObject<{
14
20
  key: z.ZodString;
@@ -19,14 +25,15 @@ declare const querySchema: z.ZodObject<{
19
25
  }, z.core.$strip>>>;
20
26
  }, z.core.$strip>;
21
27
  type RawQueryRequest = z.infer<typeof querySchema>;
22
- declare const defaultMutationSchema: z.ZodObject<{
28
+ declare const syncDeltaSchema: z.ZodObject<{
23
29
  id: z.ZodOptional<z.ZodString>;
24
- type: z.ZodLiteral<"MUTATE">;
30
+ type: z.ZodLiteral<"SYNC">;
25
31
  resource: z.ZodString;
26
- resourceId: z.ZodOptional<z.ZodString>;
27
- procedure: z.ZodEnum<{
32
+ resourceId: z.ZodString;
33
+ op: z.ZodEnum<{
28
34
  INSERT: "INSERT";
29
35
  UPDATE: "UPDATE";
36
+ DELETE: "DELETE";
30
37
  }>;
31
38
  payload: z.ZodRecord<z.ZodString, z.ZodObject<{
32
39
  value: z.ZodNullable<z.ZodAny>;
@@ -39,83 +46,43 @@ declare const defaultMutationSchema: z.ZodObject<{
39
46
  originMutationId: z.ZodOptional<z.ZodString>;
40
47
  }, z.core.$strip>>;
41
48
  }, z.core.$strip>;
42
- type DefaultMutation = Omit<z.infer<typeof defaultMutationSchema>, "resourceId"> & {
43
- resourceId: string;
44
- };
49
+ type SyncDelta = z.infer<typeof syncDeltaSchema>;
45
50
 
46
51
  type ConditionalPromise<T, P extends boolean> = P extends true ? Promise<T> : T;
47
52
  type PromiseOrSync<T> = T | Promise<T>;
48
53
 
49
- /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
50
-
51
- declare abstract class Storage implements DataSource {
52
- /**
53
- * @deprecated Use db.[collection].one(id).get() instead
54
- */
55
- abstract findOne<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, id: string, options?: {
56
- include?: TInclude;
57
- }): Promise<InferLiveObject<T, TInclude> | undefined>;
58
- /**
59
- * @deprecated Use db.[collection].where({...}).get() instead
60
- */
61
- abstract find<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, options?: {
62
- where?: WhereClause<T>;
63
- include?: TInclude;
64
- limit?: number;
65
- sort?: {
66
- key: string;
67
- direction: "asc" | "desc";
68
- }[];
69
- }): Promise<InferLiveObject<T, TInclude>[]>;
70
- /**
71
- * @deprecated Use db.[collection].insert({...}) instead
72
- */
73
- insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
74
- /**
75
- * @deprecated Use db.[collection].update(id, {...}) instead
76
- */
77
- update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
78
- abstract transaction<T>(fn: (opts: {
79
- trx: Storage;
80
- commit: () => Promise<void>;
81
- rollback: () => Promise<void>;
82
- }) => Promise<T>): Promise<T>;
83
- }
84
-
85
- /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
86
-
87
- declare class Batcher {
88
- private storage;
89
- private queue;
90
- private scheduled;
91
- constructor(storage: Storage);
92
- rawFind<T extends LiveObjectAny>({ resource, commonWhere, uniqueWhere, ...rest }: {
93
- resource: string;
94
- commonWhere?: Record<string, any>;
95
- uniqueWhere?: Record<string, any>;
96
- include?: Record<string, any>;
97
- limit?: number;
98
- sort?: {
99
- key: string;
100
- direction: "asc" | "desc";
101
- }[];
102
- }): Promise<MaterializedLiveType<T>[]>;
103
- private getBatchKey;
104
- private processBatch;
105
- private executeBatchedRequests;
106
- }
107
-
108
54
  interface DataSource {
109
55
  get(query: RawQueryRequest, extra?: {
110
56
  context?: any;
111
- batcher?: Batcher;
112
57
  }): PromiseOrSync<any[]>;
113
58
  }
114
59
 
115
60
  /** biome-ignore-all lint/complexity/noBannedTypes: <explanation> */
116
61
 
62
+ interface QueryExecutor extends DataSource {
63
+ subscribe(query: RawQueryRequest, callback: (value: any[]) => void): () => void;
64
+ }
117
65
  type InferQueryResult<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection>, TSingle extends boolean = false> = TSingle extends true ? Simplify<InferLiveObject<TCollection, TInclude>> | undefined : Simplify<InferLiveObject<TCollection, TInclude>>[];
66
+ /**
67
+ * Type-only brand recording a {@link QueryBuilder}'s inferable parameters.
68
+ *
69
+ * `CustomQueryResult` (client entry point) has to recognise a query-builder
70
+ * value returned from a route handler whose type flows through the *server*
71
+ * entry point. The two entry points are emitted as separate `.d.ts` graphs, so
72
+ * each gets its own `declare class QueryBuilder`; because the class has
73
+ * `private` members, TypeScript compares those declarations *nominally* and any
74
+ * `extends QueryBuilder<...>` check across the boundary fails. Narrowing on this
75
+ * structural brand instead makes the check independent of class identity — and
76
+ * therefore also of duplicate installed package versions.
77
+ */
78
+ interface QueryBuilderBrand<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection>, TSingle extends boolean> {
79
+ collection: TCollection;
80
+ include: TInclude;
81
+ single: TSingle;
82
+ }
118
83
  declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection> = {}, TSingle extends boolean = false, TShouldAwait extends boolean = false> {
84
+ /** Never assigned at runtime; exists only to carry {@link QueryBuilderBrand}. */
85
+ readonly __queryBuilderBrand: QueryBuilderBrand<TCollection, TInclude, TSingle>;
119
86
  private _collection;
120
87
  private _client;
121
88
  private _where;
@@ -148,6 +115,42 @@ declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends I
148
115
 
149
116
  /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
150
117
 
118
+ declare abstract class Storage implements DataSource {
119
+ /**
120
+ * @deprecated Use db.[collection].one(id).get() instead
121
+ */
122
+ abstract findOne<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, id: string, options?: {
123
+ include?: TInclude;
124
+ }): Promise<InferLiveObject<T, TInclude> | undefined>;
125
+ /**
126
+ * @deprecated Use db.[collection].where({...}).get() instead
127
+ */
128
+ abstract find<T extends LiveObjectAny, TInclude extends IncludeClause<T> | undefined = undefined>(resource: T, options?: {
129
+ where?: WhereClause<T>;
130
+ include?: TInclude;
131
+ limit?: number;
132
+ sort?: {
133
+ key: string;
134
+ direction: "asc" | "desc";
135
+ }[];
136
+ }): Promise<InferLiveObject<T, TInclude>[]>;
137
+ /**
138
+ * @deprecated Use db.[collection].insert({...}) instead
139
+ */
140
+ insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
141
+ /**
142
+ * @deprecated Use db.[collection].update(id, {...}) instead
143
+ */
144
+ update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
145
+ abstract transaction<T>(fn: (opts: {
146
+ trx: Storage;
147
+ commit: () => Promise<void>;
148
+ rollback: () => Promise<void>;
149
+ }) => Promise<T>): Promise<T>;
150
+ }
151
+
152
+ /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
153
+
151
154
  /**
152
155
  * A QueryBuilder with added insert() and update() mutation methods for server-side use.
153
156
  */
@@ -214,100 +217,20 @@ type ServerDB<TSchema extends Schema<any>> = {
214
217
  */
215
218
  declare function createServerDB<TSchema extends Schema<any>>(storage: Storage, schema: TSchema, context?: Record<string, any>): ServerDB<TSchema>;
216
219
 
217
- /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
218
- /** biome-ignore-all lint/style/noNonNullAssertion: false positive */
220
+ /** biome-ignore-all lint/suspicious/noExplicitAny: hooks operate generically over any entity shape */
219
221
 
220
- type AnyProcedureRoute = ProcedureRoute<Middleware<any>, Record<string, any>, Record<string, any>, any, any>;
221
- type AnyRouteOrProcedure = AnyRoute | AnyProcedureRoute;
222
- type RouteRecord = Record<string, AnyRouteOrProcedure>;
223
- declare class Router<TRoutes extends RouteRecord> {
224
- readonly routes: TRoutes;
225
- readonly hooksRegistry: Map<string, Hooks<any, any, any>>;
226
- private constructor();
227
- static create<TRoutes extends RouteRecord>(opts: {
228
- routes: TRoutes;
229
- }): Router<TRoutes>;
230
- getHooks(resourceName: string): Hooks<any, any, any> | undefined;
231
- }
232
- declare const router: <TSchema extends Schema<any>, TRoutes extends Record<keyof TSchema, Route<any, any, any, any, any, any>> & Record<string, Route<any, any, any, any, any, any> | ProcedureRoute<any, any, any, any, any>>>(opts: {
233
- schema: TSchema;
234
- routes: TRoutes;
235
- }) => Router<TRoutes>;
236
- type AnyRouter = Router<any>;
237
- type QueryResult<TShape extends LiveObjectAny> = {
238
- data: MaterializedLiveType<TShape>[];
239
- unsubscribe?: () => void;
240
- };
241
- type MutationResult<TShape extends LiveObjectAny> = {
242
- data: MaterializedLiveType<TShape>;
243
- acceptedValues: Record<string, any> | null;
244
- };
245
- type Mutation<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput, TContext = Record<string, any>> = {
246
- _type: "mutation";
247
- inputValidator: TInputValidator;
248
- handler: (opts: {
249
- req: MutationRequest<TInputValidator extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<TInputValidator> : undefined, TContext>;
250
- db: ServerDB<any>;
251
- }) => TOutput;
252
- };
253
- interface QueryProcedureRequest<TInput = any, TContext = Record<string, any>> extends BaseRequest<TContext> {
254
- type: "CUSTOM_QUERY";
255
- input: TInput;
256
- resource: string;
257
- procedure: string;
258
- }
259
- type Query<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput, TContext = Record<string, any>> = {
260
- _type: "query";
261
- inputValidator: TInputValidator;
262
- handler: (opts: {
263
- req: QueryProcedureRequest<TInputValidator extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<TInputValidator> : undefined, TContext>;
264
- db: ServerDB<any>;
265
- }) => TOutput;
266
- };
267
- type Procedure<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput, TContext = Record<string, any>> = Mutation<TInputValidator, TOutput, TContext> | Query<TInputValidator, TOutput, TContext>;
268
- type QueryCreator<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> = {
269
- (): {
270
- handler: <TOutput>(handler: (opts: {
271
- req: QueryProcedureRequest<undefined, TContext>;
272
- db: ServerDB<TSchema>;
273
- }) => TOutput) => Query<StandardSchemaV1<any, undefined>, TOutput, TContext>;
274
- };
275
- <TInputValidator extends StandardSchemaV1<any, any>>(validator: TInputValidator): {
276
- handler: <THandler extends (opts: {
277
- req: QueryProcedureRequest<StandardSchemaV1.InferOutput<TInputValidator>, TContext>;
278
- db: ServerDB<TSchema>;
279
- }) => any>(handler: THandler) => Query<TInputValidator, ReturnType<THandler>, TContext>;
280
- };
281
- };
282
- type MutationCreator<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> = {
283
- (): {
284
- handler: <TOutput>(handler: (opts: {
285
- req: MutationRequest<undefined, TContext>;
286
- db: ServerDB<TSchema>;
287
- }) => TOutput) => Mutation<StandardSchemaV1<any, undefined>, TOutput, TContext>;
288
- };
289
- <TInputValidator extends StandardSchemaV1<any, any>>(validator: TInputValidator): {
290
- handler: <THandler extends (opts: {
291
- req: MutationRequest<StandardSchemaV1.InferOutput<TInputValidator>, TContext>;
292
- db: ServerDB<TSchema>;
293
- }) => any>(handler: THandler) => Mutation<TInputValidator, ReturnType<THandler>, TContext>;
294
- };
295
- };
296
- type ReadAuthorizationHandler<TShape extends LiveObjectAny, TContext = Record<string, any>> = (opts: {
297
- ctx: TContext;
298
- }) => WhereClause<TShape> | boolean;
299
- type MutationAuthorizationHandler<TShape extends LiveObjectAny, TContext = Record<string, any>> = (opts: {
300
- ctx: TContext;
301
- value: Simplify<InferLiveObjectWithRelationalIds<TShape>>;
302
- }) => WhereClause<TShape> | boolean;
303
- type Authorization<TShape extends LiveObjectAny, TContext = Record<string, any>> = {
304
- read?: ReadAuthorizationHandler<TShape, TContext>;
305
- insert?: MutationAuthorizationHandler<TShape, TContext>;
306
- update?: {
307
- preMutation?: MutationAuthorizationHandler<TShape, TContext>;
308
- postMutation?: MutationAuthorizationHandler<TShape, TContext>;
309
- };
310
- };
222
+ /**
223
+ * Database lifecycle hooks.
224
+ *
225
+ * These fire from the storage layer around every committed write (insert /
226
+ * update), regardless of how the write was produced — a custom mutation
227
+ * handler calling `db.x.insert(...)`, a transaction, etc. They are *not* tied
228
+ * to a particular mutation procedure.
229
+ *
230
+ * `before*` handlers may return a transformed raw value to replace what gets
231
+ * persisted; returning `void` leaves the value unchanged. `after*` handlers run
232
+ * once the write is committed.
233
+ */
311
234
  type BeforeInsertHook<TShape extends LiveObjectAny, TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> = (opts: {
312
235
  ctx?: TContext;
313
236
  value: Simplify<InferLiveObjectWithRelationalIds<TShape>> & {
@@ -354,73 +277,8 @@ type Hooks<TShape extends LiveObjectAny, TSchema extends Schema<any> = Schema<an
354
277
  beforeUpdate?: BeforeUpdateHook<TShape, TSchema, TContext>;
355
278
  afterUpdate?: AfterUpdateHook<TShape, TSchema, TContext>;
356
279
  };
357
- declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>, TCustomQueries extends Record<string, Query<any, any>>, TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> {
358
- readonly resourceSchema: TResourceSchema;
359
- readonly middlewares: Set<TMiddleware>;
360
- readonly customMutations: TCustomMutations;
361
- readonly customQueries: TCustomQueries;
362
- readonly authorization?: Authorization<TResourceSchema, TContext>;
363
- readonly hooks?: Hooks<TResourceSchema, TSchema, TContext>;
364
- constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, customQueries?: TCustomQueries, authorization?: Authorization<TResourceSchema, TContext>, hooks?: Hooks<TResourceSchema, TSchema, TContext>);
365
- use(...middlewares: TMiddleware[]): this;
366
- withProcedures<T extends Record<string, Procedure<any, any, any>>>(procedureFactory: (opts: {
367
- mutation: MutationCreator<TSchema, TContext>;
368
- query: QueryCreator<TSchema, TContext>;
369
- }) => T): Route<TResourceSchema, TMiddleware, { [K in keyof T as T[K] extends Mutation<any, any, Record<string, any>> ? K : never]: Extract<T[K], Mutation<any, any, Record<string, any>>>; }, { [K_1 in keyof T as T[K_1] extends Query<any, any, Record<string, any>> ? K_1 : never]: Extract<T[K_1], Query<any, any, Record<string, any>>>; }, TSchema, TContext>;
370
- /**
371
- * @deprecated Use `withProcedures` instead
372
- */
373
- withMutations<T extends Record<string, Mutation<any, any>>>(mutationFactory: (opts: {
374
- mutation: MutationCreator<TSchema, TContext>;
375
- }) => T): Route<TResourceSchema, TMiddleware, { [K in keyof T as T[K] extends Mutation<any, any, Record<string, any>> ? K : never]: Extract<T[K], Mutation<any, any, Record<string, any>>>; }, { [K_1 in keyof T as T[K_1] extends Query<any, any, Record<string, any>> ? K_1 : never]: Extract<T[K_1], Query<any, any, Record<string, any>>>; }, TSchema, TContext>;
376
- /**
377
- * @deprecated Declare hooks with `defineHooks` and pass them to `server({ hooks })` instead.
378
- */
379
- withHooks(hooks: Hooks<TResourceSchema, TSchema, TContext>): Route<TResourceSchema, TMiddleware, TCustomMutations, TCustomQueries, TSchema, TContext>;
380
- getAuthorizationClause(req: QueryRequest): WhereClause<TResourceSchema> | undefined | boolean;
381
- private handleSet;
382
- private wrapInMiddlewares;
383
- }
384
- declare class ProcedureRoute<TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>, TCustomQueries extends Record<string, Query<any, any>>, TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> {
385
- readonly resourceSchema: undefined;
386
- readonly middlewares: Set<TMiddleware>;
387
- readonly customMutations: TCustomMutations;
388
- readonly customQueries: TCustomQueries;
389
- constructor(customMutations?: TCustomMutations, customQueries?: TCustomQueries);
390
- use(...middlewares: TMiddleware[]): this;
391
- getAuthorizationClause(): undefined;
392
- private wrapInMiddlewares;
393
- }
394
- type TypedMiddleware<TContextIn, TContextOut> = {
395
- _brand: "TypedMiddleware";
396
- _rawMiddleware: Middleware<any>;
397
- _contextIn?: TContextIn;
398
- _contextOut?: TContextOut;
399
- };
400
- declare function createMiddleware<TContextIn, TContextOut = TContextIn>(fn: (opts: {
401
- ctx: TContextIn;
402
- req: Request<TContextIn>;
403
- next: (ctx: TContextOut) => any;
404
- }) => any): TypedMiddleware<TContextIn, TContextOut>;
405
- declare class RouteFactory<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> {
406
- private middlewares;
407
- private constructor();
408
- collectionRoute<T extends LiveObjectAny>(shape: T, authorization?: Authorization<T, TContext>): Route<T, Middleware<any>, Record<string, never>, Record<string, never>, TSchema, TContext>;
409
- withProcedures<T extends Record<string, Procedure<any, any, any>>>(procedureFactory: (opts: {
410
- mutation: MutationCreator<TSchema, TContext>;
411
- query: QueryCreator<TSchema, TContext>;
412
- }) => T): ProcedureRoute<Middleware<any>, { [K in keyof T as T[K] extends Mutation<any, any, Record<string, any>> ? K : never]: T[K]; } & Record<string, Mutation<any, any, Record<string, any>>>, { [K_1 in keyof T as T[K_1] extends Query<any, any, Record<string, any>> ? K_1 : never]: T[K_1]; } & Record<string, Query<any, any, Record<string, any>>>, TSchema, TContext>;
413
- use<TNewContext>(mw: TypedMiddleware<TContext, TNewContext>): RouteFactory<TSchema, TNewContext>;
414
- use(...middlewares: Middleware<any>[]): RouteFactory<TSchema, TContext>;
415
- static create<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>>(): RouteFactory<TSchema, TContext>;
416
- }
417
- declare const routeFactory: typeof RouteFactory.create;
418
- type AnyRoute = Route<LiveObjectAny, Middleware<any>, Record<string, any>, Record<string, any>, any, any>;
419
-
420
- /** biome-ignore-all lint/suspicious/noExplicitAny: hooks operate generically over any entity shape */
421
-
422
280
  /**
423
- * Schema-keyed registry of lifecycle hooks.
281
+ * Schema-keyed registry of database lifecycle hooks.
424
282
  *
425
283
  * Top-level keys are constrained to entity names on `TSchema`. Per-entity
426
284
  * payloads (`value`, `rawValue`, `previousValue`, …) are inferred from the
@@ -430,11 +288,11 @@ type HooksRegistry<TSchema extends Schema<any>, TContext = Record<string, any>>
430
288
  [K in keyof TSchema]?: TSchema[K] extends LiveObjectAny ? Hooks<TSchema[K], TSchema, TContext> : never;
431
289
  };
432
290
  /**
433
- * Declares lifecycle hooks for a schema.
291
+ * Declares database lifecycle hooks for a schema.
434
292
  *
435
293
  * Identity function whose generic parameters constrain the returned object's
436
294
  * top-level keys to schema entity names and thread `TContext` through to
437
- * handler payloads.
295
+ * handler payloads. Pass the result to `server({ hooks })`.
438
296
  *
439
297
  * @example
440
298
  * ```ts
@@ -466,6 +324,114 @@ declare const mergeEntityHooks: (slices: Array<AnyHooks | undefined>) => AnyHook
466
324
  */
467
325
  declare const mergeHooks: <TSchema extends Schema<any>, TContext = Record<string, any>>(...definitions: HooksRegistry<TSchema, TContext>[]) => HooksRegistry<TSchema, TContext>;
468
326
 
327
+ /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
328
+ /** biome-ignore-all lint/style/noNonNullAssertion: false positive */
329
+
330
+ type AnyRoute = Route<Middleware<any>, Record<string, any>, Record<string, any>, any, any>;
331
+ type RouteRecord = Record<string, AnyRoute>;
332
+ declare class Router<TRoutes extends RouteRecord, TSchema extends Schema<any> = Schema<any>> {
333
+ readonly routes: TRoutes;
334
+ readonly schema: TSchema;
335
+ private constructor();
336
+ static create<TRoutes extends RouteRecord, TSchema extends Schema<any>>(opts: {
337
+ routes: TRoutes;
338
+ schema: TSchema;
339
+ }): Router<TRoutes, TSchema>;
340
+ }
341
+ declare const router: <TSchema extends Schema<any>, TRoutes extends RouteRecord>(opts: {
342
+ schema: TSchema;
343
+ routes: TRoutes;
344
+ }) => Router<TRoutes, TSchema>;
345
+ type AnyRouter = Router<any, any>;
346
+ type Mutation<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput, TContext = Record<string, any>> = {
347
+ _type: 'mutation';
348
+ inputValidator: TInputValidator;
349
+ handler: (opts: {
350
+ req: MutationRequest<TInputValidator extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<TInputValidator> : undefined, TContext>;
351
+ db: ServerDB<any>;
352
+ }) => TOutput;
353
+ };
354
+ interface QueryProcedureRequest<TInput = any, TContext = Record<string, any>> extends BaseRequest<TContext> {
355
+ type: 'CUSTOM_QUERY';
356
+ input: TInput;
357
+ resource: string;
358
+ procedure: string;
359
+ }
360
+ type Query<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput, TContext = Record<string, any>> = {
361
+ _type: 'query';
362
+ inputValidator: TInputValidator;
363
+ handler: (opts: {
364
+ req: QueryProcedureRequest<TInputValidator extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<TInputValidator> : undefined, TContext>;
365
+ db: ServerDB<any>;
366
+ }) => TOutput;
367
+ };
368
+ type Procedure<TInputValidator extends StandardSchemaV1<any, any> | never, TOutput, TContext = Record<string, any>> = Mutation<TInputValidator, TOutput, TContext> | Query<TInputValidator, TOutput, TContext>;
369
+ type QueryCreator<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> = {
370
+ (): {
371
+ handler: <TOutput>(handler: (opts: {
372
+ req: QueryProcedureRequest<undefined, TContext>;
373
+ db: ServerDB<TSchema>;
374
+ }) => TOutput) => Query<StandardSchemaV1<any, undefined>, TOutput, TContext>;
375
+ };
376
+ <TInputValidator extends StandardSchemaV1<any, any>>(validator: TInputValidator): {
377
+ handler: <THandler extends (opts: {
378
+ req: QueryProcedureRequest<StandardSchemaV1.InferOutput<TInputValidator>, TContext>;
379
+ db: ServerDB<TSchema>;
380
+ }) => any>(handler: THandler) => Query<TInputValidator, ReturnType<THandler>, TContext>;
381
+ };
382
+ };
383
+ type MutationCreator<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> = {
384
+ (): {
385
+ handler: <TOutput>(handler: (opts: {
386
+ req: MutationRequest<undefined, TContext>;
387
+ db: ServerDB<TSchema>;
388
+ }) => TOutput) => Mutation<StandardSchemaV1<any, undefined>, TOutput, TContext>;
389
+ };
390
+ <TInputValidator extends StandardSchemaV1<any, any>>(validator: TInputValidator): {
391
+ handler: <THandler extends (opts: {
392
+ req: MutationRequest<StandardSchemaV1.InferOutput<TInputValidator>, TContext>;
393
+ db: ServerDB<TSchema>;
394
+ }) => any>(handler: THandler) => Mutation<TInputValidator, ReturnType<THandler>, TContext>;
395
+ };
396
+ };
397
+ declare class Route<TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>, TCustomQueries extends Record<string, Query<any, any>>, TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> {
398
+ readonly middlewares: Set<TMiddleware>;
399
+ readonly customMutations: TCustomMutations;
400
+ readonly customQueries: TCustomQueries;
401
+ constructor(customMutations?: TCustomMutations, customQueries?: TCustomQueries);
402
+ use(...middlewares: TMiddleware[]): this;
403
+ private wrapInMiddlewares;
404
+ }
405
+ type TypedMiddleware<TContextIn, TContextOut> = {
406
+ _brand: 'TypedMiddleware';
407
+ _rawMiddleware: Middleware<any>;
408
+ _contextIn?: TContextIn;
409
+ _contextOut?: TContextOut;
410
+ };
411
+ declare function createMiddleware<TContextIn, TContextOut = TContextIn>(fn: (opts: {
412
+ ctx: TContextIn;
413
+ req: Request<TContextIn>;
414
+ next: (ctx: TContextOut) => any;
415
+ }) => any): TypedMiddleware<TContextIn, TContextOut>;
416
+ declare class RouteFactory<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>> {
417
+ private middlewares;
418
+ private constructor();
419
+ withProcedures<T extends Record<string, Procedure<any, any, any>>>(procedureFactory: (opts: {
420
+ mutation: MutationCreator<TSchema, TContext>;
421
+ query: QueryCreator<TSchema, TContext>;
422
+ }) => T): Route<Middleware<any>, { [K in keyof T as T[K] extends Mutation<any, any, Record<string, any>> ? K : never]: Extract<T[K], Mutation<any, any, Record<string, any>>>; }, { [K_1 in keyof T as T[K_1] extends Query<any, any, Record<string, any>> ? K_1 : never]: Extract<T[K_1], Query<any, any, Record<string, any>>>; }, TSchema, TContext>;
423
+ /**
424
+ * @deprecated Use `withProcedures` instead
425
+ */
426
+ withMutations<T extends Record<string, Mutation<any, any>>>(mutationFactory: (opts: {
427
+ mutation: MutationCreator<TSchema, TContext>;
428
+ }) => T): Route<Middleware<any>, { [K in keyof T as T[K] extends Mutation<any, any, Record<string, any>> ? K : never]: Extract<T[K], Mutation<any, any, Record<string, any>>>; }, { [K_1 in keyof T as T[K_1] extends Query<any, any, Record<string, any>> ? K_1 : never]: Extract<T[K_1], Query<any, any, Record<string, any>>>; }, TSchema, TContext>;
429
+ use<TNewContext>(mw: TypedMiddleware<TContext, TNewContext>): RouteFactory<TSchema, TNewContext>;
430
+ use(...middlewares: Middleware<any>[]): RouteFactory<TSchema, TContext>;
431
+ static create<TSchema extends Schema<any> = Schema<any>, TContext = Record<string, any>>(): RouteFactory<TSchema, TContext>;
432
+ }
433
+ declare const routeFactory: typeof RouteFactory.create;
434
+
469
435
  /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
470
436
 
471
437
  declare class SQLStorage extends Storage {
@@ -528,18 +494,18 @@ interface BaseRequest<TContext = Record<string, any>> {
528
494
  context: TContext;
529
495
  }
530
496
  interface QueryRequest<TContext = Record<string, any>> extends BaseRequest<TContext>, RawQueryRequest {
531
- type: "QUERY";
497
+ type: 'QUERY';
532
498
  }
533
499
  interface MutationRequest<TInput = any, TContext = Record<string, any>> extends BaseRequest<TContext> {
534
- type: "MUTATE";
500
+ type: 'MUTATE';
535
501
  input: TInput;
536
502
  resource: string;
537
503
  resourceId?: string;
538
504
  procedure: string;
539
505
  }
540
506
  type Request<TContext = Record<string, any>> = QueryRequest<TContext> | MutationRequest<any, TContext> | QueryProcedureRequest<any, TContext>;
541
- type ContextProvider<TContext = Record<string, any>> = (req: Omit<BaseRequest, "context"> & {
542
- transport: "HTTP" | "WEBSOCKET";
507
+ type ContextProvider<TContext = Record<string, any>> = (req: Omit<BaseRequest, 'context'> & {
508
+ transport: 'HTTP' | 'WEBSOCKET';
543
509
  }) => TContext | Promise<TContext>;
544
510
  type NextFunction<O, R = Request> = (req: R) => PromiseOrSync<O>;
545
511
  type Middleware<T = any> = (opts: {
@@ -575,16 +541,12 @@ declare class Server<TRouter extends AnyRouter, TContext = Record<string, any>>
575
541
  logLevel?: LogLevel;
576
542
  }): Server<TRouter, Record<string, any>>;
577
543
  getHooks(resourceName: string): Hooks<any, any, any> | undefined;
578
- handleQuery(opts: {
579
- req: QueryRequest;
580
- subscription?: (mutation: DefaultMutation) => void;
581
- }): Promise<QueryResult<any>>;
582
544
  handleMutation(opts: {
583
545
  req: MutationRequest;
584
546
  }): Promise<any>;
585
547
  handleCustomQuery(opts: {
586
548
  req: QueryProcedureRequest;
587
- subscription?: (mutation: DefaultMutation) => void;
549
+ subscription?: (mutation: SyncDelta) => void;
588
550
  }): Promise<any>;
589
551
  use(middleware: Middleware<any>): this;
590
552
  context(contextProvider: ContextProvider<TContext>): this;
@@ -593,4 +555,4 @@ declare class Server<TRouter extends AnyRouter, TContext = Record<string, any>>
593
555
  }
594
556
  declare const server: typeof Server.create;
595
557
 
596
- export { type AfterInsertHook, type AfterUpdateHook, type AnyProcedureRoute, type AnyRoute, type AnyRouteOrProcedure, type AnyRouter, type Authorization, type BaseRequest, type BeforeInsertHook, type BeforeUpdateHook, type ContextProvider, type Hooks, type HooksRegistry, type Middleware, type Mutation, type MutationAuthorizationHandler, type MutationRequest, type MutationResult, type NextFunction, type Procedure, ProcedureRoute, type Query, type QueryProcedureRequest, type QueryRequest, type QueryResult, type ReadAuthorizationHandler, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, type ServerCollection, type ServerDB, Storage, type TypedMiddleware, createMiddleware, createServerDB, defineHooks, expressAdapter, mergeEntityHooks, mergeHooks, routeFactory, router, server };
558
+ export { type AfterInsertHook, type AfterUpdateHook, type AnyRoute, type AnyRouter, type BaseRequest, type BeforeInsertHook, type BeforeUpdateHook, type ContextProvider, type Hooks, type HooksRegistry, type Middleware, type Mutation, type MutationRequest, type NextFunction, type Procedure, type Query, QueryBuilder, type QueryExecutor, type QueryProcedureRequest, type QueryRequest, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, type ServerCollection, type ServerDB, Storage, type TypedMiddleware, createMiddleware, createServerDB, defineHooks, expressAdapter, mergeEntityHooks, mergeHooks, routeFactory, router, server };