@orpc/experimental-durable-iterator 0.0.0-next.e7bc0b8 → 0.0.0-next.ea1d4fd

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
@@ -17,6 +17,9 @@
17
17
  <a href="https://discord.gg/TXEbwRBvQn">
18
18
  <img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
19
19
  </a>
20
+ <a href="https://deepwiki.com/unnoq/orpc">
21
+ <img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki">
22
+ </a>
20
23
  </div>
21
24
 
22
25
  <h3 align="center">Typesafe APIs Made Simple 🪄</h3>
@@ -39,6 +39,12 @@ interface DurableIteratorLinkPluginOptions<T extends ClientContext> extends Omit
39
39
  * @default NaN (disabled)
40
40
  */
41
41
  refreshTokenBeforeExpireInSeconds?: Value<Promisable<number>, [tokenPayload: DurableIteratorTokenPayload, options: StandardLinkInterceptorOptions<T>]>;
42
+ /**
43
+ * Minimum delay between token refresh attempts.
44
+ *
45
+ * @default 2 (seconds)
46
+ */
47
+ refreshTokenDelayInSeconds?: Value<Promisable<number>, [tokenPayload: DurableIteratorTokenPayload, options: StandardLinkInterceptorOptions<T>]>;
42
48
  }
43
49
  /**
44
50
  * @see {@link https://orpc.unnoq.com/docs/integrations/durable-iterator Durable Iterator Integration}
@@ -52,8 +58,9 @@ declare class DurableIteratorLinkPlugin<T extends ClientContext> implements Stan
52
58
  private readonly url;
53
59
  private readonly createId;
54
60
  private readonly refreshTokenBeforeExpireInSeconds;
61
+ private readonly refreshTokenDelayInSeconds;
55
62
  private readonly linkOptions;
56
- constructor({ url, refreshTokenBeforeExpireInSeconds, ...options }: DurableIteratorLinkPluginOptions<T>);
63
+ constructor({ url, refreshTokenBeforeExpireInSeconds, refreshTokenDelayInSeconds, ...options }: DurableIteratorLinkPluginOptions<T>);
57
64
  init(options: StandardLinkOptions<T>): void;
58
65
  private validateToken;
59
66
  }
@@ -39,6 +39,12 @@ interface DurableIteratorLinkPluginOptions<T extends ClientContext> extends Omit
39
39
  * @default NaN (disabled)
40
40
  */
41
41
  refreshTokenBeforeExpireInSeconds?: Value<Promisable<number>, [tokenPayload: DurableIteratorTokenPayload, options: StandardLinkInterceptorOptions<T>]>;
42
+ /**
43
+ * Minimum delay between token refresh attempts.
44
+ *
45
+ * @default 2 (seconds)
46
+ */
47
+ refreshTokenDelayInSeconds?: Value<Promisable<number>, [tokenPayload: DurableIteratorTokenPayload, options: StandardLinkInterceptorOptions<T>]>;
42
48
  }
43
49
  /**
44
50
  * @see {@link https://orpc.unnoq.com/docs/integrations/durable-iterator Durable Iterator Integration}
@@ -52,8 +58,9 @@ declare class DurableIteratorLinkPlugin<T extends ClientContext> implements Stan
52
58
  private readonly url;
53
59
  private readonly createId;
54
60
  private readonly refreshTokenBeforeExpireInSeconds;
61
+ private readonly refreshTokenDelayInSeconds;
55
62
  private readonly linkOptions;
56
- constructor({ url, refreshTokenBeforeExpireInSeconds, ...options }: DurableIteratorLinkPluginOptions<T>);
63
+ constructor({ url, refreshTokenBeforeExpireInSeconds, refreshTokenDelayInSeconds, ...options }: DurableIteratorLinkPluginOptions<T>);
57
64
  init(options: StandardLinkOptions<T>): void;
58
65
  private validateToken;
59
66
  }
@@ -1,11 +1,11 @@
1
- import { c as createClientDurableIterator } from '../shared/experimental-durable-iterator.B3M42lLK.mjs';
2
- export { g as getClientDurableIteratorToken } from '../shared/experimental-durable-iterator.B3M42lLK.mjs';
1
+ import { c as createClientDurableIterator } from '../shared/experimental-durable-iterator.sCul6zQj.mjs';
2
+ export { g as getClientDurableIteratorToken } from '../shared/experimental-durable-iterator.sCul6zQj.mjs';
3
3
  import { createORPCClient } from '@orpc/client';
4
4
  import { ClientRetryPlugin } from '@orpc/client/plugins';
5
5
  import { RPCLink } from '@orpc/client/websocket';
6
6
  import { fallback, value, toArray, AsyncIteratorClass, retry, stringifyJSON } from '@orpc/shared';
7
7
  import { WebSocket } from 'partysocket';
8
- import { d as DURABLE_ITERATOR_ID_PARAM, c as DURABLE_ITERATOR_TOKEN_PARAM, D as DurableIteratorError, b as DURABLE_ITERATOR_PLUGIN_HEADER_KEY, a as DURABLE_ITERATOR_PLUGIN_HEADER_VALUE, p as parseDurableIteratorToken } from '../shared/experimental-durable-iterator.DZOLL3sf.mjs';
8
+ import { d as DURABLE_ITERATOR_ID_PARAM, c as DURABLE_ITERATOR_TOKEN_PARAM, D as DurableIteratorError, b as DURABLE_ITERATOR_PLUGIN_HEADER_KEY, a as DURABLE_ITERATOR_PLUGIN_HEADER_VALUE, p as parseDurableIteratorToken } from '../shared/experimental-durable-iterator.C144gAzf.mjs';
9
9
  import '@orpc/server/helpers';
10
10
  import 'valibot';
11
11
 
@@ -18,11 +18,13 @@ class DurableIteratorLinkPlugin {
18
18
  url;
19
19
  createId;
20
20
  refreshTokenBeforeExpireInSeconds;
21
+ refreshTokenDelayInSeconds;
21
22
  linkOptions;
22
- constructor({ url, refreshTokenBeforeExpireInSeconds, ...options }) {
23
+ constructor({ url, refreshTokenBeforeExpireInSeconds, refreshTokenDelayInSeconds, ...options }) {
23
24
  this.url = url;
24
25
  this.createId = fallback(options.createId, () => crypto.randomUUID());
25
26
  this.refreshTokenBeforeExpireInSeconds = fallback(refreshTokenBeforeExpireInSeconds, Number.NaN);
27
+ this.refreshTokenDelayInSeconds = fallback(refreshTokenDelayInSeconds, 2);
26
28
  this.linkOptions = options;
27
29
  }
28
30
  init(options) {
@@ -62,31 +64,37 @@ class DurableIteratorLinkPlugin {
62
64
  let refreshTokenBeforeExpireTimeoutId;
63
65
  const refreshTokenBeforeExpire = async () => {
64
66
  const beforeSeconds = await value(this.refreshTokenBeforeExpireInSeconds, tokenAndPayload.payload, options2);
67
+ const delayMilliseconds = await value(this.refreshTokenDelayInSeconds, tokenAndPayload.payload, options2) * 1e3;
65
68
  if (isFinished || !Number.isFinite(beforeSeconds)) {
66
69
  return;
67
70
  }
68
- const nowInSeconds = Math.floor(Date.now() / 1e3);
69
- refreshTokenBeforeExpireTimeoutId = setTimeout(async () => {
70
- const newTokenAndPayload = await retry({ times: Number.POSITIVE_INFINITY, delay: 2e3 }, async (exit) => {
71
- try {
72
- const output2 = await next();
73
- return this.validateToken(output2, options2.path);
74
- } catch (err) {
75
- if (isFinished) {
76
- exit(err);
71
+ refreshTokenBeforeExpireTimeoutId = setTimeout(
72
+ async () => {
73
+ const newTokenAndPayload = await retry({ times: Number.POSITIVE_INFINITY, delay: delayMilliseconds }, async (exit) => {
74
+ try {
75
+ const output2 = await next();
76
+ return this.validateToken(output2, options2.path);
77
+ } catch (err) {
78
+ if (isFinished) {
79
+ exit(err);
80
+ }
81
+ throw err;
77
82
  }
78
- throw err;
83
+ });
84
+ const canProactivelyUpdateToken = newTokenAndPayload.payload.chn === tokenAndPayload.payload.chn && stringifyJSON(newTokenAndPayload.payload.tags) === stringifyJSON(tokenAndPayload.payload.tags);
85
+ tokenAndPayload = newTokenAndPayload;
86
+ await refreshTokenBeforeExpire();
87
+ if (canProactivelyUpdateToken) {
88
+ await durableClient.updateToken({ token: tokenAndPayload.token });
89
+ } else {
90
+ websocket.reconnect();
79
91
  }
80
- });
81
- const canProactivelyUpdateToken = newTokenAndPayload.payload.chn === tokenAndPayload.payload.chn && stringifyJSON(newTokenAndPayload.payload.tags) === stringifyJSON(tokenAndPayload.payload.tags);
82
- tokenAndPayload = newTokenAndPayload;
83
- await refreshTokenBeforeExpire();
84
- if (canProactivelyUpdateToken) {
85
- await durableClient.updateToken({ token: tokenAndPayload.token });
86
- } else {
87
- websocket.reconnect();
88
- }
89
- }, (tokenAndPayload.payload.exp - nowInSeconds - beforeSeconds) * 1e3);
92
+ },
93
+ Math.max(
94
+ refreshTokenBeforeExpireTimeoutId === void 0 ? 0 : delayMilliseconds,
95
+ (tokenAndPayload.payload.exp - beforeSeconds) * 1e3 - Date.now()
96
+ )
97
+ );
90
98
  };
91
99
  refreshTokenBeforeExpire();
92
100
  const closeConnection = () => {
@@ -96,6 +96,9 @@ interface EventResumeStorageOptions extends StandardRPCJsonSerializerOptions {
96
96
  *
97
97
  * @remarks
98
98
  * - Use infinite values to disable
99
+ * - Note that for performance, expired event cleanup is deferred. This means
100
+ * expired events may remain in storage for a short period beyond their
101
+ * retention time.
99
102
  *
100
103
  * @default NaN (disabled)
101
104
  */
@@ -135,6 +138,7 @@ declare class EventResumeStorage<T extends object> {
135
138
  get(websocket: DurableIteratorWebsocket, lastEventId: string): T[];
136
139
  private initSchema;
137
140
  private resetSchema;
141
+ private lastCleanupTime;
138
142
  private cleanupExpiredEvents;
139
143
  private serializeEventPayload;
140
144
  private deserializeEventPayload;
@@ -96,6 +96,9 @@ interface EventResumeStorageOptions extends StandardRPCJsonSerializerOptions {
96
96
  *
97
97
  * @remarks
98
98
  * - Use infinite values to disable
99
+ * - Note that for performance, expired event cleanup is deferred. This means
100
+ * expired events may remain in storage for a short period beyond their
101
+ * retention time.
99
102
  *
100
103
  * @default NaN (disabled)
101
104
  */
@@ -135,6 +138,7 @@ declare class EventResumeStorage<T extends object> {
135
138
  get(websocket: DurableIteratorWebsocket, lastEventId: string): T[];
136
139
  private initSchema;
137
140
  private resetSchema;
141
+ private lastCleanupTime;
138
142
  private cleanupExpiredEvents;
139
143
  private serializeEventPayload;
140
144
  private deserializeEventPayload;
@@ -3,7 +3,7 @@ export { withEventMeta } from '@orpc/server';
3
3
  import { HibernationEventIterator, encodeHibernationRPCEvent, HibernationPlugin } from '@orpc/server/hibernation';
4
4
  import { RPCHandler } from '@orpc/server/websocket';
5
5
  import { fallback, parseEmptyableJSON, stringifyJSON, get, toArray, intercept } from '@orpc/shared';
6
- import { D as DurableIteratorError, v as verifyDurableIteratorToken, c as DURABLE_ITERATOR_TOKEN_PARAM, d as DURABLE_ITERATOR_ID_PARAM } from '../shared/experimental-durable-iterator.DZOLL3sf.mjs';
6
+ import { D as DurableIteratorError, v as verifyDurableIteratorToken, c as DURABLE_ITERATOR_TOKEN_PARAM, d as DURABLE_ITERATOR_ID_PARAM } from '../shared/experimental-durable-iterator.C144gAzf.mjs';
7
7
  import { d as durableIteratorContract } from '../shared/experimental-durable-iterator.BRB0hiXN.mjs';
8
8
  import { StandardRPCJsonSerializer } from '@orpc/client/standard';
9
9
  import { DurableObject } from 'cloudflare:workers';
@@ -241,7 +241,13 @@ class EventResumeStorage {
241
241
  `);
242
242
  this.initSchema();
243
243
  }
244
+ lastCleanupTime;
244
245
  cleanupExpiredEvents() {
246
+ const now = Date.now();
247
+ if (this.lastCleanupTime && this.lastCleanupTime + this.retentionSeconds * 1e3 > now) {
248
+ return;
249
+ }
250
+ this.lastCleanupTime = now;
245
251
  this.durableState.storage.sql.exec(`
246
252
  DELETE FROM "${this.schemaPrefix}events" WHERE stored_at < unixepoch() - ?
247
253
  `, this.retentionSeconds);
package/dist/index.d.mts CHANGED
@@ -11,7 +11,7 @@ import '@orpc/client/plugins';
11
11
 
12
12
  declare const DURABLE_ITERATOR_TOKEN_PARAM: "token";
13
13
  declare const DURABLE_ITERATOR_ID_PARAM: "id";
14
- declare const DURABLE_ITERATOR_PLUGIN_HEADER_KEY: "x-orpc-dei";
14
+ declare const DURABLE_ITERATOR_PLUGIN_HEADER_KEY: "x-orpc-durable-iterator";
15
15
  declare const DURABLE_ITERATOR_PLUGIN_HEADER_VALUE: "1";
16
16
 
17
17
  declare const durableIteratorContract: {
@@ -52,8 +52,6 @@ interface DurableIteratorOptions<T extends DurableIteratorObject<any>, RPC exten
52
52
  * The methods that are allowed to be called remotely.
53
53
  *
54
54
  * @warning Please use .rpc method to set this field in case ts complains about value you pass
55
- *
56
- * @default []
57
55
  */
58
56
  rpc?: readonly RPC[];
59
57
  }
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ import '@orpc/client/plugins';
11
11
 
12
12
  declare const DURABLE_ITERATOR_TOKEN_PARAM: "token";
13
13
  declare const DURABLE_ITERATOR_ID_PARAM: "id";
14
- declare const DURABLE_ITERATOR_PLUGIN_HEADER_KEY: "x-orpc-dei";
14
+ declare const DURABLE_ITERATOR_PLUGIN_HEADER_KEY: "x-orpc-durable-iterator";
15
15
  declare const DURABLE_ITERATOR_PLUGIN_HEADER_VALUE: "1";
16
16
 
17
17
  declare const durableIteratorContract: {
@@ -52,8 +52,6 @@ interface DurableIteratorOptions<T extends DurableIteratorObject<any>, RPC exten
52
52
  * The methods that are allowed to be called remotely.
53
53
  *
54
54
  * @warning Please use .rpc method to set this field in case ts complains about value you pass
55
- *
56
- * @default []
57
55
  */
58
56
  rpc?: readonly RPC[];
59
57
  }
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { s as signDurableIteratorToken, D as DurableIteratorError, a as DURABLE_ITERATOR_PLUGIN_HEADER_VALUE, b as DURABLE_ITERATOR_PLUGIN_HEADER_KEY } from './shared/experimental-durable-iterator.DZOLL3sf.mjs';
2
- export { d as DURABLE_ITERATOR_ID_PARAM, c as DURABLE_ITERATOR_TOKEN_PARAM, p as parseDurableIteratorToken, v as verifyDurableIteratorToken } from './shared/experimental-durable-iterator.DZOLL3sf.mjs';
1
+ import { s as signDurableIteratorToken, D as DurableIteratorError, a as DURABLE_ITERATOR_PLUGIN_HEADER_VALUE, b as DURABLE_ITERATOR_PLUGIN_HEADER_KEY } from './shared/experimental-durable-iterator.C144gAzf.mjs';
2
+ export { d as DURABLE_ITERATOR_ID_PARAM, c as DURABLE_ITERATOR_TOKEN_PARAM, p as parseDurableIteratorToken, v as verifyDurableIteratorToken } from './shared/experimental-durable-iterator.C144gAzf.mjs';
3
3
  export { d as durableIteratorContract } from './shared/experimental-durable-iterator.BRB0hiXN.mjs';
4
4
  import { AsyncIteratorClass } from '@orpc/shared';
5
- import { c as createClientDurableIterator, g as getClientDurableIteratorToken } from './shared/experimental-durable-iterator.B3M42lLK.mjs';
5
+ import { c as createClientDurableIterator, g as getClientDurableIteratorToken } from './shared/experimental-durable-iterator.sCul6zQj.mjs';
6
6
  import '@orpc/client';
7
7
  import '@orpc/client/plugins';
8
8
  import '@orpc/client/websocket';
@@ -4,7 +4,7 @@ import * as v from 'valibot';
4
4
 
5
5
  const DURABLE_ITERATOR_TOKEN_PARAM = "token";
6
6
  const DURABLE_ITERATOR_ID_PARAM = "id";
7
- const DURABLE_ITERATOR_PLUGIN_HEADER_KEY = "x-orpc-dei";
7
+ const DURABLE_ITERATOR_PLUGIN_HEADER_KEY = "x-orpc-durable-iterator";
8
8
  const DURABLE_ITERATOR_PLUGIN_HEADER_VALUE = "1";
9
9
 
10
10
  class DurableIteratorError extends Error {
@@ -1,6 +1,6 @@
1
1
  import { createORPCClient } from '@orpc/client';
2
2
  import { isAsyncIteratorObject } from '@orpc/shared';
3
- import { p as parseDurableIteratorToken } from './experimental-durable-iterator.DZOLL3sf.mjs';
3
+ import { p as parseDurableIteratorToken } from './experimental-durable-iterator.C144gAzf.mjs';
4
4
 
5
5
  const CLIENT_DURABLE_ITERATOR_TOKEN_SYMBOL = Symbol("ORPC_CLIENT_DURABLE_ITERATOR_TOKEN");
6
6
  function createClientDurableIterator(iterator, link, options) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/experimental-durable-iterator",
3
3
  "type": "module",
4
- "version": "0.0.0-next.e7bc0b8",
4
+ "version": "0.0.0-next.ea1d4fd",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -34,17 +34,17 @@
34
34
  "dist"
35
35
  ],
36
36
  "dependencies": {
37
- "partysocket": "^1.1.5",
37
+ "partysocket": "^1.1.6",
38
38
  "valibot": "^1.1.0",
39
- "@orpc/client": "0.0.0-next.e7bc0b8",
40
- "@orpc/contract": "0.0.0-next.e7bc0b8",
41
- "@orpc/server": "0.0.0-next.e7bc0b8",
42
- "@orpc/shared": "0.0.0-next.e7bc0b8"
39
+ "@orpc/contract": "0.0.0-next.ea1d4fd",
40
+ "@orpc/shared": "0.0.0-next.ea1d4fd",
41
+ "@orpc/server": "0.0.0-next.ea1d4fd",
42
+ "@orpc/client": "0.0.0-next.ea1d4fd"
43
43
  },
44
44
  "devDependencies": {
45
- "@cloudflare/workers-types": "^4.20250923.0",
45
+ "@cloudflare/workers-types": "^4.20251109.0",
46
46
  "@types/node": "^22.15.30",
47
- "@orpc/standard-server-peer": "0.0.0-next.e7bc0b8"
47
+ "@orpc/standard-server-peer": "0.0.0-next.ea1d4fd"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "unbuild",