arri 0.13.0 → 0.15.1

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 CHANGED
@@ -149,7 +149,9 @@ Setup your npm scripts:
149
149
 
150
150
  ## Usage
151
151
 
152
- ### File Based Routing
152
+ ### Creating Procedures
153
+
154
+ #### File Based Routing
153
155
 
154
156
  Arri RPC comes with an optional file based router that will automatically register functions in the `./procedures` directory that end with the `.rpc.ts` file extension.
155
157
 
@@ -184,7 +186,7 @@ export default defineRpc({
184
186
  });
185
187
  ```
186
188
 
187
- #### Customizing the File Based Router
189
+ ##### Customizing the File Based Router
188
190
 
189
191
  ```ts
190
192
  export default defineConfig({
@@ -194,7 +196,7 @@ export default defineConfig({
194
196
  });
195
197
  ```
196
198
 
197
- ### Manual Routing
199
+ #### Manual Routing
198
200
 
199
201
  ```ts
200
202
  // using the app instance
@@ -208,6 +210,76 @@ router.rpc('sayHello', {...})
208
210
  app.use(router)
209
211
  ```
210
212
 
213
+ #### Creating Event Stream Procedures
214
+
215
+ Event stream procedures make use of [Server Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) to stream events to clients.
216
+
217
+ Normal events will have the event type `message`. Error events will have the event type `error`, and a `done` event will be sent when closing the connection. Additionally the `EventStreamConnection` will periodically since a `ping` event to keep the connection alive
218
+
219
+ ```ts
220
+ /// standard event ///
221
+ id: string | undefined;
222
+ event: "message";
223
+ data: Response; // whatever you have specified as the response serialized to json
224
+
225
+ /// error event ///
226
+ id: string | undefined;
227
+ event: "error";
228
+ data: ArriRequestError; // serialized to json
229
+
230
+ /// done event ///
231
+ event: "done";
232
+ data: "this stream has ended";
233
+
234
+ /// ping event ///
235
+ event: "ping";
236
+ data: "";
237
+ ```
238
+
239
+ ##### Example Usage:
240
+
241
+ ```ts
242
+ // procedures/users/watchUser.rpc.ts
243
+ export default defineEventStreamRpc({
244
+ params: a.object({
245
+ userId: a.string(),
246
+ }),
247
+ response: a.object({
248
+ id: a.string(),
249
+ name: a.string(),
250
+ createdAt: a.timestamp(),
251
+ updatedAt: a.timestamp(),
252
+ }),
253
+ handler({ params, connection }) {
254
+ // send a message every second
255
+ const interval = setInterval(async () => {
256
+ await connection.push({
257
+ id: "1",
258
+ name: "John Doe",
259
+ createdAt: new Date(),
260
+ updatedAt: new Date(),
261
+ });
262
+ }, 1000);
263
+ // cleanup when the client disconnects
264
+ connection.on("disconnect", () => {
265
+ clearInterval(interval);
266
+ });
267
+ // start streaming events to the client
268
+ connection.start();
269
+ },
270
+ });
271
+ ```
272
+
273
+ #### EventStreamConnection methods
274
+
275
+ ```ts
276
+ connection.push(data: Data, eventId?: string)
277
+ connection.pushError(error: ArriRequestError, eventId?: string)
278
+ connection.start()
279
+ connection.end()
280
+ connection.on(e: 'disconnect' | 'end', callback: () => any)
281
+ ```
282
+
211
283
  ### Adding Non-RPC Routes
212
284
 
213
285
  You can also add generic endpoints for instances when a message-based RPC endpoint doesn't fit.
package/dist/cli.cjs CHANGED
@@ -12,7 +12,7 @@ const esbuild = require('esbuild');
12
12
  const esbuildPluginReplace = require('esbuild-plugin-replace');
13
13
  const path = require('pathe');
14
14
  const prettier = require('prettier');
15
- const config = require('./shared/arri.165b8604.cjs');
15
+ const config = require('./shared/arri.2eb37786.cjs');
16
16
  const globby = require('globby');
17
17
  const scule = require('scule');
18
18
  const arriCodegenDart = require('arri-codegen-dart');
@@ -93,11 +93,7 @@ async function createAppWithRoutesModule(config) {
93
93
  for(const route of routes) {
94
94
  app.rpc({
95
95
  name: route.id,
96
- method: route.route.method,
97
- params: route.route.params,
98
- response: route.route.response,
99
- handler: route.route.handler,
100
- postHandler: route.route.postHandler,
96
+ ...route.route,
101
97
  });
102
98
  }
103
99
  export default app`,
package/dist/cli.mjs CHANGED
@@ -11,7 +11,7 @@ import { build as build$1 } from 'esbuild';
11
11
  import { replace } from 'esbuild-plugin-replace';
12
12
  import path from 'pathe';
13
13
  import prettier from 'prettier';
14
- import { n as defaultConfig, m as isResolvedArriConfig, a as DEV_DEFINITION_ENDPOINT } from './shared/arri.cc0da87a.mjs';
14
+ import { n as defaultConfig, m as isResolvedArriConfig, a as DEV_DEFINITION_ENDPOINT } from './shared/arri.28516ef9.mjs';
15
15
  import { globby } from 'globby';
16
16
  import { camelCase, kebabCase } from 'scule';
17
17
  import { dartClientGenerator } from 'arri-codegen-dart';
@@ -69,11 +69,7 @@ async function createAppWithRoutesModule(config) {
69
69
  for(const route of routes) {
70
70
  app.rpc({
71
71
  name: route.id,
72
- method: route.route.method,
73
- params: route.route.params,
74
- response: route.route.response,
75
- handler: route.route.handler,
76
- postHandler: route.route.postHandler,
72
+ ...route.route,
77
73
  });
78
74
  }
79
75
  export default app`,
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const config = require('./shared/arri.165b8604.cjs');
3
+ const config = require('./shared/arri.2eb37786.cjs');
4
4
  const h3 = require('h3');
5
5
  require('arri-validate');
6
6
  require('arri-codegen-utils');
@@ -13,24 +13,32 @@ exports.ArriRouter = config.ArriRouter;
13
13
  exports.DEV_DEFINITION_ENDPOINT = config.DEV_DEFINITION_ENDPOINT;
14
14
  exports.DEV_ENDPOINT_ROOT = config.DEV_ENDPOINT_ROOT;
15
15
  exports.ErrorResponse = config.ErrorResponse;
16
+ exports.EventStreamConnection = config.EventStreamConnection;
16
17
  exports.createRpcDefinition = config.createRpcDefinition;
17
18
  exports.defaultConfig = config.defaultConfig;
18
19
  exports.defineConfig = config.defineConfig;
19
20
  exports.defineError = config.defineError;
21
+ exports.defineEventStreamRpc = config.defineEventStreamRpc;
20
22
  exports.defineRoute = config.defineRoute;
21
23
  exports.defineRpc = config.defineRpc;
22
24
  exports.errorResponseFromValidationErrors = config.errorResponseFromValidationErrors;
25
+ exports.formatSse = config.formatSse;
26
+ exports.formatSseList = config.formatSseList;
23
27
  exports.getRpcParamName = config.getRpcParamName;
24
28
  exports.getRpcPath = config.getRpcPath;
25
29
  exports.getRpcResponseName = config.getRpcResponseName;
26
30
  exports.handleH3Error = config.handleH3Error;
27
31
  exports.handleRoute = config.handleRoute;
28
32
  exports.isArriConfig = config.isArriConfig;
33
+ exports.isEventStreamRpc = config.isEventStreamRpc;
29
34
  exports.isResolvedArriConfig = config.isResolvedArriConfig;
30
35
  exports.isRpc = config.isRpc;
31
36
  exports.isRpcParamSchema = config.isRpcParamSchema;
37
+ exports.registerEventStreamRpc = config.registerEventStreamRpc;
32
38
  exports.registerRoute = config.registerRoute;
33
39
  exports.registerRpc = config.registerRpc;
40
+ exports.setSseHeaders = config.setSseHeaders;
41
+ exports.validateRpcRequestInput = config.validateRpcRequestInput;
34
42
  exports.defineMiddleware = defineMiddleware;
35
43
  Object.keys(h3).forEach(function (k) {
36
44
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = h3[k];
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { HttpMethod, RpcHttpMethod, RpcDefinition, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
- import { AObjectSchema, ASchema, InferType, ARecordSchema, ADiscriminatorSchema, a, ValidationError } from 'arri-validate';
3
- import { H3EventContext, H3Event, Router, App, H3Error } from 'h3';
1
+ import { HttpMethod, RpcHttpMethod, RpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
+ import { AObjectSchema, ASchema, InferType, a, ValidationError, ARecordSchema, ADiscriminatorSchema } from 'arri-validate';
3
+ import { H3EventContext, H3Event, Router, H3Error, App } from 'h3';
4
4
  export * from 'h3';
5
5
  import { BuildOptions } from 'esbuild';
6
6
 
@@ -44,20 +44,103 @@ type RouteOptions = Pick<ArriOptions, "onAfterResponse" | "onBeforeResponse" | "
44
44
  declare function registerRoute(router: Router, route: ArriRoute<any>, opts: RouteOptions): void;
45
45
  declare function handleRoute(router: Router, method: HttpMethod, route: ArriRoute<any>, opts: RouteOptions): void;
46
46
 
47
+ declare const ErrorResponse: AObjectSchema<{
48
+ statusCode: number;
49
+ statusMessage: string;
50
+ stack?: string | undefined;
51
+ data?: any;
52
+ }, false>;
53
+ type ErrorResponse = a.infer<typeof ErrorResponse>;
54
+ declare function defineError(statusCode: StatusCode, input?: Partial<Omit<ErrorResponse, "statusCode" | "stack">> & {
55
+ stack?: string;
56
+ }): H3Error;
57
+ declare function errorResponseFromValidationErrors(errors: ValidationError["errors"], prefixText?: string): H3Error;
58
+ type StatusCode = number | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 507 | 511;
59
+ declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions["onError"]): Promise<void>;
60
+
61
+ declare function setSseHeaders(event: H3Event): void;
62
+ declare function defineEventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, "isEventStream">): EventStreamRpc<TParams, TResponse>;
63
+ declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
64
+ interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<Rpc<true, TParams, TResponse>, "handler" | "postHandler"> {
65
+ isEventStream: true;
66
+ handler: EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
67
+ }
68
+ type EventStreamRpcHandler<TParams, TResponse> = (context: EventStreamRpcHandlerContext<TParams, TResponse>, event: EventStreamRpcEvent<TParams, TResponse>) => void | Promise<void>;
69
+ interface EventStreamRpcEvent<TParams, TResponse> extends RpcEvent<TParams> {
70
+ connection: EventStreamConnection<TResponse>;
71
+ }
72
+ interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends RpcHandlerContext<TParams> {
73
+ connection: EventStreamConnection<TResponse>;
74
+ }
75
+ interface EventStreamConnectionOptions<TData> {
76
+ serializer: (input: TData) => string;
77
+ pingInterval?: number;
78
+ }
79
+ /**
80
+ * A server sent event
81
+ */
82
+ interface Sse {
83
+ id?: string;
84
+ event?: string;
85
+ data: string;
86
+ }
87
+ declare function formatSse({ id, data, event }: Sse): string;
88
+ declare function formatSseList(events: Sse[]): string;
89
+ declare class EventStreamConnection<TData> {
90
+ lastEventId: string | undefined;
91
+ private readonly writable;
92
+ private readonly readable;
93
+ private readonly writer;
94
+ private readonly encoder;
95
+ private readonly serializer;
96
+ private readonly h3Event;
97
+ private pingInterval;
98
+ private readonly pingIntervalMs;
99
+ constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
100
+ /**
101
+ * Start sending the event stream to the client
102
+ */
103
+ start(): void;
104
+ /**
105
+ * Publish a new event. Events published with this hook will trigger the `onData()` hooks of any connected clients.
106
+ */
107
+ push(data: TData[], eventId?: string): Promise<void>;
108
+ push(data: TData, eventId?: string): Promise<void>;
109
+ /**
110
+ * Publish an error event. This will trigger the `onError` hooks of any connected clients.
111
+ */
112
+ pushError(error: ErrorResponse, eventId?: string): Promise<void>;
113
+ private publishEvents;
114
+ private publishEvent;
115
+ private cleanup;
116
+ /**
117
+ * Tell clients that the stream has ended and close the connection.
118
+ */
119
+ end(): Promise<void>;
120
+ on(event: "disconnect", callback: () => any): void;
121
+ on(event: "end", callback: () => any): void;
122
+ }
123
+ declare function registerEventStreamRpc(router: Router, path: string, procedure: EventStreamRpc<any, any> & {
124
+ name: string;
125
+ }, opts: RouteOptions): void;
126
+
47
127
  type RpcParamSchema<TObjectInner = any, TRecordInner extends ASchema = any, TDiscriminatorInner = any> = AObjectSchema<TObjectInner> | ARecordSchema<TRecordInner> | ADiscriminatorSchema<TDiscriminatorInner>;
48
128
  declare function isRpcParamSchema(input: unknown): input is RpcParamSchema;
49
- interface ArriProcedure<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined> {
50
- description?: string;
129
+ interface NamedRpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Rpc<TIsEventStream, TParams, TResponse> {
130
+ name: string;
131
+ }
132
+ interface Rpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
51
133
  method?: RpcHttpMethod;
52
134
  path?: string;
135
+ description?: string;
53
136
  params: TParams;
54
137
  response: TResponse;
55
- handler: ArriProcedureHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : void>;
56
- postHandler?: ArriProcedurePostHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
57
- }
58
- interface ArriNamedProcedure<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined> extends ArriProcedure<TParams, TResponse> {
59
- name: string;
138
+ isEventStream?: TIsEventStream;
139
+ pingInterval?: TIsEventStream extends true ? number : undefined;
140
+ handler: TIsEventStream extends true ? EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined> : RpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : void>;
141
+ postHandler?: TIsEventStream extends true ? undefined : RpcPostHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
60
142
  }
143
+ type HttpRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined> = Omit<Rpc<false, TParams, TResponse>, "isEventStream">;
61
144
  type HandlerContext = Record<string, any>;
62
145
  interface RpcHandlerContext<TParams = undefined> extends HandlerContext, Omit<H3EventContext, "params"> {
63
146
  rpcName: string;
@@ -72,31 +155,37 @@ interface RpcEvent<TParams = undefined> extends Omit<H3Event, "context"> {
72
155
  interface RpcPostEvent<TParams = undefined, TResponse = undefined> extends Omit<H3Event, "context"> {
73
156
  context: RpcPostHandlerContext<TParams, TResponse>;
74
157
  }
75
- type ArriProcedureHandler<TParams, TResponse> = (context: RpcHandlerContext<TParams>, event: RpcEvent<TParams>) => TResponse | Promise<TResponse>;
76
- type ArriProcedurePostHandler<TParams, TResponse> = (context: RpcPostHandlerContext<TParams, TResponse>, event: RpcPostEvent<TParams, TResponse>) => any;
77
- declare function isRpc(input: any): input is ArriProcedure<any, any>;
78
- declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: ArriProcedure<TParams, TResponse>): ArriProcedure<TParams, TResponse>;
79
- declare function createRpcDefinition(rpcName: string, httpPath: string, procedure: ArriProcedure<any, any>): RpcDefinition;
158
+ type RpcHandler<TParams, TResponse> = (context: RpcHandlerContext<TParams>, event: RpcEvent<TParams>) => TResponse | Promise<TResponse>;
159
+ type RpcPostHandler<TParams, TResponse> = (context: RpcPostHandlerContext<TParams, TResponse>, event: RpcPostEvent<TParams, TResponse>) => any;
160
+ declare function isRpc(input: unknown): input is Rpc<any, any>;
161
+ declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: HttpRpc<TParams, TResponse>): Rpc<false, TParams, TResponse>;
162
+ declare function createRpcDefinition(rpcName: string, httpPath: string, procedure: Rpc<any, any, any>): RpcDefinition;
80
163
  declare function getRpcPath(rpcName: string, prefix?: string): string;
81
- declare function getRpcParamName(rpcName: string, procedure: ArriProcedure<any, any>): string | undefined;
82
- declare function getRpcResponseName(rpcName: string, procedure: ArriProcedure<any, any>): string | undefined;
83
- declare function registerRpc(router: Router, path: string, procedure: ArriNamedProcedure<any, any>, opts: RouteOptions): void;
164
+ declare function getRpcParamName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
165
+ declare function getRpcResponseName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
166
+ declare function registerRpc(router: Router, path: string, procedure: NamedRpc<any, any, any>, opts: RouteOptions): void;
167
+ declare function validateRpcRequestInput(event: H3Event, httpMethod: RpcHttpMethod, schema: ASchema): Promise<void>;
84
168
 
85
169
  interface ArriRouterBase {
86
- rpc: <TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: ArriNamedProcedure<TParams, TResponse>) => void;
170
+ rpc: <TIsEventStream extends boolean, TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>) => void;
87
171
  route: <TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>) => void;
172
+ registerModels: (models: ModelMap) => void;
88
173
  }
89
174
  declare class ArriRouter implements ArriRouterBase {
90
175
  private readonly procedures;
91
176
  private readonly routes;
92
- rpc<TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: ArriNamedProcedure<TParams, TResponse>): void;
177
+ private readonly models;
178
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>): void;
93
179
  route<TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
94
- getProcedures(): ArriNamedProcedure<any, any>[];
180
+ registerModels(models: ModelMap): void;
181
+ getProcedures(): NamedRpc<any, any, any>[];
95
182
  getRoutes(): ArriRoute<any, any, any, any>[];
183
+ getModels(): ModelMap;
96
184
  }
97
185
 
98
186
  declare const DEV_ENDPOINT_ROOT = "/__arri_dev__";
99
187
  declare const DEV_DEFINITION_ENDPOINT = "/__arri_dev__/__definition";
188
+ type ModelMap = Record<string, SchemaFormProperties | SchemaFormDiscriminator | SchemaFormValues>;
100
189
  declare class ArriApp implements ArriRouterBase {
101
190
  __isArri__: boolean;
102
191
  readonly h3App: App;
@@ -113,8 +202,9 @@ declare class ArriApp implements ArriRouterBase {
113
202
  private readonly onError;
114
203
  constructor(opts?: ArriOptions);
115
204
  use(input: Middleware | ArriRouter): void;
116
- rpc<TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: ArriNamedProcedure<TParams, TResponse>): void;
205
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>): void;
117
206
  route<TPath extends string, TQuery extends AObjectSchema<any, any>, TBody extends ASchema<any>, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
207
+ registerModels(models: ModelMap): void;
118
208
  getAppDefinition(): AppDefinition;
119
209
  }
120
210
  interface ArriOptions {
@@ -135,20 +225,6 @@ interface ArriOptions {
135
225
  onError?: (error: H3Error, event: MiddlewareEvent) => void | Promise<void>;
136
226
  }
137
227
 
138
- declare const ErrorResponse: AObjectSchema<{
139
- statusCode: number;
140
- statusMessage: string;
141
- stack?: string | undefined;
142
- data?: any;
143
- }, false>;
144
- type ErrorResponse = a.infer<typeof ErrorResponse>;
145
- declare function defineError(statusCode: StatusCode, input?: Partial<Omit<ErrorResponse, "statusCode" | "stack">> & {
146
- stack?: string;
147
- }): H3Error;
148
- declare function errorResponseFromValidationErrors(errors: ValidationError["errors"], prefixText?: string): H3Error;
149
- type StatusCode = number | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 507 | 511;
150
- declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions["onError"]): Promise<void>;
151
-
152
228
  interface ArriConfig {
153
229
  port: number;
154
230
  entry: string;
@@ -170,4 +246,4 @@ type ResolvedArriConfig = Required<ArriConfig>;
170
246
  declare const defaultConfig: Required<ArriConfig>;
171
247
  declare function defineConfig(config: ArriConfig): ResolvedArriConfig;
172
248
 
173
- export { ArriApp, type ArriConfig, type ArriNamedProcedure, type ArriOptions, type ArriProcedure, type ArriProcedureHandler, type ArriProcedurePostHandler, type ArriRoute, ArriRouter, type ArriRouterBase, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, ErrorResponse, type ExtractParam, type ExtractParams, type HandlerContext, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type PostRouteEvent, type PostRouteEventContext, type ResolvedArriConfig, type RouteEvent, type RouteEventContext, type RouteOptions, type RpcEvent, type RpcHandlerContext, type RpcParamSchema, type RpcPostEvent, type RpcPostHandlerContext, type StatusCode, createRpcDefinition, defaultConfig, defineConfig, defineError, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isResolvedArriConfig, isRpc, isRpcParamSchema, registerRoute, registerRpc };
249
+ export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, ErrorResponse, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, type EventStreamRpcEvent, type EventStreamRpcHandler, type EventStreamRpcHandlerContext, type ExtractParam, type ExtractParams, type HandlerContext, type HttpRpc, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type ModelMap, type NamedRpc, type PostRouteEvent, type PostRouteEventContext, type ResolvedArriConfig, type RouteEvent, type RouteEventContext, type RouteOptions, type Rpc, type RpcEvent, type RpcHandler, type RpcHandlerContext, type RpcParamSchema, type RpcPostEvent, type RpcPostHandler, type RpcPostHandlerContext, type Sse, type StatusCode, createRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, formatSse, formatSseList, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, setSseHeaders, validateRpcRequestInput };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { HttpMethod, RpcHttpMethod, RpcDefinition, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
- import { AObjectSchema, ASchema, InferType, ARecordSchema, ADiscriminatorSchema, a, ValidationError } from 'arri-validate';
3
- import { H3EventContext, H3Event, Router, App, H3Error } from 'h3';
1
+ import { HttpMethod, RpcHttpMethod, RpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
+ import { AObjectSchema, ASchema, InferType, a, ValidationError, ARecordSchema, ADiscriminatorSchema } from 'arri-validate';
3
+ import { H3EventContext, H3Event, Router, H3Error, App } from 'h3';
4
4
  export * from 'h3';
5
5
  import { BuildOptions } from 'esbuild';
6
6
 
@@ -44,20 +44,103 @@ type RouteOptions = Pick<ArriOptions, "onAfterResponse" | "onBeforeResponse" | "
44
44
  declare function registerRoute(router: Router, route: ArriRoute<any>, opts: RouteOptions): void;
45
45
  declare function handleRoute(router: Router, method: HttpMethod, route: ArriRoute<any>, opts: RouteOptions): void;
46
46
 
47
+ declare const ErrorResponse: AObjectSchema<{
48
+ statusCode: number;
49
+ statusMessage: string;
50
+ stack?: string | undefined;
51
+ data?: any;
52
+ }, false>;
53
+ type ErrorResponse = a.infer<typeof ErrorResponse>;
54
+ declare function defineError(statusCode: StatusCode, input?: Partial<Omit<ErrorResponse, "statusCode" | "stack">> & {
55
+ stack?: string;
56
+ }): H3Error;
57
+ declare function errorResponseFromValidationErrors(errors: ValidationError["errors"], prefixText?: string): H3Error;
58
+ type StatusCode = number | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 507 | 511;
59
+ declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions["onError"]): Promise<void>;
60
+
61
+ declare function setSseHeaders(event: H3Event): void;
62
+ declare function defineEventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, "isEventStream">): EventStreamRpc<TParams, TResponse>;
63
+ declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
64
+ interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<Rpc<true, TParams, TResponse>, "handler" | "postHandler"> {
65
+ isEventStream: true;
66
+ handler: EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
67
+ }
68
+ type EventStreamRpcHandler<TParams, TResponse> = (context: EventStreamRpcHandlerContext<TParams, TResponse>, event: EventStreamRpcEvent<TParams, TResponse>) => void | Promise<void>;
69
+ interface EventStreamRpcEvent<TParams, TResponse> extends RpcEvent<TParams> {
70
+ connection: EventStreamConnection<TResponse>;
71
+ }
72
+ interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends RpcHandlerContext<TParams> {
73
+ connection: EventStreamConnection<TResponse>;
74
+ }
75
+ interface EventStreamConnectionOptions<TData> {
76
+ serializer: (input: TData) => string;
77
+ pingInterval?: number;
78
+ }
79
+ /**
80
+ * A server sent event
81
+ */
82
+ interface Sse {
83
+ id?: string;
84
+ event?: string;
85
+ data: string;
86
+ }
87
+ declare function formatSse({ id, data, event }: Sse): string;
88
+ declare function formatSseList(events: Sse[]): string;
89
+ declare class EventStreamConnection<TData> {
90
+ lastEventId: string | undefined;
91
+ private readonly writable;
92
+ private readonly readable;
93
+ private readonly writer;
94
+ private readonly encoder;
95
+ private readonly serializer;
96
+ private readonly h3Event;
97
+ private pingInterval;
98
+ private readonly pingIntervalMs;
99
+ constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
100
+ /**
101
+ * Start sending the event stream to the client
102
+ */
103
+ start(): void;
104
+ /**
105
+ * Publish a new event. Events published with this hook will trigger the `onData()` hooks of any connected clients.
106
+ */
107
+ push(data: TData[], eventId?: string): Promise<void>;
108
+ push(data: TData, eventId?: string): Promise<void>;
109
+ /**
110
+ * Publish an error event. This will trigger the `onError` hooks of any connected clients.
111
+ */
112
+ pushError(error: ErrorResponse, eventId?: string): Promise<void>;
113
+ private publishEvents;
114
+ private publishEvent;
115
+ private cleanup;
116
+ /**
117
+ * Tell clients that the stream has ended and close the connection.
118
+ */
119
+ end(): Promise<void>;
120
+ on(event: "disconnect", callback: () => any): void;
121
+ on(event: "end", callback: () => any): void;
122
+ }
123
+ declare function registerEventStreamRpc(router: Router, path: string, procedure: EventStreamRpc<any, any> & {
124
+ name: string;
125
+ }, opts: RouteOptions): void;
126
+
47
127
  type RpcParamSchema<TObjectInner = any, TRecordInner extends ASchema = any, TDiscriminatorInner = any> = AObjectSchema<TObjectInner> | ARecordSchema<TRecordInner> | ADiscriminatorSchema<TDiscriminatorInner>;
48
128
  declare function isRpcParamSchema(input: unknown): input is RpcParamSchema;
49
- interface ArriProcedure<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined> {
50
- description?: string;
129
+ interface NamedRpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Rpc<TIsEventStream, TParams, TResponse> {
130
+ name: string;
131
+ }
132
+ interface Rpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
51
133
  method?: RpcHttpMethod;
52
134
  path?: string;
135
+ description?: string;
53
136
  params: TParams;
54
137
  response: TResponse;
55
- handler: ArriProcedureHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : void>;
56
- postHandler?: ArriProcedurePostHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
57
- }
58
- interface ArriNamedProcedure<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined> extends ArriProcedure<TParams, TResponse> {
59
- name: string;
138
+ isEventStream?: TIsEventStream;
139
+ pingInterval?: TIsEventStream extends true ? number : undefined;
140
+ handler: TIsEventStream extends true ? EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined> : RpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : void>;
141
+ postHandler?: TIsEventStream extends true ? undefined : RpcPostHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
60
142
  }
143
+ type HttpRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined> = Omit<Rpc<false, TParams, TResponse>, "isEventStream">;
61
144
  type HandlerContext = Record<string, any>;
62
145
  interface RpcHandlerContext<TParams = undefined> extends HandlerContext, Omit<H3EventContext, "params"> {
63
146
  rpcName: string;
@@ -72,31 +155,37 @@ interface RpcEvent<TParams = undefined> extends Omit<H3Event, "context"> {
72
155
  interface RpcPostEvent<TParams = undefined, TResponse = undefined> extends Omit<H3Event, "context"> {
73
156
  context: RpcPostHandlerContext<TParams, TResponse>;
74
157
  }
75
- type ArriProcedureHandler<TParams, TResponse> = (context: RpcHandlerContext<TParams>, event: RpcEvent<TParams>) => TResponse | Promise<TResponse>;
76
- type ArriProcedurePostHandler<TParams, TResponse> = (context: RpcPostHandlerContext<TParams, TResponse>, event: RpcPostEvent<TParams, TResponse>) => any;
77
- declare function isRpc(input: any): input is ArriProcedure<any, any>;
78
- declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: ArriProcedure<TParams, TResponse>): ArriProcedure<TParams, TResponse>;
79
- declare function createRpcDefinition(rpcName: string, httpPath: string, procedure: ArriProcedure<any, any>): RpcDefinition;
158
+ type RpcHandler<TParams, TResponse> = (context: RpcHandlerContext<TParams>, event: RpcEvent<TParams>) => TResponse | Promise<TResponse>;
159
+ type RpcPostHandler<TParams, TResponse> = (context: RpcPostHandlerContext<TParams, TResponse>, event: RpcPostEvent<TParams, TResponse>) => any;
160
+ declare function isRpc(input: unknown): input is Rpc<any, any>;
161
+ declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: HttpRpc<TParams, TResponse>): Rpc<false, TParams, TResponse>;
162
+ declare function createRpcDefinition(rpcName: string, httpPath: string, procedure: Rpc<any, any, any>): RpcDefinition;
80
163
  declare function getRpcPath(rpcName: string, prefix?: string): string;
81
- declare function getRpcParamName(rpcName: string, procedure: ArriProcedure<any, any>): string | undefined;
82
- declare function getRpcResponseName(rpcName: string, procedure: ArriProcedure<any, any>): string | undefined;
83
- declare function registerRpc(router: Router, path: string, procedure: ArriNamedProcedure<any, any>, opts: RouteOptions): void;
164
+ declare function getRpcParamName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
165
+ declare function getRpcResponseName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
166
+ declare function registerRpc(router: Router, path: string, procedure: NamedRpc<any, any, any>, opts: RouteOptions): void;
167
+ declare function validateRpcRequestInput(event: H3Event, httpMethod: RpcHttpMethod, schema: ASchema): Promise<void>;
84
168
 
85
169
  interface ArriRouterBase {
86
- rpc: <TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: ArriNamedProcedure<TParams, TResponse>) => void;
170
+ rpc: <TIsEventStream extends boolean, TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>) => void;
87
171
  route: <TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>) => void;
172
+ registerModels: (models: ModelMap) => void;
88
173
  }
89
174
  declare class ArriRouter implements ArriRouterBase {
90
175
  private readonly procedures;
91
176
  private readonly routes;
92
- rpc<TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: ArriNamedProcedure<TParams, TResponse>): void;
177
+ private readonly models;
178
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>): void;
93
179
  route<TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
94
- getProcedures(): ArriNamedProcedure<any, any>[];
180
+ registerModels(models: ModelMap): void;
181
+ getProcedures(): NamedRpc<any, any, any>[];
95
182
  getRoutes(): ArriRoute<any, any, any, any>[];
183
+ getModels(): ModelMap;
96
184
  }
97
185
 
98
186
  declare const DEV_ENDPOINT_ROOT = "/__arri_dev__";
99
187
  declare const DEV_DEFINITION_ENDPOINT = "/__arri_dev__/__definition";
188
+ type ModelMap = Record<string, SchemaFormProperties | SchemaFormDiscriminator | SchemaFormValues>;
100
189
  declare class ArriApp implements ArriRouterBase {
101
190
  __isArri__: boolean;
102
191
  readonly h3App: App;
@@ -113,8 +202,9 @@ declare class ArriApp implements ArriRouterBase {
113
202
  private readonly onError;
114
203
  constructor(opts?: ArriOptions);
115
204
  use(input: Middleware | ArriRouter): void;
116
- rpc<TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: ArriNamedProcedure<TParams, TResponse>): void;
205
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>): void;
117
206
  route<TPath extends string, TQuery extends AObjectSchema<any, any>, TBody extends ASchema<any>, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
207
+ registerModels(models: ModelMap): void;
118
208
  getAppDefinition(): AppDefinition;
119
209
  }
120
210
  interface ArriOptions {
@@ -135,20 +225,6 @@ interface ArriOptions {
135
225
  onError?: (error: H3Error, event: MiddlewareEvent) => void | Promise<void>;
136
226
  }
137
227
 
138
- declare const ErrorResponse: AObjectSchema<{
139
- statusCode: number;
140
- statusMessage: string;
141
- stack?: string | undefined;
142
- data?: any;
143
- }, false>;
144
- type ErrorResponse = a.infer<typeof ErrorResponse>;
145
- declare function defineError(statusCode: StatusCode, input?: Partial<Omit<ErrorResponse, "statusCode" | "stack">> & {
146
- stack?: string;
147
- }): H3Error;
148
- declare function errorResponseFromValidationErrors(errors: ValidationError["errors"], prefixText?: string): H3Error;
149
- type StatusCode = number | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 507 | 511;
150
- declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions["onError"]): Promise<void>;
151
-
152
228
  interface ArriConfig {
153
229
  port: number;
154
230
  entry: string;
@@ -170,4 +246,4 @@ type ResolvedArriConfig = Required<ArriConfig>;
170
246
  declare const defaultConfig: Required<ArriConfig>;
171
247
  declare function defineConfig(config: ArriConfig): ResolvedArriConfig;
172
248
 
173
- export { ArriApp, type ArriConfig, type ArriNamedProcedure, type ArriOptions, type ArriProcedure, type ArriProcedureHandler, type ArriProcedurePostHandler, type ArriRoute, ArriRouter, type ArriRouterBase, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, ErrorResponse, type ExtractParam, type ExtractParams, type HandlerContext, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type PostRouteEvent, type PostRouteEventContext, type ResolvedArriConfig, type RouteEvent, type RouteEventContext, type RouteOptions, type RpcEvent, type RpcHandlerContext, type RpcParamSchema, type RpcPostEvent, type RpcPostHandlerContext, type StatusCode, createRpcDefinition, defaultConfig, defineConfig, defineError, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isResolvedArriConfig, isRpc, isRpcParamSchema, registerRoute, registerRpc };
249
+ export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, ErrorResponse, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, type EventStreamRpcEvent, type EventStreamRpcHandler, type EventStreamRpcHandlerContext, type ExtractParam, type ExtractParams, type HandlerContext, type HttpRpc, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type ModelMap, type NamedRpc, type PostRouteEvent, type PostRouteEventContext, type ResolvedArriConfig, type RouteEvent, type RouteEventContext, type RouteOptions, type Rpc, type RpcEvent, type RpcHandler, type RpcHandlerContext, type RpcParamSchema, type RpcPostEvent, type RpcPostHandler, type RpcPostHandlerContext, type Sse, type StatusCode, createRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, formatSse, formatSseList, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, setSseHeaders, validateRpcRequestInput };