@hotmeshio/hotmesh 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/build/package.json +16 -14
- package/build/services/hotmesh/index.d.ts +9 -11
- package/build/services/hotmesh/index.js +9 -11
- package/build/services/memflow/entity.d.ts +168 -4
- package/build/services/memflow/entity.js +177 -15
- package/build/services/memflow/workflow/index.d.ts +2 -4
- package/build/services/memflow/workflow/index.js +2 -4
- package/build/services/memflow/workflow/interruption.d.ts +6 -4
- package/build/services/memflow/workflow/interruption.js +6 -4
- package/build/services/memflow/workflow/waitFor.js +1 -0
- package/build/services/search/index.d.ts +10 -0
- package/build/services/search/providers/postgres/postgres.d.ts +12 -0
- package/build/services/search/providers/postgres/postgres.js +209 -0
- package/build/services/search/providers/redis/ioredis.d.ts +4 -0
- package/build/services/search/providers/redis/ioredis.js +13 -0
- package/build/services/search/providers/redis/redis.d.ts +4 -0
- package/build/services/search/providers/redis/redis.js +13 -0
- package/build/services/store/providers/postgres/kvsql.d.ts +13 -37
- package/build/services/store/providers/postgres/kvsql.js +2 -2
- package/build/services/store/providers/postgres/kvtypes/hash/basic.d.ts +16 -0
- package/build/services/store/providers/postgres/kvtypes/hash/basic.js +480 -0
- package/build/services/store/providers/postgres/kvtypes/hash/expire.d.ts +5 -0
- package/build/services/store/providers/postgres/kvtypes/hash/expire.js +33 -0
- package/build/services/store/providers/postgres/kvtypes/hash/index.d.ts +29 -0
- package/build/services/store/providers/postgres/kvtypes/hash/index.js +190 -0
- package/build/services/store/providers/postgres/kvtypes/hash/jsonb.d.ts +14 -0
- package/build/services/store/providers/postgres/kvtypes/hash/jsonb.js +699 -0
- package/build/services/store/providers/postgres/kvtypes/hash/scan.d.ts +10 -0
- package/build/services/store/providers/postgres/kvtypes/hash/scan.js +91 -0
- package/build/services/store/providers/postgres/kvtypes/hash/types.d.ts +19 -0
- package/build/services/store/providers/postgres/kvtypes/hash/types.js +2 -0
- package/build/services/store/providers/postgres/kvtypes/hash/utils.d.ts +18 -0
- package/build/services/store/providers/postgres/kvtypes/hash/utils.js +90 -0
- package/build/types/memflow.d.ts +1 -1
- package/build/types/meshdata.d.ts +1 -1
- package/package.json +16 -14
- package/build/services/store/providers/postgres/kvtypes/hash.d.ts +0 -60
- package/build/services/store/providers/postgres/kvtypes/hash.js +0 -1287
package/README.md
CHANGED
|
@@ -16,11 +16,11 @@ Use HotMesh to:
|
|
|
16
16
|
|
|
17
17
|
## Table of Contents
|
|
18
18
|
|
|
19
|
-
1. [Quick Start](
|
|
20
|
-
2. [Permanent Memory Architecture](
|
|
21
|
-
3. [Durable AI Agents](
|
|
22
|
-
4. [Building Pipelines with State](
|
|
23
|
-
5. [Documentation & Links](
|
|
19
|
+
1. [Quick Start](#quick-start)
|
|
20
|
+
2. [Permanent Memory Architecture](#permanent-memory-architecture)
|
|
21
|
+
3. [Durable AI Agents](#durable-ai-agents)
|
|
22
|
+
4. [Building Pipelines with State](#building-pipelines-with-state)
|
|
23
|
+
5. [Documentation & Links](#documentation--links)
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
@@ -163,6 +163,8 @@ export async function researchAgent(query: string): Promise<any> {
|
|
|
163
163
|
}
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
+
> 💡 **Developer Note**: A complete implementation of this Research Agent example with tests, OpenAI integration, and multi-perspective analysis can be found in the [test suite](./tests/memflow/agent).
|
|
167
|
+
|
|
166
168
|
#### Hooks: Perspectives
|
|
167
169
|
|
|
168
170
|
```ts
|
|
@@ -355,6 +357,8 @@ export async function triggerRefresh() {
|
|
|
355
357
|
}
|
|
356
358
|
```
|
|
357
359
|
|
|
360
|
+
> 💡 **Developer Note**: A complete implementation of this Pipeline example with OpenAI Vision integration, processing hooks, and document workflow automation can be found in the [test suite](./tests/memflow/pipeline).
|
|
361
|
+
|
|
358
362
|
---
|
|
359
363
|
|
|
360
364
|
## Documentation & Links
|
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/hotmesh",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Permanent-Memory Workflows & AI Agents",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -27,26 +27,27 @@
|
|
|
27
27
|
"test:connect:postgres": "NODE_ENV=test jest ./tests/unit/services/connector/providers/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
28
28
|
"test:connect:redis": "NODE_ENV=test jest ./tests/unit/services/connector/providers/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
29
29
|
"test:connect:nats": "NODE_ENV=test jest ./tests/unit/services/connector/providers/nats.test.ts --detectOpenHandles --forceExit --verbose",
|
|
30
|
-
"test:
|
|
31
|
-
"test:memflow": "NODE_ENV=test jest ./tests/memflow/*/*.test.ts --detectOpenHandles --forceExit --verbose",
|
|
30
|
+
"test:memflow": "NODE_ENV=test jest ./tests/memflow/*/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
32
31
|
"test:memflow:basic": "HMSH_LOGLEVEL=info NODE_ENV=test jest ./tests/memflow/basic/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
33
32
|
"test:memflow:collision": "NODE_ENV=test jest ./tests/memflow/collision/*.test.ts --detectOpenHandles --forceExit --verbose",
|
|
34
33
|
"test:memflow:fatal": "NODE_ENV=test jest ./tests/memflow/fatal/*.test.ts --detectOpenHandles --forceExit --verbose",
|
|
35
34
|
"test:memflow:goodbye": "NODE_ENV=test jest ./tests/memflow/goodbye/*.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
|
-
"test:memflow:hello": "HMSH_TELEMETRY=debug HMSH_LOGLEVEL=debug HMSH_IS_CLUSTER=true NODE_ENV=test jest ./tests/memflow/helloworld
|
|
39
|
-
"test:memflow:hook": "NODE_ENV=test jest ./tests/memflow/hook
|
|
40
|
-
"test:memflow:interrupt": "NODE_ENV=test jest ./tests/memflow/interrupt
|
|
41
|
-
"test:memflow:loopactivity": "NODE_ENV=test jest ./tests/memflow/loopactivity
|
|
42
|
-
"test:memflow:nested": "NODE_ENV=test jest ./tests/memflow/nested
|
|
43
|
-
"test:memflow:
|
|
44
|
-
"test:memflow:
|
|
45
|
-
"test:memflow:
|
|
46
|
-
"test:memflow:
|
|
37
|
+
"test:memflow:hello": "HMSH_TELEMETRY=debug HMSH_LOGLEVEL=debug HMSH_IS_CLUSTER=true NODE_ENV=test jest ./tests/memflow/helloworld/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
38
|
+
"test:memflow:hook": "NODE_ENV=test jest ./tests/memflow/hook/postgres.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",
|
|
41
|
+
"test:memflow:nested": "NODE_ENV=test jest ./tests/memflow/nested/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
42
|
+
"test:memflow:pipeline": "NODE_ENV=test jest ./tests/memflow/pipeline/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
43
|
+
"test:memflow:retry": "NODE_ENV=test jest ./tests/memflow/retry/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
44
|
+
"test:memflow:sleep": "NODE_ENV=test jest ./tests/memflow/sleep/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
45
|
+
"test:memflow:signal": "NODE_ENV=test jest ./tests/memflow/signal/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
46
|
+
"test:memflow:unknown": "NODE_ENV=test jest ./tests/memflow/unknown/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
47
|
+
"test:cycle": "NODE_ENV=test jest ./tests/functional/cycle/*.test.ts --detectOpenHandles --forceExit --verbose",
|
|
48
|
+
"test:functional": "NODE_ENV=test jest ./tests/functional/* --detectOpenHandles --forceExit --verbose",
|
|
47
49
|
"test:emit": "NODE_ENV=test jest ./tests/functional/emit/*.test.ts --detectOpenHandles --forceExit --verbose",
|
|
48
50
|
"test:pending": "NODE_ENV=test jest ./tests/functional/pending/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
49
|
-
"test:functional": "NODE_ENV=test jest ./tests/functional/* --detectOpenHandles --forceExit --verbose",
|
|
50
51
|
"test:hmsh": "NODE_ENV=test jest ./tests/functional/*.test.ts --detectOpenHandles --verbose --forceExit",
|
|
51
52
|
"test:hook": "NODE_ENV=test jest ./tests/functional/hook/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
52
53
|
"test:interrupt": "NODE_ENV=test jest ./tests/functional/interrupt/*.test.ts --detectOpenHandles --forceExit --verbose",
|
|
@@ -74,7 +75,6 @@
|
|
|
74
75
|
"test:sub:postgres": "NODE_ENV=test jest ./tests/functional/sub/providers/postgres/postgres.test.ts --detectOpenHandles --forceExit --verbose",
|
|
75
76
|
"test:sub:nats": "NODE_ENV=test jest ./tests/functional/sub/providers/nats/nats.test.ts --detectOpenHandles --forceExit --verbose",
|
|
76
77
|
"test:trigger": "NODE_ENV=test jest ./tests/unit/services/activities/trigger.test.ts --detectOpenHandles --forceExit --verbose",
|
|
77
|
-
"test:meshdata": "NODE_ENV=test jest ./tests/meshdata/postgres.test.ts --forceExit --verbose --detectOpenHandles",
|
|
78
78
|
"test:meshos": "HMSH_LOGLEVEL=info NODE_ENV=test HMSH_IS_CLUSTER=true jest ./tests/meshos/*.test.ts --forceExit --verbose --detectOpenHandles",
|
|
79
79
|
"test:meshcall": "NODE_ENV=test jest ./tests/meshcall/*.test.ts --forceExit --verbose --detectOpenHandles",
|
|
80
80
|
"test:unit": "NODE_ENV=test jest ./tests/unit/*/*/index.test.ts --detectOpenHandles --forceExit --verbose"
|
|
@@ -109,6 +109,7 @@
|
|
|
109
109
|
"@types/pg": "^8.10.0",
|
|
110
110
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
111
111
|
"@typescript-eslint/parser": "^5.62.0",
|
|
112
|
+
"dotenv": "^16.3.1",
|
|
112
113
|
"eslint": "^8.57.0",
|
|
113
114
|
"eslint-config-prettier": "^9.1.0",
|
|
114
115
|
"eslint-plugin-import": "^2.29.1",
|
|
@@ -117,6 +118,7 @@
|
|
|
117
118
|
"javascript-obfuscator": "^4.1.1",
|
|
118
119
|
"jest": "^29.5.0",
|
|
119
120
|
"nats": "^2.28.0",
|
|
121
|
+
"openai": "^5.9.0",
|
|
120
122
|
"pg": "^8.10.0",
|
|
121
123
|
"redis": "^4.6.13",
|
|
122
124
|
"rimraf": "^4.4.1",
|
|
@@ -11,7 +11,7 @@ import { JobStatsInput, GetStatsOptions, IdsResponse, StatsResponse } from '../.
|
|
|
11
11
|
import { StreamCode, StreamData, StreamDataResponse, StreamStatus } from '../../types/stream';
|
|
12
12
|
/**
|
|
13
13
|
* HotMesh is a distributed, reentrant process orchestration engine that transforms
|
|
14
|
-
*
|
|
14
|
+
* Postgres into a resilient service mesh capable of running
|
|
15
15
|
* fault-tolerant workflows across multiple services and systems.
|
|
16
16
|
*
|
|
17
17
|
* ## Core Concepts
|
|
@@ -25,14 +25,10 @@ import { StreamCode, StreamData, StreamDataResponse, StreamStatus } from '../../
|
|
|
25
25
|
* provides built-in retry logic, idempotency, and failure recovery. Your business
|
|
26
26
|
* logic doesn't need to handle timeouts or retries - the engine manages all of that.
|
|
27
27
|
*
|
|
28
|
-
* **Multi-Provider Support**: Supports Redis/ValKey, Postgres, and NATS as backend
|
|
29
|
-
* providers, allowing you to leverage existing infrastructure investments.
|
|
30
|
-
*
|
|
31
28
|
* ## Key Features
|
|
32
29
|
*
|
|
33
30
|
* - **Fault Tolerance**: Automatic retry, timeout, and failure recovery
|
|
34
31
|
* - **Distributed Execution**: No single point of failure
|
|
35
|
-
* - **Multi-Provider**: Redis, Postgres, NATS backend support
|
|
36
32
|
* - **YAML-Driven**: Model-driven development with declarative workflow definitions
|
|
37
33
|
* - **OpenTelemetry**: Built-in observability and tracing
|
|
38
34
|
* - **Durable State**: Workflow state persists across system restarts
|
|
@@ -59,15 +55,17 @@ import { StreamCode, StreamData, StreamDataResponse, StreamStatus } from '../../
|
|
|
59
55
|
* @example
|
|
60
56
|
* ```typescript
|
|
61
57
|
* import { HotMesh } from '@hotmeshio/hotmesh';
|
|
62
|
-
* import
|
|
58
|
+
* import { Client as Postgres } from 'pg';
|
|
63
59
|
*
|
|
64
|
-
* // Initialize with
|
|
60
|
+
* // Initialize with Postgres backend
|
|
65
61
|
* const hotMesh = await HotMesh.init({
|
|
66
62
|
* appId: 'my-app',
|
|
67
63
|
* engine: {
|
|
68
64
|
* connection: {
|
|
69
|
-
* class:
|
|
70
|
-
* options: {
|
|
65
|
+
* class: Postgres,
|
|
66
|
+
* options: {
|
|
67
|
+
* connectionString: 'postgresql://user:pass@localhost:5432/db'
|
|
68
|
+
* }
|
|
71
69
|
* }
|
|
72
70
|
* }
|
|
73
71
|
* });
|
|
@@ -192,9 +190,9 @@ import { StreamCode, StreamData, StreamDataResponse, StreamStatus } from '../../
|
|
|
192
190
|
* await HotMesh.stop();
|
|
193
191
|
* ```
|
|
194
192
|
*
|
|
195
|
-
* @see {@link https://hotmesh.io/
|
|
193
|
+
* @see {@link https://docs.hotmesh.io/} - Complete documentation
|
|
196
194
|
* @see {@link https://github.com/hotmeshio/samples-typescript} - Examples and tutorials
|
|
197
|
-
* @see {@link https://zenodo.org/records/12168558} -
|
|
195
|
+
* @see {@link https://zenodo.org/records/12168558} - White paper on the architecture
|
|
198
196
|
*/
|
|
199
197
|
declare class HotMesh {
|
|
200
198
|
namespace: string;
|
|
@@ -12,7 +12,7 @@ const worker_1 = require("../worker");
|
|
|
12
12
|
const enums_1 = require("../../modules/enums");
|
|
13
13
|
/**
|
|
14
14
|
* HotMesh is a distributed, reentrant process orchestration engine that transforms
|
|
15
|
-
*
|
|
15
|
+
* Postgres into a resilient service mesh capable of running
|
|
16
16
|
* fault-tolerant workflows across multiple services and systems.
|
|
17
17
|
*
|
|
18
18
|
* ## Core Concepts
|
|
@@ -26,14 +26,10 @@ const enums_1 = require("../../modules/enums");
|
|
|
26
26
|
* provides built-in retry logic, idempotency, and failure recovery. Your business
|
|
27
27
|
* logic doesn't need to handle timeouts or retries - the engine manages all of that.
|
|
28
28
|
*
|
|
29
|
-
* **Multi-Provider Support**: Supports Redis/ValKey, Postgres, and NATS as backend
|
|
30
|
-
* providers, allowing you to leverage existing infrastructure investments.
|
|
31
|
-
*
|
|
32
29
|
* ## Key Features
|
|
33
30
|
*
|
|
34
31
|
* - **Fault Tolerance**: Automatic retry, timeout, and failure recovery
|
|
35
32
|
* - **Distributed Execution**: No single point of failure
|
|
36
|
-
* - **Multi-Provider**: Redis, Postgres, NATS backend support
|
|
37
33
|
* - **YAML-Driven**: Model-driven development with declarative workflow definitions
|
|
38
34
|
* - **OpenTelemetry**: Built-in observability and tracing
|
|
39
35
|
* - **Durable State**: Workflow state persists across system restarts
|
|
@@ -60,15 +56,17 @@ const enums_1 = require("../../modules/enums");
|
|
|
60
56
|
* @example
|
|
61
57
|
* ```typescript
|
|
62
58
|
* import { HotMesh } from '@hotmeshio/hotmesh';
|
|
63
|
-
* import
|
|
59
|
+
* import { Client as Postgres } from 'pg';
|
|
64
60
|
*
|
|
65
|
-
* // Initialize with
|
|
61
|
+
* // Initialize with Postgres backend
|
|
66
62
|
* const hotMesh = await HotMesh.init({
|
|
67
63
|
* appId: 'my-app',
|
|
68
64
|
* engine: {
|
|
69
65
|
* connection: {
|
|
70
|
-
* class:
|
|
71
|
-
* options: {
|
|
66
|
+
* class: Postgres,
|
|
67
|
+
* options: {
|
|
68
|
+
* connectionString: 'postgresql://user:pass@localhost:5432/db'
|
|
69
|
+
* }
|
|
72
70
|
* }
|
|
73
71
|
* }
|
|
74
72
|
* });
|
|
@@ -193,9 +191,9 @@ const enums_1 = require("../../modules/enums");
|
|
|
193
191
|
* await HotMesh.stop();
|
|
194
192
|
* ```
|
|
195
193
|
*
|
|
196
|
-
* @see {@link https://hotmesh.io/
|
|
194
|
+
* @see {@link https://docs.hotmesh.io/} - Complete documentation
|
|
197
195
|
* @see {@link https://github.com/hotmeshio/samples-typescript} - Examples and tutorials
|
|
198
|
-
* @see {@link https://zenodo.org/records/12168558} -
|
|
196
|
+
* @see {@link https://zenodo.org/records/12168558} - White paper on the architecture
|
|
199
197
|
*/
|
|
200
198
|
class HotMesh {
|
|
201
199
|
/**
|
|
@@ -62,7 +62,7 @@ export declare class Entity {
|
|
|
62
62
|
* const entity = await workflow.entity();
|
|
63
63
|
* await entity.set({ user: { id: 123, name: "John" } });
|
|
64
64
|
*/
|
|
65
|
-
set(value:
|
|
65
|
+
set<T>(value: T): Promise<T>;
|
|
66
66
|
/**
|
|
67
67
|
* Deep merges the provided object with the existing entity
|
|
68
68
|
*
|
|
@@ -79,7 +79,7 @@ export declare class Entity {
|
|
|
79
79
|
* const user = await entity.get("user");
|
|
80
80
|
* const email = await entity.get("user.email");
|
|
81
81
|
*/
|
|
82
|
-
get(path?: string): Promise<
|
|
82
|
+
get<T>(path?: string): Promise<T>;
|
|
83
83
|
/**
|
|
84
84
|
* Deletes a value from the entity by path
|
|
85
85
|
*
|
|
@@ -137,7 +137,171 @@ export declare class Entity {
|
|
|
137
137
|
*/
|
|
138
138
|
setIfNotExists(path: string, value: any): Promise<any>;
|
|
139
139
|
/**
|
|
140
|
-
*
|
|
140
|
+
* Finds entity records matching complex conditions using JSONB/SQL queries.
|
|
141
|
+
* This is a readonly operation that queries across all entities of a given type.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* // Basic find with simple conditions
|
|
146
|
+
* const activeUsers = await Entity.find(
|
|
147
|
+
* 'user',
|
|
148
|
+
* { status: 'active', country: 'US' },
|
|
149
|
+
* hotMeshClient
|
|
150
|
+
* );
|
|
151
|
+
*
|
|
152
|
+
* // Complex query with comparison operators
|
|
153
|
+
* const seniorUsers = await Entity.find(
|
|
154
|
+
* 'user',
|
|
155
|
+
* {
|
|
156
|
+
* age: { $gte: 65 },
|
|
157
|
+
* status: 'active',
|
|
158
|
+
* 'preferences.notifications': true
|
|
159
|
+
* },
|
|
160
|
+
* hotMeshClient,
|
|
161
|
+
* { limit: 10, offset: 0 }
|
|
162
|
+
* );
|
|
163
|
+
*
|
|
164
|
+
* // Query with multiple conditions and nested objects
|
|
165
|
+
* const premiumUsers = await Entity.find(
|
|
166
|
+
* 'user',
|
|
167
|
+
* {
|
|
168
|
+
* 'subscription.type': 'premium',
|
|
169
|
+
* 'subscription.status': 'active',
|
|
170
|
+
* 'billing.amount': { $gt: 100 },
|
|
171
|
+
* 'profile.verified': true
|
|
172
|
+
* },
|
|
173
|
+
* hotMeshClient,
|
|
174
|
+
* { limit: 20 }
|
|
175
|
+
* );
|
|
176
|
+
*
|
|
177
|
+
* // Array conditions
|
|
178
|
+
* const taggedPosts = await Entity.find(
|
|
179
|
+
* 'post',
|
|
180
|
+
* {
|
|
181
|
+
* 'tags': { $in: ['typescript', 'javascript'] },
|
|
182
|
+
* 'status': 'published',
|
|
183
|
+
* 'views': { $gte: 1000 }
|
|
184
|
+
* },
|
|
185
|
+
* hotMeshClient
|
|
186
|
+
* );
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
static find(entity: string, conditions: Record<string, any>, hotMeshClient: HotMesh, options?: {
|
|
190
|
+
limit?: number;
|
|
191
|
+
offset?: number;
|
|
192
|
+
}): Promise<any[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Finds a specific entity record by its ID using direct JSONB/SQL queries.
|
|
195
|
+
* This is the most efficient method for retrieving a single entity record.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* // Basic findById usage
|
|
200
|
+
* const user = await Entity.findById('user', 'user123', hotMeshClient);
|
|
201
|
+
*
|
|
202
|
+
* // Example with type checking
|
|
203
|
+
* interface User {
|
|
204
|
+
* id: string;
|
|
205
|
+
* name: string;
|
|
206
|
+
* email: string;
|
|
207
|
+
* preferences: {
|
|
208
|
+
* theme: 'light' | 'dark';
|
|
209
|
+
* notifications: boolean;
|
|
210
|
+
* };
|
|
211
|
+
* }
|
|
212
|
+
*
|
|
213
|
+
* const typedUser = await Entity.findById<User>('user', 'user456', hotMeshClient);
|
|
214
|
+
* console.log(typedUser.preferences.theme); // 'light' | 'dark'
|
|
215
|
+
*
|
|
216
|
+
* // Error handling example
|
|
217
|
+
* try {
|
|
218
|
+
* const order = await Entity.findById('order', 'order789', hotMeshClient);
|
|
219
|
+
* if (!order) {
|
|
220
|
+
* console.log('Order not found');
|
|
221
|
+
* return;
|
|
222
|
+
* }
|
|
223
|
+
* console.log('Order details:', order);
|
|
224
|
+
* } catch (error) {
|
|
225
|
+
* console.error('Error fetching order:', error);
|
|
226
|
+
* }
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
static findById(entity: string, id: string, hotMeshClient: HotMesh): Promise<any>;
|
|
230
|
+
/**
|
|
231
|
+
* Finds entity records matching a specific field condition using JSONB/SQL queries.
|
|
232
|
+
* Supports various operators for flexible querying across all entities of a type.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```typescript
|
|
236
|
+
* // Basic equality search
|
|
237
|
+
* const activeUsers = await Entity.findByCondition(
|
|
238
|
+
* 'user',
|
|
239
|
+
* 'status',
|
|
240
|
+
* 'active',
|
|
241
|
+
* '=',
|
|
242
|
+
* hotMeshClient,
|
|
243
|
+
* { limit: 20 }
|
|
244
|
+
* );
|
|
245
|
+
*
|
|
246
|
+
* // Numeric comparison
|
|
247
|
+
* const highValueOrders = await Entity.findByCondition(
|
|
248
|
+
* 'order',
|
|
249
|
+
* 'total_amount',
|
|
250
|
+
* 1000,
|
|
251
|
+
* '>=',
|
|
252
|
+
* hotMeshClient
|
|
253
|
+
* );
|
|
254
|
+
*
|
|
255
|
+
* // Pattern matching with LIKE
|
|
256
|
+
* const gmailUsers = await Entity.findByCondition(
|
|
257
|
+
* 'user',
|
|
258
|
+
* 'email',
|
|
259
|
+
* '%@gmail.com',
|
|
260
|
+
* 'LIKE',
|
|
261
|
+
* hotMeshClient
|
|
262
|
+
* );
|
|
263
|
+
*
|
|
264
|
+
* // IN operator for multiple values
|
|
265
|
+
* const specificProducts = await Entity.findByCondition(
|
|
266
|
+
* 'product',
|
|
267
|
+
* 'category',
|
|
268
|
+
* ['electronics', 'accessories'],
|
|
269
|
+
* 'IN',
|
|
270
|
+
* hotMeshClient
|
|
271
|
+
* );
|
|
272
|
+
*
|
|
273
|
+
* // Not equals operator
|
|
274
|
+
* const nonPremiumUsers = await Entity.findByCondition(
|
|
275
|
+
* 'user',
|
|
276
|
+
* 'subscription_type',
|
|
277
|
+
* 'premium',
|
|
278
|
+
* '!=',
|
|
279
|
+
* hotMeshClient
|
|
280
|
+
* );
|
|
281
|
+
*
|
|
282
|
+
* // Date comparison
|
|
283
|
+
* const recentOrders = await Entity.findByCondition(
|
|
284
|
+
* 'order',
|
|
285
|
+
* 'created_at',
|
|
286
|
+
* new Date('2024-01-01'),
|
|
287
|
+
* '>',
|
|
288
|
+
* hotMeshClient,
|
|
289
|
+
* { limit: 50 }
|
|
290
|
+
* );
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
static findByCondition(entity: string, field: string, value: any, operator: '=' | '!=' | '>' | '<' | '>=' | '<=' | 'LIKE' | 'IN', hotMeshClient: HotMesh, options?: {
|
|
294
|
+
limit?: number;
|
|
295
|
+
offset?: number;
|
|
296
|
+
}): Promise<any[]>;
|
|
297
|
+
/**
|
|
298
|
+
* Creates an efficient GIN index for a specific entity field to optimize queries.
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```typescript
|
|
302
|
+
* await Entity.createIndex('user', 'email', hotMeshClient);
|
|
303
|
+
* await Entity.createIndex('user', 'status', hotMeshClient);
|
|
304
|
+
* ```
|
|
141
305
|
*/
|
|
142
|
-
|
|
306
|
+
static createIndex(entity: string, field: string, hotMeshClient: HotMesh, indexType?: 'gin'): Promise<void>;
|
|
143
307
|
}
|
|
@@ -71,7 +71,7 @@ class Entity {
|
|
|
71
71
|
'@context': JSON.stringify(value),
|
|
72
72
|
[ssGuid]: '', // Pass replay ID to hash module for transactional replay storage
|
|
73
73
|
});
|
|
74
|
-
return result
|
|
74
|
+
return result;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* Deep merges the provided object with the existing entity
|
|
@@ -278,22 +278,184 @@ class Entity {
|
|
|
278
278
|
});
|
|
279
279
|
return newValue;
|
|
280
280
|
}
|
|
281
|
+
// Static readonly find methods for cross-entity querying (not tied to specific workflow)
|
|
281
282
|
/**
|
|
282
|
-
*
|
|
283
|
+
* Finds entity records matching complex conditions using JSONB/SQL queries.
|
|
284
|
+
* This is a readonly operation that queries across all entities of a given type.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* // Basic find with simple conditions
|
|
289
|
+
* const activeUsers = await Entity.find(
|
|
290
|
+
* 'user',
|
|
291
|
+
* { status: 'active', country: 'US' },
|
|
292
|
+
* hotMeshClient
|
|
293
|
+
* );
|
|
294
|
+
*
|
|
295
|
+
* // Complex query with comparison operators
|
|
296
|
+
* const seniorUsers = await Entity.find(
|
|
297
|
+
* 'user',
|
|
298
|
+
* {
|
|
299
|
+
* age: { $gte: 65 },
|
|
300
|
+
* status: 'active',
|
|
301
|
+
* 'preferences.notifications': true
|
|
302
|
+
* },
|
|
303
|
+
* hotMeshClient,
|
|
304
|
+
* { limit: 10, offset: 0 }
|
|
305
|
+
* );
|
|
306
|
+
*
|
|
307
|
+
* // Query with multiple conditions and nested objects
|
|
308
|
+
* const premiumUsers = await Entity.find(
|
|
309
|
+
* 'user',
|
|
310
|
+
* {
|
|
311
|
+
* 'subscription.type': 'premium',
|
|
312
|
+
* 'subscription.status': 'active',
|
|
313
|
+
* 'billing.amount': { $gt: 100 },
|
|
314
|
+
* 'profile.verified': true
|
|
315
|
+
* },
|
|
316
|
+
* hotMeshClient,
|
|
317
|
+
* { limit: 20 }
|
|
318
|
+
* );
|
|
319
|
+
*
|
|
320
|
+
* // Array conditions
|
|
321
|
+
* const taggedPosts = await Entity.find(
|
|
322
|
+
* 'post',
|
|
323
|
+
* {
|
|
324
|
+
* 'tags': { $in: ['typescript', 'javascript'] },
|
|
325
|
+
* 'status': 'published',
|
|
326
|
+
* 'views': { $gte: 1000 }
|
|
327
|
+
* },
|
|
328
|
+
* hotMeshClient
|
|
329
|
+
* );
|
|
330
|
+
* ```
|
|
283
331
|
*/
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
332
|
+
static async find(entity, conditions, hotMeshClient, options) {
|
|
333
|
+
// Use SearchService for JSONB/SQL querying
|
|
334
|
+
const searchClient = hotMeshClient.engine.search;
|
|
335
|
+
return await searchClient.findEntities(entity, conditions, options);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Finds a specific entity record by its ID using direct JSONB/SQL queries.
|
|
339
|
+
* This is the most efficient method for retrieving a single entity record.
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* ```typescript
|
|
343
|
+
* // Basic findById usage
|
|
344
|
+
* const user = await Entity.findById('user', 'user123', hotMeshClient);
|
|
345
|
+
*
|
|
346
|
+
* // Example with type checking
|
|
347
|
+
* interface User {
|
|
348
|
+
* id: string;
|
|
349
|
+
* name: string;
|
|
350
|
+
* email: string;
|
|
351
|
+
* preferences: {
|
|
352
|
+
* theme: 'light' | 'dark';
|
|
353
|
+
* notifications: boolean;
|
|
354
|
+
* };
|
|
355
|
+
* }
|
|
356
|
+
*
|
|
357
|
+
* const typedUser = await Entity.findById<User>('user', 'user456', hotMeshClient);
|
|
358
|
+
* console.log(typedUser.preferences.theme); // 'light' | 'dark'
|
|
359
|
+
*
|
|
360
|
+
* // Error handling example
|
|
361
|
+
* try {
|
|
362
|
+
* const order = await Entity.findById('order', 'order789', hotMeshClient);
|
|
363
|
+
* if (!order) {
|
|
364
|
+
* console.log('Order not found');
|
|
365
|
+
* return;
|
|
366
|
+
* }
|
|
367
|
+
* console.log('Order details:', order);
|
|
368
|
+
* } catch (error) {
|
|
369
|
+
* console.error('Error fetching order:', error);
|
|
370
|
+
* }
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
static async findById(entity, id, hotMeshClient) {
|
|
374
|
+
// Use SearchService for JSONB/SQL querying
|
|
375
|
+
const searchClient = hotMeshClient.engine.search;
|
|
376
|
+
return await searchClient.findEntityById(entity, id);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Finds entity records matching a specific field condition using JSONB/SQL queries.
|
|
380
|
+
* Supports various operators for flexible querying across all entities of a type.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```typescript
|
|
384
|
+
* // Basic equality search
|
|
385
|
+
* const activeUsers = await Entity.findByCondition(
|
|
386
|
+
* 'user',
|
|
387
|
+
* 'status',
|
|
388
|
+
* 'active',
|
|
389
|
+
* '=',
|
|
390
|
+
* hotMeshClient,
|
|
391
|
+
* { limit: 20 }
|
|
392
|
+
* );
|
|
393
|
+
*
|
|
394
|
+
* // Numeric comparison
|
|
395
|
+
* const highValueOrders = await Entity.findByCondition(
|
|
396
|
+
* 'order',
|
|
397
|
+
* 'total_amount',
|
|
398
|
+
* 1000,
|
|
399
|
+
* '>=',
|
|
400
|
+
* hotMeshClient
|
|
401
|
+
* );
|
|
402
|
+
*
|
|
403
|
+
* // Pattern matching with LIKE
|
|
404
|
+
* const gmailUsers = await Entity.findByCondition(
|
|
405
|
+
* 'user',
|
|
406
|
+
* 'email',
|
|
407
|
+
* '%@gmail.com',
|
|
408
|
+
* 'LIKE',
|
|
409
|
+
* hotMeshClient
|
|
410
|
+
* );
|
|
411
|
+
*
|
|
412
|
+
* // IN operator for multiple values
|
|
413
|
+
* const specificProducts = await Entity.findByCondition(
|
|
414
|
+
* 'product',
|
|
415
|
+
* 'category',
|
|
416
|
+
* ['electronics', 'accessories'],
|
|
417
|
+
* 'IN',
|
|
418
|
+
* hotMeshClient
|
|
419
|
+
* );
|
|
420
|
+
*
|
|
421
|
+
* // Not equals operator
|
|
422
|
+
* const nonPremiumUsers = await Entity.findByCondition(
|
|
423
|
+
* 'user',
|
|
424
|
+
* 'subscription_type',
|
|
425
|
+
* 'premium',
|
|
426
|
+
* '!=',
|
|
427
|
+
* hotMeshClient
|
|
428
|
+
* );
|
|
429
|
+
*
|
|
430
|
+
* // Date comparison
|
|
431
|
+
* const recentOrders = await Entity.findByCondition(
|
|
432
|
+
* 'order',
|
|
433
|
+
* 'created_at',
|
|
434
|
+
* new Date('2024-01-01'),
|
|
435
|
+
* '>',
|
|
436
|
+
* hotMeshClient,
|
|
437
|
+
* { limit: 50 }
|
|
438
|
+
* );
|
|
439
|
+
* ```
|
|
440
|
+
*/
|
|
441
|
+
static async findByCondition(entity, field, value, operator = '=', hotMeshClient, options) {
|
|
442
|
+
// Use SearchService for JSONB/SQL querying
|
|
443
|
+
const searchClient = hotMeshClient.engine.search;
|
|
444
|
+
return await searchClient.findEntitiesByCondition(entity, field, value, operator, options);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Creates an efficient GIN index for a specific entity field to optimize queries.
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* ```typescript
|
|
451
|
+
* await Entity.createIndex('user', 'email', hotMeshClient);
|
|
452
|
+
* await Entity.createIndex('user', 'status', hotMeshClient);
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
static async createIndex(entity, field, hotMeshClient, indexType = 'gin') {
|
|
456
|
+
// Use SearchService for index creation
|
|
457
|
+
const searchClient = hotMeshClient.engine.search;
|
|
458
|
+
return await searchClient.createEntityIndex(entity, field, indexType);
|
|
297
459
|
}
|
|
298
460
|
}
|
|
299
461
|
exports.Entity = Entity;
|
|
@@ -12,6 +12,7 @@ import { random } from './random';
|
|
|
12
12
|
import { signal } from './signal';
|
|
13
13
|
import { hook } from './hook';
|
|
14
14
|
import { interrupt } from './interrupt';
|
|
15
|
+
import { didInterrupt } from './interruption';
|
|
15
16
|
import { all } from './all';
|
|
16
17
|
import { sleepFor } from './sleepFor';
|
|
17
18
|
import { waitFor } from './waitFor';
|
|
@@ -22,10 +23,6 @@ import { entity } from './entityMethods';
|
|
|
22
23
|
* These methods ensure deterministic replay, persistence of state, and error handling across
|
|
23
24
|
* re-entrant workflow executions.
|
|
24
25
|
*
|
|
25
|
-
* By refactoring the original single-file implementation into submodules,
|
|
26
|
-
* we maintain clear separation of concerns and improved maintainability,
|
|
27
|
-
* while preserving type information and full functionality.
|
|
28
|
-
*
|
|
29
26
|
* @example
|
|
30
27
|
* ```typescript
|
|
31
28
|
* import { MemFlow } from '@hotmeshio/hotmesh';
|
|
@@ -62,6 +59,7 @@ export declare class WorkflowService {
|
|
|
62
59
|
static random: typeof random;
|
|
63
60
|
static signal: typeof signal;
|
|
64
61
|
static hook: typeof hook;
|
|
62
|
+
static didInterrupt: typeof didInterrupt;
|
|
65
63
|
static interrupt: typeof interrupt;
|
|
66
64
|
static all: typeof all;
|
|
67
65
|
static sleepFor: typeof sleepFor;
|