@arrirpc/server 0.79.1 → 0.80.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
@@ -225,7 +225,7 @@ Arri Event streams sent the following event types:
225
225
  - `message` - A standard message with the response data serialized as JSON
226
226
  - `start` - A starting message to start the stream
227
227
  - `done` - A message to tell clients that there will be no more events
228
- - `ping` - A message periodically sent by the server to keep the connection alive.
228
+ - `heartbeat` - A message periodically sent by the server to keep the connection alive.
229
229
 
230
230
  ```ts
231
231
  /// message event ///
@@ -237,8 +237,8 @@ data: Response; // whatever you have specified as the response serialized to jso
237
237
  event: 'done';
238
238
  data: 'this stream has ended';
239
239
 
240
- /// ping event ///
241
- event: 'ping';
240
+ /// heartbeat event ///
241
+ event: 'heartbeat';
242
242
  data: '';
243
243
  ```
244
244
 
package/dist/index.cjs CHANGED
@@ -472,7 +472,7 @@ function getSchemaName(rpcName, type, schema) {
472
472
  function defineEventStreamRpc(config) {
473
473
  return {
474
474
  ...config,
475
- method: config.method ?? "get",
475
+ method: config.method ?? "post",
476
476
  isEventStream: true,
477
477
  transport: "http"
478
478
  };
@@ -484,16 +484,32 @@ class EventStreamConnection {
484
484
  lastEventId;
485
485
  validator;
486
486
  // for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
487
- pingInterval = void 0;
488
- pingIntervalMs;
487
+ heartbeatInterval = void 0;
488
+ heartbeatMs;
489
+ sendHeartbeat;
489
490
  eventStream;
491
+ _isClosed = false;
490
492
  constructor(event, opts) {
491
- this.eventStream = h3.createEventStream(event);
493
+ this.heartbeatMs = opts.heartbeatMs ?? 2e4;
494
+ this.sendHeartbeat = opts.heartbeatEnabled ?? true;
495
+ h3.setResponseHeader(
496
+ event,
497
+ "heartbeat-interval",
498
+ this.heartbeatMs.toString()
499
+ );
500
+ this.eventStream = h3.createEventStream(event, { autoclose: false });
501
+ event.node.req.once("close", () => {
502
+ if (this._isClosed) return;
503
+ this.eventStream.close();
504
+ });
505
+ event.node.res.once("close", () => {
506
+ if (this._isClosed) return;
507
+ this.eventStream.close();
508
+ });
492
509
  this.lastEventId = h3.getHeader(event, "Last-Event-Id");
493
- this.pingIntervalMs = opts.pingInterval ?? 6e4;
494
510
  this.validator = opts.validator;
495
511
  this.eventStream.onClosed(() => {
496
- this.cleanup();
512
+ this._cleanup();
497
513
  });
498
514
  }
499
515
  /**
@@ -505,12 +521,15 @@ class EventStreamConnection {
505
521
  event: "start",
506
522
  data: "connection successful"
507
523
  });
508
- this.pingInterval = setInterval(async () => {
509
- await this.eventStream.push({
510
- event: "ping",
511
- data: ""
512
- });
513
- }, this.pingIntervalMs);
524
+ if (this.sendHeartbeat) {
525
+ this.heartbeatInterval = setInterval(async () => {
526
+ console.log("SENDING_HEARTBEAT");
527
+ await this.eventStream.push({
528
+ event: "heartbeat",
529
+ data: ""
530
+ });
531
+ }, this.heartbeatMs);
532
+ }
514
533
  }
515
534
  async push(data, eventId) {
516
535
  if (!this.validator) return;
@@ -552,9 +571,10 @@ class EventStreamConnection {
552
571
  errors
553
572
  };
554
573
  }
555
- cleanup() {
556
- if (this.pingInterval) {
557
- clearInterval(this.pingInterval);
574
+ _cleanup() {
575
+ this._isClosed = true;
576
+ if (this.heartbeatInterval) {
577
+ clearInterval(this.heartbeatInterval);
558
578
  }
559
579
  }
560
580
  /**
@@ -574,7 +594,7 @@ class EventStreamConnection {
574
594
  function registerEventStreamRpc(router, path, procedure, opts) {
575
595
  const paramValidator = procedure.params ? getSchemaValidator(procedure.name, "params", procedure.params) : void 0;
576
596
  const responseValidator = procedure.response ? getSchemaValidator(procedure.name, "response", procedure.response) : void 0;
577
- const httpMethod = procedure.method ?? "get";
597
+ const httpMethod = procedure.method ?? "post";
578
598
  const handler = h3.eventHandler(async (event) => {
579
599
  event.context.rpcName = procedure.name;
580
600
  if (h3.isPreflightRequest(event)) {
@@ -597,7 +617,8 @@ function registerEventStreamRpc(router, path, procedure, opts) {
597
617
  );
598
618
  }
599
619
  const stream = new EventStreamConnection(event, {
600
- pingInterval: procedure.pingInterval,
620
+ heartbeatMs: procedure.heartbeatMs,
621
+ heartbeatEnabled: procedure.heartbeatEnabled,
601
622
  validator: responseValidator
602
623
  });
603
624
  event.context.stream = stream;
package/dist/index.d.cts CHANGED
@@ -102,14 +102,17 @@ interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends R
102
102
  }
103
103
  interface EventStreamConnectionOptions<TData> {
104
104
  validator?: RequestValidator<TData>;
105
- pingInterval?: number;
105
+ heartbeatMs?: number;
106
+ heartbeatEnabled?: boolean;
106
107
  }
107
108
  declare class EventStreamConnection<TData> {
108
109
  readonly lastEventId?: string;
109
110
  private readonly validator?;
110
- private pingInterval;
111
- private readonly pingIntervalMs;
111
+ private heartbeatInterval;
112
+ private readonly heartbeatMs;
113
+ private readonly sendHeartbeat;
112
114
  readonly eventStream: EventStream;
115
+ private _isClosed;
113
116
  constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
114
117
  /**
115
118
  * Send the stream to the client. This must be called before sending any events.
@@ -120,7 +123,7 @@ declare class EventStreamConnection<TData> {
120
123
  */
121
124
  push(data: TData[], eventId?: string): Promise<SsePushResult[]>;
122
125
  push(data: TData, eventId?: string): Promise<SsePushResult>;
123
- private cleanup;
126
+ private _cleanup;
124
127
  /**
125
128
  * Tell clients that the stream has ended and close the connection.
126
129
  */
@@ -152,7 +155,8 @@ interface HttpRpc<TIsEventStream extends boolean = false, TParams extends RpcPar
152
155
  response: TResponse;
153
156
  isDeprecated?: boolean;
154
157
  isEventStream?: TIsEventStream;
155
- pingInterval?: TIsEventStream extends true ? number : undefined;
158
+ heartbeatMs?: TIsEventStream extends true ? number : never;
159
+ heartbeatEnabled?: TIsEventStream extends true ? boolean : never;
156
160
  handler: TIsEventStream extends true ? EventStreamRpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined> : RpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : void>;
157
161
  postHandler?: TIsEventStream extends true ? undefined : RpcPostHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined>;
158
162
  }
package/dist/index.d.mts CHANGED
@@ -102,14 +102,17 @@ interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends R
102
102
  }
103
103
  interface EventStreamConnectionOptions<TData> {
104
104
  validator?: RequestValidator<TData>;
105
- pingInterval?: number;
105
+ heartbeatMs?: number;
106
+ heartbeatEnabled?: boolean;
106
107
  }
107
108
  declare class EventStreamConnection<TData> {
108
109
  readonly lastEventId?: string;
109
110
  private readonly validator?;
110
- private pingInterval;
111
- private readonly pingIntervalMs;
111
+ private heartbeatInterval;
112
+ private readonly heartbeatMs;
113
+ private readonly sendHeartbeat;
112
114
  readonly eventStream: EventStream;
115
+ private _isClosed;
113
116
  constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
114
117
  /**
115
118
  * Send the stream to the client. This must be called before sending any events.
@@ -120,7 +123,7 @@ declare class EventStreamConnection<TData> {
120
123
  */
121
124
  push(data: TData[], eventId?: string): Promise<SsePushResult[]>;
122
125
  push(data: TData, eventId?: string): Promise<SsePushResult>;
123
- private cleanup;
126
+ private _cleanup;
124
127
  /**
125
128
  * Tell clients that the stream has ended and close the connection.
126
129
  */
@@ -152,7 +155,8 @@ interface HttpRpc<TIsEventStream extends boolean = false, TParams extends RpcPar
152
155
  response: TResponse;
153
156
  isDeprecated?: boolean;
154
157
  isEventStream?: TIsEventStream;
155
- pingInterval?: TIsEventStream extends true ? number : undefined;
158
+ heartbeatMs?: TIsEventStream extends true ? number : never;
159
+ heartbeatEnabled?: TIsEventStream extends true ? boolean : never;
156
160
  handler: TIsEventStream extends true ? EventStreamRpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined> : RpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : void>;
157
161
  postHandler?: TIsEventStream extends true ? undefined : RpcPostHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined>;
158
162
  }
package/dist/index.d.ts CHANGED
@@ -102,14 +102,17 @@ interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends R
102
102
  }
103
103
  interface EventStreamConnectionOptions<TData> {
104
104
  validator?: RequestValidator<TData>;
105
- pingInterval?: number;
105
+ heartbeatMs?: number;
106
+ heartbeatEnabled?: boolean;
106
107
  }
107
108
  declare class EventStreamConnection<TData> {
108
109
  readonly lastEventId?: string;
109
110
  private readonly validator?;
110
- private pingInterval;
111
- private readonly pingIntervalMs;
111
+ private heartbeatInterval;
112
+ private readonly heartbeatMs;
113
+ private readonly sendHeartbeat;
112
114
  readonly eventStream: EventStream;
115
+ private _isClosed;
113
116
  constructor(event: H3Event, opts: EventStreamConnectionOptions<TData>);
114
117
  /**
115
118
  * Send the stream to the client. This must be called before sending any events.
@@ -120,7 +123,7 @@ declare class EventStreamConnection<TData> {
120
123
  */
121
124
  push(data: TData[], eventId?: string): Promise<SsePushResult[]>;
122
125
  push(data: TData, eventId?: string): Promise<SsePushResult>;
123
- private cleanup;
126
+ private _cleanup;
124
127
  /**
125
128
  * Tell clients that the stream has ended and close the connection.
126
129
  */
@@ -152,7 +155,8 @@ interface HttpRpc<TIsEventStream extends boolean = false, TParams extends RpcPar
152
155
  response: TResponse;
153
156
  isDeprecated?: boolean;
154
157
  isEventStream?: TIsEventStream;
155
- pingInterval?: TIsEventStream extends true ? number : undefined;
158
+ heartbeatMs?: TIsEventStream extends true ? number : never;
159
+ heartbeatEnabled?: TIsEventStream extends true ? boolean : never;
156
160
  handler: TIsEventStream extends true ? EventStreamRpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined> : RpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : void>;
157
161
  postHandler?: TIsEventStream extends true ? undefined : RpcPostHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined>;
158
162
  }
package/dist/index.mjs CHANGED
@@ -471,7 +471,7 @@ function getSchemaName(rpcName, type, schema) {
471
471
  function defineEventStreamRpc(config) {
472
472
  return {
473
473
  ...config,
474
- method: config.method ?? "get",
474
+ method: config.method ?? "post",
475
475
  isEventStream: true,
476
476
  transport: "http"
477
477
  };
@@ -483,16 +483,32 @@ class EventStreamConnection {
483
483
  lastEventId;
484
484
  validator;
485
485
  // for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
486
- pingInterval = void 0;
487
- pingIntervalMs;
486
+ heartbeatInterval = void 0;
487
+ heartbeatMs;
488
+ sendHeartbeat;
488
489
  eventStream;
490
+ _isClosed = false;
489
491
  constructor(event, opts) {
490
- this.eventStream = createEventStream(event);
492
+ this.heartbeatMs = opts.heartbeatMs ?? 2e4;
493
+ this.sendHeartbeat = opts.heartbeatEnabled ?? true;
494
+ setResponseHeader(
495
+ event,
496
+ "heartbeat-interval",
497
+ this.heartbeatMs.toString()
498
+ );
499
+ this.eventStream = createEventStream(event, { autoclose: false });
500
+ event.node.req.once("close", () => {
501
+ if (this._isClosed) return;
502
+ this.eventStream.close();
503
+ });
504
+ event.node.res.once("close", () => {
505
+ if (this._isClosed) return;
506
+ this.eventStream.close();
507
+ });
491
508
  this.lastEventId = getHeader(event, "Last-Event-Id");
492
- this.pingIntervalMs = opts.pingInterval ?? 6e4;
493
509
  this.validator = opts.validator;
494
510
  this.eventStream.onClosed(() => {
495
- this.cleanup();
511
+ this._cleanup();
496
512
  });
497
513
  }
498
514
  /**
@@ -504,12 +520,15 @@ class EventStreamConnection {
504
520
  event: "start",
505
521
  data: "connection successful"
506
522
  });
507
- this.pingInterval = setInterval(async () => {
508
- await this.eventStream.push({
509
- event: "ping",
510
- data: ""
511
- });
512
- }, this.pingIntervalMs);
523
+ if (this.sendHeartbeat) {
524
+ this.heartbeatInterval = setInterval(async () => {
525
+ console.log("SENDING_HEARTBEAT");
526
+ await this.eventStream.push({
527
+ event: "heartbeat",
528
+ data: ""
529
+ });
530
+ }, this.heartbeatMs);
531
+ }
513
532
  }
514
533
  async push(data, eventId) {
515
534
  if (!this.validator) return;
@@ -551,9 +570,10 @@ class EventStreamConnection {
551
570
  errors
552
571
  };
553
572
  }
554
- cleanup() {
555
- if (this.pingInterval) {
556
- clearInterval(this.pingInterval);
573
+ _cleanup() {
574
+ this._isClosed = true;
575
+ if (this.heartbeatInterval) {
576
+ clearInterval(this.heartbeatInterval);
557
577
  }
558
578
  }
559
579
  /**
@@ -573,7 +593,7 @@ class EventStreamConnection {
573
593
  function registerEventStreamRpc(router, path, procedure, opts) {
574
594
  const paramValidator = procedure.params ? getSchemaValidator(procedure.name, "params", procedure.params) : void 0;
575
595
  const responseValidator = procedure.response ? getSchemaValidator(procedure.name, "response", procedure.response) : void 0;
576
- const httpMethod = procedure.method ?? "get";
596
+ const httpMethod = procedure.method ?? "post";
577
597
  const handler = eventHandler(async (event) => {
578
598
  event.context.rpcName = procedure.name;
579
599
  if (isPreflightRequest(event)) {
@@ -596,7 +616,8 @@ function registerEventStreamRpc(router, path, procedure, opts) {
596
616
  );
597
617
  }
598
618
  const stream = new EventStreamConnection(event, {
599
- pingInterval: procedure.pingInterval,
619
+ heartbeatMs: procedure.heartbeatMs,
620
+ heartbeatEnabled: procedure.heartbeatEnabled,
600
621
  validator: responseValidator
601
622
  });
602
623
  event.context.stream = stream;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrirpc/server",
3
- "version": "0.79.1",
3
+ "version": "0.80.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -28,11 +28,11 @@
28
28
  "scule": "^1.3.0",
29
29
  "source-map-support": "^0.5.21",
30
30
  "uncrypto": "^0.1.3",
31
- "@arrirpc/codegen-utils": "0.79.1",
32
- "@arrirpc/schema": "0.79.1",
33
- "arri": "0.79.1"
31
+ "@arrirpc/codegen-utils": "0.80.1",
32
+ "arri": "0.80.1",
33
+ "@arrirpc/schema": "0.80.1"
34
34
  },
35
35
  "devDependencies": {
36
- "bun-types": "^1.2.14"
36
+ "bun-types": "^1.2.15"
37
37
  }
38
38
  }