@hotmeshio/hotmesh 0.7.0 → 0.8.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 (73) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/README.md +1 -1
  3. package/build/index.d.ts +1 -3
  4. package/build/index.js +1 -5
  5. package/build/modules/utils.js +3 -31
  6. package/build/package.json +16 -27
  7. package/build/services/activities/activity.d.ts +43 -6
  8. package/build/services/activities/activity.js +262 -54
  9. package/build/services/activities/await.js +2 -2
  10. package/build/services/activities/cycle.js +1 -1
  11. package/build/services/activities/hook.d.ts +5 -0
  12. package/build/services/activities/hook.js +22 -19
  13. package/build/services/activities/interrupt.js +17 -25
  14. package/build/services/activities/signal.d.ts +4 -2
  15. package/build/services/activities/signal.js +27 -24
  16. package/build/services/activities/worker.js +2 -2
  17. package/build/services/collator/index.d.ts +123 -25
  18. package/build/services/collator/index.js +224 -101
  19. package/build/services/connector/factory.d.ts +1 -1
  20. package/build/services/connector/factory.js +1 -11
  21. package/build/services/engine/index.d.ts +5 -5
  22. package/build/services/engine/index.js +36 -15
  23. package/build/services/router/consumption/index.js +1 -1
  24. package/build/services/search/factory.js +1 -9
  25. package/build/services/store/factory.js +1 -9
  26. package/build/services/store/index.d.ts +5 -0
  27. package/build/services/store/providers/postgres/kvsql.d.ts +4 -0
  28. package/build/services/store/providers/postgres/kvsql.js +4 -0
  29. package/build/services/store/providers/postgres/kvtransaction.d.ts +2 -0
  30. package/build/services/store/providers/postgres/kvtransaction.js +23 -0
  31. package/build/services/store/providers/postgres/kvtypes/hash/basic.d.ts +51 -0
  32. package/build/services/store/providers/postgres/kvtypes/hash/basic.js +193 -1
  33. package/build/services/store/providers/postgres/kvtypes/hash/index.d.ts +4 -0
  34. package/build/services/store/providers/postgres/kvtypes/hash/index.js +6 -0
  35. package/build/services/store/providers/postgres/postgres.d.ts +20 -0
  36. package/build/services/store/providers/postgres/postgres.js +38 -1
  37. package/build/services/stream/factory.js +1 -17
  38. package/build/services/stream/providers/postgres/scout.js +2 -2
  39. package/build/services/sub/factory.js +1 -9
  40. package/build/services/sub/index.d.ts +1 -1
  41. package/build/services/sub/providers/postgres/postgres.d.ts +1 -1
  42. package/build/services/sub/providers/postgres/postgres.js +25 -10
  43. package/build/services/task/index.d.ts +1 -1
  44. package/build/services/task/index.js +2 -6
  45. package/build/types/index.d.ts +0 -1
  46. package/build/types/index.js +1 -4
  47. package/build/types/provider.d.ts +1 -1
  48. package/index.ts +0 -4
  49. package/package.json +16 -27
  50. package/build/services/connector/providers/ioredis.d.ts +0 -9
  51. package/build/services/connector/providers/ioredis.js +0 -26
  52. package/build/services/connector/providers/redis.d.ts +0 -9
  53. package/build/services/connector/providers/redis.js +0 -38
  54. package/build/services/search/providers/redis/ioredis.d.ts +0 -23
  55. package/build/services/search/providers/redis/ioredis.js +0 -189
  56. package/build/services/search/providers/redis/redis.d.ts +0 -23
  57. package/build/services/search/providers/redis/redis.js +0 -202
  58. package/build/services/store/providers/redis/_base.d.ts +0 -137
  59. package/build/services/store/providers/redis/_base.js +0 -980
  60. package/build/services/store/providers/redis/ioredis.d.ts +0 -20
  61. package/build/services/store/providers/redis/ioredis.js +0 -190
  62. package/build/services/store/providers/redis/redis.d.ts +0 -18
  63. package/build/services/store/providers/redis/redis.js +0 -199
  64. package/build/services/stream/providers/redis/ioredis.d.ts +0 -61
  65. package/build/services/stream/providers/redis/ioredis.js +0 -272
  66. package/build/services/stream/providers/redis/redis.d.ts +0 -61
  67. package/build/services/stream/providers/redis/redis.js +0 -305
  68. package/build/services/sub/providers/redis/ioredis.d.ts +0 -20
  69. package/build/services/sub/providers/redis/ioredis.js +0 -161
  70. package/build/services/sub/providers/redis/redis.d.ts +0 -18
  71. package/build/services/sub/providers/redis/redis.js +0 -148
  72. package/build/types/redis.d.ts +0 -258
  73. package/build/types/redis.js +0 -11
@@ -187,13 +187,7 @@ class PostgresSubService extends index_1.SubService {
187
187
  PostgresSubService.clientHandlers.delete(this.eventClient);
188
188
  }
189
189
  }
190
- async publish(keyType, message, appId, topic) {
191
- // Check if client is still connected before attempting to publish
192
- // This prevents "Client was closed and is not queryable" errors during cleanup
193
- if (this.storeClient._ending || this.storeClient._ended) {
194
- this.logger?.debug('postgres-publish-skipped-closed-client', { appId, topic });
195
- return false;
196
- }
190
+ async publish(keyType, message, appId, topic, transaction) {
197
191
  const [originalKey, safeKey] = this.mintSafeKey(keyType, {
198
192
  appId,
199
193
  engineId: topic,
@@ -224,11 +218,32 @@ class PostgresSubService extends index_1.SubService {
224
218
  jid,
225
219
  });
226
220
  }
227
- // Publish the message using the safe topic
221
+ // Escape single quotes for SQL
222
+ payload = payload.replace(/'/g, "''");
223
+ // If transaction provided and has addCommand (KVSQL Multi pattern),
224
+ // add NOTIFY to transaction
225
+ if (transaction &&
226
+ typeof transaction.addCommand === 'function') {
227
+ // Add NOTIFY to transaction - will execute when transaction.exec() is called
228
+ transaction.addCommand(`NOTIFY "${safeKey}", '${payload}'`, [], 'void');
229
+ this.logger.debug(`postgres-publish-transactional`, {
230
+ originalKey,
231
+ safeKey
232
+ });
233
+ return true;
234
+ }
235
+ // Non-transactional publish - execute immediately
236
+ // Check if client is still connected before attempting to publish
237
+ if (this.storeClient._ending || this.storeClient._ended) {
238
+ this.logger?.debug('postgres-publish-skipped-closed-client', { appId, topic });
239
+ return false;
240
+ }
228
241
  try {
229
- payload = payload.replace(/'/g, "''");
230
242
  await this.storeClient.query(`NOTIFY "${safeKey}", '${payload}'`);
231
- this.logger.debug(`postgres-publish`, { originalKey, safeKey });
243
+ this.logger.debug(`postgres-publish`, {
244
+ originalKey,
245
+ safeKey
246
+ });
232
247
  return true;
233
248
  }
234
249
  catch (err) {
@@ -14,7 +14,7 @@ declare class TaskService {
14
14
  constructor(store: StoreService<ProviderClient, ProviderTransaction>, logger: ILogger);
15
15
  processWebHooks(hookEventCallback: HookInterface): Promise<void>;
16
16
  enqueueWorkItems(keys: string[]): Promise<void>;
17
- registerJobForCleanup(jobId: string, inSeconds: number, options: JobCompletionOptions): Promise<void>;
17
+ registerJobForCleanup(jobId: string, inSeconds: number, options: JobCompletionOptions, transaction?: ProviderTransaction): Promise<void>;
18
18
  registerTimeHook(jobId: string, gId: string, activityId: string, type: WorkListTaskType, inSeconds: number, dad: string, transaction?: ProviderTransaction): Promise<void>;
19
19
  /**
20
20
  * Should this engine instance play the role of 'scout' on behalf
@@ -34,13 +34,9 @@ class TaskService {
34
34
  async enqueueWorkItems(keys) {
35
35
  await this.store.addTaskQueues(keys);
36
36
  }
37
- async registerJobForCleanup(jobId, inSeconds = enums_1.HMSH_EXPIRE_DURATION, options) {
37
+ async registerJobForCleanup(jobId, inSeconds = enums_1.HMSH_EXPIRE_DURATION, options, transaction) {
38
38
  if (inSeconds > 0) {
39
- await this.store.expireJob(jobId, inSeconds);
40
- // const fromNow = Date.now() + inSeconds * 1000;
41
- // const fidelityMS = HMSH_FIDELITY_SECONDS * 1000;
42
- // const timeSlot = Math.floor(fromNow / fidelityMS) * fidelityMS;
43
- // await this.store.registerDependenciesForCleanup(jobId, timeSlot, options);
39
+ await this.store.expireJob(jobId, inSeconds, transaction);
44
40
  }
45
41
  }
46
42
  async registerTimeHook(jobId, gId, activityId, type, inSeconds = enums_1.HMSH_FIDELITY_SECONDS, dad, transaction) {
@@ -17,7 +17,6 @@ export { MeshCallConnectParams, MeshCallExecParams, MeshCallCronParams, MeshCall
17
17
  export { PostgresClassType, PostgresClientOptions, PostgresClientType, PostgresConsumerGroup, PostgresPendingMessage, PostgresPoolClientType, PostgresQueryConfigType, PostgresQueryResultType, PostgresStreamMessage, PostgresStreamOptions, PostgresTransaction, } from './postgres';
18
18
  export { ActivateMessage, CronMessage, JobMessage, JobMessageCallback, PingMessage, PongMessage, QuorumMessage, QuorumMessageCallback, QuorumProfile, RollCallMessage, RollCallOptions, SubscriptionCallback, SubscriptionOptions, SystemHealth, ThrottleMessage, ThrottleOptions, WorkMessage, } from './quorum';
19
19
  export { NatsAckPolicy, NatsAckPolicyExplicitType, NatsClassType, NatsClientType, NatsClientOptions, NatsConsumerConfigType, NatsJetStreamManager, NatsConnection, NatsJetStreamType, NatsConnectionOptions, NatsConsumerConfig, NatsConsumerInfo, NatsConsumerManager, NatsDeliveryInfo, NatsJetStreamOptions, NatsError, NatsErrorType, NatsJetStreamClient, NatsJsMsg, NatsMessageType, NatsMsgExpect, NatsPubAck, NatsPubAckType, NatsPublishOptions, NatsRetentionPolicy, NatsRetentionPolicyWorkqueueType, NatsSequenceInfo, NatsStorageMemoryType, NatsStorageType, NatsStreamConfig, NatsStreamInfo, NatsStreamManager, NatsStreamConfigType, NatsStreamInfoType, NatsStreamOptions, NatsStreamState, NatsTransaction, } from './nats';
20
- export { RedisClass, RedisRedisClientType, RedisRedisClientOptions, RedisRedisClassType, IORedisClientType, RedisClient, RedisMulti, RedisRedisMultiType, IORedisClientOptions, IORedisClassType, IORedisMultiType, RedisOptions, isRedisClient, isIORedisClient, } from './redis';
21
20
  export { JSONSchema, StringAnyType, StringScalarType, StringStringType, SymbolMap, SymbolMaps, SymbolRanges, Symbols, SymbolSets, } from './serializer';
22
21
  export { AggregatedData, CountByFacet, GetStatsOptions, IdsData, Measure, MeasureIds, MetricTypes, StatType, StatsType, IdsResponse, JobStats, JobStatsInput, JobStatsRange, StatsResponse, Segment, TimeSegment, } from './stats';
23
22
  export { ReclaimedMessageType, RetryPolicy, RouterConfig, StreamCode, StreamConfig, StreamData, StreamDataType, StreamError, StreamDataResponse, StreamMessage, StreamMessageMetadata, StreamProviderType, StreamRetryPolicy, StreamRole, StreamStats, StreamStatus, PublishMessageConfig, } from './stream';
@@ -1,15 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ValueType = exports.trace = exports.SpanKind = exports.SpanStatusCode = exports.propagation = exports.metrics = exports.context = exports.StreamStatus = exports.StreamRole = exports.StreamDataType = exports.isIORedisClient = exports.isRedisClient = exports.KeyType = exports.HookGate = exports.CollationFaultType = void 0;
3
+ exports.ValueType = exports.trace = exports.SpanKind = exports.SpanStatusCode = exports.propagation = exports.metrics = exports.context = exports.StreamStatus = exports.StreamRole = exports.StreamDataType = exports.KeyType = exports.HookGate = exports.CollationFaultType = void 0;
4
4
  var collator_1 = require("./collator");
5
5
  Object.defineProperty(exports, "CollationFaultType", { enumerable: true, get: function () { return collator_1.CollationFaultType; } });
6
6
  var hook_1 = require("./hook");
7
7
  Object.defineProperty(exports, "HookGate", { enumerable: true, get: function () { return hook_1.HookGate; } });
8
8
  var hotmesh_1 = require("./hotmesh");
9
9
  Object.defineProperty(exports, "KeyType", { enumerable: true, get: function () { return hotmesh_1.KeyType; } });
10
- var redis_1 = require("./redis");
11
- Object.defineProperty(exports, "isRedisClient", { enumerable: true, get: function () { return redis_1.isRedisClient; } });
12
- Object.defineProperty(exports, "isIORedisClient", { enumerable: true, get: function () { return redis_1.isIORedisClient; } });
13
10
  var stream_1 = require("./stream");
14
11
  Object.defineProperty(exports, "StreamDataType", { enumerable: true, get: function () { return stream_1.StreamDataType; } });
15
12
  Object.defineProperty(exports, "StreamRole", { enumerable: true, get: function () { return stream_1.StreamRole; } });
@@ -12,7 +12,7 @@ export interface ProviderClass {
12
12
  export interface ProviderOptions {
13
13
  [key: string]: any;
14
14
  }
15
- export type Providers = 'nats' | 'postgres' | 'redis' | 'ioredis';
15
+ export type Providers = 'nats' | 'postgres';
16
16
  /**
17
17
  * A provider transaction is a set of operations that are executed
18
18
  * atomically by the provider. The transaction is created by calling
package/index.ts CHANGED
@@ -16,17 +16,13 @@ import * as Enums from './modules/enums';
16
16
  import * as KeyStore from './modules/key';
17
17
  import { ConnectorService as Connector } from './services/connector/factory';
18
18
  import { PostgresConnection as ConnectorPostgres } from './services/connector/providers/postgres';
19
- import { RedisConnection as ConnectorIORedis } from './services/connector/providers/ioredis';
20
- import { RedisConnection as ConnectorRedis } from './services/connector/providers/redis';
21
19
  import { NatsConnection as ConnectorNATS } from './services/connector/providers/nats';
22
20
 
23
21
  export {
24
22
  //Provider Connectors
25
23
  Connector, //factory
26
- ConnectorIORedis,
27
24
  ConnectorNATS,
28
25
  ConnectorPostgres,
29
- ConnectorRedis,
30
26
 
31
27
  //Top-level Modules
32
28
  HotMesh,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Permanent-Memory Workflows & AI Agents",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -23,58 +23,51 @@
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",
27
26
  "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",
29
27
  "test:connect:nats": "NODE_ENV=test jest ./tests/unit/services/connector/providers/nats.test.ts --detectOpenHandles --forceExit --verbose",
30
28
  "test:memflow": "NODE_ENV=test jest ./tests/memflow/*/*.test.ts --detectOpenHandles --forceExit --verbose",
29
+ "test:memflow:postgres": "HMSH_LOGLEVEL=info NODE_ENV=test jest ./tests/memflow/*/postgres.test.ts --detectOpenHandles --forceExit --verbose",
31
30
  "test:memflow:basic": "HMSH_LOGLEVEL=info NODE_ENV=test jest ./tests/memflow/basic/postgres.test.ts --detectOpenHandles --forceExit --verbose",
32
31
  "test:memflow:collision": "NODE_ENV=test jest ./tests/memflow/collision/postgres.test.ts --detectOpenHandles --forceExit --verbose",
33
32
  "test:memflow:fatal": "NODE_ENV=test jest ./tests/memflow/fatal/*.test.ts --detectOpenHandles --forceExit --verbose",
34
33
  "test:memflow:goodbye": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/memflow/goodbye/postgres.test.ts --detectOpenHandles --forceExit --verbose",
35
- "test:memflow:interceptor": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/memflow/interceptor/postgres.test.ts --detectOpenHandles --forceExit --verbose",
34
+ "test:memflow:interceptor": "NODE_ENV=test HMSH_LOGLEVEL=info jest ./tests/memflow/interceptor/postgres.test.ts --detectOpenHandles --forceExit --verbose",
36
35
  "test:memflow:entity": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/memflow/entity/postgres.test.ts --detectOpenHandles --forceExit --verbose",
37
36
  "test:memflow:agent": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/memflow/agent/postgres.test.ts --detectOpenHandles --forceExit --verbose",
38
37
  "test:memflow:hello": "HMSH_TELEMETRY=debug HMSH_LOGLEVEL=debug NODE_ENV=test jest ./tests/memflow/helloworld/postgres.test.ts --detectOpenHandles --forceExit --verbose",
39
38
  "test:memflow:hook": "NODE_ENV=test jest ./tests/memflow/hook/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",
39
+ "test:memflow:interrupt": "NODE_ENV=test jest ./tests/memflow/interrupt/postgres.test.ts --detectOpenHandles --forceExit --verbose",
40
+ "test:memflow:loopactivity": "NODE_ENV=test jest ./tests/memflow/loopactivity/postgres.test.ts --detectOpenHandles --forceExit --verbose",
42
41
  "test:memflow:nested": "NODE_ENV=test jest ./tests/memflow/nested/postgres.test.ts --detectOpenHandles --forceExit --verbose",
43
42
  "test:memflow:pipeline": "NODE_ENV=test jest ./tests/memflow/pipeline/postgres.test.ts --detectOpenHandles --forceExit --verbose",
44
43
  "test:memflow:retry": "NODE_ENV=test jest ./tests/memflow/retry/postgres.test.ts --detectOpenHandles --forceExit --verbose",
45
44
  "test:memflow:retrypolicy": "NODE_ENV=test jest ./tests/memflow/retry-policy/*.test.ts --detectOpenHandles --forceExit --verbose",
46
45
  "test:memflow:sleep": "NODE_ENV=test jest ./tests/memflow/sleep/postgres.test.ts --detectOpenHandles --forceExit --verbose",
47
46
  "test:memflow:signal": "NODE_ENV=test jest ./tests/memflow/signal/postgres.test.ts --detectOpenHandles --forceExit --verbose",
48
- "test:memflow:unknown": "NODE_ENV=test jest ./tests/memflow/unknown/*.test.ts --detectOpenHandles --forceExit --verbose",
47
+ "test:memflow:unknown": "NODE_ENV=test jest ./tests/memflow/unknown/postgres.test.ts --detectOpenHandles --forceExit --verbose",
49
48
  "test:cycle": "NODE_ENV=test jest ./tests/functional/cycle/*.test.ts --detectOpenHandles --forceExit --verbose",
50
- "test:functional": "NODE_ENV=test jest ./tests/functional/* --detectOpenHandles --forceExit --verbose",
49
+ "test:functional": "NODE_ENV=test jest ./tests/functional/**/postgres.test.ts --detectOpenHandles --forceExit --verbose",
51
50
  "test:emit": "NODE_ENV=test jest ./tests/functional/emit/*.test.ts --detectOpenHandles --forceExit --verbose",
52
51
  "test:pending": "NODE_ENV=test jest ./tests/functional/pending/index.test.ts --detectOpenHandles --forceExit --verbose",
53
- "test:hmsh": "NODE_ENV=test jest ./tests/functional/*.test.ts --detectOpenHandles --verbose --forceExit",
52
+ "test:hmsh": "NODE_ENV=test jest ./tests/functional/postgres.test.ts --detectOpenHandles --verbose --forceExit",
54
53
  "test:hook": "NODE_ENV=test jest ./tests/functional/hook/postgres.test.ts --detectOpenHandles --forceExit --verbose",
55
- "test:interrupt": "NODE_ENV=test jest ./tests/functional/interrupt/*.test.ts --detectOpenHandles --forceExit --verbose",
54
+ "test:interrupt": "NODE_ENV=test jest ./tests/functional/interrupt/postgres.test.ts --detectOpenHandles --forceExit --verbose",
56
55
  "test:parallel": "NODE_ENV=test jest ./tests/functional/parallel/index.test.ts --detectOpenHandles --forceExit --verbose",
57
56
  "test:pipe": "NODE_ENV=test jest ./tests/unit/services/pipe/index.test.ts --detectOpenHandles --forceExit --verbose",
58
57
  "test:quorum": "NODE_ENV=test jest ./tests/functional/quorum/postgres.test.ts --detectOpenHandles --forceExit --verbose",
59
- "test:reclaim": "NODE_ENV=test jest ./tests/functional/reclaim/*.test.ts --detectOpenHandles --forceExit --verbose",
60
- "test:redeploy": "NODE_ENV=test jest ./tests/functional/redeploy/*.test.ts --detectOpenHandles --forceExit --verbose",
58
+ "test:reclaim": "NODE_ENV=test jest ./tests/functional/reclaim/postgres.test.ts --detectOpenHandles --forceExit --verbose",
59
+ "test:redeploy": "NODE_ENV=test jest ./tests/functional/redeploy/postgres.test.ts --detectOpenHandles --forceExit --verbose",
61
60
  "test:reporter": "NODE_ENV=test jest ./tests/unit/services/reporter/index.test.ts --detectOpenHandles --forceExit --verbose",
62
- "test:reentrant": "NODE_ENV=test jest ./tests/functional/reentrant/*.test.ts --detectOpenHandles --forceExit --verbose",
63
- "test:retry": "NODE_ENV=test jest ./tests/functional/retry/*.test.ts --detectOpenHandles --forceExit --verbose",
61
+ "test:reentrant": "NODE_ENV=test jest ./tests/functional/reentrant/postgres.test.ts --detectOpenHandles --forceExit --verbose",
62
+ "test:retry": "NODE_ENV=test jest ./tests/functional/retry/postgres.test.ts --detectOpenHandles --forceExit --verbose",
64
63
  "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",
66
- "test:signal": "NODE_ENV=test jest ./tests/functional/signal/*.test.ts --detectOpenHandles --forceExit --verbose",
64
+ "test:sequence": "NODE_ENV=test HMSH_LOGLEVEL=info jest ./tests/functional/sequence/postgres.test.ts --detectOpenHandles --forceExit --verbose",
65
+ "test:signal": "NODE_ENV=test jest ./tests/functional/signal/postgres.test.ts --detectOpenHandles --forceExit --verbose",
67
66
  "test:status": "NODE_ENV=test jest ./tests/functional/status/index.test.ts --detectOpenHandles --forceExit --verbose",
68
67
  "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",
71
68
  "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",
74
69
  "test:stream:postgres": "NODE_ENV=test jest ./tests/functional/stream/providers/postgres/postgres.test.ts --detectOpenHandles --forceExit --verbose",
75
70
  "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",
78
71
  "test:sub:postgres": "NODE_ENV=test jest ./tests/functional/sub/providers/postgres/postgres.test.ts --detectOpenHandles --forceExit --verbose",
79
72
  "test:sub:nats": "NODE_ENV=test jest ./tests/functional/sub/providers/nats/nats.test.ts --detectOpenHandles --forceExit --verbose",
80
73
  "test:trigger": "NODE_ENV=test jest ./tests/unit/services/activities/trigger.test.ts --detectOpenHandles --forceExit --verbose",
@@ -116,13 +109,11 @@
116
109
  "eslint-config-prettier": "^9.1.0",
117
110
  "eslint-plugin-import": "^2.29.1",
118
111
  "eslint-plugin-prettier": "^5.1.3",
119
- "ioredis": "^5.3.2",
120
112
  "javascript-obfuscator": "^0.6.2",
121
113
  "jest": "^29.5.0",
122
114
  "nats": "^2.28.0",
123
115
  "openai": "^5.9.0",
124
116
  "pg": "^8.10.0",
125
- "redis": "^4.6.13",
126
117
  "rimraf": "^4.4.1",
127
118
  "terser": "^5.37.0",
128
119
  "ts-jest": "^29.0.5",
@@ -132,9 +123,7 @@
132
123
  "typescript": "^5.0.4"
133
124
  },
134
125
  "peerDependencies": {
135
- "ioredis": "^4.0.0 || ^5.0.0",
136
126
  "nats": "^2.0.0",
137
- "pg": "^8.0.0",
138
- "redis": "^4.0.0"
127
+ "pg": "^8.0.0"
139
128
  }
140
129
  }
@@ -1,9 +0,0 @@
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 };
@@ -1,26 +0,0 @@
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;
@@ -1,9 +0,0 @@
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 };
@@ -1,38 +0,0 @@
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;
@@ -1,23 +0,0 @@
1
- import { SearchService } from '../../index';
2
- import { ILogger } from '../../../logger';
3
- import { IORedisClientType } from '../../../../types/redis';
4
- declare class IORedisSearchService extends SearchService<IORedisClientType> {
5
- constructor(searchClient: IORedisClientType, storeClient?: IORedisClientType);
6
- init(namespace: string, appId: string, logger: ILogger): Promise<void>;
7
- createSearchIndex(indexName: string, prefixes: string[], schema: string[]): Promise<void>;
8
- listSearchIndexes(): Promise<string[]>;
9
- updateContext(key: string, fields: Record<string, string>): Promise<any>;
10
- setFields(key: string, fields: Record<string, string>): Promise<number>;
11
- getField(key: string, field: string): Promise<string>;
12
- getFields(key: string, fields: string[]): Promise<string[]>;
13
- getAllFields(key: string): Promise<Record<string, string>>;
14
- deleteFields(key: string, fields: string[]): Promise<number>;
15
- incrementFieldByFloat(key: string, field: string, increment: number): Promise<number>;
16
- sendQuery(...query: [string, ...string[]]): Promise<any>;
17
- sendIndexedQuery(index: string, query: string[]): Promise<string[]>;
18
- findEntities(): Promise<any[]>;
19
- findEntityById(): Promise<any>;
20
- findEntitiesByCondition(): Promise<any[]>;
21
- createEntityIndex(): Promise<void>;
22
- }
23
- export { IORedisSearchService };
@@ -1,189 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IORedisSearchService = void 0;
4
- const index_1 = require("../../index");
5
- class IORedisSearchService extends index_1.SearchService {
6
- constructor(searchClient, storeClient) {
7
- super(searchClient, storeClient);
8
- }
9
- async init(namespace, appId, logger) {
10
- this.namespace = namespace;
11
- this.appId = appId;
12
- this.logger = logger;
13
- }
14
- async createSearchIndex(indexName, prefixes, schema) {
15
- try {
16
- await this.searchClient.call('FT.CREATE', indexName, 'ON', 'HASH', 'PREFIX', prefixes.length.toString(), ...prefixes, 'SCHEMA', ...schema);
17
- }
18
- catch (error) {
19
- this.logger.info('Error creating search index', { error });
20
- throw error;
21
- }
22
- }
23
- async listSearchIndexes() {
24
- try {
25
- const indexes = await this.searchClient.call('FT._LIST');
26
- return indexes;
27
- }
28
- catch (error) {
29
- this.logger.info('Error listing search indexes', { error });
30
- throw error;
31
- }
32
- }
33
- async updateContext(key, fields) {
34
- // Find replay ID if present (field with hyphen, not the @udata field)
35
- const replayId = Object.keys(fields).find((k) => k.includes('-') && !k.startsWith('@'));
36
- // Route based on @udata operation
37
- if ('@udata:set' in fields) {
38
- const udata = JSON.parse(fields['@udata:set']);
39
- const fieldsToSet = Array.isArray(udata)
40
- ? Object.fromEntries(Array.from({ length: udata.length / 2 }, (_, i) => [
41
- udata[i * 2],
42
- udata[i * 2 + 1],
43
- ]))
44
- : udata;
45
- const result = await this.setFields(key, fieldsToSet);
46
- if (replayId)
47
- await this.searchClient.hset(key, { [replayId]: String(result) });
48
- return result;
49
- }
50
- if ('@udata:get' in fields) {
51
- const result = await this.getField(key, fields['@udata:get']);
52
- if (replayId)
53
- await this.searchClient.hset(key, { [replayId]: result });
54
- return result;
55
- }
56
- if ('@udata:mget' in fields) {
57
- const result = await this.getFields(key, JSON.parse(fields['@udata:mget']));
58
- if (replayId)
59
- await this.searchClient.hset(key, { [replayId]: result.join('|||') });
60
- return result;
61
- }
62
- if ('@udata:delete' in fields) {
63
- const result = await this.deleteFields(key, JSON.parse(fields['@udata:delete']));
64
- if (replayId)
65
- await this.searchClient.hset(key, { [replayId]: String(result) });
66
- return result;
67
- }
68
- if ('@udata:increment' in fields) {
69
- const { field, value } = JSON.parse(fields['@udata:increment']);
70
- const result = await this.incrementFieldByFloat(key, field, value);
71
- if (replayId)
72
- await this.searchClient.hset(key, { [replayId]: String(result) });
73
- return result;
74
- }
75
- if ('@udata:multiply' in fields) {
76
- const { field, value } = JSON.parse(fields['@udata:multiply']);
77
- const result = await this.incrementFieldByFloat(key, field, Math.log(value));
78
- if (replayId)
79
- await this.searchClient.hset(key, { [replayId]: String(result) });
80
- return result;
81
- }
82
- if ('@udata:all' in fields) {
83
- const all = await this.getAllFields(key);
84
- const result = Object.fromEntries(Object.entries(all).filter(([k]) => k.startsWith('_')));
85
- if (replayId)
86
- await this.searchClient.hset(key, { [replayId]: JSON.stringify(result) });
87
- return result;
88
- }
89
- // Default: call setFields
90
- return await this.setFields(key, fields);
91
- }
92
- async setFields(key, fields) {
93
- try {
94
- const result = await this.searchClient.hset(key, fields);
95
- return Number(result);
96
- }
97
- catch (error) {
98
- this.logger.error(`Error setting fields for key: ${key}`, { error });
99
- throw error;
100
- }
101
- }
102
- async getField(key, field) {
103
- try {
104
- return await this.searchClient.hget(key, field);
105
- }
106
- catch (error) {
107
- this.logger.error(`Error getting field ${field} for key: ${key}`, {
108
- error,
109
- });
110
- throw error;
111
- }
112
- }
113
- async getFields(key, fields) {
114
- try {
115
- return await this.searchClient.hmget(key, [...fields]);
116
- }
117
- catch (error) {
118
- this.logger.error(`Error getting fields for key: ${key}`, { error });
119
- throw error;
120
- }
121
- }
122
- async getAllFields(key) {
123
- try {
124
- return await this.searchClient.hgetall(key);
125
- }
126
- catch (error) {
127
- this.logger.error(`Error getting fields for key: ${key}`, { error });
128
- throw error;
129
- }
130
- }
131
- async deleteFields(key, fields) {
132
- try {
133
- const result = await this.searchClient.hdel(key, ...fields);
134
- return Number(result);
135
- }
136
- catch (error) {
137
- this.logger.error(`Error deleting fields for key: ${key}`, { error });
138
- throw error;
139
- }
140
- }
141
- async incrementFieldByFloat(key, field, increment) {
142
- try {
143
- const result = await this.searchClient.hincrbyfloat(key, field, increment);
144
- return Number(result);
145
- }
146
- catch (error) {
147
- this.logger.error(`Error incrementing field ${field} for key: ${key}`, {
148
- error,
149
- });
150
- throw error;
151
- }
152
- }
153
- async sendQuery(...query) {
154
- try {
155
- return await this.searchClient.call(...query);
156
- }
157
- catch (error) {
158
- this.logger.error('Error executing query', { error });
159
- throw error;
160
- }
161
- }
162
- async sendIndexedQuery(index, query) {
163
- try {
164
- if (query[0]?.startsWith('FT.')) {
165
- const [cmd, ...rest] = query;
166
- return (await this.searchClient.call(cmd, ...rest));
167
- }
168
- return (await this.searchClient.call('FT.SEARCH', index, ...query));
169
- }
170
- catch (error) {
171
- this.logger.error('Error executing query', { error });
172
- throw error;
173
- }
174
- }
175
- // Entity methods - not implemented for Redis (postgres-specific JSONB operations)
176
- async findEntities() {
177
- throw new Error('Entity findEntities not supported in Redis - use PostgreSQL');
178
- }
179
- async findEntityById() {
180
- throw new Error('Entity findEntityById not supported in Redis - use PostgreSQL');
181
- }
182
- async findEntitiesByCondition() {
183
- throw new Error('Entity findEntitiesByCondition not supported in Redis - use PostgreSQL');
184
- }
185
- async createEntityIndex() {
186
- throw new Error('Entity createEntityIndex not supported in Redis - use PostgreSQL');
187
- }
188
- }
189
- exports.IORedisSearchService = IORedisSearchService;
@@ -1,23 +0,0 @@
1
- import { SearchService } from '../../index';
2
- import { ILogger } from '../../../logger';
3
- import { RedisRedisClientType } from '../../../../types/redis';
4
- declare class RedisSearchService extends SearchService<RedisRedisClientType> {
5
- constructor(searchClient: RedisRedisClientType, storeClient?: RedisRedisClientType);
6
- init(namespace: string, appId: string, logger: ILogger): Promise<void>;
7
- createSearchIndex(indexName: string, prefixes: string[], schema: string[]): Promise<void>;
8
- listSearchIndexes(): Promise<string[]>;
9
- updateContext(key: string, fields: Record<string, string>): Promise<any>;
10
- setFields(key: string, fields: Record<string, string>): Promise<number>;
11
- getField(key: string, field: string): Promise<string>;
12
- getFields(key: string, fields: string[]): Promise<string[]>;
13
- getAllFields(key: string): Promise<Record<string, string>>;
14
- deleteFields(key: string, fields: string[]): Promise<number>;
15
- incrementFieldByFloat(key: string, field: string, increment: number): Promise<number>;
16
- sendQuery(...query: any[]): Promise<any>;
17
- sendIndexedQuery(index: string, query: string[]): Promise<string[]>;
18
- findEntities(): Promise<any[]>;
19
- findEntityById(): Promise<any>;
20
- findEntitiesByCondition(): Promise<any[]>;
21
- createEntityIndex(): Promise<void>;
22
- }
23
- export { RedisSearchService };