@hotmeshio/hotmesh 0.6.0 → 0.7.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.
Files changed (85) hide show
  1. package/README.md +179 -142
  2. package/build/index.d.ts +3 -1
  3. package/build/index.js +5 -1
  4. package/build/modules/enums.d.ts +18 -0
  5. package/build/modules/enums.js +27 -1
  6. package/build/modules/utils.d.ts +27 -0
  7. package/build/modules/utils.js +79 -1
  8. package/build/package.json +24 -10
  9. package/build/services/connector/factory.d.ts +1 -1
  10. package/build/services/connector/factory.js +15 -1
  11. package/build/services/connector/providers/ioredis.d.ts +9 -0
  12. package/build/services/connector/providers/ioredis.js +26 -0
  13. package/build/services/connector/providers/postgres.js +3 -0
  14. package/build/services/connector/providers/redis.d.ts +9 -0
  15. package/build/services/connector/providers/redis.js +38 -0
  16. package/build/services/hotmesh/index.d.ts +66 -15
  17. package/build/services/hotmesh/index.js +84 -15
  18. package/build/services/memflow/index.d.ts +100 -14
  19. package/build/services/memflow/index.js +100 -14
  20. package/build/services/memflow/worker.d.ts +97 -0
  21. package/build/services/memflow/worker.js +217 -0
  22. package/build/services/memflow/workflow/proxyActivities.d.ts +74 -3
  23. package/build/services/memflow/workflow/proxyActivities.js +81 -4
  24. package/build/services/router/consumption/index.d.ts +2 -1
  25. package/build/services/router/consumption/index.js +38 -2
  26. package/build/services/router/error-handling/index.d.ts +3 -3
  27. package/build/services/router/error-handling/index.js +48 -13
  28. package/build/services/router/index.d.ts +1 -0
  29. package/build/services/router/index.js +2 -1
  30. package/build/services/search/factory.js +8 -0
  31. package/build/services/search/providers/redis/ioredis.d.ts +23 -0
  32. package/build/services/search/providers/redis/ioredis.js +189 -0
  33. package/build/services/search/providers/redis/redis.d.ts +23 -0
  34. package/build/services/search/providers/redis/redis.js +202 -0
  35. package/build/services/store/factory.js +9 -1
  36. package/build/services/store/index.d.ts +3 -2
  37. package/build/services/store/providers/postgres/kvtypes/hash/basic.js +36 -6
  38. package/build/services/store/providers/postgres/kvtypes/hash/expire.js +12 -2
  39. package/build/services/store/providers/postgres/kvtypes/hash/scan.js +30 -10
  40. package/build/services/store/providers/postgres/kvtypes/list.js +68 -10
  41. package/build/services/store/providers/postgres/kvtypes/string.js +60 -10
  42. package/build/services/store/providers/postgres/kvtypes/zset.js +92 -22
  43. package/build/services/store/providers/postgres/postgres.d.ts +3 -3
  44. package/build/services/store/providers/redis/_base.d.ts +137 -0
  45. package/build/services/store/providers/redis/_base.js +980 -0
  46. package/build/services/store/providers/redis/ioredis.d.ts +20 -0
  47. package/build/services/store/providers/redis/ioredis.js +190 -0
  48. package/build/services/store/providers/redis/redis.d.ts +18 -0
  49. package/build/services/store/providers/redis/redis.js +199 -0
  50. package/build/services/stream/factory.js +17 -1
  51. package/build/services/stream/providers/postgres/kvtables.js +76 -23
  52. package/build/services/stream/providers/postgres/lifecycle.d.ts +19 -0
  53. package/build/services/stream/providers/postgres/lifecycle.js +54 -0
  54. package/build/services/stream/providers/postgres/messages.d.ts +56 -0
  55. package/build/services/stream/providers/postgres/messages.js +253 -0
  56. package/build/services/stream/providers/postgres/notifications.d.ts +59 -0
  57. package/build/services/stream/providers/postgres/notifications.js +357 -0
  58. package/build/services/stream/providers/postgres/postgres.d.ts +110 -11
  59. package/build/services/stream/providers/postgres/postgres.js +196 -488
  60. package/build/services/stream/providers/postgres/scout.d.ts +68 -0
  61. package/build/services/stream/providers/postgres/scout.js +233 -0
  62. package/build/services/stream/providers/postgres/stats.d.ts +49 -0
  63. package/build/services/stream/providers/postgres/stats.js +113 -0
  64. package/build/services/stream/providers/redis/ioredis.d.ts +61 -0
  65. package/build/services/stream/providers/redis/ioredis.js +272 -0
  66. package/build/services/stream/providers/redis/redis.d.ts +61 -0
  67. package/build/services/stream/providers/redis/redis.js +305 -0
  68. package/build/services/sub/factory.js +8 -0
  69. package/build/services/sub/providers/postgres/postgres.js +37 -5
  70. package/build/services/sub/providers/redis/ioredis.d.ts +20 -0
  71. package/build/services/sub/providers/redis/ioredis.js +161 -0
  72. package/build/services/sub/providers/redis/redis.d.ts +18 -0
  73. package/build/services/sub/providers/redis/redis.js +148 -0
  74. package/build/services/worker/index.d.ts +1 -0
  75. package/build/services/worker/index.js +2 -0
  76. package/build/types/hotmesh.d.ts +42 -2
  77. package/build/types/index.d.ts +4 -3
  78. package/build/types/index.js +4 -1
  79. package/build/types/memflow.d.ts +32 -0
  80. package/build/types/provider.d.ts +17 -1
  81. package/build/types/redis.d.ts +258 -0
  82. package/build/types/redis.js +11 -0
  83. package/build/types/stream.d.ts +92 -1
  84. package/index.ts +4 -0
  85. package/package.json +24 -10
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Permanent-Memory Workflows & AI Agents",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -23,11 +23,13 @@
23
23
  "test:await": "NODE_ENV=test jest ./tests/functional/awaiter/postgres.test.ts --detectOpenHandles --forceExit --verbose",
24
24
  "test:compile": "NODE_ENV=test jest ./tests/functional/compile/index.test.ts --detectOpenHandles --forceExit --verbose",
25
25
  "test:connect": "NODE_ENV=test jest ./tests/unit/services/connector/* --detectOpenHandles --forceExit --verbose",
26
+ "test:connect:ioredis": "NODE_ENV=test jest ./tests/unit/services/connector/providers/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
26
27
  "test:connect:postgres": "NODE_ENV=test jest ./tests/unit/services/connector/providers/postgres.test.ts --detectOpenHandles --forceExit --verbose",
28
+ "test:connect:redis": "NODE_ENV=test jest ./tests/unit/services/connector/providers/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
27
29
  "test:connect:nats": "NODE_ENV=test jest ./tests/unit/services/connector/providers/nats.test.ts --detectOpenHandles --forceExit --verbose",
28
- "test:memflow": "NODE_ENV=test jest ./tests/memflow/*/postgres.test.ts --detectOpenHandles --forceExit --verbose",
30
+ "test:memflow": "NODE_ENV=test jest ./tests/memflow/*/*.test.ts --detectOpenHandles --forceExit --verbose",
29
31
  "test:memflow:basic": "HMSH_LOGLEVEL=info NODE_ENV=test jest ./tests/memflow/basic/postgres.test.ts --detectOpenHandles --forceExit --verbose",
30
- "test:memflow:collision": "NODE_ENV=test jest ./tests/memflow/collision/*.test.ts --detectOpenHandles --forceExit --verbose",
32
+ "test:memflow:collision": "NODE_ENV=test jest ./tests/memflow/collision/postgres.test.ts --detectOpenHandles --forceExit --verbose",
31
33
  "test:memflow:fatal": "NODE_ENV=test jest ./tests/memflow/fatal/*.test.ts --detectOpenHandles --forceExit --verbose",
32
34
  "test:memflow:goodbye": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/memflow/goodbye/postgres.test.ts --detectOpenHandles --forceExit --verbose",
33
35
  "test:memflow:interceptor": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/memflow/interceptor/postgres.test.ts --detectOpenHandles --forceExit --verbose",
@@ -35,36 +37,44 @@
35
37
  "test:memflow:agent": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/memflow/agent/postgres.test.ts --detectOpenHandles --forceExit --verbose",
36
38
  "test:memflow:hello": "HMSH_TELEMETRY=debug HMSH_LOGLEVEL=debug NODE_ENV=test jest ./tests/memflow/helloworld/postgres.test.ts --detectOpenHandles --forceExit --verbose",
37
39
  "test:memflow:hook": "NODE_ENV=test jest ./tests/memflow/hook/postgres.test.ts --detectOpenHandles --forceExit --verbose",
38
- "test:memflow:interrupt": "NODE_ENV=test jest ./tests/memflow/interrupt/postgres.test.ts --detectOpenHandles --forceExit --verbose",
39
- "test:memflow:loopactivity": "NODE_ENV=test jest ./tests/memflow/loopactivity/postgres.test.ts --detectOpenHandles --forceExit --verbose",
40
+ "test:memflow:interrupt": "NODE_ENV=test jest ./tests/memflow/interrupt/*.test.ts --detectOpenHandles --forceExit --verbose",
41
+ "test:memflow:loopactivity": "NODE_ENV=test jest ./tests/memflow/loopactivity/*.test.ts --detectOpenHandles --forceExit --verbose",
40
42
  "test:memflow:nested": "NODE_ENV=test jest ./tests/memflow/nested/postgres.test.ts --detectOpenHandles --forceExit --verbose",
41
43
  "test:memflow:pipeline": "NODE_ENV=test jest ./tests/memflow/pipeline/postgres.test.ts --detectOpenHandles --forceExit --verbose",
42
44
  "test:memflow:retry": "NODE_ENV=test jest ./tests/memflow/retry/postgres.test.ts --detectOpenHandles --forceExit --verbose",
45
+ "test:memflow:retrypolicy": "NODE_ENV=test jest ./tests/memflow/retry-policy/*.test.ts --detectOpenHandles --forceExit --verbose",
43
46
  "test:memflow:sleep": "NODE_ENV=test jest ./tests/memflow/sleep/postgres.test.ts --detectOpenHandles --forceExit --verbose",
44
47
  "test:memflow:signal": "NODE_ENV=test jest ./tests/memflow/signal/postgres.test.ts --detectOpenHandles --forceExit --verbose",
45
- "test:memflow:unknown": "NODE_ENV=test jest ./tests/memflow/unknown/postgres.test.ts --detectOpenHandles --forceExit --verbose",
48
+ "test:memflow:unknown": "NODE_ENV=test jest ./tests/memflow/unknown/*.test.ts --detectOpenHandles --forceExit --verbose",
46
49
  "test:cycle": "NODE_ENV=test jest ./tests/functional/cycle/*.test.ts --detectOpenHandles --forceExit --verbose",
47
50
  "test:functional": "NODE_ENV=test jest ./tests/functional/* --detectOpenHandles --forceExit --verbose",
48
51
  "test:emit": "NODE_ENV=test jest ./tests/functional/emit/*.test.ts --detectOpenHandles --forceExit --verbose",
49
52
  "test:pending": "NODE_ENV=test jest ./tests/functional/pending/index.test.ts --detectOpenHandles --forceExit --verbose",
50
53
  "test:hmsh": "NODE_ENV=test jest ./tests/functional/*.test.ts --detectOpenHandles --verbose --forceExit",
51
- "test:hook": "NODE_ENV=test jest ./tests/functional/hook/index.test.ts --detectOpenHandles --forceExit --verbose",
54
+ "test:hook": "NODE_ENV=test jest ./tests/functional/hook/postgres.test.ts --detectOpenHandles --forceExit --verbose",
52
55
  "test:interrupt": "NODE_ENV=test jest ./tests/functional/interrupt/*.test.ts --detectOpenHandles --forceExit --verbose",
53
56
  "test:parallel": "NODE_ENV=test jest ./tests/functional/parallel/index.test.ts --detectOpenHandles --forceExit --verbose",
54
57
  "test:pipe": "NODE_ENV=test jest ./tests/unit/services/pipe/index.test.ts --detectOpenHandles --forceExit --verbose",
55
- "test:quorum": "NODE_ENV=test jest ./tests/functional/quorum/*.test.ts --detectOpenHandles --forceExit --verbose",
58
+ "test:quorum": "NODE_ENV=test jest ./tests/functional/quorum/postgres.test.ts --detectOpenHandles --forceExit --verbose",
56
59
  "test:reclaim": "NODE_ENV=test jest ./tests/functional/reclaim/*.test.ts --detectOpenHandles --forceExit --verbose",
57
60
  "test:redeploy": "NODE_ENV=test jest ./tests/functional/redeploy/*.test.ts --detectOpenHandles --forceExit --verbose",
58
61
  "test:reporter": "NODE_ENV=test jest ./tests/unit/services/reporter/index.test.ts --detectOpenHandles --forceExit --verbose",
59
62
  "test:reentrant": "NODE_ENV=test jest ./tests/functional/reentrant/*.test.ts --detectOpenHandles --forceExit --verbose",
60
63
  "test:retry": "NODE_ENV=test jest ./tests/functional/retry/*.test.ts --detectOpenHandles --forceExit --verbose",
61
- "test:sequence": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/functional/sequence/postgres.test.ts --detectOpenHandles --forceExit --verbose",
64
+ "test:retrypolicy": "NODE_ENV=test jest ./tests/functional/retry-policy/*.test.ts --detectOpenHandles --forceExit --verbose",
65
+ "test:sequence": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/functional/sequence/*.test.ts --detectOpenHandles --forceExit --verbose",
62
66
  "test:signal": "NODE_ENV=test jest ./tests/functional/signal/*.test.ts --detectOpenHandles --forceExit --verbose",
63
67
  "test:status": "NODE_ENV=test jest ./tests/functional/status/index.test.ts --detectOpenHandles --forceExit --verbose",
64
68
  "test:providers": "NODE_ENV=test jest ./tests/functional/*/providers/*/*.test.ts --detectOpenHandles --forceExit --verbose",
69
+ "test:store:ioredis": "NODE_ENV=test jest ./tests/functional/store/providers/redis/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
70
+ "test:store:redis": "NODE_ENV=test jest ./tests/functional/store/providers/redis/redis.test.ts --detectOpenHandles --forceExit --verbose",
65
71
  "test:store:postgres": "NODE_ENV=test jest ./tests/functional/store/providers/postgres/postgres.test.ts --detectOpenHandles --forceExit --verbose",
72
+ "test:stream:ioredis": "NODE_ENV=test jest ./tests/functional/stream/providers/redis/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
73
+ "test:stream:redis": "NODE_ENV=test jest ./tests/functional/stream/providers/redis/redis.test.ts --detectOpenHandles --forceExit --verbose",
66
74
  "test:stream:postgres": "NODE_ENV=test jest ./tests/functional/stream/providers/postgres/postgres.test.ts --detectOpenHandles --forceExit --verbose",
67
75
  "test:stream:nats": "NODE_ENV=test jest ./tests/functional/stream/providers/nats/nats.test.ts --detectOpenHandles --forceExit --verbose",
76
+ "test:sub:ioredis": "NODE_ENV=test jest ./tests/functional/sub/providers/redis/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
77
+ "test:sub:redis": "NODE_ENV=test jest ./tests/functional/sub/providers/redis/redis.test.ts --detectOpenHandles --forceExit --verbose",
68
78
  "test:sub:postgres": "NODE_ENV=test jest ./tests/functional/sub/providers/postgres/postgres.test.ts --detectOpenHandles --forceExit --verbose",
69
79
  "test:sub:nats": "NODE_ENV=test jest ./tests/functional/sub/providers/nats/nats.test.ts --detectOpenHandles --forceExit --verbose",
70
80
  "test:trigger": "NODE_ENV=test jest ./tests/unit/services/activities/trigger.test.ts --detectOpenHandles --forceExit --verbose",
@@ -106,11 +116,13 @@
106
116
  "eslint-config-prettier": "^9.1.0",
107
117
  "eslint-plugin-import": "^2.29.1",
108
118
  "eslint-plugin-prettier": "^5.1.3",
119
+ "ioredis": "^5.3.2",
109
120
  "javascript-obfuscator": "^0.6.2",
110
121
  "jest": "^29.5.0",
111
122
  "nats": "^2.28.0",
112
123
  "openai": "^5.9.0",
113
124
  "pg": "^8.10.0",
125
+ "redis": "^4.6.13",
114
126
  "rimraf": "^4.4.1",
115
127
  "terser": "^5.37.0",
116
128
  "ts-jest": "^29.0.5",
@@ -120,7 +132,9 @@
120
132
  "typescript": "^5.0.4"
121
133
  },
122
134
  "peerDependencies": {
135
+ "ioredis": "^4.0.0 || ^5.0.0",
123
136
  "nats": "^2.0.0",
124
- "pg": "^8.0.0"
137
+ "pg": "^8.0.0",
138
+ "redis": "^4.0.0"
125
139
  }
126
140
  }
@@ -3,7 +3,7 @@ import { ProviderConfig, ProviderNativeClient } from '../../types/provider';
3
3
  export declare class ConnectorService {
4
4
  static disconnectAll(): Promise<void>;
5
5
  /**
6
- * Connect to a provider (postgres, nats) and return the native
6
+ * Connect to a provider (redis, nats, postgres) and return the native
7
7
  * client. Connections are handled by the engine and worker routers at
8
8
  * initialization, but the factory method provided here is useful
9
9
  * for testing provider configurations.
@@ -2,15 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConnectorService = void 0;
4
4
  const utils_1 = require("../../modules/utils");
5
+ const ioredis_1 = require("./providers/ioredis");
5
6
  const nats_1 = require("./providers/nats");
6
7
  const postgres_1 = require("./providers/postgres");
8
+ const redis_1 = require("./providers/redis");
7
9
  class ConnectorService {
8
10
  static async disconnectAll() {
11
+ await redis_1.RedisConnection.disconnectAll();
12
+ await ioredis_1.RedisConnection.disconnectAll();
9
13
  await postgres_1.PostgresConnection.disconnectAll();
10
14
  await nats_1.NatsConnection.disconnectAll();
11
15
  }
12
16
  /**
13
- * Connect to a provider (postgres, nats) and return the native
17
+ * Connect to a provider (redis, nats, postgres) and return the native
14
18
  * client. Connections are handled by the engine and worker routers at
15
19
  * initialization, but the factory method provided here is useful
16
20
  * for testing provider configurations.
@@ -69,10 +73,20 @@ class ConnectorService {
69
73
  const providerClass = ProviderConfig.class;
70
74
  const options = ProviderConfig.options;
71
75
  const providerName = ProviderConfig.provider || (0, utils_1.identifyProvider)(providerClass); //e.g. 'postgres.poolclient'
76
+ if (!providerName) {
77
+ throw new Error(`Unable to identify provider type. Please explicitly set the 'provider' field in your connection config. ` +
78
+ `Received class: ${providerClass?.constructor?.name || 'unknown'}`);
79
+ }
72
80
  const providerType = providerName.split('.')[0]; //e.g. 'postgres'
73
81
  let clientInstance;
74
82
  const id = (0, utils_1.guid)();
75
83
  switch (providerType) {
84
+ case 'redis':
85
+ clientInstance = await redis_1.RedisConnection.connect(id, providerClass, options, { provider: providerName });
86
+ break;
87
+ case 'ioredis':
88
+ clientInstance = await ioredis_1.RedisConnection.connect(id, providerClass, options, { provider: providerName });
89
+ break;
76
90
  case 'nats':
77
91
  clientInstance = await nats_1.NatsConnection.connect(id, providerClass, options, { provider: providerName });
78
92
  break;
@@ -0,0 +1,9 @@
1
+ import { AbstractConnection } from '..';
2
+ import { IORedisClientOptions as RedisClientOptions, IORedisClassType as RedisClassType, IORedisClientType as RedisClientType } from '../../../types/redis';
3
+ declare class RedisConnection extends AbstractConnection<RedisClassType, RedisClientOptions> {
4
+ defaultOptions: RedisClientOptions;
5
+ createConnection(Redis: RedisClassType, options: RedisClientOptions): Promise<RedisClientType>;
6
+ getClient(): RedisClientType;
7
+ closeConnection(connection: RedisClientType): Promise<void>;
8
+ }
9
+ export { RedisConnection };
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisConnection = void 0;
4
+ const __1 = require("..");
5
+ class RedisConnection extends __1.AbstractConnection {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.defaultOptions = {
9
+ host: 'localhost',
10
+ port: 6379,
11
+ };
12
+ }
13
+ async createConnection(Redis, options) {
14
+ return new Redis(options);
15
+ }
16
+ getClient() {
17
+ if (!this.connection) {
18
+ throw new Error('Redis client is not connected');
19
+ }
20
+ return this.connection;
21
+ }
22
+ async closeConnection(connection) {
23
+ await connection.quit();
24
+ }
25
+ }
26
+ exports.RedisConnection = RedisConnection;
@@ -121,7 +121,10 @@ class PostgresConnection extends __1.AbstractConnection {
121
121
  this.disconnecting = true;
122
122
  await this.disconnectPoolClients();
123
123
  await this.disconnectConnections();
124
+ // Clear taskQueue connections cache when disconnecting all
124
125
  this.taskQueueConnections.clear();
126
+ // Clear the base class instances cache to allow reconnection with same IDs
127
+ this.instances.clear();
125
128
  this.disconnecting = false;
126
129
  }
127
130
  }
@@ -0,0 +1,9 @@
1
+ import { AbstractConnection } from '..';
2
+ import { RedisRedisClassType as RedisClassType, RedisRedisClientType as RedisClientType, RedisRedisClientOptions as RedisClientOptions } from '../../../types/redis';
3
+ declare class RedisConnection extends AbstractConnection<RedisClassType, RedisClientOptions> {
4
+ defaultOptions: RedisClientOptions;
5
+ createConnection(Redis: Partial<RedisClassType>, options: RedisClientOptions): Promise<Partial<RedisClientType>>;
6
+ getClient(): RedisClientType;
7
+ closeConnection(connection: any): Promise<void>;
8
+ }
9
+ export { RedisConnection, RedisClientType };
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisConnection = void 0;
4
+ const __1 = require("..");
5
+ class RedisConnection extends __1.AbstractConnection {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.defaultOptions = {
9
+ socket: {
10
+ host: 'localhost',
11
+ port: 6379,
12
+ tls: false,
13
+ },
14
+ };
15
+ }
16
+ async createConnection(Redis, options) {
17
+ return new Promise((resolve, reject) => {
18
+ const client = Redis.createClient(options);
19
+ client.on('error', (error) => {
20
+ reject(error);
21
+ });
22
+ client.on('ready', () => {
23
+ resolve(client);
24
+ });
25
+ client.connect();
26
+ });
27
+ }
28
+ getClient() {
29
+ if (!this.connection) {
30
+ throw new Error('Redis client is not connected');
31
+ }
32
+ return this.connection;
33
+ }
34
+ async closeConnection(connection) {
35
+ await connection.quit();
36
+ }
37
+ }
38
+ exports.RedisConnection = RedisConnection;
@@ -10,30 +10,19 @@ import { StringAnyType, StringStringType } from '../../types/serializer';
10
10
  import { JobStatsInput, GetStatsOptions, IdsResponse, StatsResponse } from '../../types/stats';
11
11
  import { StreamCode, StreamData, StreamDataResponse, StreamStatus } from '../../types/stream';
12
12
  /**
13
- * HotMesh is a distributed, reentrant process orchestration engine that transforms
14
- * Postgres into a resilient service mesh capable of running
13
+ * HotMesh transforms Postgres into a durable workflow orchestration engine capable of running
15
14
  * fault-tolerant workflows across multiple services and systems.
16
15
  *
17
- * ## Core Concepts
18
- *
19
- * **Distributed Quorum Architecture**: HotMesh operates as a distributed quorum
20
- * where multiple engine and worker instances coordinate using CQRS principles.
21
- * Each member reads from assigned topic queues and writes results to other queues,
22
- * creating emergent workflow orchestration without a central controller.
23
- *
24
- * **Reentrant Process Engine**: Unlike traditional workflow engines, HotMesh
25
- * provides built-in retry logic, idempotency, and failure recovery. Your business
26
- * logic doesn't need to handle timeouts or retries - the engine manages all of that.
27
- *
28
16
  * ## Key Features
29
17
  *
30
- * - **Fault Tolerance**: Automatic retry, timeout, and failure recovery
18
+ * - **Fault Tolerance**: Automatic retry with exponential backoff and configurable policies
31
19
  * - **Distributed Execution**: No single point of failure
32
20
  * - **YAML-Driven**: Model-driven development with declarative workflow definitions
33
21
  * - **OpenTelemetry**: Built-in observability and tracing
34
22
  * - **Durable State**: Workflow state persists across system restarts
35
23
  * - **Pattern Matching**: Pub/sub with wildcard pattern support
36
24
  * - **Throttling**: Dynamic flow control and backpressure management
25
+ * - **Retry Policies**: PostgreSQL-native retry configuration with exponential backoff
37
26
  *
38
27
  * ## Architecture
39
28
  *
@@ -225,7 +214,12 @@ declare class HotMesh {
225
214
  * similarly to the engine, but as an array with
226
215
  * multiple worker objects.
227
216
  *
228
- * @example
217
+ * ## Retry Policy Configuration
218
+ *
219
+ * HotMesh supports robust retry policies with exponential backoff for PostgreSQL.
220
+ * Configure retry behavior at the stream level for automatic fault tolerance.
221
+ *
222
+ * @example Basic Configuration
229
223
  * ```typescript
230
224
  * const config: HotMeshConfig = {
231
225
  * appId: 'myapp',
@@ -241,6 +235,57 @@ declare class HotMesh {
241
235
  * };
242
236
  * const hotMesh = await HotMesh.init(config);
243
237
  * ```
238
+ *
239
+ * @example With Retry Policy (PostgreSQL)
240
+ * ```typescript
241
+ * import { HotMesh } from '@hotmeshio/hotmesh';
242
+ * import { Client as Postgres } from 'pg';
243
+ *
244
+ * const hotMesh = await HotMesh.init({
245
+ * appId: 'my-app',
246
+ * engine: {
247
+ * connection: {
248
+ * class: Postgres,
249
+ * options: { connectionString: 'postgresql://...' }
250
+ * },
251
+ * // Default retry policy for engine streams
252
+ * retryPolicy: {
253
+ * maximumAttempts: 5, // Retry up to 5 times
254
+ * backoffCoefficient: 2, // Exponential: 2^0, 2^1, 2^2...
255
+ * maximumInterval: '300s' // Cap delay at 5 minutes
256
+ * }
257
+ * },
258
+ * workers: [{
259
+ * topic: 'order.process',
260
+ * connection: {
261
+ * class: Postgres,
262
+ * options: { connectionString: 'postgresql://...' }
263
+ * },
264
+ * // Worker-specific retry policy
265
+ * retryPolicy: {
266
+ * maximumAttempts: 10,
267
+ * backoffCoefficient: 1.5,
268
+ * maximumInterval: '600s'
269
+ * },
270
+ * callback: async (data) => {
271
+ * // Your business logic here
272
+ * // Failures will automatically retry with exponential backoff
273
+ * return { status: 'success', data: processedData };
274
+ * }
275
+ * }]
276
+ * });
277
+ * ```
278
+ *
279
+ * **Retry Policy Options**:
280
+ * - `maximumAttempts` - Maximum retry attempts before failure (default: 3)
281
+ * - `backoffCoefficient` - Base for exponential backoff calculation (default: 10)
282
+ * - `maximumInterval` - Maximum delay between retries in seconds or duration string (default: '120s')
283
+ *
284
+ * **Retry Delays**: For `backoffCoefficient: 2`, delays are: 2s, 4s, 8s, 16s, 32s...
285
+ * capped at `maximumInterval`.
286
+ *
287
+ * **Note**: Retry policies are stored in PostgreSQL columns for efficient querying and
288
+ * observability. Each retry creates a new message, preserving message immutability.
244
289
  */
245
290
  static init(config: HotMeshConfig): Promise<HotMesh>;
246
291
  /**
@@ -272,6 +317,12 @@ declare class HotMesh {
272
317
  * @private
273
318
  */
274
319
  private initTaskQueue;
320
+ /**
321
+ * Apply retry policy to the stream connection within a ProviderConfig or ProvidersConfig.
322
+ * Handles both short-form (ProviderConfig) and long-form (ProvidersConfig) connection configs.
323
+ * @private
324
+ */
325
+ private applyRetryPolicy;
275
326
  /**
276
327
  * Starts a workflow
277
328
  * @example
@@ -11,30 +11,19 @@ const router_1 = require("../router");
11
11
  const worker_1 = require("../worker");
12
12
  const enums_1 = require("../../modules/enums");
13
13
  /**
14
- * HotMesh is a distributed, reentrant process orchestration engine that transforms
15
- * Postgres into a resilient service mesh capable of running
14
+ * HotMesh transforms Postgres into a durable workflow orchestration engine capable of running
16
15
  * fault-tolerant workflows across multiple services and systems.
17
16
  *
18
- * ## Core Concepts
19
- *
20
- * **Distributed Quorum Architecture**: HotMesh operates as a distributed quorum
21
- * where multiple engine and worker instances coordinate using CQRS principles.
22
- * Each member reads from assigned topic queues and writes results to other queues,
23
- * creating emergent workflow orchestration without a central controller.
24
- *
25
- * **Reentrant Process Engine**: Unlike traditional workflow engines, HotMesh
26
- * provides built-in retry logic, idempotency, and failure recovery. Your business
27
- * logic doesn't need to handle timeouts or retries - the engine manages all of that.
28
- *
29
17
  * ## Key Features
30
18
  *
31
- * - **Fault Tolerance**: Automatic retry, timeout, and failure recovery
19
+ * - **Fault Tolerance**: Automatic retry with exponential backoff and configurable policies
32
20
  * - **Distributed Execution**: No single point of failure
33
21
  * - **YAML-Driven**: Model-driven development with declarative workflow definitions
34
22
  * - **OpenTelemetry**: Built-in observability and tracing
35
23
  * - **Durable State**: Workflow state persists across system restarts
36
24
  * - **Pattern Matching**: Pub/sub with wildcard pattern support
37
25
  * - **Throttling**: Dynamic flow control and backpressure management
26
+ * - **Retry Policies**: PostgreSQL-native retry configuration with exponential backoff
38
27
  *
39
28
  * ## Architecture
40
29
  *
@@ -229,7 +218,12 @@ class HotMesh {
229
218
  * similarly to the engine, but as an array with
230
219
  * multiple worker objects.
231
220
  *
232
- * @example
221
+ * ## Retry Policy Configuration
222
+ *
223
+ * HotMesh supports robust retry policies with exponential backoff for PostgreSQL.
224
+ * Configure retry behavior at the stream level for automatic fault tolerance.
225
+ *
226
+ * @example Basic Configuration
233
227
  * ```typescript
234
228
  * const config: HotMeshConfig = {
235
229
  * appId: 'myapp',
@@ -245,6 +239,57 @@ class HotMesh {
245
239
  * };
246
240
  * const hotMesh = await HotMesh.init(config);
247
241
  * ```
242
+ *
243
+ * @example With Retry Policy (PostgreSQL)
244
+ * ```typescript
245
+ * import { HotMesh } from '@hotmeshio/hotmesh';
246
+ * import { Client as Postgres } from 'pg';
247
+ *
248
+ * const hotMesh = await HotMesh.init({
249
+ * appId: 'my-app',
250
+ * engine: {
251
+ * connection: {
252
+ * class: Postgres,
253
+ * options: { connectionString: 'postgresql://...' }
254
+ * },
255
+ * // Default retry policy for engine streams
256
+ * retryPolicy: {
257
+ * maximumAttempts: 5, // Retry up to 5 times
258
+ * backoffCoefficient: 2, // Exponential: 2^0, 2^1, 2^2...
259
+ * maximumInterval: '300s' // Cap delay at 5 minutes
260
+ * }
261
+ * },
262
+ * workers: [{
263
+ * topic: 'order.process',
264
+ * connection: {
265
+ * class: Postgres,
266
+ * options: { connectionString: 'postgresql://...' }
267
+ * },
268
+ * // Worker-specific retry policy
269
+ * retryPolicy: {
270
+ * maximumAttempts: 10,
271
+ * backoffCoefficient: 1.5,
272
+ * maximumInterval: '600s'
273
+ * },
274
+ * callback: async (data) => {
275
+ * // Your business logic here
276
+ * // Failures will automatically retry with exponential backoff
277
+ * return { status: 'success', data: processedData };
278
+ * }
279
+ * }]
280
+ * });
281
+ * ```
282
+ *
283
+ * **Retry Policy Options**:
284
+ * - `maximumAttempts` - Maximum retry attempts before failure (default: 3)
285
+ * - `backoffCoefficient` - Base for exponential backoff calculation (default: 10)
286
+ * - `maximumInterval` - Maximum delay between retries in seconds or duration string (default: '120s')
287
+ *
288
+ * **Retry Delays**: For `backoffCoefficient: 2`, delays are: 2s, 4s, 8s, 16s, 32s...
289
+ * capped at `maximumInterval`.
290
+ *
291
+ * **Note**: Retry policies are stored in PostgreSQL columns for efficient querying and
292
+ * observability. Each retry creates a new message, preserving message immutability.
248
293
  */
249
294
  static async init(config) {
250
295
  const instance = new HotMesh();
@@ -275,6 +320,10 @@ class HotMesh {
275
320
  if (config.engine.connection.readonly) {
276
321
  config.engine.readonly = true;
277
322
  }
323
+ // Apply retry policy to stream connection if provided
324
+ if (config.engine.retryPolicy) {
325
+ this.applyRetryPolicy(config.engine.connection, config.engine.retryPolicy);
326
+ }
278
327
  // Initialize task queue for engine
279
328
  config.engine.taskQueue = this.initTaskQueue(config.engine.taskQueue, config.taskQueue);
280
329
  await factory_1.ConnectorService.initClients(config.engine);
@@ -313,6 +362,10 @@ class HotMesh {
313
362
  // Initialize task queues for workers
314
363
  if (config.workers) {
315
364
  for (const worker of config.workers) {
365
+ // Apply retry policy to stream connection if provided
366
+ if (worker.retryPolicy) {
367
+ this.applyRetryPolicy(worker.connection, worker.retryPolicy);
368
+ }
316
369
  worker.taskQueue = this.initTaskQueue(worker.taskQueue, config.taskQueue);
317
370
  }
318
371
  }
@@ -337,6 +390,22 @@ class HotMesh {
337
390
  // Default queue as fallback
338
391
  return enums_1.DEFAULT_TASK_QUEUE;
339
392
  }
393
+ /**
394
+ * Apply retry policy to the stream connection within a ProviderConfig or ProvidersConfig.
395
+ * Handles both short-form (ProviderConfig) and long-form (ProvidersConfig) connection configs.
396
+ * @private
397
+ */
398
+ applyRetryPolicy(connection, retryPolicy) {
399
+ // Check if this is ProvidersConfig (has 'stream' property)
400
+ if ('stream' in connection && connection.stream) {
401
+ // Long-form: apply to the stream sub-config
402
+ connection.stream.retryPolicy = retryPolicy;
403
+ }
404
+ else {
405
+ // Short-form: apply directly to the connection
406
+ connection.retryPolicy = retryPolicy;
407
+ }
408
+ }
340
409
  // ************* PUB/SUB METHODS *************
341
410
  /**
342
411
  * Starts a workflow