@hotmeshio/hotmesh 0.5.6 → 0.5.8
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 +132 -258
- package/build/index.d.ts +1 -3
- package/build/index.js +1 -5
- package/build/modules/enums.d.ts +0 -5
- package/build/modules/enums.js +1 -6
- package/build/modules/utils.d.ts +1 -1
- package/build/modules/utils.js +2 -29
- package/build/package.json +5 -17
- package/build/services/activities/hook.js +1 -5
- package/build/services/compiler/index.d.ts +2 -2
- package/build/services/compiler/index.js +4 -4
- package/build/services/connector/factory.d.ts +1 -1
- package/build/services/connector/factory.js +1 -11
- package/build/services/exporter/index.d.ts +8 -8
- package/build/services/exporter/index.js +8 -8
- package/build/services/memflow/client.js +1 -8
- package/build/services/memflow/connection.d.ts +0 -2
- package/build/services/memflow/connection.js +0 -2
- package/build/services/memflow/exporter.d.ts +3 -3
- package/build/services/memflow/exporter.js +3 -3
- package/build/services/memflow/index.d.ts +1 -1
- package/build/services/memflow/index.js +1 -1
- package/build/services/memflow/schemas/factory.js +1 -1
- package/build/services/memflow/search.d.ts +11 -4
- package/build/services/memflow/search.js +98 -71
- package/build/services/memflow/worker.d.ts +1 -1
- package/build/services/memflow/worker.js +1 -1
- package/build/services/memflow/workflow/execHookBatch.d.ts +54 -0
- package/build/services/memflow/workflow/execHookBatch.js +77 -0
- package/build/services/memflow/workflow/index.d.ts +2 -0
- package/build/services/memflow/workflow/index.js +2 -0
- package/build/services/meshcall/index.d.ts +1 -1
- package/build/services/meshcall/index.js +1 -1
- package/build/services/reporter/index.d.ts +1 -1
- package/build/services/reporter/index.js +12 -12
- package/build/services/search/factory.js +0 -8
- package/build/services/search/providers/postgres/postgres.js +1 -1
- package/build/services/store/cache.d.ts +1 -1
- package/build/services/store/cache.js +1 -1
- package/build/services/store/factory.js +1 -9
- package/build/services/store/index.d.ts +1 -1
- package/build/services/store/providers/postgres/kvtables.js +23 -0
- package/build/services/store/providers/postgres/kvtypes/hash/index.js +57 -0
- package/build/services/store/providers/postgres/kvtypes/hash/udata.d.ts +10 -0
- package/build/services/store/providers/postgres/kvtypes/hash/udata.js +384 -0
- package/build/services/store/providers/postgres/postgres.js +2 -6
- package/build/services/stream/factory.js +0 -16
- package/build/services/sub/factory.js +0 -8
- package/build/services/sub/providers/nats/nats.js +0 -1
- package/build/services/sub/providers/postgres/postgres.d.ts +1 -0
- package/build/services/sub/providers/postgres/postgres.js +19 -11
- package/build/services/task/index.js +0 -1
- package/build/types/activity.d.ts +1 -5
- package/build/types/hotmesh.d.ts +0 -5
- package/build/types/index.d.ts +0 -1
- package/build/types/index.js +1 -4
- package/build/types/job.d.ts +1 -1
- package/build/types/memflow.d.ts +5 -4
- package/build/types/meshcall.d.ts +0 -25
- package/build/types/provider.d.ts +1 -1
- package/build/types/stream.d.ts +1 -6
- package/index.ts +0 -4
- package/package.json +5 -17
- package/build/services/connector/providers/ioredis.d.ts +0 -9
- package/build/services/connector/providers/ioredis.js +0 -26
- package/build/services/connector/providers/redis.d.ts +0 -9
- package/build/services/connector/providers/redis.js +0 -38
- package/build/services/search/providers/redis/ioredis.d.ts +0 -23
- package/build/services/search/providers/redis/ioredis.js +0 -134
- package/build/services/search/providers/redis/redis.d.ts +0 -23
- package/build/services/search/providers/redis/redis.js +0 -147
- package/build/services/store/providers/redis/_base.d.ts +0 -137
- package/build/services/store/providers/redis/_base.js +0 -980
- package/build/services/store/providers/redis/ioredis.d.ts +0 -20
- package/build/services/store/providers/redis/ioredis.js +0 -180
- package/build/services/store/providers/redis/redis.d.ts +0 -18
- package/build/services/store/providers/redis/redis.js +0 -199
- package/build/services/stream/providers/redis/ioredis.d.ts +0 -61
- package/build/services/stream/providers/redis/ioredis.js +0 -272
- package/build/services/stream/providers/redis/redis.d.ts +0 -61
- package/build/services/stream/providers/redis/redis.js +0 -305
- package/build/services/sub/providers/redis/ioredis.d.ts +0 -17
- package/build/services/sub/providers/redis/ioredis.js +0 -81
- package/build/services/sub/providers/redis/redis.d.ts +0 -17
- package/build/services/sub/providers/redis/redis.js +0 -72
- package/build/types/redis.d.ts +0 -258
- package/build/types/redis.js +0 -11
package/README.md
CHANGED
|
@@ -1,315 +1,189 @@
|
|
|
1
1
|
# HotMesh
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Integrate AI automation into your current stack — without breaking it**
|
|
4
4
|
|
|
5
|
-

|
|
5
|
+

|
|
6
6
|
|
|
7
|
-
HotMesh
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Why Choose HotMesh
|
|
7
|
+
HotMesh modernizes existing business systems by introducing a durable workflow layer that connects AI, automation, and human-in-the-loop steps — **without replacing your current stack**.
|
|
8
|
+
Each process runs with persistent memory in Postgres, surviving retries, crashes, and human delays.
|
|
12
9
|
|
|
10
|
+
```bash
|
|
11
|
+
npm install @hotmeshio/hotmesh
|
|
12
|
+
```
|
|
13
13
|
|
|
14
|
-
- **One memory model** across all your agents and pipelines. No more designing custom persistence for each workflow.
|
|
15
|
-
- **Automatic reliability** with transactional safety, replay protection, and crash recovery built-in.
|
|
16
|
-
- **Natural concurrency** through isolated hooks that can run in parallel without coordination overhead.
|
|
17
|
-
- **Operational transparency** using standard SQL to query live pipeline status and agent memory.
|
|
18
|
-
- **Multi-tenant ready** with clean schema isolation and flexible indexing.
|
|
19
14
|
---
|
|
20
15
|
|
|
21
|
-
##
|
|
22
|
-
|
|
23
|
-
### 1. Entities
|
|
24
|
-
|
|
25
|
-
Durable JSONB documents representing *process memory*. Each entity:
|
|
16
|
+
## What It Solves
|
|
26
17
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* Is versioned implicitly by transactional history.
|
|
30
|
-
* Can be partially indexed for targeted query performance.
|
|
18
|
+
Modernization often stalls where systems meet people and AI.
|
|
19
|
+
HotMesh builds a **durable execution bridge** across those seams — linking your database, APIs, RPA, and AI agents into one recoverable process.
|
|
31
20
|
|
|
32
|
-
|
|
21
|
+
* **AI that can fail safely** — retries, resumable state, and confidence tracking
|
|
22
|
+
* **Human steps that don’t block** — pause for days, resume instantly
|
|
23
|
+
* **Legacy systems that stay connected** — SQL and RPA coexist seamlessly
|
|
24
|
+
* **Full visibility** — query workflows and outcomes directly in SQL
|
|
33
25
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Re‑entrant, idempotent, interruptible units of work that *maintain* an entity. Hooks can:
|
|
37
|
-
|
|
38
|
-
* Start, stop, or be re‑invoked without corrupting state.
|
|
39
|
-
* Run concurrently (Postgres ensures isolation on write).
|
|
40
|
-
* Emit signals to let coordinators or sibling hooks know a perspective / phase completed.
|
|
41
|
-
|
|
42
|
-
### 3. Workflow Coordinators
|
|
43
|
-
|
|
44
|
-
Thin entrypoints that:
|
|
26
|
+
---
|
|
45
27
|
|
|
46
|
-
|
|
47
|
-
* Fan out perspective / phase hooks.
|
|
48
|
-
* Optionally synthesize or finalize.
|
|
49
|
-
* Return a snapshot (often the final entity state) — *the workflow result is just memory*.
|
|
28
|
+
## Core Model
|
|
50
29
|
|
|
51
|
-
###
|
|
30
|
+
### Entity — the Business Process Record
|
|
52
31
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| `set` | Replace full value (first write or reset) | `await e.set({ user: { id: 123, name: "John" } })` |
|
|
56
|
-
| `merge` | Deep JSON merge | `await e.merge({ user: { email: "john@example.com" } })` |
|
|
57
|
-
| `append` | Append to an array field | `await e.append('items', { id: 1, name: "New Item" })` |
|
|
58
|
-
| `prepend` | Add to start of array field | `await e.prepend('items', { id: 0, name: "First Item" })` |
|
|
59
|
-
| `remove` | Remove item from array by index | `await e.remove('items', 0)` |
|
|
60
|
-
| `increment` | Numeric counters / progress | `await e.increment('counter', 5)` |
|
|
61
|
-
| `toggle` | Toggle boolean value | `await e.toggle('settings.enabled')` |
|
|
62
|
-
| `setIfNotExists` | Set value only if path doesn't exist | `await e.setIfNotExists('user.id', 123)` |
|
|
63
|
-
| `delete` | Remove field at specified path | `await e.delete('user.email')` |
|
|
64
|
-
| `get` | Read value at path (or full entity) | `await e.get('user.email')` |
|
|
65
|
-
| `signal` | Mark hook milestone / unlock waiters | `await MemFlow.workflow.signal('phase-x', data)` |
|
|
32
|
+
Every workflow writes to a durable JSON document in Postgres called an **Entity**.
|
|
33
|
+
It becomes the shared memory between APIs, RPA jobs, LLM agents, and human operators.
|
|
66
34
|
|
|
67
|
-
|
|
35
|
+
```ts
|
|
36
|
+
const e = await MemFlow.workflow.entity();
|
|
37
|
+
|
|
38
|
+
// initialize from a source event
|
|
39
|
+
await e.set({
|
|
40
|
+
caseId: "A42",
|
|
41
|
+
stage: "verification",
|
|
42
|
+
retries: 0,
|
|
43
|
+
notes: []
|
|
44
|
+
});
|
|
68
45
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
country: 'US'
|
|
46
|
+
// AI step adds structured output
|
|
47
|
+
await e.merge({
|
|
48
|
+
aiSummary: { result: "Verified coverage", confidence: 0.93 },
|
|
49
|
+
stage: "approval",
|
|
74
50
|
});
|
|
75
51
|
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
'order',
|
|
79
|
-
'total_amount',
|
|
80
|
-
1000,
|
|
81
|
-
'>=',
|
|
82
|
-
hotMeshClient
|
|
83
|
-
);
|
|
52
|
+
// human operator review
|
|
53
|
+
await e.append("notes", { reviewer: "ops1", comment: "ok to proceed" });
|
|
84
54
|
|
|
85
|
-
//
|
|
86
|
-
|
|
55
|
+
// maintain counters
|
|
56
|
+
await e.increment("retries", 1);
|
|
87
57
|
|
|
88
|
-
//
|
|
89
|
-
await
|
|
58
|
+
// retrieve current process state
|
|
59
|
+
const data = await e.get();
|
|
90
60
|
```
|
|
91
61
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
## Table of Contents
|
|
95
|
-
|
|
96
|
-
1. [Quick Start](#quick-start)
|
|
97
|
-
2. [Memory Architecture](#memory-architecture)
|
|
98
|
-
3. [Durable AI Agents](#durable-ai-agents)
|
|
99
|
-
4. [Stateful Pipelines](#stateful-pipelines)
|
|
100
|
-
5. [Indexing Strategy](#indexing-strategy)
|
|
101
|
-
6. [Operational Notes](#operational-notes)
|
|
102
|
-
7. [Documentation & Links](#documentation--links)
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Quick Start
|
|
107
|
-
|
|
108
|
-
### Install
|
|
62
|
+
**Minimal surface contract**
|
|
109
63
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
64
|
+
| Command | Purpose |
|
|
65
|
+
| ------------- | ---------------------------------- |
|
|
66
|
+
| `set()` | Initialize workflow state |
|
|
67
|
+
| `merge()` | Update any JSON path |
|
|
68
|
+
| `append()` | Add entries to lists (logs, notes) |
|
|
69
|
+
| `increment()` | Maintain counters or metrics |
|
|
70
|
+
| `get()` | Retrieve current state |
|
|
113
71
|
|
|
114
|
-
|
|
115
|
-
```ts
|
|
116
|
-
import { MemFlow } from '@hotmeshio/hotmesh';
|
|
117
|
-
import { Client as Postgres } from 'pg';
|
|
118
|
-
|
|
119
|
-
async function main() {
|
|
120
|
-
// Auto-provisions required tables/index scaffolding on first run
|
|
121
|
-
const mf = await MemFlow.init({
|
|
122
|
-
appId: 'my-app',
|
|
123
|
-
engine: {
|
|
124
|
-
connection: {
|
|
125
|
-
class: Postgres,
|
|
126
|
-
options: { connectionString: process.env.DATABASE_URL }
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Start a durable research agent (entity-backed workflow)
|
|
132
|
-
const handle = await mf.workflow.start({
|
|
133
|
-
entity: 'research-agent',
|
|
134
|
-
workflowName: 'researchAgent',
|
|
135
|
-
workflowId: 'agent-session-jane-001',
|
|
136
|
-
args: ['Long-term impacts of renewable energy subsidies'],
|
|
137
|
-
taskQueue: 'agents'
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
console.log('Final Memory Snapshot:', await handle.result());
|
|
141
|
-
}
|
|
72
|
+
Entities are stored in plain SQL tables, directly queryable:
|
|
142
73
|
|
|
143
|
-
|
|
74
|
+
```sql
|
|
75
|
+
SELECT id, context->>'stage', context->'aiSummary'->>'result'
|
|
76
|
+
FROM my_app.jobs
|
|
77
|
+
WHERE entity = 'claims-review'
|
|
78
|
+
AND context->>'stage' != 'complete';
|
|
144
79
|
```
|
|
145
80
|
|
|
146
|
-
### Value Checklist (What You Did *Not* Have To Do)
|
|
147
|
-
- Create tables / migrations
|
|
148
|
-
- Define per-agent caches
|
|
149
|
-
- Implement optimistic locking
|
|
150
|
-
- Build a queue fan‑out mechanism
|
|
151
|
-
- Hand-roll replay protection
|
|
152
|
-
|
|
153
81
|
---
|
|
154
82
|
|
|
155
|
-
|
|
156
|
-
|
|
83
|
+
### Hook — Parallel Work Units
|
|
84
|
+
|
|
85
|
+
Hooks are stateless functions that operate on the shared Entity.
|
|
86
|
+
Each hook executes independently (API, RPA, or AI), retrying automatically until success.
|
|
157
87
|
|
|
158
|
-
### Programmatic Indexing
|
|
159
88
|
```ts
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const agents = await MemFlow.Entity.find('research-agent', {
|
|
165
|
-
isPremium: true,
|
|
166
|
-
needsVerification: true
|
|
167
|
-
}, hotMeshClient);
|
|
89
|
+
await MemFlow.workflow.execHook({
|
|
90
|
+
workflowName: "verifyCoverage",
|
|
91
|
+
args: ["A42"]
|
|
92
|
+
});
|
|
168
93
|
```
|
|
169
94
|
|
|
170
|
-
|
|
171
|
-
```sql
|
|
172
|
-
-- Same index via SQL (more control over index type/conditions)
|
|
173
|
-
CREATE INDEX idx_research_agents_premium ON my_app.jobs (id)
|
|
174
|
-
WHERE entity = 'research-agent' AND (context->>'isPremium')::boolean = true;
|
|
95
|
+
To run independent work in parallel, use a **batch execution** pattern:
|
|
175
96
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
97
|
+
```ts
|
|
98
|
+
// Run independent research perspectives in parallel using batch execution
|
|
99
|
+
await MemFlow.workflow.execHookBatch([
|
|
100
|
+
{
|
|
101
|
+
key: 'optimistic',
|
|
102
|
+
options: {
|
|
103
|
+
taskQueue: 'agents',
|
|
104
|
+
workflowName: 'optimisticPerspective',
|
|
105
|
+
args: [query],
|
|
106
|
+
signalId: 'optimistic-complete'
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
key: 'skeptical',
|
|
111
|
+
options: {
|
|
112
|
+
taskQueue: 'agents',
|
|
113
|
+
workflowName: 'skepticalPerspective',
|
|
114
|
+
args: [query],
|
|
115
|
+
signalId: 'skeptical-complete'
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
]);
|
|
182
119
|
```
|
|
183
120
|
|
|
184
|
-
|
|
185
|
-
1. *Model intent, not mechanics.* Keep ephemeral calculation artifacts minimal; store derived values only if reused.
|
|
186
|
-
2. *Index sparingly.* Each index is a write amplification cost. Start with 1–2 selective partial indexes.
|
|
187
|
-
3. *Keep arrays append‑only where possible.* Supports audit and replay semantics cheaply.
|
|
188
|
-
4. *Choose your tool:* Use Entity methods for standard queries, raw SQL for complex analytics or custom indexes.
|
|
121
|
+
Each hook runs in its own recoverable context, allowing AI, API, and RPA agents to operate independently while writing to the same durable Entity.
|
|
189
122
|
|
|
190
123
|
---
|
|
191
124
|
|
|
192
|
-
##
|
|
193
|
-
Agents become simpler: the *agent* is the memory record; hooks supply perspectives, verification, enrichment, or lifecycle progression.
|
|
194
|
-
|
|
195
|
-
### Coordinator (Research Agent)
|
|
196
|
-
```ts
|
|
197
|
-
export async function researchAgent(query: string) {
|
|
198
|
-
const entity = await MemFlow.workflow.entity();
|
|
199
|
-
|
|
200
|
-
const initial = {
|
|
201
|
-
query,
|
|
202
|
-
findings: [],
|
|
203
|
-
perspectives: {},
|
|
204
|
-
confidence: 0,
|
|
205
|
-
verification: {},
|
|
206
|
-
status: 'researching',
|
|
207
|
-
startTime: new Date().toISOString()
|
|
208
|
-
};
|
|
209
|
-
await entity.set<typeof initial>(initial);
|
|
210
|
-
|
|
211
|
-
// Fan-out perspectives
|
|
212
|
-
await MemFlow.workflow.execHook({ taskQueue: 'agents', workflowName: 'optimisticPerspective', args: [query], signalId: 'optimistic-complete' });
|
|
213
|
-
await MemFlow.workflow.execHook({ taskQueue: 'agents', workflowName: 'skepticalPerspective', args: [query], signalId: 'skeptical-complete' });
|
|
214
|
-
await MemFlow.workflow.execHook({ taskQueue: 'agents', workflowName: 'verificationHook', args: [query], signalId: 'verification-complete' });
|
|
215
|
-
await MemFlow.workflow.execHook({ taskQueue: 'agents', workflowName: 'synthesizePerspectives', args: [], signalId: 'synthesis-complete' });
|
|
216
|
-
|
|
217
|
-
return await entity.get();
|
|
218
|
-
}
|
|
219
|
-
```
|
|
125
|
+
## Example — AI-Assisted Claims Review
|
|
220
126
|
|
|
221
|
-
### Synthesis Hook
|
|
222
127
|
```ts
|
|
223
|
-
export async function
|
|
128
|
+
export async function claimsWorkflow(caseId: string) {
|
|
224
129
|
const e = await MemFlow.workflow.entity();
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
await
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
130
|
+
await e.set({ caseId, stage: "intake", approved: false });
|
|
131
|
+
|
|
132
|
+
// Run verification and summarization in parallel
|
|
133
|
+
await MemFlow.workflow.execHookBatch([
|
|
134
|
+
{
|
|
135
|
+
key: 'verifyCoverage',
|
|
136
|
+
options: {
|
|
137
|
+
taskQueue: 'agents',
|
|
138
|
+
workflowName: 'verifyCoverage',
|
|
139
|
+
args: [caseId],
|
|
140
|
+
signalId: 'verify-complete'
|
|
233
141
|
}
|
|
234
142
|
},
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
143
|
+
{
|
|
144
|
+
key: 'generateSummary',
|
|
145
|
+
options: {
|
|
146
|
+
taskQueue: 'agents',
|
|
147
|
+
workflowName: 'generateSummary',
|
|
148
|
+
args: [caseId],
|
|
149
|
+
signalId: 'summary-complete'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
]);
|
|
240
153
|
|
|
241
|
-
|
|
154
|
+
// Wait for human sign-off
|
|
155
|
+
const approval = await MemFlow.workflow.waitFor("human-approval");
|
|
156
|
+
await e.merge({ approved: approval === true, stage: "complete" });
|
|
242
157
|
|
|
243
|
-
|
|
158
|
+
return await e.get();
|
|
159
|
+
}
|
|
160
|
+
```
|
|
244
161
|
|
|
245
|
-
|
|
246
|
-
Pipelines are identical in structure to agents: a coordinator seeds memory; phase hooks advance state; the entity is the audit trail.
|
|
162
|
+
This bridges:
|
|
247
163
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const pipeline = await MemFlow.workflow.entity();
|
|
252
|
-
|
|
253
|
-
const initial = {
|
|
254
|
-
documentId: `doc-${Date.now()}`,
|
|
255
|
-
status: 'started',
|
|
256
|
-
startTime: new Date().toISOString(),
|
|
257
|
-
imageRefs: [],
|
|
258
|
-
extractedInfo: [],
|
|
259
|
-
validationResults: [],
|
|
260
|
-
finalResult: null,
|
|
261
|
-
processingSteps: [],
|
|
262
|
-
errors: [],
|
|
263
|
-
pageSignals: {}
|
|
264
|
-
};
|
|
265
|
-
await pipeline.set<typeof initial>(initial);
|
|
266
|
-
|
|
267
|
-
await pipeline.merge({ status: 'loading-images' });
|
|
268
|
-
await pipeline.append('processingSteps', 'image-load-started');
|
|
269
|
-
const imageRefs = await activities.loadImagePages();
|
|
270
|
-
if (!imageRefs?.length) throw new Error('No image references found');
|
|
271
|
-
await pipeline.merge({ imageRefs });
|
|
272
|
-
await pipeline.append('processingSteps', 'image-load-completed');
|
|
273
|
-
|
|
274
|
-
// Page hooks
|
|
275
|
-
for (const [i, ref] of imageRefs.entries()) {
|
|
276
|
-
const page = i + 1;
|
|
277
|
-
await MemFlow.workflow.execHook({
|
|
278
|
-
taskQueue: 'pipeline',
|
|
279
|
-
workflowName: 'pageProcessingHook',
|
|
280
|
-
args: [ref, page, initial.documentId],
|
|
281
|
-
signalId: `page-${page}-complete`
|
|
282
|
-
});
|
|
283
|
-
}
|
|
164
|
+
* an existing insurance or EHR system (status + audit trail)
|
|
165
|
+
* LLM agents for data validation and summarization
|
|
166
|
+
* a human reviewer for final sign-off
|
|
284
167
|
|
|
285
|
-
|
|
286
|
-
await MemFlow.workflow.execHook({ taskQueue: 'pipeline', workflowName: 'validationHook', args: [initial.documentId], signalId: 'validation-complete' });
|
|
287
|
-
// Approval
|
|
288
|
-
await MemFlow.workflow.execHook({ taskQueue: 'pipeline', workflowName: 'approvalHook', args: [initial.documentId], signalId: 'approval-complete' });
|
|
289
|
-
// Notification
|
|
290
|
-
await MemFlow.workflow.execHook({ taskQueue: 'pipeline', workflowName: 'notificationHook', args: [initial.documentId], signalId: 'processing-complete' });
|
|
168
|
+
—all within one recoverable workflow record.
|
|
291
169
|
|
|
292
|
-
|
|
293
|
-
await pipeline.append('processingSteps', 'pipeline-completed');
|
|
294
|
-
return await pipeline.get();
|
|
295
|
-
}
|
|
296
|
-
```
|
|
170
|
+
---
|
|
297
171
|
|
|
298
|
-
|
|
299
|
-
- *Replay Friendly*: Each hook can be retried; pipeline memory records invariant progress markers (`processingSteps`).
|
|
300
|
-
- *Parallelizable*: Pages fan out naturally without manual queue wiring.
|
|
301
|
-
- *Auditable*: Entire lifecycle captured in a single evolving JSON record.
|
|
172
|
+
## Why It Fits Integration Work
|
|
302
173
|
|
|
303
|
-
|
|
174
|
+
HotMesh is purpose-built for **incremental modernization**.
|
|
304
175
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
176
|
+
| Need | What HotMesh Provides |
|
|
177
|
+
| ----------------------------- | ---------------------------------------- |
|
|
178
|
+
| Tie AI into legacy apps | Durable SQL bridge with full visibility |
|
|
179
|
+
| Keep human review steps | Wait-for-signal workflows |
|
|
180
|
+
| Handle unstable APIs | Built-in retries and exponential backoff |
|
|
181
|
+
| Trace process across systems | Unified JSON entity per workflow |
|
|
182
|
+
| Store long-running AI results | Durable state for agents and automations |
|
|
310
183
|
|
|
311
184
|
---
|
|
312
185
|
|
|
313
186
|
## License
|
|
314
|
-
|
|
315
|
-
|
|
187
|
+
|
|
188
|
+
Apache 2.0 — free to build, integrate, and deploy.
|
|
189
|
+
Do not resell the core engine as a hosted service.
|
package/build/index.d.ts
CHANGED
|
@@ -16,9 +16,7 @@ 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
|
export { Connector, //factory
|
|
23
|
-
|
|
21
|
+
ConnectorNATS, ConnectorPostgres, HotMesh, HotMeshConfig, MeshCall, MemFlow, Client, Connection, proxyActivities, Search, Entity, Worker, workflow, WorkflowHandle, Enums, Errors, Utils, KeyStore, };
|
|
24
22
|
export * as Types from './types';
|
package/build/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Types = exports.KeyStore = exports.Utils = exports.Errors = exports.Enums = exports.WorkflowHandle = exports.workflow = exports.Worker = exports.Entity = exports.Search = exports.proxyActivities = exports.Connection = exports.Client = exports.MemFlow = exports.MeshCall = exports.HotMesh = exports.
|
|
26
|
+
exports.Types = exports.KeyStore = exports.Utils = exports.Errors = exports.Enums = exports.WorkflowHandle = exports.workflow = exports.Worker = exports.Entity = exports.Search = exports.proxyActivities = exports.Connection = exports.Client = exports.MemFlow = exports.MeshCall = exports.HotMesh = exports.ConnectorPostgres = exports.ConnectorNATS = exports.Connector = void 0;
|
|
27
27
|
const hotmesh_1 = require("./services/hotmesh");
|
|
28
28
|
Object.defineProperty(exports, "HotMesh", { enumerable: true, get: function () { return hotmesh_1.HotMesh; } });
|
|
29
29
|
const meshcall_1 = require("./services/meshcall");
|
|
@@ -58,10 +58,6 @@ const factory_1 = require("./services/connector/factory");
|
|
|
58
58
|
Object.defineProperty(exports, "Connector", { enumerable: true, get: function () { return factory_1.ConnectorService; } });
|
|
59
59
|
const postgres_1 = require("./services/connector/providers/postgres");
|
|
60
60
|
Object.defineProperty(exports, "ConnectorPostgres", { enumerable: true, get: function () { return postgres_1.PostgresConnection; } });
|
|
61
|
-
const ioredis_1 = require("./services/connector/providers/ioredis");
|
|
62
|
-
Object.defineProperty(exports, "ConnectorIORedis", { enumerable: true, get: function () { return ioredis_1.RedisConnection; } });
|
|
63
|
-
const redis_1 = require("./services/connector/providers/redis");
|
|
64
|
-
Object.defineProperty(exports, "ConnectorRedis", { enumerable: true, get: function () { return redis_1.RedisConnection; } });
|
|
65
61
|
const nats_1 = require("./services/connector/providers/nats");
|
|
66
62
|
Object.defineProperty(exports, "ConnectorNATS", { enumerable: true, get: function () { return nats_1.NatsConnection; } });
|
|
67
63
|
exports.Types = __importStar(require("./types"));
|
package/build/modules/enums.d.ts
CHANGED
|
@@ -7,11 +7,6 @@ export declare const HMSH_LOGLEVEL: LogLevel;
|
|
|
7
7
|
* Determines the log level for telemetry. The default is 'info' which emits worker and trigger spans. 'debug' emits all spans.
|
|
8
8
|
*/
|
|
9
9
|
export declare const HMSH_TELEMETRY: "debug" | "info";
|
|
10
|
-
/**
|
|
11
|
-
* If Redis, explicitly sets whether the application is running in a cluster. The default is false.
|
|
12
|
-
* @deprecated
|
|
13
|
-
*/
|
|
14
|
-
export declare const HMSH_IS_CLUSTER: boolean;
|
|
15
10
|
/**
|
|
16
11
|
* Default cleanup time for signal in the db when its associated job is completed.
|
|
17
12
|
*/
|
package/build/modules/enums.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_TASK_QUEUE = exports.HMSH_GUID_SIZE = exports.HMSH_SCOUT_INTERVAL_SECONDS = exports.HMSH_FIDELITY_SECONDS = exports.HMSH_EXPIRE_DURATION = exports.HMSH_XPENDING_COUNT = exports.HMSH_XCLAIM_COUNT = exports.HMSH_XCLAIM_DELAY_MS = exports.HMSH_BLOCK_TIME_MS = exports.HMSH_MEMFLOW_EXP_BACKOFF = exports.HMSH_MEMFLOW_MAX_INTERVAL = exports.HMSH_MEMFLOW_MAX_ATTEMPTS = exports.HMSH_GRADUATED_INTERVAL_MS = exports.HMSH_MAX_TIMEOUT_MS = exports.HMSH_MAX_RETRIES = exports.MAX_DELAY = exports.MAX_STREAM_RETRIES = exports.INITIAL_STREAM_BACKOFF = exports.MAX_STREAM_BACKOFF = exports.HMSH_EXPIRE_JOB_SECONDS = exports.HMSH_OTT_WAIT_TIME = exports.HMSH_DEPLOYMENT_PAUSE = exports.HMSH_DEPLOYMENT_DELAY = exports.HMSH_ACTIVATION_MAX_RETRY = exports.HMSH_QUORUM_DELAY_MS = exports.HMSH_QUORUM_ROLLCALL_CYCLES = exports.HMSH_STATUS_UNKNOWN = exports.HMSH_CODE_MEMFLOW_RETRYABLE = exports.HMSH_CODE_MEMFLOW_FATAL = exports.HMSH_CODE_MEMFLOW_MAXED = exports.HMSH_CODE_MEMFLOW_TIMEOUT = exports.HMSH_CODE_MEMFLOW_WAIT = exports.HMSH_CODE_MEMFLOW_PROXY = exports.HMSH_CODE_MEMFLOW_CHILD = exports.HMSH_CODE_MEMFLOW_ALL = exports.HMSH_CODE_MEMFLOW_SLEEP = exports.HMSH_CODE_UNACKED = exports.HMSH_CODE_TIMEOUT = exports.HMSH_CODE_UNKNOWN = exports.HMSH_CODE_INTERRUPT = exports.HMSH_CODE_NOTFOUND = exports.HMSH_CODE_PENDING = exports.HMSH_CODE_SUCCESS = exports.HMSH_SIGNAL_EXPIRE = exports.
|
|
3
|
+
exports.DEFAULT_TASK_QUEUE = exports.HMSH_GUID_SIZE = exports.HMSH_SCOUT_INTERVAL_SECONDS = exports.HMSH_FIDELITY_SECONDS = exports.HMSH_EXPIRE_DURATION = exports.HMSH_XPENDING_COUNT = exports.HMSH_XCLAIM_COUNT = exports.HMSH_XCLAIM_DELAY_MS = exports.HMSH_BLOCK_TIME_MS = exports.HMSH_MEMFLOW_EXP_BACKOFF = exports.HMSH_MEMFLOW_MAX_INTERVAL = exports.HMSH_MEMFLOW_MAX_ATTEMPTS = exports.HMSH_GRADUATED_INTERVAL_MS = exports.HMSH_MAX_TIMEOUT_MS = exports.HMSH_MAX_RETRIES = exports.MAX_DELAY = exports.MAX_STREAM_RETRIES = exports.INITIAL_STREAM_BACKOFF = exports.MAX_STREAM_BACKOFF = exports.HMSH_EXPIRE_JOB_SECONDS = exports.HMSH_OTT_WAIT_TIME = exports.HMSH_DEPLOYMENT_PAUSE = exports.HMSH_DEPLOYMENT_DELAY = exports.HMSH_ACTIVATION_MAX_RETRY = exports.HMSH_QUORUM_DELAY_MS = exports.HMSH_QUORUM_ROLLCALL_CYCLES = exports.HMSH_STATUS_UNKNOWN = exports.HMSH_CODE_MEMFLOW_RETRYABLE = exports.HMSH_CODE_MEMFLOW_FATAL = exports.HMSH_CODE_MEMFLOW_MAXED = exports.HMSH_CODE_MEMFLOW_TIMEOUT = exports.HMSH_CODE_MEMFLOW_WAIT = exports.HMSH_CODE_MEMFLOW_PROXY = exports.HMSH_CODE_MEMFLOW_CHILD = exports.HMSH_CODE_MEMFLOW_ALL = exports.HMSH_CODE_MEMFLOW_SLEEP = exports.HMSH_CODE_UNACKED = exports.HMSH_CODE_TIMEOUT = exports.HMSH_CODE_UNKNOWN = exports.HMSH_CODE_INTERRUPT = exports.HMSH_CODE_NOTFOUND = exports.HMSH_CODE_PENDING = exports.HMSH_CODE_SUCCESS = exports.HMSH_SIGNAL_EXPIRE = exports.HMSH_TELEMETRY = exports.HMSH_LOGLEVEL = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Determines the log level for the application. The default is 'info'.
|
|
6
6
|
*/
|
|
@@ -9,11 +9,6 @@ exports.HMSH_LOGLEVEL = process.env.HMSH_LOGLEVEL || 'info';
|
|
|
9
9
|
* Determines the log level for telemetry. The default is 'info' which emits worker and trigger spans. 'debug' emits all spans.
|
|
10
10
|
*/
|
|
11
11
|
exports.HMSH_TELEMETRY = process.env.HMSH_TELEMETRY || 'info';
|
|
12
|
-
/**
|
|
13
|
-
* If Redis, explicitly sets whether the application is running in a cluster. The default is false.
|
|
14
|
-
* @deprecated
|
|
15
|
-
*/
|
|
16
|
-
exports.HMSH_IS_CLUSTER = process.env.HMSH_IS_CLUSTER === 'true';
|
|
17
12
|
/**
|
|
18
13
|
* Default cleanup time for signal in the db when its associated job is completed.
|
|
19
14
|
*/
|
package/build/modules/utils.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export declare function identifyProvider(provider: any): Providers | null;
|
|
|
31
31
|
*/
|
|
32
32
|
export declare const polyfill: {
|
|
33
33
|
/**
|
|
34
|
-
* `
|
|
34
|
+
* `connection` is the generic replacement
|
|
35
35
|
*/
|
|
36
36
|
providerConfig(obj: any): any;
|
|
37
37
|
};
|
package/build/modules/utils.js
CHANGED
|
@@ -79,38 +79,11 @@ function identifyProvider(provider) {
|
|
|
79
79
|
else if (provider.toString().toLowerCase().includes('nats')) {
|
|
80
80
|
return 'nats';
|
|
81
81
|
}
|
|
82
|
-
else if ('defineCommand' in prototype ||
|
|
83
|
-
Object.keys(prototype).includes('multi')) {
|
|
84
|
-
return 'ioredis';
|
|
85
|
-
}
|
|
86
|
-
else if (Object.keys(prototype).includes('Multi')) {
|
|
87
|
-
return 'redis';
|
|
88
|
-
}
|
|
89
|
-
if (provider.constructor) {
|
|
90
|
-
if (provider.constructor.name === 'Redis' ||
|
|
91
|
-
provider.constructor.name === 'EventEmitter') {
|
|
92
|
-
if ('hset' in provider) {
|
|
93
|
-
return 'ioredis';
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
else if (provider.constructor.name === 'ProviderClient' ||
|
|
97
|
-
provider.constructor.name === 'Commander') {
|
|
98
|
-
if ('HSET' in provider) {
|
|
99
|
-
return 'redis';
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
82
|
let type = null;
|
|
104
83
|
if (Object.keys(provider).includes('connection') ||
|
|
105
84
|
!isNaN(provider.totalCount) && !isNaN(provider.idleCount)) {
|
|
106
85
|
type = 'postgres';
|
|
107
86
|
}
|
|
108
|
-
else if (Object.keys(provider).includes('Pipeline')) {
|
|
109
|
-
type = 'ioredis';
|
|
110
|
-
}
|
|
111
|
-
else if (Object.keys(provider).includes('createClient')) {
|
|
112
|
-
type = 'redis';
|
|
113
|
-
}
|
|
114
87
|
else if (prototype.constructor.toString().includes('NatsConnectionImpl')) {
|
|
115
88
|
type = 'nats';
|
|
116
89
|
}
|
|
@@ -122,10 +95,10 @@ exports.identifyProvider = identifyProvider;
|
|
|
122
95
|
*/
|
|
123
96
|
exports.polyfill = {
|
|
124
97
|
/**
|
|
125
|
-
* `
|
|
98
|
+
* `connection` is the generic replacement
|
|
126
99
|
*/
|
|
127
100
|
providerConfig(obj) {
|
|
128
|
-
return obj?.connection ?? obj?.
|
|
101
|
+
return obj?.connection ?? obj?.connections;
|
|
129
102
|
},
|
|
130
103
|
};
|
|
131
104
|
/**
|