arri 0.36.0 → 0.37.0

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
@@ -18,6 +18,7 @@ Typescript implementation of Arri RPC. It's built on top of [H3](https://github.
18
18
  - [Key Concepts](#key-concepts)
19
19
  - [Arri Definition File](#arri-definition-file)
20
20
  - [How Procedures Map To Endpoints](#how-procedures-map-to-endpoints)
21
+ - [H3 Support](#h3-support)
21
22
  - [Arri CLI](#arri-cli)
22
23
 
23
24
  ## Quickstart
@@ -107,24 +108,9 @@ Create an app entry file in your src directory. The name of the file must match
107
108
  ```ts
108
109
  // ./src/app.ts
109
110
  import { ArriApp } from "arri";
110
- import { a } from "arri-validate";
111
111
 
112
112
  const app = new ArriApp();
113
113
 
114
- app.rpc("sayHello", {
115
- params: a.object({
116
- name: a.string(),
117
- }),
118
- response: a.object({
119
- message: a.string(),
120
- }),
121
- handler({ params }) {
122
- return {
123
- message: `Hello ${params.name}`,
124
- };
125
- },
126
- });
127
-
128
114
  export default app;
129
115
  ```
130
116
 
@@ -480,6 +466,37 @@ The supported HTTP methods are as follows:
480
466
 
481
467
  When using a get method the RPC params will be mapped as query parameters which will be coerced into their type using the `a.coerce` method from `arri-validate`. Get methods support all basic scalar types however arrays and nested objects are not supported.
482
468
 
469
+ ### H3 Support
470
+ Arri is built on top of [H3](https://h3.unjs.io/utils/request#getrequestipevent) so many of the concepts that apply to H3 also apply to Arri.
471
+
472
+ #### Accessing Utilities
473
+ Arri re-eports all of the H3 utilities.
474
+
475
+ ```ts
476
+ import { getRequestIP, setResponseHeader } from 'arri';
477
+ ```
478
+
479
+ #### Accessing H3 Events
480
+ You can access H3 events from inside procedures handlers.
481
+
482
+ ```ts
483
+ defineRpc({
484
+ params: undefined,
485
+ response: undefined,
486
+ handler(_, event) {
487
+ getRequestIP(event);
488
+ }
489
+ )
490
+
491
+ defineEventStreamRpc({
492
+ params: undefined,
493
+ response: undefined,
494
+ handler(_, event) {
495
+ getRequestIP(event);
496
+ }
497
+ )
498
+ ```
499
+
483
500
  ## Arri CLI
484
501
 
485
502
  ```bash
package/dist/cli.cjs CHANGED
@@ -11,7 +11,7 @@ const esbuild = require('esbuild');
11
11
  const esbuildPluginReplace = require('esbuild-plugin-replace');
12
12
  const path = require('pathe');
13
13
  const prettier = require('prettier');
14
- const config = require('./shared/arri.087dabd0.cjs');
14
+ const config = require('./shared/arri.1ce0fa20.cjs');
15
15
  const consola = require('consola');
16
16
  const globby = require('globby');
17
17
  const scule = require('scule');
@@ -93,10 +93,17 @@ async function createAppWithRoutesModule(config) {
93
93
  ).join(",\n")}
94
94
  ];
95
95
  for(const route of routes) {
96
- app.rpc({
97
- name: route.id,
98
- ...route.route,
99
- });
96
+ if(route.route.transport === 'http') {
97
+ app.rpc({
98
+ name: route.id,
99
+ ...route.route,
100
+ });
101
+ } else {
102
+ app.wsRpc({
103
+ name: route.id,
104
+ ...route.route,
105
+ });
106
+ }
100
107
  }
101
108
  export default app`,
102
109
  { parser: "typescript", tabWidth: 4 }
@@ -321,6 +328,14 @@ import app from './${OUT_APP_FILE}';
321
328
  void listen(toNodeListener(app.h3App), {
322
329
  port: process.env.PORT ?? ${config.port},
323
330
  public: true,
331
+ ws: {
332
+ resolve(info) {
333
+ if (app.h3App.websocket?.resolve) {
334
+ return app.h3App.websocket.resolve(info);
335
+ }
336
+ return app.h3App.websocket?.hooks ?? app.h3App.handler?.__websocket__ ?? {};
337
+ }
338
+ },
324
339
  http2: ${config.http2 ?? false},
325
340
  ${httpsString}
326
341
  });`;
@@ -471,7 +486,8 @@ const startListener = (config, showQr = false) => listhen.listenAndWatch(path__d
471
486
  logger,
472
487
  qr: showQr,
473
488
  https: config.https,
474
- http2: config.http2
489
+ http2: config.http2,
490
+ ws: true
475
491
  });
476
492
  async function bundleFilesContext(config) {
477
493
  const serverContent = `import app from './${OUT_APP_FILE}';
package/dist/cli.mjs CHANGED
@@ -10,7 +10,7 @@ import { build as build$1 } from 'esbuild';
10
10
  import { replace } from 'esbuild-plugin-replace';
11
11
  import path from 'pathe';
12
12
  import prettier from 'prettier';
13
- import { q as defaultConfig, o as isArriConfig, p as isResolvedArriConfig, a as DEV_DEFINITION_ENDPOINT } from './shared/arri.b0950dad.mjs';
13
+ import { q as defaultConfig, o as isArriConfig, p as isResolvedArriConfig, a as DEV_DEFINITION_ENDPOINT } from './shared/arri.90dd1716.mjs';
14
14
  import { createConsola } from 'consola';
15
15
  import { globby } from 'globby';
16
16
  import { camelCase, kebabCase } from 'scule';
@@ -69,10 +69,17 @@ async function createAppWithRoutesModule(config) {
69
69
  ).join(",\n")}
70
70
  ];
71
71
  for(const route of routes) {
72
- app.rpc({
73
- name: route.id,
74
- ...route.route,
75
- });
72
+ if(route.route.transport === 'http') {
73
+ app.rpc({
74
+ name: route.id,
75
+ ...route.route,
76
+ });
77
+ } else {
78
+ app.wsRpc({
79
+ name: route.id,
80
+ ...route.route,
81
+ });
82
+ }
76
83
  }
77
84
  export default app`,
78
85
  { parser: "typescript", tabWidth: 4 }
@@ -297,6 +304,14 @@ import app from './${OUT_APP_FILE}';
297
304
  void listen(toNodeListener(app.h3App), {
298
305
  port: process.env.PORT ?? ${config.port},
299
306
  public: true,
307
+ ws: {
308
+ resolve(info) {
309
+ if (app.h3App.websocket?.resolve) {
310
+ return app.h3App.websocket.resolve(info);
311
+ }
312
+ return app.h3App.websocket?.hooks ?? app.h3App.handler?.__websocket__ ?? {};
313
+ }
314
+ },
300
315
  http2: ${config.http2 ?? false},
301
316
  ${httpsString}
302
317
  });`;
@@ -447,7 +462,8 @@ const startListener = (config, showQr = false) => listenAndWatch(path.resolve(co
447
462
  logger,
448
463
  qr: showQr,
449
464
  https: config.https,
450
- http2: config.http2
465
+ http2: config.http2,
466
+ ws: true
451
467
  });
452
468
  async function bundleFilesContext(config) {
453
469
  const serverContent = `import app from './${OUT_APP_FILE}';
package/dist/index.cjs CHANGED
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const config = require('./shared/arri.087dabd0.cjs');
3
+ const config = require('./shared/arri.1ce0fa20.cjs');
4
4
  const h3 = require('h3');
5
5
  require('arri-codegen-utils');
6
+ require('consola');
6
7
  require('arri-validate');
7
8
  require('h3-sse');
8
9
  require('scule');
@@ -16,14 +17,17 @@ exports.ArriServerErrorResponse = config.ArriServerErrorResponse;
16
17
  exports.DEV_DEFINITION_ENDPOINT = config.DEV_DEFINITION_ENDPOINT;
17
18
  exports.DEV_ENDPOINT_ROOT = config.DEV_ENDPOINT_ROOT;
18
19
  exports.EventStreamConnection = config.EventStreamConnection;
20
+ exports.WsPeer = config.WsPeer;
19
21
  exports.createAppDefinition = config.createAppDefinition;
20
22
  exports.createHttpRpcDefinition = config.createHttpRpcDefinition;
23
+ exports.createWsRpcDefinition = config.createWsRpcDefinition;
21
24
  exports.defaultConfig = config.defaultConfig;
22
25
  exports.defineConfig = config.defineConfig;
23
26
  exports.defineError = config.defineError;
24
27
  exports.defineEventStreamRpc = config.defineEventStreamRpc;
25
28
  exports.defineRoute = config.defineRoute;
26
29
  exports.defineRpc = config.defineRpc;
30
+ exports.defineWebsocketRpc = config.defineWebsocketRpc;
27
31
  exports.errorResponseFromValidationErrors = config.errorResponseFromValidationErrors;
28
32
  exports.getRpcParamName = config.getRpcParamName;
29
33
  exports.getRpcPath = config.getRpcPath;
@@ -38,6 +42,7 @@ exports.isRpcParamSchema = config.isRpcParamSchema;
38
42
  exports.registerEventStreamRpc = config.registerEventStreamRpc;
39
43
  exports.registerRoute = config.registerRoute;
40
44
  exports.registerRpc = config.registerRpc;
45
+ exports.registerWebsocketRpc = config.registerWebsocketRpc;
41
46
  exports.validateRpcRequestInput = config.validateRpcRequestInput;
42
47
  exports.defineMiddleware = defineMiddleware;
43
48
  Object.keys(h3).forEach(function (k) {
package/dist/index.d.cts CHANGED
@@ -1,8 +1,9 @@
1
- import { HttpMethod, RpcHttpMethod, HttpRpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
- import { AObjectSchema, a, ValidationError, ASchema, InferType, ValueError, ADiscriminatorSchema } from 'arri-validate';
1
+ import { HttpMethod, WsRpcDefinition, RpcHttpMethod, HttpRpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
+ import { AObjectSchema, a, ValidationError, ASchema, InferType, ValueError, CompiledValidator, ADiscriminatorSchema } from 'arri-validate';
3
3
  import { H3Error, H3Event, H3EventContext, Router, App } from 'h3';
4
4
  export * from 'h3';
5
5
  import { EventStream } from 'h3-sse';
6
+ import { Peer, WSError } from 'crossws';
6
7
  import { BuildOptions } from 'esbuild';
7
8
 
8
9
  declare class ArriServerError extends Error {
@@ -67,7 +68,7 @@ type RouteOptions = Pick<ArriOptions, "onAfterResponse" | "onBeforeResponse" | "
67
68
  declare function registerRoute(router: Router, route: ArriRoute<any>, opts: RouteOptions): void;
68
69
  declare function handleRoute(router: Router, method: HttpMethod, route: ArriRoute<any>, opts: RouteOptions): void;
69
70
 
70
- declare function defineEventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, "isEventStream">): EventStreamRpc<TParams, TResponse>;
71
+ declare function defineEventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, "isEventStream" | "transport">): EventStreamRpc<TParams, TResponse>;
71
72
  declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
72
73
  interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<Rpc<true, TParams, TResponse>, "handler" | "postHandler"> {
73
74
  isEventStream: true;
@@ -116,12 +117,62 @@ declare function registerEventStreamRpc(router: Router, path: string, procedure:
116
117
  name: string;
117
118
  }, opts: RouteOptions): void;
118
119
 
120
+ interface NamedWebsocketRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends WebsocketRpc<TParams, TResponse> {
121
+ name: string;
122
+ }
123
+ interface WebsocketRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
124
+ transport: "ws";
125
+ description?: string;
126
+ path?: string;
127
+ isDeprecated?: boolean;
128
+ params: TParams;
129
+ response: TResponse;
130
+ pingInterval?: boolean;
131
+ handler: WebSocketRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
132
+ }
133
+ interface WsPeerOpts<TResponse> {
134
+ validator?: CompiledValidator<ASchema<TResponse>>;
135
+ context: WsPeerContext;
136
+ }
137
+ interface WsPeerContext extends Record<string, any> {
138
+ rpcName: string;
139
+ queryParams?: Record<string, string>;
140
+ clientAddress?: string;
141
+ }
142
+ declare class WsPeer<TResponse> {
143
+ private readonly _peer;
144
+ private readonly _validator?;
145
+ context: WsPeerContext;
146
+ url: string;
147
+ constructor(peer: Peer, opts: WsPeerOpts<TResponse>);
148
+ send(data: TResponse): number | undefined;
149
+ sendError(err: ArriServerErrorResponse): number;
150
+ close(): void;
151
+ subscribe(channel: string): void;
152
+ unsubscribe(channel: string): void;
153
+ publish(channel: string, message: TResponse): void;
154
+ readyState(): (0 | 1 | 2 | 3) | -1;
155
+ }
156
+ interface WebSocketRpcHandler<TParams, TResponse> {
157
+ onOpen: (peer: WsPeer<TResponse>) => void;
158
+ onMessage: (peer: WsPeer<TResponse>, message: TParams) => void;
159
+ onClose: (peer: WsPeer<TResponse>, details: {
160
+ code?: number;
161
+ reason?: string;
162
+ }) => void;
163
+ onError: (peer: WsPeer<TResponse>, error: WSError) => void;
164
+ }
165
+ declare function defineWebsocketRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(def: Omit<WebsocketRpc<TParams, TResponse>, "transport">): WebsocketRpc<TParams, TResponse>;
166
+ declare function registerWebsocketRpc(router: Router, path: string, rpc: NamedWebsocketRpc<any, any>): void;
167
+ declare function createWsRpcDefinition(rpcName: string, path: string, rpc: NamedWebsocketRpc<any, any>): WsRpcDefinition;
168
+
119
169
  type RpcParamSchema<TObjectInner = any, TDiscriminatorInner = any> = AObjectSchema<TObjectInner> | ADiscriminatorSchema<TDiscriminatorInner>;
120
170
  declare function isRpcParamSchema(input: unknown): input is RpcParamSchema;
121
171
  interface NamedRpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Rpc<TIsEventStream, TParams, TResponse> {
122
172
  name: string;
123
173
  }
124
174
  interface Rpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
175
+ transport: "http";
125
176
  method?: RpcHttpMethod;
126
177
  path?: string;
127
178
  description?: string;
@@ -151,16 +202,17 @@ interface RpcPostEvent<TParams = undefined, TResponse = undefined> extends Omit<
151
202
  type RpcHandler<TParams, TResponse> = (context: RpcHandlerContext<TParams>, event: RpcEvent<TParams>) => TResponse | Promise<TResponse>;
152
203
  type RpcPostHandler<TParams, TResponse> = (context: RpcPostHandlerContext<TParams, TResponse>, event: RpcPostEvent<TParams, TResponse>) => any;
153
204
  declare function isRpc(input: unknown): input is Rpc<any, any>;
154
- declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: HttpRpc<TParams, TResponse>): Rpc<false, TParams, TResponse>;
205
+ declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<HttpRpc<TParams, TResponse>, "transport">): Rpc<false, TParams, TResponse>;
155
206
  declare function createHttpRpcDefinition(rpcName: string, httpPath: string, procedure: Rpc<any, any, any>): HttpRpcDefinition;
156
207
  declare function getRpcPath(rpcName: string, prefix?: string): string;
157
- declare function getRpcParamName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
158
- declare function getRpcResponseName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
208
+ declare function getRpcParamName(rpcName: string, procedure: Rpc<any, any, any> | WebsocketRpc<any, any>): string | undefined;
209
+ declare function getRpcResponseName(rpcName: string, procedure: Rpc<any, any, any> | WebsocketRpc<any, any>): string | undefined;
159
210
  declare function registerRpc(router: Router, path: string, procedure: NamedRpc<any, any, any>, opts: RouteOptions): void;
160
211
  declare function validateRpcRequestInput(event: H3Event, httpMethod: RpcHttpMethod, schema: ASchema): Promise<void>;
161
212
 
162
213
  interface ArriRouterBase {
163
- rpc: <TIsEventStream extends boolean, TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>) => void;
214
+ rpc: <TIsEventStream extends boolean, TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: Omit<NamedRpc<TIsEventStream, TParams, TResponse>, "transport">) => void;
215
+ wsRpc: <TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(procedure: Omit<NamedWebsocketRpc<TParams, TResponse>, "transport">) => void;
164
216
  route: <TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>) => void;
165
217
  registerModels: (models: ModelMap) => void;
166
218
  }
@@ -168,10 +220,11 @@ declare class ArriRouter implements ArriRouterBase {
168
220
  private readonly procedures;
169
221
  private readonly routes;
170
222
  private readonly models;
171
- 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;
223
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: Omit<NamedRpc<TIsEventStream, TParams, TResponse>, "transport">): void;
224
+ wsRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(procedure: Omit<NamedWebsocketRpc<TParams, TResponse>, "transport">): void;
172
225
  route<TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
173
226
  registerModels(models: ModelMap): void;
174
- getProcedures(): NamedRpc<any, any, any>[];
227
+ getProcedures(): (NamedWebsocketRpc<any, any> | NamedRpc<any, any, any>)[];
175
228
  getRoutes(): ArriRoute<any, any, any, any>[];
176
229
  getModels(): ModelMap;
177
230
  }
@@ -195,9 +248,11 @@ declare class ArriApp implements ArriRouterBase {
195
248
  private readonly _onBeforeResponse;
196
249
  private readonly _onError;
197
250
  private readonly _debug;
251
+ readonly definitionPath: string;
198
252
  constructor(opts?: ArriOptions);
199
253
  use(input: Middleware | ArriRouter): void;
200
- 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;
254
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: Omit<NamedRpc<TIsEventStream, TParams, TResponse>, "transport">): void;
255
+ wsRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(procedure: Omit<NamedWebsocketRpc<TParams, TResponse>, "transport">): void;
201
256
  route<TPath extends string, TQuery extends AObjectSchema<any, any>, TBody extends ASchema<any>, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
202
257
  registerModels(models: ModelMap): void;
203
258
  getAppDefinition(): AppDefinition;
@@ -247,4 +302,4 @@ type ResolvedArriConfig = Required<ArriConfig>;
247
302
  declare const defaultConfig: Required<ArriConfig>;
248
303
  declare function defineConfig(config: ArriConfig): ResolvedArriConfig;
249
304
 
250
- export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, ArriServerError, ArriServerErrorResponse, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, 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 StatusCode, createAppDefinition, createHttpRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
305
+ export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, ArriServerError, ArriServerErrorResponse, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, type EventStreamRpcHandler, type EventStreamRpcHandlerContext, type ExtractParam, type ExtractParams, type HandlerContext, type HttpRpc, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type ModelMap, type NamedRpc, type NamedWebsocketRpc, 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 StatusCode, type WebSocketRpcHandler, type WebsocketRpc, WsPeer, type WsPeerContext, createAppDefinition, createHttpRpcDefinition, createWsRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineWebsocketRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, registerWebsocketRpc, validateRpcRequestInput };
package/dist/index.d.mts CHANGED
@@ -1,8 +1,9 @@
1
- import { HttpMethod, RpcHttpMethod, HttpRpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
- import { AObjectSchema, a, ValidationError, ASchema, InferType, ValueError, ADiscriminatorSchema } from 'arri-validate';
1
+ import { HttpMethod, WsRpcDefinition, RpcHttpMethod, HttpRpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition, ClientGenerator } from 'arri-codegen-utils';
2
+ import { AObjectSchema, a, ValidationError, ASchema, InferType, ValueError, CompiledValidator, ADiscriminatorSchema } from 'arri-validate';
3
3
  import { H3Error, H3Event, H3EventContext, Router, App } from 'h3';
4
4
  export * from 'h3';
5
5
  import { EventStream } from 'h3-sse';
6
+ import { Peer, WSError } from 'crossws';
6
7
  import { BuildOptions } from 'esbuild';
7
8
 
8
9
  declare class ArriServerError extends Error {
@@ -67,7 +68,7 @@ type RouteOptions = Pick<ArriOptions, "onAfterResponse" | "onBeforeResponse" | "
67
68
  declare function registerRoute(router: Router, route: ArriRoute<any>, opts: RouteOptions): void;
68
69
  declare function handleRoute(router: Router, method: HttpMethod, route: ArriRoute<any>, opts: RouteOptions): void;
69
70
 
70
- declare function defineEventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, "isEventStream">): EventStreamRpc<TParams, TResponse>;
71
+ declare function defineEventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, "isEventStream" | "transport">): EventStreamRpc<TParams, TResponse>;
71
72
  declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
72
73
  interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<Rpc<true, TParams, TResponse>, "handler" | "postHandler"> {
73
74
  isEventStream: true;
@@ -116,12 +117,62 @@ declare function registerEventStreamRpc(router: Router, path: string, procedure:
116
117
  name: string;
117
118
  }, opts: RouteOptions): void;
118
119
 
120
+ interface NamedWebsocketRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends WebsocketRpc<TParams, TResponse> {
121
+ name: string;
122
+ }
123
+ interface WebsocketRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
124
+ transport: "ws";
125
+ description?: string;
126
+ path?: string;
127
+ isDeprecated?: boolean;
128
+ params: TParams;
129
+ response: TResponse;
130
+ pingInterval?: boolean;
131
+ handler: WebSocketRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
132
+ }
133
+ interface WsPeerOpts<TResponse> {
134
+ validator?: CompiledValidator<ASchema<TResponse>>;
135
+ context: WsPeerContext;
136
+ }
137
+ interface WsPeerContext extends Record<string, any> {
138
+ rpcName: string;
139
+ queryParams?: Record<string, string>;
140
+ clientAddress?: string;
141
+ }
142
+ declare class WsPeer<TResponse> {
143
+ private readonly _peer;
144
+ private readonly _validator?;
145
+ context: WsPeerContext;
146
+ url: string;
147
+ constructor(peer: Peer, opts: WsPeerOpts<TResponse>);
148
+ send(data: TResponse): number | undefined;
149
+ sendError(err: ArriServerErrorResponse): number;
150
+ close(): void;
151
+ subscribe(channel: string): void;
152
+ unsubscribe(channel: string): void;
153
+ publish(channel: string, message: TResponse): void;
154
+ readyState(): (0 | 1 | 2 | 3) | -1;
155
+ }
156
+ interface WebSocketRpcHandler<TParams, TResponse> {
157
+ onOpen: (peer: WsPeer<TResponse>) => void;
158
+ onMessage: (peer: WsPeer<TResponse>, message: TParams) => void;
159
+ onClose: (peer: WsPeer<TResponse>, details: {
160
+ code?: number;
161
+ reason?: string;
162
+ }) => void;
163
+ onError: (peer: WsPeer<TResponse>, error: WSError) => void;
164
+ }
165
+ declare function defineWebsocketRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(def: Omit<WebsocketRpc<TParams, TResponse>, "transport">): WebsocketRpc<TParams, TResponse>;
166
+ declare function registerWebsocketRpc(router: Router, path: string, rpc: NamedWebsocketRpc<any, any>): void;
167
+ declare function createWsRpcDefinition(rpcName: string, path: string, rpc: NamedWebsocketRpc<any, any>): WsRpcDefinition;
168
+
119
169
  type RpcParamSchema<TObjectInner = any, TDiscriminatorInner = any> = AObjectSchema<TObjectInner> | ADiscriminatorSchema<TDiscriminatorInner>;
120
170
  declare function isRpcParamSchema(input: unknown): input is RpcParamSchema;
121
171
  interface NamedRpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Rpc<TIsEventStream, TParams, TResponse> {
122
172
  name: string;
123
173
  }
124
174
  interface Rpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
175
+ transport: "http";
125
176
  method?: RpcHttpMethod;
126
177
  path?: string;
127
178
  description?: string;
@@ -151,16 +202,17 @@ interface RpcPostEvent<TParams = undefined, TResponse = undefined> extends Omit<
151
202
  type RpcHandler<TParams, TResponse> = (context: RpcHandlerContext<TParams>, event: RpcEvent<TParams>) => TResponse | Promise<TResponse>;
152
203
  type RpcPostHandler<TParams, TResponse> = (context: RpcPostHandlerContext<TParams, TResponse>, event: RpcPostEvent<TParams, TResponse>) => any;
153
204
  declare function isRpc(input: unknown): input is Rpc<any, any>;
154
- declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: HttpRpc<TParams, TResponse>): Rpc<false, TParams, TResponse>;
205
+ declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<HttpRpc<TParams, TResponse>, "transport">): Rpc<false, TParams, TResponse>;
155
206
  declare function createHttpRpcDefinition(rpcName: string, httpPath: string, procedure: Rpc<any, any, any>): HttpRpcDefinition;
156
207
  declare function getRpcPath(rpcName: string, prefix?: string): string;
157
- declare function getRpcParamName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
158
- declare function getRpcResponseName(rpcName: string, procedure: Rpc<any, any, any>): string | undefined;
208
+ declare function getRpcParamName(rpcName: string, procedure: Rpc<any, any, any> | WebsocketRpc<any, any>): string | undefined;
209
+ declare function getRpcResponseName(rpcName: string, procedure: Rpc<any, any, any> | WebsocketRpc<any, any>): string | undefined;
159
210
  declare function registerRpc(router: Router, path: string, procedure: NamedRpc<any, any, any>, opts: RouteOptions): void;
160
211
  declare function validateRpcRequestInput(event: H3Event, httpMethod: RpcHttpMethod, schema: ASchema): Promise<void>;
161
212
 
162
213
  interface ArriRouterBase {
163
- rpc: <TIsEventStream extends boolean, TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: NamedRpc<TIsEventStream, TParams, TResponse>) => void;
214
+ rpc: <TIsEventStream extends boolean, TParams extends AObjectSchema<any, any> | undefined, TResponse extends AObjectSchema<any, any> | undefined>(procedure: Omit<NamedRpc<TIsEventStream, TParams, TResponse>, "transport">) => void;
215
+ wsRpc: <TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(procedure: Omit<NamedWebsocketRpc<TParams, TResponse>, "transport">) => void;
164
216
  route: <TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>) => void;
165
217
  registerModels: (models: ModelMap) => void;
166
218
  }
@@ -168,10 +220,11 @@ declare class ArriRouter implements ArriRouterBase {
168
220
  private readonly procedures;
169
221
  private readonly routes;
170
222
  private readonly models;
171
- 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;
223
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: Omit<NamedRpc<TIsEventStream, TParams, TResponse>, "transport">): void;
224
+ wsRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(procedure: Omit<NamedWebsocketRpc<TParams, TResponse>, "transport">): void;
172
225
  route<TPath extends string, TQuery extends AObjectSchema<any, any> = any, TBody extends ASchema<any> = any, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
173
226
  registerModels(models: ModelMap): void;
174
- getProcedures(): NamedRpc<any, any, any>[];
227
+ getProcedures(): (NamedWebsocketRpc<any, any> | NamedRpc<any, any, any>)[];
175
228
  getRoutes(): ArriRoute<any, any, any, any>[];
176
229
  getModels(): ModelMap;
177
230
  }
@@ -195,9 +248,11 @@ declare class ArriApp implements ArriRouterBase {
195
248
  private readonly _onBeforeResponse;
196
249
  private readonly _onError;
197
250
  private readonly _debug;
251
+ readonly definitionPath: string;
198
252
  constructor(opts?: ArriOptions);
199
253
  use(input: Middleware | ArriRouter): void;
200
- 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;
254
+ rpc<TIsEventStream extends boolean = false, TParams extends AObjectSchema<any, any> | undefined = undefined, TResponse extends AObjectSchema<any, any> | undefined = undefined>(procedure: Omit<NamedRpc<TIsEventStream, TParams, TResponse>, "transport">): void;
255
+ wsRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(procedure: Omit<NamedWebsocketRpc<TParams, TResponse>, "transport">): void;
201
256
  route<TPath extends string, TQuery extends AObjectSchema<any, any>, TBody extends ASchema<any>, TResponse = any>(route: ArriRoute<TPath, TQuery, TBody, TResponse>): void;
202
257
  registerModels(models: ModelMap): void;
203
258
  getAppDefinition(): AppDefinition;
@@ -247,4 +302,4 @@ type ResolvedArriConfig = Required<ArriConfig>;
247
302
  declare const defaultConfig: Required<ArriConfig>;
248
303
  declare function defineConfig(config: ArriConfig): ResolvedArriConfig;
249
304
 
250
- export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, ArriServerError, ArriServerErrorResponse, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, 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 StatusCode, createAppDefinition, createHttpRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
305
+ export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, ArriServerError, ArriServerErrorResponse, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, type EventStreamRpcHandler, type EventStreamRpcHandlerContext, type ExtractParam, type ExtractParams, type HandlerContext, type HttpRpc, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type ModelMap, type NamedRpc, type NamedWebsocketRpc, 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 StatusCode, type WebSocketRpcHandler, type WebsocketRpc, WsPeer, type WsPeerContext, createAppDefinition, createHttpRpcDefinition, createWsRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineWebsocketRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, registerWebsocketRpc, validateRpcRequestInput };