@resonatehq/sdk 0.11.2 → 0.11.4

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.
Files changed (130) hide show
  1. package/README.md +1 -1
  2. package/dist/{async → src/async}/context.d.ts +0 -1
  3. package/dist/{async → src/async}/context.js +0 -1
  4. package/dist/{async → src/async}/core.d.ts +0 -1
  5. package/dist/{async → src/async}/core.js +0 -1
  6. package/dist/{async → src/async}/index.d.ts +0 -1
  7. package/dist/{async → src/async}/index.js +0 -1
  8. package/dist/{async → src/async}/resonate.d.ts +0 -1
  9. package/dist/{async → src/async}/resonate.js +0 -1
  10. package/dist/{clock.d.ts → src/clock.d.ts} +0 -1
  11. package/dist/{clock.js → src/clock.js} +0 -1
  12. package/dist/{codec.d.ts → src/codec.d.ts} +0 -1
  13. package/dist/{codec.js → src/codec.js} +0 -1
  14. package/dist/{computation.d.ts → src/computation.d.ts} +0 -1
  15. package/dist/{computation.js → src/computation.js} +0 -1
  16. package/dist/{context.d.ts → src/context.d.ts} +0 -1
  17. package/dist/{context.js → src/context.js} +0 -1
  18. package/dist/{core.d.ts → src/core.d.ts} +0 -1
  19. package/dist/{core.js → src/core.js} +0 -1
  20. package/dist/{coroutine.d.ts → src/coroutine.d.ts} +0 -1
  21. package/dist/{coroutine.js → src/coroutine.js} +0 -1
  22. package/dist/{decorator.d.ts → src/decorator.d.ts} +0 -1
  23. package/dist/{decorator.js → src/decorator.js} +0 -1
  24. package/dist/{encryptor.d.ts → src/encryptor.d.ts} +0 -1
  25. package/dist/{encryptor.js → src/encryptor.js} +0 -1
  26. package/dist/{exceptions.d.ts → src/exceptions.d.ts} +0 -1
  27. package/dist/{exceptions.js → src/exceptions.js} +0 -1
  28. package/dist/{heartbeat.d.ts → src/heartbeat.d.ts} +0 -1
  29. package/dist/{heartbeat.js → src/heartbeat.js} +0 -1
  30. package/dist/{index.d.ts → src/index.d.ts} +0 -1
  31. package/dist/{index.js → src/index.js} +0 -1
  32. package/dist/{logger.d.ts → src/logger.d.ts} +0 -1
  33. package/dist/{logger.js → src/logger.js} +0 -1
  34. package/dist/{network → src/network}/http.d.ts +0 -1
  35. package/dist/{network → src/network}/http.js +0 -1
  36. package/dist/{network → src/network}/local.d.ts +0 -1
  37. package/dist/{network → src/network}/local.js +9 -1
  38. package/dist/{network → src/network}/nats.d.ts +0 -1
  39. package/dist/{network → src/network}/nats.js +0 -1
  40. package/dist/{network → src/network}/network.d.ts +0 -1
  41. package/dist/src/network/network.js +1 -0
  42. package/dist/src/network/postgres.d.ts +49 -0
  43. package/dist/src/network/postgres.js +155 -0
  44. package/dist/{network → src/network}/types.d.ts +0 -1
  45. package/dist/{network → src/network}/types.js +0 -1
  46. package/dist/{options.d.ts → src/options.d.ts} +0 -1
  47. package/dist/{options.js → src/options.js} +0 -1
  48. package/dist/{platform.d.ts → src/platform.d.ts} +0 -1
  49. package/dist/{platform.js → src/platform.js} +0 -1
  50. package/dist/{promises.d.ts → src/promises.d.ts} +0 -1
  51. package/dist/{promises.js → src/promises.js} +0 -1
  52. package/dist/{registry.d.ts → src/registry.d.ts} +0 -1
  53. package/dist/{registry.js → src/registry.js} +0 -1
  54. package/dist/{resonate.d.ts → src/resonate.d.ts} +0 -1
  55. package/dist/{resonate.js → src/resonate.js} +0 -1
  56. package/dist/{retries.d.ts → src/retries.d.ts} +0 -1
  57. package/dist/{retries.js → src/retries.js} +0 -1
  58. package/dist/{schedules.d.ts → src/schedules.d.ts} +0 -1
  59. package/dist/{schedules.js → src/schedules.js} +0 -1
  60. package/dist/{trace.d.ts → src/trace.d.ts} +0 -1
  61. package/dist/{trace.js → src/trace.js} +0 -1
  62. package/dist/{types.d.ts → src/types.d.ts} +0 -1
  63. package/dist/src/types.js +1 -0
  64. package/dist/{util.d.ts → src/util.d.ts} +0 -1
  65. package/dist/{util.js → src/util.js} +0 -1
  66. package/package.json +46 -25
  67. package/dist/async/context.d.ts.map +0 -1
  68. package/dist/async/context.js.map +0 -1
  69. package/dist/async/core.d.ts.map +0 -1
  70. package/dist/async/core.js.map +0 -1
  71. package/dist/async/index.d.ts.map +0 -1
  72. package/dist/async/index.js.map +0 -1
  73. package/dist/async/resonate.d.ts.map +0 -1
  74. package/dist/async/resonate.js.map +0 -1
  75. package/dist/clock.d.ts.map +0 -1
  76. package/dist/clock.js.map +0 -1
  77. package/dist/codec.d.ts.map +0 -1
  78. package/dist/codec.js.map +0 -1
  79. package/dist/computation.d.ts.map +0 -1
  80. package/dist/computation.js.map +0 -1
  81. package/dist/context.d.ts.map +0 -1
  82. package/dist/context.js.map +0 -1
  83. package/dist/core.d.ts.map +0 -1
  84. package/dist/core.js.map +0 -1
  85. package/dist/coroutine.d.ts.map +0 -1
  86. package/dist/coroutine.js.map +0 -1
  87. package/dist/decorator.d.ts.map +0 -1
  88. package/dist/decorator.js.map +0 -1
  89. package/dist/encryptor.d.ts.map +0 -1
  90. package/dist/encryptor.js.map +0 -1
  91. package/dist/exceptions.d.ts.map +0 -1
  92. package/dist/exceptions.js.map +0 -1
  93. package/dist/heartbeat.d.ts.map +0 -1
  94. package/dist/heartbeat.js.map +0 -1
  95. package/dist/index.d.ts.map +0 -1
  96. package/dist/index.js.map +0 -1
  97. package/dist/logger.d.ts.map +0 -1
  98. package/dist/logger.js.map +0 -1
  99. package/dist/network/http.d.ts.map +0 -1
  100. package/dist/network/http.js.map +0 -1
  101. package/dist/network/local.d.ts.map +0 -1
  102. package/dist/network/local.js.map +0 -1
  103. package/dist/network/nats.d.ts.map +0 -1
  104. package/dist/network/nats.js.map +0 -1
  105. package/dist/network/network.d.ts.map +0 -1
  106. package/dist/network/network.js +0 -2
  107. package/dist/network/network.js.map +0 -1
  108. package/dist/network/types.d.ts.map +0 -1
  109. package/dist/network/types.js.map +0 -1
  110. package/dist/options.d.ts.map +0 -1
  111. package/dist/options.js.map +0 -1
  112. package/dist/platform.d.ts.map +0 -1
  113. package/dist/platform.js.map +0 -1
  114. package/dist/promises.d.ts.map +0 -1
  115. package/dist/promises.js.map +0 -1
  116. package/dist/registry.d.ts.map +0 -1
  117. package/dist/registry.js.map +0 -1
  118. package/dist/resonate.d.ts.map +0 -1
  119. package/dist/resonate.js.map +0 -1
  120. package/dist/retries.d.ts.map +0 -1
  121. package/dist/retries.js.map +0 -1
  122. package/dist/schedules.d.ts.map +0 -1
  123. package/dist/schedules.js.map +0 -1
  124. package/dist/trace.d.ts.map +0 -1
  125. package/dist/trace.js.map +0 -1
  126. package/dist/types.d.ts.map +0 -1
  127. package/dist/types.js +0 -2
  128. package/dist/types.js.map +0 -1
  129. package/dist/util.d.ts.map +0 -1
  130. package/dist/util.js.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Resonate TypeScript SDK
4
4
 
5
- [![cicd](https://github.com/resonatehq/resonate-sdk-ts/actions/workflows/cicd.yaml/badge.svg)](https://github.com/resonatehq/resonate-sdk-ts/actions/workflows/cicd.yaml)
5
+ [![ci](https://github.com/resonatehq/resonate-sdk-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/resonatehq/resonate-sdk-ts/actions/workflows/ci.yml)
6
6
  [![codecov](https://codecov.io/gh/resonatehq/resonate-sdk-ts/branch/main/graph/badge.svg)](https://codecov.io/gh/resonatehq/resonate-sdk-ts)
7
7
  [![dst](https://github.com/resonatehq/resonate-sdk-ts/actions/workflows/dst.yml/badge.svg)](https://github.com/resonatehq/resonate-sdk-ts/actions/workflows/dst.yml)
8
8
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
@@ -267,4 +267,3 @@ export declare function run(ctx: AsyncContext, func: AnyFunc, args: any[]): Prom
267
267
  */
268
268
  export declare function runWithRetry(makeCtx: (attempt: number) => AsyncContext, func: AnyFunc, args: any[], policy: RetryPolicy, nonRetryableErrors: Array<new (...args: any[]) => Error>, clock: Clock, timeoutAt: number): Promise<Outcome>;
269
269
  export {};
270
- //# sourceMappingURL=context.d.ts.map
@@ -595,4 +595,3 @@ export async function runWithRetry(makeCtx, func, args, policy, nonRetryableErro
595
595
  await delay(retryIn);
596
596
  }
597
597
  }
598
- //# sourceMappingURL=context.js.map
@@ -58,4 +58,3 @@ export declare class Core {
58
58
  private fulfillTask;
59
59
  onMessage(msg: Message): Promise<Status | undefined>;
60
60
  }
61
- //# sourceMappingURL=core.d.ts.map
@@ -236,4 +236,3 @@ function isValidData(data) {
236
236
  }
237
237
  return true;
238
238
  }
239
- //# sourceMappingURL=core.js.map
@@ -2,4 +2,3 @@ export { Constant, Exponential, Linear, Never, type RetryPolicy } from "../retri
2
2
  export { type AnyFunc, type Context, type DetachedHandle, DurablePromise, type Info } from "./context.js";
3
3
  export { Core, type Done, type Status, type Suspended } from "./core.js";
4
4
  export { Resonate, type ResonateFunc, type ResonateHandle, type ResonateSchedule, } from "./resonate.js";
5
- //# sourceMappingURL=index.d.ts.map
@@ -14,4 +14,3 @@ export { DurablePromise } from "./context.js";
14
14
  // long-running `Resonate` class with its network recv loop and heartbeat.
15
15
  export { Core } from "./core.js";
16
16
  export { Resonate, } from "./resonate.js";
17
- //# sourceMappingURL=index.js.map
@@ -95,4 +95,3 @@ export declare class Resonate {
95
95
  private subscribe;
96
96
  private notify;
97
97
  }
98
- //# sourceMappingURL=resonate.d.ts.map
@@ -384,4 +384,3 @@ export class Resonate {
384
384
  }
385
385
  }
386
386
  }
387
- //# sourceMappingURL=resonate.js.map
@@ -8,4 +8,3 @@ export declare class StepClock {
8
8
  time: number;
9
9
  now(): number;
10
10
  }
11
- //# sourceMappingURL=clock.d.ts.map
@@ -9,4 +9,3 @@ export class StepClock {
9
9
  return this.time++;
10
10
  }
11
11
  }
12
- //# sourceMappingURL=clock.js.map
@@ -8,4 +8,3 @@ export declare class Codec {
8
8
  decode(value: Value | undefined): any | undefined;
9
9
  decodePromise(promise: PromiseRecord): PromiseRecord;
10
10
  }
11
- //# sourceMappingURL=codec.d.ts.map
@@ -112,4 +112,3 @@ export class Codec {
112
112
  };
113
113
  }
114
114
  }
115
- //# sourceMappingURL=codec.js.map
@@ -37,4 +37,3 @@ export declare class Computation {
37
37
  private processGenerator;
38
38
  private processFunction;
39
39
  }
40
- //# sourceMappingURL=computation.d.ts.map
@@ -153,4 +153,3 @@ function isValidData(data) {
153
153
  }
154
154
  return true;
155
155
  }
156
- //# sourceMappingURL=computation.js.map
@@ -278,4 +278,3 @@ export declare class InnerContext implements Context {
278
278
  }): PromiseCreateReq;
279
279
  seqid(): string;
280
280
  }
281
- //# sourceMappingURL=context.d.ts.map
@@ -451,4 +451,3 @@ export class InnerContext {
451
451
  return `${this.id}.${this.seq}`;
452
452
  }
453
453
  }
454
- //# sourceMappingURL=context.js.map
@@ -42,4 +42,3 @@ export declare class Core {
42
42
  private fulfillTask;
43
43
  onMessage(msg: Message): Promise<Status | undefined>;
44
44
  }
45
- //# sourceMappingURL=core.d.ts.map
@@ -143,4 +143,3 @@ export class Core {
143
143
  return this.executeUntilBlocked(res.data.task, rootPromise, res.data.preload);
144
144
  }
145
145
  }
146
- //# sourceMappingURL=core.js.map
@@ -34,4 +34,3 @@ export declare class Coroutine<T> {
34
34
  private settle;
35
35
  private completedPromise;
36
36
  }
37
- //# sourceMappingURL=coroutine.d.ts.map
@@ -256,4 +256,3 @@ export class Coroutine {
256
256
  };
257
257
  }
258
258
  }
259
- //# sourceMappingURL=coroutine.js.map
@@ -66,4 +66,3 @@ export declare class Decorator<TRet> {
66
66
  private toLiteral;
67
67
  private safeGeneratorNext;
68
68
  }
69
- //# sourceMappingURL=decorator.d.ts.map
@@ -147,4 +147,3 @@ export class Decorator {
147
147
  }
148
148
  }
149
149
  }
150
- //# sourceMappingURL=decorator.js.map
@@ -7,4 +7,3 @@ export declare class NoopEncryptor implements Encryptor {
7
7
  encrypt(plaintext: Value): Value;
8
8
  decrypt(ciphertext: Value): Value;
9
9
  }
10
- //# sourceMappingURL=encryptor.d.ts.map
@@ -6,4 +6,3 @@ export class NoopEncryptor {
6
6
  return ciphertext;
7
7
  }
8
8
  }
9
- //# sourceMappingURL=encryptor.js.map
@@ -36,4 +36,3 @@ declare const _default: {
36
36
  SERVER_ERROR: (m: any, r?: boolean, e?: ResonateServerError) => ResonateError;
37
37
  };
38
38
  export default _default;
39
- //# sourceMappingURL=exceptions.d.ts.map
@@ -86,4 +86,3 @@ export default {
86
86
  return new ResonateError("99", "Server", m, { retriable: r, serverError: e });
87
87
  },
88
88
  };
89
- //# sourceMappingURL=exceptions.js.map
@@ -21,4 +21,3 @@ export declare class NoopHeartbeat implements Heartbeat {
21
21
  start(): void;
22
22
  stop(): void;
23
23
  }
24
- //# sourceMappingURL=heartbeat.d.ts.map
@@ -47,4 +47,3 @@ export class NoopHeartbeat {
47
47
  start() { }
48
48
  stop() { }
49
49
  }
50
- //# sourceMappingURL=heartbeat.js.map
@@ -17,4 +17,3 @@ export { Resonate, type ResonateFunc, type ResonateHandle } from "./resonate.js"
17
17
  export { Constant, Exponential, Linear, Never, type RetryPolicy } from "./retries.js";
18
18
  export { awaitThenResumeOrSuspend, blockIsSole, dedupIsSole, type Event, exclusiveLifecycle, isWellFormed, rootSpawn, rpcHasCallee, runHasCallee, spawnIsFirst, type Trace, TraceCollector, terminalIsLast, uniqueSpawn, uniqueTerminal, } from "./trace.js";
19
19
  export type { Effects, Func } from "./types.js";
20
- //# sourceMappingURL=index.d.ts.map
@@ -13,4 +13,3 @@ export { Registry } from "./registry.js";
13
13
  export { Resonate } from "./resonate.js";
14
14
  export { Constant, Exponential, Linear, Never } from "./retries.js";
15
15
  export { awaitThenResumeOrSuspend, blockIsSole, dedupIsSole, exclusiveLifecycle, isWellFormed, rootSpawn, rpcHasCallee, runHasCallee, spawnIsFirst, TraceCollector, terminalIsLast, uniqueSpawn, uniqueTerminal, } from "./trace.js";
16
- //# sourceMappingURL=index.js.map
@@ -30,4 +30,3 @@ export declare class ConsoleLogger implements Logger {
30
30
  private shouldLog;
31
31
  private emit;
32
32
  }
33
- //# sourceMappingURL=logger.d.ts.map
@@ -51,4 +51,3 @@ export class ConsoleLogger {
51
51
  writer(JSON.stringify(entry));
52
52
  }
53
53
  }
54
- //# sourceMappingURL=logger.js.map
@@ -63,4 +63,3 @@ export declare class PollMessageSource implements HttpAdapter {
63
63
  stop(): Promise<void>;
64
64
  onReceive(callback: (msg: Message) => void): void;
65
65
  }
66
- //# sourceMappingURL=http.d.ts.map
@@ -253,4 +253,3 @@ export class PollMessageSource {
253
253
  this.callbacks.push(callback);
254
254
  }
255
255
  }
256
- //# sourceMappingURL=http.js.map
@@ -185,4 +185,3 @@ export declare class LocalNetwork implements Network {
185
185
  recv(callback: (msg: Message) => void): void;
186
186
  private dispatchMessages;
187
187
  }
188
- //# sourceMappingURL=local.d.ts.map
@@ -768,6 +768,15 @@ export class Server {
768
768
  return { response: this.response("schedule.get", 200, { schedule: this.toScheduleRecord(schedule) }), changes: [] };
769
769
  }
770
770
  scheduleCreate(now, req) {
771
+ // Mirror the server's create-time validation: every fired promise needs a
772
+ // routing target, so a schedule whose promiseTags lack resonate:target is
773
+ // rejected up front (same status and message as the real server).
774
+ if (!req.data.promiseTags || !("resonate:target" in req.data.promiseTags)) {
775
+ return {
776
+ response: this.response("schedule.create", 400, "promiseTags must include a resonate:target tag"),
777
+ changes: [],
778
+ };
779
+ }
771
780
  const existingSchedule = this.schedules.get(req.data.id);
772
781
  if (existingSchedule) {
773
782
  return {
@@ -1346,4 +1355,3 @@ export class LocalNetwork {
1346
1355
  }
1347
1356
  }
1348
1357
  }
1349
- //# sourceMappingURL=local.js.map
@@ -56,4 +56,3 @@ export declare class NatsNetwork implements Network {
56
56
  recv(callback: (msg: Message) => void): void;
57
57
  private onMsg;
58
58
  }
59
- //# sourceMappingURL=nats.d.ts.map
@@ -269,4 +269,3 @@ export class NatsNetwork {
269
269
  }
270
270
  }
271
271
  }
272
- //# sourceMappingURL=nats.js.map
@@ -14,4 +14,3 @@ export interface Network {
14
14
  send: Send;
15
15
  recv: Recv;
16
16
  }
17
- //# sourceMappingURL=network.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ import type { Logger } from "../logger.js";
2
+ import type { Network } from "./network.js";
3
+ import type { Message, Request, Response } from "./types.js";
4
+ export interface PostgresNetworkConfig {
5
+ /** Postgres connection string (e.g. postgres://user:pass@host:5432/db). */
6
+ connectionString: string;
7
+ /** Worker group; a task targets the group (anycast). Default "default". */
8
+ group?: string;
9
+ /** This process's id; a callback/listener targets it (unicast). Defaults to a random id. */
10
+ pid?: string;
11
+ /** Fallback poll interval (ms) so timers still fire if a NOTIFY is missed. */
12
+ tickMs?: number;
13
+ logger?: Logger;
14
+ }
15
+ export declare class PostgresNetwork implements Network {
16
+ readonly unicast: string;
17
+ readonly anycast: string;
18
+ private readonly connectionString;
19
+ private readonly group;
20
+ private readonly pid;
21
+ private readonly tickMs;
22
+ private readonly logger?;
23
+ private poolPromise?;
24
+ private listenClient?;
25
+ private callbacks;
26
+ private timer?;
27
+ private draining;
28
+ private redrain;
29
+ private stopped;
30
+ constructor(cfg: PostgresNetworkConfig);
31
+ match(target: string): string;
32
+ private pg;
33
+ private getPool;
34
+ init(): Promise<void>;
35
+ stop(): Promise<void>;
36
+ send: <K extends Request["kind"]>(req: Extract<Request, {
37
+ kind: K;
38
+ }>) => Promise<Extract<Response, {
39
+ kind: K;
40
+ }>>;
41
+ recv(callback: (msg: Message) => void): void;
42
+ private deliver;
43
+ /** Fire due timers, then dequeue this node's outbox rows, delivering each. */
44
+ private drain;
45
+ /** Dequeue rows addressed to `address` in batches until the backlog is empty. */
46
+ private dequeue;
47
+ /** Fallback tick so timers and missed NOTIFYs still advance the pump. */
48
+ private scheduleNext;
49
+ }
@@ -0,0 +1,155 @@
1
+ export class PostgresNetwork {
2
+ unicast;
3
+ anycast;
4
+ connectionString;
5
+ group;
6
+ pid;
7
+ tickMs;
8
+ logger;
9
+ // `pg` is loaded lazily (optional peer dependency); the pool is memoized so
10
+ // send() works even before init() resolves (the SDK does not await init()).
11
+ poolPromise;
12
+ listenClient;
13
+ callbacks = [];
14
+ timer;
15
+ draining = false;
16
+ redrain = false;
17
+ stopped = false;
18
+ constructor(cfg) {
19
+ this.connectionString = cfg.connectionString;
20
+ this.group = cfg.group ?? "default";
21
+ this.pid = cfg.pid ?? crypto.randomUUID().replace(/-/g, "");
22
+ this.tickMs = cfg.tickMs ?? 250;
23
+ this.logger = cfg.logger;
24
+ // A task targets the group (anycast); a callback/listener targets this
25
+ // specific process (unicast). The poll:// scheme mirrors the poll
26
+ // adapter's addressing and is what the schema accepts for listeners.
27
+ this.unicast = `poll://uni@${this.group}/${this.pid}`;
28
+ this.anycast = `poll://any@${this.group}`;
29
+ }
30
+ match(target) {
31
+ return `poll://any@${target}`;
32
+ }
33
+ async pg() {
34
+ const m = (await import("pg"));
35
+ const PoolCtor = (m.Pool ?? m.default?.Pool);
36
+ const ClientCtor = (m.Client ?? m.default?.Client);
37
+ return { Pool: PoolCtor, Client: ClientCtor };
38
+ }
39
+ getPool() {
40
+ if (!this.poolPromise) {
41
+ this.poolPromise = this.pg().then((pg) => new pg.Pool({ connectionString: this.connectionString, max: 8 }));
42
+ }
43
+ return this.poolPromise;
44
+ }
45
+ async init() {
46
+ const pool = await this.getPool();
47
+ // A dedicated connection held open for LISTEN; node-postgres surfaces
48
+ // notifications as 'notification' events. The schema NOTIFYs on a channel
49
+ // derived from each row's address, so listen on this node's addresses.
50
+ const pg = await this.pg();
51
+ this.listenClient = new pg.Client({ connectionString: this.connectionString });
52
+ await this.listenClient.connect();
53
+ this.listenClient.on("notification", () => void this.drain());
54
+ this.listenClient.on("error", (err) => this.logger?.warn({ component: "network", error: err.message }, "postgres listen error"));
55
+ for (const address of [this.unicast, this.anycast]) {
56
+ const { rows } = await pool.query("SELECT resonate.outbox_channel($1) AS channel", [address]);
57
+ await this.listenClient.query(`LISTEN "${rows[0].channel}"`);
58
+ }
59
+ this.scheduleNext();
60
+ await this.drain();
61
+ this.logger?.info({ component: "network", group: this.group, pid: this.pid }, "postgres network initialized");
62
+ }
63
+ async stop() {
64
+ this.stopped = true;
65
+ if (this.timer)
66
+ clearTimeout(this.timer);
67
+ try {
68
+ await this.listenClient?.end();
69
+ }
70
+ catch {
71
+ /* already closed */
72
+ }
73
+ try {
74
+ await (await this.poolPromise)?.end();
75
+ }
76
+ catch {
77
+ /* already closed */
78
+ }
79
+ }
80
+ send = async (req) => {
81
+ const pool = await this.getPool();
82
+ const { rows } = await pool.query("SELECT resonate.resonate_rpc($1::jsonb) AS res", [JSON.stringify(req)]);
83
+ return rows[0].res;
84
+ };
85
+ recv(callback) {
86
+ this.callbacks.push(callback);
87
+ }
88
+ // --- runtime pump ---------------------------------------------------------
89
+ deliver(msg) {
90
+ for (const cb of this.callbacks)
91
+ cb(msg);
92
+ }
93
+ /** Fire due timers, then dequeue this node's outbox rows, delivering each. */
94
+ async drain() {
95
+ if (this.stopped)
96
+ return;
97
+ if (this.draining) {
98
+ this.redrain = true; // coalesce concurrent wakes into one pass
99
+ return;
100
+ }
101
+ this.draining = true;
102
+ try {
103
+ const pool = await this.getPool();
104
+ // No-arg overload: timers fire on database time (clock_timestamp), so
105
+ // every node shares one time authority regardless of local clock skew,
106
+ // and concurrent calls from multiple nodes are safe (advisory locks,
107
+ // idempotent handlers).
108
+ await pool.query("SELECT resonate.process_timeouts()");
109
+ // Addressed, destructive dequeue (FOR UPDATE SKIP LOCKED): this node
110
+ // only consumes rows addressed to it, and same-group nodes split the
111
+ // anycast stream. Delivery is at-least-once: if we crash after
112
+ // dequeuing an execute row but before the task is claimed, the task
113
+ // stays pending and the server re-emits it on the task retry timeout
114
+ // (stale duplicates fail acquire with a 409, which the SDK tolerates).
115
+ // Execute rows target the task's target address (anycast by default);
116
+ // unblock rows target the listener's address (this node's unicast).
117
+ for (const address of [this.anycast, this.unicast]) {
118
+ await this.dequeue(pool, "SELECT task_id, version FROM resonate.dequeue_execute($1, $2)", address, (r) => this.deliver({ kind: "execute", head: {}, data: { task: { id: r.task_id, version: r.version } } }));
119
+ }
120
+ await this.dequeue(pool, "SELECT promise FROM resonate.dequeue_unblock($1, $2)", this.unicast, (r) => this.deliver({ kind: "unblock", head: {}, data: { promise: r.promise } }));
121
+ }
122
+ catch (err) {
123
+ if (!this.stopped) {
124
+ this.logger?.warn({ component: "network", error: err.message }, "postgres drain error");
125
+ }
126
+ }
127
+ finally {
128
+ this.draining = false;
129
+ if (this.redrain) {
130
+ this.redrain = false;
131
+ void this.drain();
132
+ }
133
+ this.scheduleNext();
134
+ }
135
+ }
136
+ /** Dequeue rows addressed to `address` in batches until the backlog is empty. */
137
+ async dequeue(pool, sql, address, deliver) {
138
+ const limit = 100;
139
+ while (true) {
140
+ const { rows } = await pool.query(sql, [address, limit]);
141
+ for (const r of rows)
142
+ deliver(r);
143
+ if (rows.length < limit)
144
+ return;
145
+ }
146
+ }
147
+ /** Fallback tick so timers and missed NOTIFYs still advance the pump. */
148
+ scheduleNext() {
149
+ if (this.stopped)
150
+ return;
151
+ if (this.timer)
152
+ clearTimeout(this.timer);
153
+ this.timer = setTimeout(() => void this.drain(), this.tickMs);
154
+ }
155
+ }
@@ -1277,4 +1277,3 @@ export declare function isScheduleRecord(val: unknown): val is ScheduleRecord;
1277
1277
  export declare function isExecuteMsg(val: unknown): val is ExecuteMsg;
1278
1278
  export declare function isUnblockMsg(val: unknown): val is UnblockMsg;
1279
1279
  export declare function isMessage(val: unknown): val is Message;
1280
- //# sourceMappingURL=types.d.ts.map
@@ -917,4 +917,3 @@ export function isUnblockMsg(val) {
917
917
  export function isMessage(val) {
918
918
  return isExecuteMsg(val) || isUnblockMsg(val);
919
919
  }
920
- //# sourceMappingURL=types.js.map
@@ -42,4 +42,3 @@ export declare class Options {
42
42
  nonRetryableErrors?: Array<new (...args: any[]) => Error>;
43
43
  });
44
44
  }
45
- //# sourceMappingURL=options.d.ts.map
@@ -31,4 +31,3 @@ export class Options {
31
31
  this.nonRetryableErrors = nonRetryableErrors;
32
32
  }
33
33
  }
34
- //# sourceMappingURL=options.js.map
@@ -1,4 +1,3 @@
1
1
  export declare function randomUUID(): string;
2
2
  export declare function delay(ms: number): Promise<void>;
3
3
  export declare function getEnv(name: string): string | undefined;
4
- //# sourceMappingURL=platform.d.ts.map
@@ -21,4 +21,3 @@ export function getEnv(name) {
21
21
  return undefined;
22
22
  return process.env[name];
23
23
  }
24
- //# sourceMappingURL=platform.js.map
@@ -51,4 +51,3 @@ export declare class Promises {
51
51
  promise: PromiseRecord;
52
52
  }>;
53
53
  }
54
- //# sourceMappingURL=promises.d.ts.map
@@ -119,4 +119,3 @@ export class Promises {
119
119
  return { promise: res.data.promise };
120
120
  }
121
121
  }
122
- //# sourceMappingURL=promises.js.map
@@ -11,4 +11,3 @@ export declare class Registry {
11
11
  get(func: string | Func, version?: number): RegistryItem | undefined;
12
12
  private latest;
13
13
  }
14
- //# sourceMappingURL=registry.d.ts.map
@@ -33,4 +33,3 @@ export class Registry {
33
33
  return Math.max(...(Object.keys(registry ?? {}).map(Number) || [1]));
34
34
  }
35
35
  }
36
- //# sourceMappingURL=registry.js.map
@@ -165,4 +165,3 @@ export declare class Resonate {
165
165
  private subscribe;
166
166
  private notify;
167
167
  }
168
- //# sourceMappingURL=resonate.d.ts.map
@@ -483,4 +483,3 @@ export class Resonate {
483
483
  }
484
484
  }
485
485
  }
486
- //# sourceMappingURL=resonate.js.map
@@ -74,4 +74,3 @@ export declare class Never implements RetryPolicy {
74
74
  data: {};
75
75
  };
76
76
  }
77
- //# sourceMappingURL=retries.d.ts.map
@@ -95,4 +95,3 @@ export class Never {
95
95
  };
96
96
  }
97
97
  }
98
- //# sourceMappingURL=retries.js.map
@@ -19,4 +19,3 @@ export declare class Schedules {
19
19
  }): Promise<ScheduleRecord>;
20
20
  delete(id: string): Promise<undefined>;
21
21
  }
22
- //# sourceMappingURL=schedules.d.ts.map
@@ -62,4 +62,3 @@ export class Schedules {
62
62
  return undefined;
63
63
  }
64
64
  }
65
- //# sourceMappingURL=schedules.js.map
@@ -87,4 +87,3 @@ export declare function isWellFormed(t: Trace): boolean;
87
87
  * still be well-formed, only the await→resume/suspend pairing is dropped.
88
88
  */
89
89
  export declare function isWellFormedLifecycle(t: Trace): boolean;
90
- //# sourceMappingURL=trace.d.ts.map
@@ -243,4 +243,3 @@ export function isWellFormedLifecycle(t) {
243
243
  rpcHasCallee(t) &&
244
244
  rootSpawn(t));
245
245
  }
246
- //# sourceMappingURL=trace.js.map
@@ -18,4 +18,3 @@ export type Effects = {
18
18
  promiseCreate: (req: PromiseCreateReq, func?: string) => Promise<PromiseRecord>;
19
19
  promiseSettle: (req: PromiseSettleReq, func?: string) => Promise<PromiseRecord>;
20
20
  };
21
- //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -25,4 +25,3 @@ export declare function buildEffects(send: Send, codec: Codec, fence: {
25
25
  id: string;
26
26
  version: number;
27
27
  }, preload?: PromiseRecord[]): Effects;
28
- //# sourceMappingURL=util.d.ts.map
@@ -202,4 +202,3 @@ export function buildEffects(send, codec, fence, preload = []) {
202
202
  },
203
203
  };
204
204
  }
205
- //# sourceMappingURL=util.js.map