arri 0.24.1 → 0.25.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/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.f4b47a61.cjs');
15
+ const config = require('./shared/arri.65113bc6.cjs');
16
16
  const globby = require('globby');
17
17
  const scule = require('scule');
18
18
  const arriCodegenDart = require('arri-codegen-dart');
@@ -22,7 +22,7 @@ const chokidar = require('chokidar');
22
22
  const Degit = require('degit');
23
23
  require('h3');
24
24
  require('arri-validate');
25
- require('node:process');
25
+ require('h3-sse');
26
26
 
27
27
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
28
28
 
@@ -49,9 +49,9 @@ const Degit__default = /*#__PURE__*/_interopDefaultCompat(Degit);
49
49
 
50
50
  const GEN_APP_FILE = "__arri_app.js";
51
51
  const GEN_SERVER_ENTRY_FILE = "__arri_server.js";
52
- const OUT_APP_FILE = "app.js";
53
- const OUT_SERVER_ENTRY = "server.js";
54
- const OUT_CODEGEN = "codegen.js";
52
+ const OUT_APP_FILE = "app.mjs";
53
+ const OUT_SERVER_ENTRY = "server.mjs";
54
+ const OUT_CODEGEN = "codegen.mjs";
55
55
  async function setupWorkingDir(config) {
56
56
  const arriDir = path__default.resolve(config.rootDir, config.buildDir);
57
57
  const outDir = path__default.resolve(config.rootDir, ".output");
@@ -294,7 +294,7 @@ async function createServerEntryFile(config) {
294
294
  js: `import { createRequire as topLevelCreateRequire } from 'module';
295
295
  const require = topLevelCreateRequire(import.meta.url);`
296
296
  },
297
- plugins: [esbuildPluginReplace.replace({ "virtual:arri/app": "./app.js" })],
297
+ plugins: [esbuildPluginReplace.replace({ "virtual:arri/app": "./app.mjs" })],
298
298
  allowOverwrite: true,
299
299
  outfile: path__default.resolve(config.rootDir, ".output", OUT_SERVER_ENTRY)
300
300
  });
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.ebc63bd6.mjs';
14
+ import { n as defaultConfig, m as isResolvedArriConfig, a as DEV_DEFINITION_ENDPOINT } from './shared/arri.ba3f283e.mjs';
15
15
  import { globby } from 'globby';
16
16
  import { camelCase, kebabCase } from 'scule';
17
17
  import { dartClientGenerator } from 'arri-codegen-dart';
@@ -21,13 +21,13 @@ import chokidar from 'chokidar';
21
21
  import Degit from 'degit';
22
22
  import 'h3';
23
23
  import 'arri-validate';
24
- import 'node:process';
24
+ import 'h3-sse';
25
25
 
26
26
  const GEN_APP_FILE = "__arri_app.js";
27
27
  const GEN_SERVER_ENTRY_FILE = "__arri_server.js";
28
- const OUT_APP_FILE = "app.js";
29
- const OUT_SERVER_ENTRY = "server.js";
30
- const OUT_CODEGEN = "codegen.js";
28
+ const OUT_APP_FILE = "app.mjs";
29
+ const OUT_SERVER_ENTRY = "server.mjs";
30
+ const OUT_CODEGEN = "codegen.mjs";
31
31
  async function setupWorkingDir(config) {
32
32
  const arriDir = path.resolve(config.rootDir, config.buildDir);
33
33
  const outDir = path.resolve(config.rootDir, ".output");
@@ -270,7 +270,7 @@ async function createServerEntryFile(config) {
270
270
  js: `import { createRequire as topLevelCreateRequire } from 'module';
271
271
  const require = topLevelCreateRequire(import.meta.url);`
272
272
  },
273
- plugins: [replace({ "virtual:arri/app": "./app.js" })],
273
+ plugins: [replace({ "virtual:arri/app": "./app.mjs" })],
274
274
  allowOverwrite: true,
275
275
  outfile: path.resolve(config.rootDir, ".output", OUT_SERVER_ENTRY)
276
276
  });
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const config = require('./shared/arri.f4b47a61.cjs');
3
+ const config = require('./shared/arri.65113bc6.cjs');
4
4
  const h3 = require('h3');
5
5
  require('arri-validate');
6
- require('node:process');
6
+ require('h3-sse');
7
7
  require('arri-codegen-utils');
8
8
  require('scule');
9
9
 
@@ -23,8 +23,6 @@ exports.defineEventStreamRpc = config.defineEventStreamRpc;
23
23
  exports.defineRoute = config.defineRoute;
24
24
  exports.defineRpc = config.defineRpc;
25
25
  exports.errorResponseFromValidationErrors = config.errorResponseFromValidationErrors;
26
- exports.formatSse = config.formatSse;
27
- exports.formatSseList = config.formatSseList;
28
26
  exports.getRpcParamName = config.getRpcParamName;
29
27
  exports.getRpcPath = config.getRpcPath;
30
28
  exports.getRpcResponseName = config.getRpcResponseName;
@@ -38,7 +36,6 @@ exports.isRpcParamSchema = config.isRpcParamSchema;
38
36
  exports.registerEventStreamRpc = config.registerEventStreamRpc;
39
37
  exports.registerRoute = config.registerRoute;
40
38
  exports.registerRpc = config.registerRpc;
41
- exports.setSseHeaders = config.setSseHeaders;
42
39
  exports.validateRpcRequestInput = config.validateRpcRequestInput;
43
40
  exports.defineMiddleware = defineMiddleware;
44
41
  Object.keys(h3).forEach(function (k) {
package/dist/index.d.cts CHANGED
@@ -2,6 +2,7 @@ import { HttpMethod, RpcHttpMethod, RpcDefinition, SchemaFormProperties, SchemaF
2
2
  import { AObjectSchema, ASchema, InferType, a, ValidationError, ValueError, ARecordSchema, ADiscriminatorSchema } from 'arri-validate';
3
3
  import { H3EventContext, H3Event, Router, H3Error, App } from 'h3';
4
4
  export * from 'h3';
5
+ import { EventStream } from 'h3-sse';
5
6
  import { BuildOptions } from 'esbuild';
6
7
 
7
8
  interface MiddlewareEventContext extends H3EventContext {
@@ -58,19 +59,15 @@ declare function errorResponseFromValidationErrors(errors: ValidationError["erro
58
59
  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
60
  declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions["onError"]): Promise<void>;
60
61
 
61
- declare function setSseHeaders(event: H3Event): void;
62
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
63
  declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
64
64
  interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<Rpc<true, TParams, TResponse>, "handler" | "postHandler"> {
65
65
  isEventStream: true;
66
66
  handler: EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
67
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
- }
68
+ type EventStreamRpcHandler<TParams, TResponse> = (context: EventStreamRpcHandlerContext<TParams, TResponse>, event: RpcEvent<TResponse>) => void | Promise<void>;
72
69
  interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends RpcHandlerContext<TParams> {
73
- connection: EventStreamConnection<TResponse>;
70
+ stream: EventStreamConnection<TResponse>;
74
71
  }
75
72
  interface EventStreamConnectionOptions<TData> {
76
73
  validator: (input: unknown) => input is TData;
@@ -78,29 +75,14 @@ interface EventStreamConnectionOptions<TData> {
78
75
  serializer: (input: TData) => string;
79
76
  pingInterval?: number;
80
77
  }
81
- /**
82
- * A server sent event
83
- */
84
- interface Sse {
85
- id?: string;
86
- event?: string;
87
- data: string;
88
- }
89
- declare function formatSse({ id, data, event }: Sse): string;
90
- declare function formatSseList(events: Sse[]): string;
91
78
  declare class EventStreamConnection<TData> {
92
- lastEventId: string | undefined;
93
- private readonly writable;
94
- private readonly readable;
95
- private readonly writer;
96
- private writerIsClosed;
97
- private readonly encoder;
79
+ private readonly h3Event;
98
80
  private readonly validationErrors;
99
81
  private readonly validator;
100
82
  private readonly serializer;
101
- private readonly h3Event;
102
83
  private pingInterval;
103
84
  private readonly pingIntervalMs;
85
+ readonly eventStream: EventStream;
104
86
  constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
105
87
  /**
106
88
  * Start sending the event stream to the client
@@ -115,15 +97,13 @@ declare class EventStreamConnection<TData> {
115
97
  * Publish an error event. This will trigger the `onError` hooks of any connected clients.
116
98
  */
117
99
  pushError(error: ErrorResponse, eventId?: string): Promise<void>;
118
- private publishEvents;
119
- private publishEvent;
120
100
  private cleanup;
121
101
  /**
122
102
  * Tell clients that the stream has ended and close the connection.
123
103
  */
124
- end(): Promise<void>;
125
- on(event: "disconnect", callback: () => any): void;
126
- on(event: "end", callback: () => any): void;
104
+ close(): Promise<void>;
105
+ on(event: "close", callback: () => any): void;
106
+ on(event: "request:close", callback: () => any): void;
127
107
  }
128
108
  declare function registerEventStreamRpc(router: Router, path: string, procedure: EventStreamRpc<any, any> & {
129
109
  name: string;
@@ -257,4 +237,4 @@ type ResolvedArriConfig = Required<ArriConfig>;
257
237
  declare const defaultConfig: Required<ArriConfig>;
258
238
  declare function defineConfig(config: ArriConfig): ResolvedArriConfig;
259
239
 
260
- 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 };
240
+ export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, ErrorResponse, 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, createRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
package/dist/index.d.mts CHANGED
@@ -2,6 +2,7 @@ import { HttpMethod, RpcHttpMethod, RpcDefinition, SchemaFormProperties, SchemaF
2
2
  import { AObjectSchema, ASchema, InferType, a, ValidationError, ValueError, ARecordSchema, ADiscriminatorSchema } from 'arri-validate';
3
3
  import { H3EventContext, H3Event, Router, H3Error, App } from 'h3';
4
4
  export * from 'h3';
5
+ import { EventStream } from 'h3-sse';
5
6
  import { BuildOptions } from 'esbuild';
6
7
 
7
8
  interface MiddlewareEventContext extends H3EventContext {
@@ -58,19 +59,15 @@ declare function errorResponseFromValidationErrors(errors: ValidationError["erro
58
59
  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
60
  declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions["onError"]): Promise<void>;
60
61
 
61
- declare function setSseHeaders(event: H3Event): void;
62
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
63
  declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
64
64
  interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<Rpc<true, TParams, TResponse>, "handler" | "postHandler"> {
65
65
  isEventStream: true;
66
66
  handler: EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
67
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
- }
68
+ type EventStreamRpcHandler<TParams, TResponse> = (context: EventStreamRpcHandlerContext<TParams, TResponse>, event: RpcEvent<TResponse>) => void | Promise<void>;
72
69
  interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends RpcHandlerContext<TParams> {
73
- connection: EventStreamConnection<TResponse>;
70
+ stream: EventStreamConnection<TResponse>;
74
71
  }
75
72
  interface EventStreamConnectionOptions<TData> {
76
73
  validator: (input: unknown) => input is TData;
@@ -78,29 +75,14 @@ interface EventStreamConnectionOptions<TData> {
78
75
  serializer: (input: TData) => string;
79
76
  pingInterval?: number;
80
77
  }
81
- /**
82
- * A server sent event
83
- */
84
- interface Sse {
85
- id?: string;
86
- event?: string;
87
- data: string;
88
- }
89
- declare function formatSse({ id, data, event }: Sse): string;
90
- declare function formatSseList(events: Sse[]): string;
91
78
  declare class EventStreamConnection<TData> {
92
- lastEventId: string | undefined;
93
- private readonly writable;
94
- private readonly readable;
95
- private readonly writer;
96
- private writerIsClosed;
97
- private readonly encoder;
79
+ private readonly h3Event;
98
80
  private readonly validationErrors;
99
81
  private readonly validator;
100
82
  private readonly serializer;
101
- private readonly h3Event;
102
83
  private pingInterval;
103
84
  private readonly pingIntervalMs;
85
+ readonly eventStream: EventStream;
104
86
  constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
105
87
  /**
106
88
  * Start sending the event stream to the client
@@ -115,15 +97,13 @@ declare class EventStreamConnection<TData> {
115
97
  * Publish an error event. This will trigger the `onError` hooks of any connected clients.
116
98
  */
117
99
  pushError(error: ErrorResponse, eventId?: string): Promise<void>;
118
- private publishEvents;
119
- private publishEvent;
120
100
  private cleanup;
121
101
  /**
122
102
  * Tell clients that the stream has ended and close the connection.
123
103
  */
124
- end(): Promise<void>;
125
- on(event: "disconnect", callback: () => any): void;
126
- on(event: "end", callback: () => any): void;
104
+ close(): Promise<void>;
105
+ on(event: "close", callback: () => any): void;
106
+ on(event: "request:close", callback: () => any): void;
127
107
  }
128
108
  declare function registerEventStreamRpc(router: Router, path: string, procedure: EventStreamRpc<any, any> & {
129
109
  name: string;
@@ -257,4 +237,4 @@ type ResolvedArriConfig = Required<ArriConfig>;
257
237
  declare const defaultConfig: Required<ArriConfig>;
258
238
  declare function defineConfig(config: ArriConfig): ResolvedArriConfig;
259
239
 
260
- 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 };
240
+ export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, ErrorResponse, 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, createRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { HttpMethod, RpcHttpMethod, RpcDefinition, SchemaFormProperties, SchemaF
2
2
  import { AObjectSchema, ASchema, InferType, a, ValidationError, ValueError, ARecordSchema, ADiscriminatorSchema } from 'arri-validate';
3
3
  import { H3EventContext, H3Event, Router, H3Error, App } from 'h3';
4
4
  export * from 'h3';
5
+ import { EventStream } from 'h3-sse';
5
6
  import { BuildOptions } from 'esbuild';
6
7
 
7
8
  interface MiddlewareEventContext extends H3EventContext {
@@ -58,19 +59,15 @@ declare function errorResponseFromValidationErrors(errors: ValidationError["erro
58
59
  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
60
  declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions["onError"]): Promise<void>;
60
61
 
61
- declare function setSseHeaders(event: H3Event): void;
62
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
63
  declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
64
64
  interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<Rpc<true, TParams, TResponse>, "handler" | "postHandler"> {
65
65
  isEventStream: true;
66
66
  handler: EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
67
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
- }
68
+ type EventStreamRpcHandler<TParams, TResponse> = (context: EventStreamRpcHandlerContext<TParams, TResponse>, event: RpcEvent<TResponse>) => void | Promise<void>;
72
69
  interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends RpcHandlerContext<TParams> {
73
- connection: EventStreamConnection<TResponse>;
70
+ stream: EventStreamConnection<TResponse>;
74
71
  }
75
72
  interface EventStreamConnectionOptions<TData> {
76
73
  validator: (input: unknown) => input is TData;
@@ -78,29 +75,14 @@ interface EventStreamConnectionOptions<TData> {
78
75
  serializer: (input: TData) => string;
79
76
  pingInterval?: number;
80
77
  }
81
- /**
82
- * A server sent event
83
- */
84
- interface Sse {
85
- id?: string;
86
- event?: string;
87
- data: string;
88
- }
89
- declare function formatSse({ id, data, event }: Sse): string;
90
- declare function formatSseList(events: Sse[]): string;
91
78
  declare class EventStreamConnection<TData> {
92
- lastEventId: string | undefined;
93
- private readonly writable;
94
- private readonly readable;
95
- private readonly writer;
96
- private writerIsClosed;
97
- private readonly encoder;
79
+ private readonly h3Event;
98
80
  private readonly validationErrors;
99
81
  private readonly validator;
100
82
  private readonly serializer;
101
- private readonly h3Event;
102
83
  private pingInterval;
103
84
  private readonly pingIntervalMs;
85
+ readonly eventStream: EventStream;
104
86
  constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
105
87
  /**
106
88
  * Start sending the event stream to the client
@@ -115,15 +97,13 @@ declare class EventStreamConnection<TData> {
115
97
  * Publish an error event. This will trigger the `onError` hooks of any connected clients.
116
98
  */
117
99
  pushError(error: ErrorResponse, eventId?: string): Promise<void>;
118
- private publishEvents;
119
- private publishEvent;
120
100
  private cleanup;
121
101
  /**
122
102
  * Tell clients that the stream has ended and close the connection.
123
103
  */
124
- end(): Promise<void>;
125
- on(event: "disconnect", callback: () => any): void;
126
- on(event: "end", callback: () => any): void;
104
+ close(): Promise<void>;
105
+ on(event: "close", callback: () => any): void;
106
+ on(event: "request:close", callback: () => any): void;
127
107
  }
128
108
  declare function registerEventStreamRpc(router: Router, path: string, procedure: EventStreamRpc<any, any> & {
129
109
  name: string;
@@ -257,4 +237,4 @@ type ResolvedArriConfig = Required<ArriConfig>;
257
237
  declare const defaultConfig: Required<ArriConfig>;
258
238
  declare function defineConfig(config: ArriConfig): ResolvedArriConfig;
259
239
 
260
- 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 };
240
+ export { ArriApp, type ArriConfig, type ArriOptions, type ArriRoute, ArriRouter, type ArriRouterBase, DEV_DEFINITION_ENDPOINT, DEV_ENDPOINT_ROOT, ErrorResponse, 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, createRpcDefinition, defaultConfig, defineConfig, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, handleH3Error, handleRoute, isArriConfig, isEventStreamRpc, isResolvedArriConfig, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- export { A as ArriApp, p as ArriRouter, a as DEV_DEFINITION_ENDPOINT, D as DEV_ENDPOINT_ROOT, E as ErrorResponse, B as EventStreamConnection, c as createRpcDefinition, n as defaultConfig, o as defineConfig, h as defineError, w as defineEventStreamRpc, q as defineRoute, d as defineRpc, j as errorResponseFromValidationErrors, y as formatSse, z as formatSseList, e as getRpcParamName, g as getRpcPath, f as getRpcResponseName, k as handleH3Error, t as handleRoute, l as isArriConfig, x as isEventStreamRpc, m as isResolvedArriConfig, b as isRpc, i as isRpcParamSchema, C as registerEventStreamRpc, s as registerRoute, r as registerRpc, u as setSseHeaders, v as validateRpcRequestInput } from './shared/arri.ebc63bd6.mjs';
1
+ export { A as ArriApp, p as ArriRouter, a as DEV_DEFINITION_ENDPOINT, D as DEV_ENDPOINT_ROOT, E as ErrorResponse, x as EventStreamConnection, c as createRpcDefinition, n as defaultConfig, o as defineConfig, h as defineError, u as defineEventStreamRpc, q as defineRoute, d as defineRpc, j as errorResponseFromValidationErrors, e as getRpcParamName, g as getRpcPath, f as getRpcResponseName, k as handleH3Error, t as handleRoute, l as isArriConfig, w as isEventStreamRpc, m as isResolvedArriConfig, b as isRpc, i as isRpcParamSchema, y as registerEventStreamRpc, s as registerRoute, r as registerRpc, v as validateRpcRequestInput } from './shared/arri.ba3f283e.mjs';
2
2
  export * from 'h3';
3
3
  import 'arri-validate';
4
- import 'node:process';
4
+ import 'h3-sse';
5
5
  import 'arri-codegen-utils';
6
6
  import 'scule';
7
7
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const h3 = require('h3');
4
4
  const arriValidate = require('arri-validate');
5
- const node_process = require('node:process');
5
+ const h3Sse = require('h3-sse');
6
6
  const arriCodegenUtils = require('arri-codegen-utils');
7
7
  const scule = require('scule');
8
8
 
@@ -433,19 +433,6 @@ var __publicField$2 = (obj, key, value) => {
433
433
  __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
434
434
  return value;
435
435
  };
436
- function setSseHeaders(event) {
437
- const isHttp2 = h3.getHeader(event, ":path") !== void 0 && h3.getHeader(event, ":method") !== void 0;
438
- const input = {
439
- "Content-Type": "text/event-stream",
440
- "Cache-Control": "private, no-cache, no-store, no-transform, must-revalidate, max-age=0",
441
- Pragma: "no-cache",
442
- "X-Accel-Buffering": "no"
443
- };
444
- if (!isHttp2) {
445
- input.Connection = "keep-alive";
446
- }
447
- h3.setResponseHeaders(event, input);
448
- }
449
436
  function defineEventStreamRpc(config) {
450
437
  return {
451
438
  ...config,
@@ -456,69 +443,33 @@ function defineEventStreamRpc(config) {
456
443
  function isEventStreamRpc(input) {
457
444
  return isRpc(input) && "isEventStream" in input && input.isEventStream === true;
458
445
  }
459
- function formatSse({ id, data, event }) {
460
- const parts = [];
461
- if (id) {
462
- parts.push(`id: ${id}`);
463
- }
464
- if (event) {
465
- parts.push(`event: ${event}`);
466
- }
467
- parts.push(`data: ${data}`);
468
- const payload = `${parts.join("\n")}
469
-
470
- `;
471
- return payload;
472
- }
473
- function formatSseList(events) {
474
- let output = "";
475
- for (const event of events) {
476
- output += formatSse(event);
477
- }
478
- return output;
479
- }
480
446
  class EventStreamConnection {
481
447
  constructor(event, opts) {
482
- __publicField$2(this, "lastEventId");
483
- __publicField$2(this, "writable");
484
- __publicField$2(this, "readable");
485
- __publicField$2(this, "writer");
486
- __publicField$2(this, "writerIsClosed", false);
487
- __publicField$2(this, "encoder");
448
+ __publicField$2(this, "h3Event");
488
449
  __publicField$2(this, "validationErrors");
489
450
  __publicField$2(this, "validator");
490
451
  __publicField$2(this, "serializer");
491
- __publicField$2(this, "h3Event");
492
452
  // for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
493
453
  __publicField$2(this, "pingInterval");
494
454
  __publicField$2(this, "pingIntervalMs");
455
+ __publicField$2(this, "eventStream");
495
456
  this.h3Event = event;
496
- const id = h3.getHeader(event, "Last-Event-ID");
497
- this.lastEventId = id;
498
- const { readable, writable } = new TransformStream();
499
- this.writable = writable;
500
- this.readable = readable;
501
- this.writer = writable.getWriter();
502
- this.encoder = new TextEncoder();
457
+ this.eventStream = h3Sse.createEventStream(event, true);
503
458
  this.pingIntervalMs = opts.pingInterval ?? 6e4;
504
459
  this.serializer = opts.serializer;
505
460
  this.validator = opts.validator;
506
461
  this.validationErrors = opts.validationErrors;
507
- void this.writer.closed.then(() => {
508
- this.writerIsClosed = true;
462
+ this.eventStream.on("close", () => {
463
+ this.cleanup();
509
464
  });
510
465
  }
511
466
  /**
512
467
  * Start sending the event stream to the client
513
468
  */
514
469
  start() {
515
- setSseHeaders(this.h3Event);
516
- h3.setResponseStatus(this.h3Event, 200);
517
- this.h3Event._handled = true;
518
- void h3.sendStream(this.h3Event, this.readable);
470
+ void h3Sse.sendEventStream(this.h3Event, this.eventStream);
519
471
  this.pingInterval = setInterval(async () => {
520
- await this.publishEvent({
521
- id: this.lastEventId,
472
+ await this.eventStream.push({
522
473
  event: "ping",
523
474
  data: ""
524
475
  });
@@ -548,11 +499,11 @@ class EventStreamConnection {
548
499
  data: JSON.stringify(errorResponse2)
549
500
  });
550
501
  }
551
- await this.publishEvents(events);
502
+ await this.eventStream.push(events);
552
503
  return;
553
504
  }
554
505
  if (this.validator(data)) {
555
- await this.publishEvent({
506
+ await this.eventStream.push({
556
507
  id: eventId,
557
508
  event: "message",
558
509
  data: this.serializer(data)
@@ -565,7 +516,7 @@ class EventStreamConnection {
565
516
  statusMessage: "Failed to serialize response. Response does not match specified schema.",
566
517
  data: errors
567
518
  };
568
- await this.publishEvent({
519
+ await this.eventStream.push({
569
520
  id: eventId,
570
521
  event: "error",
571
522
  data: JSON.stringify(errorResponse)
@@ -591,79 +542,34 @@ class EventStreamConnection {
591
542
  * Publish an error event. This will trigger the `onError` hooks of any connected clients.
592
543
  */
593
544
  async pushError(error, eventId) {
594
- await this.publishEvent({
545
+ await this.eventStream.push({
595
546
  id: eventId,
596
547
  event: "error",
597
548
  data: JSON.stringify(error)
598
549
  });
599
550
  }
600
- async publishEvents(events) {
601
- const payload = formatSseList(events);
602
- if (this.writerIsClosed) {
603
- try {
604
- this.h3Event.node.res.end();
605
- } catch (_) {
606
- await this.cleanup();
607
- }
608
- return;
609
- }
610
- await this.writer.write(this.encoder.encode(payload));
611
- }
612
- async publishEvent(event) {
613
- const payload = formatSse(event);
614
- if (this.writerIsClosed) {
615
- try {
616
- this.h3Event.node.res.end();
617
- } catch (_) {
618
- await this.cleanup();
619
- }
620
- return;
621
- }
622
- await this.writer.write(this.encoder.encode(payload));
623
- }
624
- async cleanup() {
551
+ cleanup() {
625
552
  if (this.pingInterval) {
626
553
  clearInterval(this.pingInterval);
627
554
  }
628
- if (!this.writerIsClosed) {
629
- try {
630
- await this.writer.close();
631
- } catch (_) {
632
- }
633
- }
634
555
  }
635
556
  /**
636
557
  * Tell clients that the stream has ended and close the connection.
637
558
  */
638
- async end() {
639
- await this.publishEvent({
559
+ async close() {
560
+ await this.eventStream.push({
640
561
  event: "done",
641
562
  data: "this stream has ended"
642
563
  }).catch();
643
- await new Promise((resolve, reject) => {
644
- node_process.nextTick(() => {
645
- try {
646
- this.h3Event.node.res.end();
647
- resolve(true);
648
- } catch (err) {
649
- reject(err);
650
- }
651
- });
652
- });
564
+ await this.eventStream.close();
653
565
  }
654
566
  on(event, callback) {
655
567
  switch (event) {
656
- case "disconnect":
657
- this.h3Event.node.req.on("close", async () => {
658
- await callback();
659
- await this.cleanup();
660
- });
568
+ case "close":
569
+ this.eventStream.on("close", callback);
661
570
  break;
662
- case "end":
663
- this.h3Event.node.req.on("end", async () => {
664
- await callback();
665
- await this.cleanup();
666
- });
571
+ case "request:close":
572
+ this.eventStream.on("request:close", callback);
667
573
  break;
668
574
  }
669
575
  }
@@ -697,7 +603,7 @@ function registerEventStreamRpc(router, path, procedure, opts) {
697
603
  procedure.params
698
604
  );
699
605
  }
700
- const connection = new EventStreamConnection(event, {
606
+ const stream = new EventStreamConnection(event, {
701
607
  pingInterval: procedure.pingInterval,
702
608
  validator: responseValidator?.validate ?? function() {
703
609
  return true;
@@ -712,11 +618,14 @@ function registerEventStreamRpc(router, path, procedure, opts) {
712
618
  return [];
713
619
  }
714
620
  });
715
- event.context.connection = connection;
621
+ event.context.stream = stream;
716
622
  await procedure.handler(
717
623
  event.context,
718
624
  event
719
625
  );
626
+ if (!event.handled && !stream.eventStream._handled) {
627
+ await h3Sse.sendEventStream(event, stream.eventStream);
628
+ }
720
629
  } catch (err) {
721
630
  await handleH3Error(err, event, opts.onError);
722
631
  }
@@ -1102,8 +1011,6 @@ exports.defineEventStreamRpc = defineEventStreamRpc;
1102
1011
  exports.defineRoute = defineRoute;
1103
1012
  exports.defineRpc = defineRpc;
1104
1013
  exports.errorResponseFromValidationErrors = errorResponseFromValidationErrors;
1105
- exports.formatSse = formatSse;
1106
- exports.formatSseList = formatSseList;
1107
1014
  exports.getRpcParamName = getRpcParamName;
1108
1015
  exports.getRpcPath = getRpcPath;
1109
1016
  exports.getRpcResponseName = getRpcResponseName;
@@ -1117,5 +1024,4 @@ exports.isRpcParamSchema = isRpcParamSchema;
1117
1024
  exports.registerEventStreamRpc = registerEventStreamRpc;
1118
1025
  exports.registerRoute = registerRoute;
1119
1026
  exports.registerRpc = registerRpc;
1120
- exports.setSseHeaders = setSseHeaders;
1121
1027
  exports.validateRpcRequestInput = validateRpcRequestInput;
@@ -1,6 +1,6 @@
1
- import { createError, isError, setResponseStatus, send, eventHandler, isPreflightRequest, setResponseHeader, readRawBody, getValidatedQuery, getHeader, setResponseHeaders, sendStream, defineEventHandler, getQuery, setHeader, createRouter, createApp, sendError } from 'h3';
1
+ import { createError, isError, setResponseStatus, send, eventHandler, isPreflightRequest, setResponseHeader, readRawBody, getValidatedQuery, defineEventHandler, getQuery, setHeader, createRouter, createApp, sendError } from 'h3';
2
2
  import { a, isAObjectSchema, isARecordSchema, isADiscriminatorSchema } from 'arri-validate';
3
- import { nextTick } from 'node:process';
3
+ import { createEventStream, sendEventStream } from 'h3-sse';
4
4
  import { isRpcHttpMethod, removeDisallowedChars } from 'arri-codegen-utils';
5
5
  import { kebabCase, pascalCase } from 'scule';
6
6
 
@@ -431,19 +431,6 @@ var __publicField$2 = (obj, key, value) => {
431
431
  __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
432
432
  return value;
433
433
  };
434
- function setSseHeaders(event) {
435
- const isHttp2 = getHeader(event, ":path") !== void 0 && getHeader(event, ":method") !== void 0;
436
- const input = {
437
- "Content-Type": "text/event-stream",
438
- "Cache-Control": "private, no-cache, no-store, no-transform, must-revalidate, max-age=0",
439
- Pragma: "no-cache",
440
- "X-Accel-Buffering": "no"
441
- };
442
- if (!isHttp2) {
443
- input.Connection = "keep-alive";
444
- }
445
- setResponseHeaders(event, input);
446
- }
447
434
  function defineEventStreamRpc(config) {
448
435
  return {
449
436
  ...config,
@@ -454,69 +441,33 @@ function defineEventStreamRpc(config) {
454
441
  function isEventStreamRpc(input) {
455
442
  return isRpc(input) && "isEventStream" in input && input.isEventStream === true;
456
443
  }
457
- function formatSse({ id, data, event }) {
458
- const parts = [];
459
- if (id) {
460
- parts.push(`id: ${id}`);
461
- }
462
- if (event) {
463
- parts.push(`event: ${event}`);
464
- }
465
- parts.push(`data: ${data}`);
466
- const payload = `${parts.join("\n")}
467
-
468
- `;
469
- return payload;
470
- }
471
- function formatSseList(events) {
472
- let output = "";
473
- for (const event of events) {
474
- output += formatSse(event);
475
- }
476
- return output;
477
- }
478
444
  class EventStreamConnection {
479
445
  constructor(event, opts) {
480
- __publicField$2(this, "lastEventId");
481
- __publicField$2(this, "writable");
482
- __publicField$2(this, "readable");
483
- __publicField$2(this, "writer");
484
- __publicField$2(this, "writerIsClosed", false);
485
- __publicField$2(this, "encoder");
446
+ __publicField$2(this, "h3Event");
486
447
  __publicField$2(this, "validationErrors");
487
448
  __publicField$2(this, "validator");
488
449
  __publicField$2(this, "serializer");
489
- __publicField$2(this, "h3Event");
490
450
  // for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
491
451
  __publicField$2(this, "pingInterval");
492
452
  __publicField$2(this, "pingIntervalMs");
453
+ __publicField$2(this, "eventStream");
493
454
  this.h3Event = event;
494
- const id = getHeader(event, "Last-Event-ID");
495
- this.lastEventId = id;
496
- const { readable, writable } = new TransformStream();
497
- this.writable = writable;
498
- this.readable = readable;
499
- this.writer = writable.getWriter();
500
- this.encoder = new TextEncoder();
455
+ this.eventStream = createEventStream(event, true);
501
456
  this.pingIntervalMs = opts.pingInterval ?? 6e4;
502
457
  this.serializer = opts.serializer;
503
458
  this.validator = opts.validator;
504
459
  this.validationErrors = opts.validationErrors;
505
- void this.writer.closed.then(() => {
506
- this.writerIsClosed = true;
460
+ this.eventStream.on("close", () => {
461
+ this.cleanup();
507
462
  });
508
463
  }
509
464
  /**
510
465
  * Start sending the event stream to the client
511
466
  */
512
467
  start() {
513
- setSseHeaders(this.h3Event);
514
- setResponseStatus(this.h3Event, 200);
515
- this.h3Event._handled = true;
516
- void sendStream(this.h3Event, this.readable);
468
+ void sendEventStream(this.h3Event, this.eventStream);
517
469
  this.pingInterval = setInterval(async () => {
518
- await this.publishEvent({
519
- id: this.lastEventId,
470
+ await this.eventStream.push({
520
471
  event: "ping",
521
472
  data: ""
522
473
  });
@@ -546,11 +497,11 @@ class EventStreamConnection {
546
497
  data: JSON.stringify(errorResponse2)
547
498
  });
548
499
  }
549
- await this.publishEvents(events);
500
+ await this.eventStream.push(events);
550
501
  return;
551
502
  }
552
503
  if (this.validator(data)) {
553
- await this.publishEvent({
504
+ await this.eventStream.push({
554
505
  id: eventId,
555
506
  event: "message",
556
507
  data: this.serializer(data)
@@ -563,7 +514,7 @@ class EventStreamConnection {
563
514
  statusMessage: "Failed to serialize response. Response does not match specified schema.",
564
515
  data: errors
565
516
  };
566
- await this.publishEvent({
517
+ await this.eventStream.push({
567
518
  id: eventId,
568
519
  event: "error",
569
520
  data: JSON.stringify(errorResponse)
@@ -589,79 +540,34 @@ class EventStreamConnection {
589
540
  * Publish an error event. This will trigger the `onError` hooks of any connected clients.
590
541
  */
591
542
  async pushError(error, eventId) {
592
- await this.publishEvent({
543
+ await this.eventStream.push({
593
544
  id: eventId,
594
545
  event: "error",
595
546
  data: JSON.stringify(error)
596
547
  });
597
548
  }
598
- async publishEvents(events) {
599
- const payload = formatSseList(events);
600
- if (this.writerIsClosed) {
601
- try {
602
- this.h3Event.node.res.end();
603
- } catch (_) {
604
- await this.cleanup();
605
- }
606
- return;
607
- }
608
- await this.writer.write(this.encoder.encode(payload));
609
- }
610
- async publishEvent(event) {
611
- const payload = formatSse(event);
612
- if (this.writerIsClosed) {
613
- try {
614
- this.h3Event.node.res.end();
615
- } catch (_) {
616
- await this.cleanup();
617
- }
618
- return;
619
- }
620
- await this.writer.write(this.encoder.encode(payload));
621
- }
622
- async cleanup() {
549
+ cleanup() {
623
550
  if (this.pingInterval) {
624
551
  clearInterval(this.pingInterval);
625
552
  }
626
- if (!this.writerIsClosed) {
627
- try {
628
- await this.writer.close();
629
- } catch (_) {
630
- }
631
- }
632
553
  }
633
554
  /**
634
555
  * Tell clients that the stream has ended and close the connection.
635
556
  */
636
- async end() {
637
- await this.publishEvent({
557
+ async close() {
558
+ await this.eventStream.push({
638
559
  event: "done",
639
560
  data: "this stream has ended"
640
561
  }).catch();
641
- await new Promise((resolve, reject) => {
642
- nextTick(() => {
643
- try {
644
- this.h3Event.node.res.end();
645
- resolve(true);
646
- } catch (err) {
647
- reject(err);
648
- }
649
- });
650
- });
562
+ await this.eventStream.close();
651
563
  }
652
564
  on(event, callback) {
653
565
  switch (event) {
654
- case "disconnect":
655
- this.h3Event.node.req.on("close", async () => {
656
- await callback();
657
- await this.cleanup();
658
- });
566
+ case "close":
567
+ this.eventStream.on("close", callback);
659
568
  break;
660
- case "end":
661
- this.h3Event.node.req.on("end", async () => {
662
- await callback();
663
- await this.cleanup();
664
- });
569
+ case "request:close":
570
+ this.eventStream.on("request:close", callback);
665
571
  break;
666
572
  }
667
573
  }
@@ -695,7 +601,7 @@ function registerEventStreamRpc(router, path, procedure, opts) {
695
601
  procedure.params
696
602
  );
697
603
  }
698
- const connection = new EventStreamConnection(event, {
604
+ const stream = new EventStreamConnection(event, {
699
605
  pingInterval: procedure.pingInterval,
700
606
  validator: responseValidator?.validate ?? function() {
701
607
  return true;
@@ -710,11 +616,14 @@ function registerEventStreamRpc(router, path, procedure, opts) {
710
616
  return [];
711
617
  }
712
618
  });
713
- event.context.connection = connection;
619
+ event.context.stream = stream;
714
620
  await procedure.handler(
715
621
  event.context,
716
622
  event
717
623
  );
624
+ if (!event.handled && !stream.eventStream._handled) {
625
+ await sendEventStream(event, stream.eventStream);
626
+ }
718
627
  } catch (err) {
719
628
  await handleH3Error(err, event, opts.onError);
720
629
  }
@@ -1086,4 +995,4 @@ function defineConfig(config) {
1086
995
  };
1087
996
  }
1088
997
 
1089
- export { ArriApp as A, EventStreamConnection as B, registerEventStreamRpc as C, DEV_ENDPOINT_ROOT as D, ErrorResponse as E, DEV_DEFINITION_ENDPOINT as a, isRpc as b, createRpcDefinition as c, defineRpc as d, getRpcParamName as e, getRpcResponseName as f, getRpcPath as g, defineError as h, isRpcParamSchema as i, errorResponseFromValidationErrors as j, handleH3Error as k, isArriConfig as l, isResolvedArriConfig as m, defaultConfig as n, defineConfig as o, ArriRouter as p, defineRoute as q, registerRpc as r, registerRoute as s, handleRoute as t, setSseHeaders as u, validateRpcRequestInput as v, defineEventStreamRpc as w, isEventStreamRpc as x, formatSse as y, formatSseList as z };
998
+ export { ArriApp as A, DEV_ENDPOINT_ROOT as D, ErrorResponse as E, DEV_DEFINITION_ENDPOINT as a, isRpc as b, createRpcDefinition as c, defineRpc as d, getRpcParamName as e, getRpcResponseName as f, getRpcPath as g, defineError as h, isRpcParamSchema as i, errorResponseFromValidationErrors as j, handleH3Error as k, isArriConfig as l, isResolvedArriConfig as m, defaultConfig as n, defineConfig as o, ArriRouter as p, defineRoute as q, registerRpc as r, registerRoute as s, handleRoute as t, defineEventStreamRpc as u, validateRpcRequestInput as v, isEventStreamRpc as w, EventStreamConnection as x, registerEventStreamRpc as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arri",
3
- "version": "0.24.1",
3
+ "version": "0.25.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -26,28 +26,29 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@joshmossas/listhen": "1.6.0",
29
- "c12": "^1.8.0",
29
+ "c12": "^1.9.0",
30
30
  "chokidar": "^3.6.0",
31
31
  "citty": "^0.1.6",
32
32
  "consola": "^3.2.3",
33
33
  "degit": "^2.8.4",
34
- "esbuild": "^0.20.0",
34
+ "esbuild": "^0.20.1",
35
35
  "esbuild-plugin-replace": "^1.4.0",
36
36
  "globby": "^14.0.1",
37
- "h3": "^1.10.1",
37
+ "h3": "^1.10.2",
38
+ "h3-sse": "^0.0.7",
38
39
  "jiti": "^1.21.0",
39
40
  "ofetch": "^1.3.3",
40
41
  "pathe": "^1.1.2",
41
42
  "prettier": "^3.2.5",
42
43
  "scule": "^1.3.0",
43
44
  "uncrypto": "^0.1.3",
44
- "arri-codegen-dart": "0.24.1",
45
- "arri-codegen-ts": "0.24.1",
46
- "arri-codegen-utils": "0.24.1",
47
- "arri-validate": "0.24.1"
45
+ "arri-codegen-ts": "0.25.0",
46
+ "arri-codegen-utils": "0.25.0",
47
+ "arri-validate": "0.25.0",
48
+ "arri-codegen-dart": "0.25.0"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@types/degit": "^2.8.6",
51
- "bun-types": "^1.0.27"
52
+ "bun-types": "^1.0.28"
52
53
  }
53
54
  }