@hotmeshio/hotmesh 0.14.2 → 0.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/package.json +5 -3
- package/build/services/durable/worker.js +4 -0
- package/build/services/engine/init.js +1 -1
- package/build/services/engine/schema.js +5 -1
- package/build/services/mapper/index.d.ts +57 -2
- package/build/services/mapper/index.js +57 -2
- package/build/services/pipe/index.d.ts +444 -10
- package/build/services/pipe/index.js +444 -10
- package/build/services/quorum/index.js +1 -1
- package/build/services/router/consumption/index.js +20 -2
- package/build/services/router/error-handling/index.js +1 -1
- package/build/services/store/factory.d.ts +1 -1
- package/build/services/store/factory.js +2 -2
- package/build/services/store/index.d.ts +1 -1
- package/build/services/store/providers/postgres/kvsql.d.ts +11 -1
- package/build/services/store/providers/postgres/kvsql.js +22 -12
- package/build/services/store/providers/postgres/kvtables.js +39 -6
- package/build/services/store/providers/postgres/kvtypes/hash/basic.js +6 -6
- package/build/services/store/providers/postgres/kvtypes/hash/scan.js +2 -1
- package/build/services/store/providers/postgres/kvtypes/list.js +7 -6
- package/build/services/store/providers/postgres/kvtypes/string.js +3 -3
- package/build/services/store/providers/postgres/kvtypes/zset.js +7 -7
- package/build/services/store/providers/postgres/postgres.d.ts +3 -2
- package/build/services/store/providers/postgres/postgres.js +55 -55
- package/build/services/store/providers/postgres/time-notify.js +18 -25
- package/build/services/store/providers/store-initializable.d.ts +1 -1
- package/build/services/stream/registry.d.ts +1 -0
- package/build/services/stream/registry.js +12 -8
- package/build/services/worker/index.js +3 -1
- package/build/types/hotmesh.d.ts +8 -0
- package/package.json +5 -3
- package/vitest.config.mts +1 -1
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/hotmesh",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.4",
|
|
4
4
|
"description": "Durable Workflow",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"obfuscate": "ts-node scripts/obfuscate.ts",
|
|
15
15
|
"clean-build": "npm run clean && npm run build",
|
|
16
16
|
"clean-build-obfuscate": "npm run clean-build && npm run obfuscate",
|
|
17
|
-
"docs": "typedoc",
|
|
18
|
-
"docs:clean": "rimraf ./docs/hotmesh && typedoc",
|
|
17
|
+
"docs": "typedoc && cp -R docs/hotmesh/* docs/ && rm -rf docs/hotmesh",
|
|
18
|
+
"docs:clean": "rimraf ./docs/hotmesh && typedoc && cp -R docs/hotmesh/* docs/ && rm -rf docs/hotmesh",
|
|
19
19
|
"lint": "eslint . --ext .ts",
|
|
20
20
|
"lint:fix": "eslint . --fix --ext .ts",
|
|
21
21
|
"start": "ts-node src/index.ts",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"test:durable:retrypolicy": "vitest run tests/durable/retry-policy",
|
|
48
48
|
"test:durable:sleep": "vitest run tests/durable/sleep/postgres.test.ts",
|
|
49
49
|
"test:durable:signal": "vitest run tests/durable/signal/postgres.test.ts",
|
|
50
|
+
"test:durable:readonly": "docker compose --profile readonly up -d --build && docker compose exec hotmesh-readonly npx vitest run --config tests/durable/readonly/vitest.config.mts",
|
|
50
51
|
"test:durable:unknown": "vitest run tests/durable/unknown/postgres.test.ts",
|
|
51
52
|
"test:durable:exporter": "HMSH_LOGLEVEL=info vitest run tests/durable/exporter",
|
|
52
53
|
"test:durable:exporter:debug": "EXPORT_DEBUG=1 HMSH_LOGLEVEL=error vitest run tests/durable/basic/postgres.test.ts",
|
|
@@ -85,6 +86,7 @@
|
|
|
85
86
|
"test:unit": "vitest run tests/unit"
|
|
86
87
|
},
|
|
87
88
|
"keywords": [
|
|
89
|
+
"Invisible Infrastructure",
|
|
88
90
|
"Headless Orchestration",
|
|
89
91
|
"Durable Workflows",
|
|
90
92
|
"Data in Motion",
|
|
@@ -516,10 +516,12 @@ class WorkerService {
|
|
|
516
516
|
if (WorkerService.instances.has(targetTopic)) {
|
|
517
517
|
return await WorkerService.instances.get(targetTopic);
|
|
518
518
|
}
|
|
519
|
+
const readonly = providerConfig.readonly ?? false;
|
|
519
520
|
const workerEntry = {
|
|
520
521
|
topic: activityTopic,
|
|
521
522
|
connection: providerConfig,
|
|
522
523
|
callback: this.wrapActivityFunctions().bind(this),
|
|
524
|
+
readonly,
|
|
523
525
|
};
|
|
524
526
|
if (config.workerCredentials) {
|
|
525
527
|
workerEntry.workerCredentials = config.workerCredentials;
|
|
@@ -644,10 +646,12 @@ class WorkerService {
|
|
|
644
646
|
const targetNamespace = config?.namespace ?? factory_1.APP_ID;
|
|
645
647
|
const optionsHash = WorkerService.hashOptions(config?.connection);
|
|
646
648
|
const targetTopic = `${optionsHash}.${targetNamespace}.${workflowTopic}`;
|
|
649
|
+
const readonly = providerConfig.readonly ?? false;
|
|
647
650
|
const workerEntry = {
|
|
648
651
|
topic: taskQueue,
|
|
649
652
|
workflowName: workflowFunctionName,
|
|
650
653
|
connection: providerConfig,
|
|
654
|
+
readonly,
|
|
651
655
|
callback: this.wrapWorkflowFunction(workflowFunction, workflowTopic, workflowFunctionName, config).bind(this),
|
|
652
656
|
};
|
|
653
657
|
if (config.workerCredentials) {
|
|
@@ -30,7 +30,7 @@ async function initSearchChannel(instance, search, store) {
|
|
|
30
30
|
}
|
|
31
31
|
exports.initSearchChannel = initSearchChannel;
|
|
32
32
|
async function initStoreChannel(instance, store) {
|
|
33
|
-
instance.store = await factory_2.StoreServiceFactory.init(store, instance.namespace, instance.appId, instance.logger);
|
|
33
|
+
instance.store = await factory_2.StoreServiceFactory.init(store, instance.namespace, instance.appId, instance.logger, instance.guid, 'engine');
|
|
34
34
|
}
|
|
35
35
|
exports.initStoreChannel = initStoreChannel;
|
|
36
36
|
async function initSubChannel(instance, sub, store) {
|
|
@@ -16,7 +16,11 @@ const activities_1 = __importDefault(require("../activities"));
|
|
|
16
16
|
async function initActivity(instance, topic, data = {}, context) {
|
|
17
17
|
const [activityId, schema] = await getSchema(instance, topic);
|
|
18
18
|
if (!schema) {
|
|
19
|
-
|
|
19
|
+
const err = new Error(`Activity schema not found for "${activityId}" (topic: ${topic}) in app ${instance.appId}. ` +
|
|
20
|
+
`This is typically caused by a worker activity whose topic collides with the graph subscribes topic. ` +
|
|
21
|
+
`Redeploy with a distinct worker topic.`);
|
|
22
|
+
err.code = 598;
|
|
23
|
+
throw err;
|
|
20
24
|
}
|
|
21
25
|
const ActivityHandler = activities_1.default[schema.type];
|
|
22
26
|
if (ActivityHandler) {
|
|
@@ -1,10 +1,42 @@
|
|
|
1
1
|
import { JobState } from '../../types/job';
|
|
2
2
|
import { TransitionRule } from '../../types/transition';
|
|
3
3
|
import { StreamCode } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* Evaluates and transforms data-mapping rules against live job state.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* MapperService is the bridge between a workflow's declarative mapping
|
|
9
|
+
* rules (including `@pipe` expressions) and the runtime job data. It
|
|
10
|
+
* recursively walks a rule tree, delegating leaf-level resolution to
|
|
11
|
+
* the {@link Pipe} engine. Static helpers such as {@link evaluate}
|
|
12
|
+
* also power transition-condition checks during workflow execution.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const mapper = new MapperService(
|
|
17
|
+
* { greeting: '{data.name}', score: { '@pipe': [['{data.x}', '{data.y}'], ['{@math.add}']] } },
|
|
18
|
+
* jobState,
|
|
19
|
+
* );
|
|
20
|
+
* const result = mapper.mapRules();
|
|
21
|
+
* // => { greeting: 'Alice', score: 7 }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
4
24
|
declare class MapperService {
|
|
5
25
|
private rules;
|
|
6
26
|
private data;
|
|
27
|
+
/**
|
|
28
|
+
* @param rules - The mapping rule tree to evaluate. May contain
|
|
29
|
+
* literal values, `{data.*}` references, or nested `@pipe` objects.
|
|
30
|
+
* @param data - The current {@link JobState} used to resolve references.
|
|
31
|
+
*/
|
|
7
32
|
constructor(rules: Record<string, unknown>, data: JobState);
|
|
33
|
+
/**
|
|
34
|
+
* Recursively resolves every rule in the tree against the current job
|
|
35
|
+
* state and returns a fully-evaluated copy.
|
|
36
|
+
*
|
|
37
|
+
* @returns A plain object mirroring the rule structure with all
|
|
38
|
+
* expressions replaced by their resolved values.
|
|
39
|
+
*/
|
|
8
40
|
mapRules(): Record<string, unknown>;
|
|
9
41
|
private traverseRules;
|
|
10
42
|
/**
|
|
@@ -20,8 +52,31 @@ declare class MapperService {
|
|
|
20
52
|
*/
|
|
21
53
|
private resolve;
|
|
22
54
|
/**
|
|
23
|
-
* Evaluates a transition rule against the current job state and
|
|
24
|
-
*
|
|
55
|
+
* Evaluates a transition rule against the current job state and an
|
|
56
|
+
* incoming Stream message code to decide whether the transition fires.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* Supports both simple boolean rules (`true` / `false`) and compound
|
|
60
|
+
* match rules with optional AND / OR gating. When the rule includes
|
|
61
|
+
* a `match` array, each entry's `actual` expression is resolved via
|
|
62
|
+
* {@link Pipe.resolve} and compared to the `expected` value.
|
|
63
|
+
*
|
|
64
|
+
* @param transitionRule - A boolean shorthand or a {@link TransitionRule}
|
|
65
|
+
* containing `code`, optional `gate`, and optional `match` conditions.
|
|
66
|
+
* @param context - The current {@link JobState} used to resolve
|
|
67
|
+
* `actual` expressions inside match entries.
|
|
68
|
+
* @param code - The {@link StreamCode} returned by the preceding
|
|
69
|
+
* activity (e.g. `200`).
|
|
70
|
+
* @returns `true` if the transition should be taken, `false` otherwise.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const shouldTransition = MapperService.evaluate(
|
|
75
|
+
* { code: 200, match: [{ expected: true, actual: '{data.isReady}' }] },
|
|
76
|
+
* jobState,
|
|
77
|
+
* 200,
|
|
78
|
+
* );
|
|
79
|
+
* ```
|
|
25
80
|
*/
|
|
26
81
|
static evaluate(transitionRule: TransitionRule | boolean, context: JobState, code: StreamCode): boolean;
|
|
27
82
|
}
|
|
@@ -2,11 +2,43 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MapperService = void 0;
|
|
4
4
|
const pipe_1 = require("../pipe");
|
|
5
|
+
/**
|
|
6
|
+
* Evaluates and transforms data-mapping rules against live job state.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* MapperService is the bridge between a workflow's declarative mapping
|
|
10
|
+
* rules (including `@pipe` expressions) and the runtime job data. It
|
|
11
|
+
* recursively walks a rule tree, delegating leaf-level resolution to
|
|
12
|
+
* the {@link Pipe} engine. Static helpers such as {@link evaluate}
|
|
13
|
+
* also power transition-condition checks during workflow execution.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const mapper = new MapperService(
|
|
18
|
+
* { greeting: '{data.name}', score: { '@pipe': [['{data.x}', '{data.y}'], ['{@math.add}']] } },
|
|
19
|
+
* jobState,
|
|
20
|
+
* );
|
|
21
|
+
* const result = mapper.mapRules();
|
|
22
|
+
* // => { greeting: 'Alice', score: 7 }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
5
25
|
class MapperService {
|
|
26
|
+
/**
|
|
27
|
+
* @param rules - The mapping rule tree to evaluate. May contain
|
|
28
|
+
* literal values, `{data.*}` references, or nested `@pipe` objects.
|
|
29
|
+
* @param data - The current {@link JobState} used to resolve references.
|
|
30
|
+
*/
|
|
6
31
|
constructor(rules, data) {
|
|
7
32
|
this.rules = rules;
|
|
8
33
|
this.data = data;
|
|
9
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Recursively resolves every rule in the tree against the current job
|
|
37
|
+
* state and returns a fully-evaluated copy.
|
|
38
|
+
*
|
|
39
|
+
* @returns A plain object mirroring the rule structure with all
|
|
40
|
+
* expressions replaced by their resolved values.
|
|
41
|
+
*/
|
|
10
42
|
mapRules() {
|
|
11
43
|
return this.traverseRules(this.rules);
|
|
12
44
|
}
|
|
@@ -46,8 +78,31 @@ class MapperService {
|
|
|
46
78
|
return pipe.process();
|
|
47
79
|
}
|
|
48
80
|
/**
|
|
49
|
-
* Evaluates a transition rule against the current job state and
|
|
50
|
-
*
|
|
81
|
+
* Evaluates a transition rule against the current job state and an
|
|
82
|
+
* incoming Stream message code to decide whether the transition fires.
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* Supports both simple boolean rules (`true` / `false`) and compound
|
|
86
|
+
* match rules with optional AND / OR gating. When the rule includes
|
|
87
|
+
* a `match` array, each entry's `actual` expression is resolved via
|
|
88
|
+
* {@link Pipe.resolve} and compared to the `expected` value.
|
|
89
|
+
*
|
|
90
|
+
* @param transitionRule - A boolean shorthand or a {@link TransitionRule}
|
|
91
|
+
* containing `code`, optional `gate`, and optional `match` conditions.
|
|
92
|
+
* @param context - The current {@link JobState} used to resolve
|
|
93
|
+
* `actual` expressions inside match entries.
|
|
94
|
+
* @param code - The {@link StreamCode} returned by the preceding
|
|
95
|
+
* activity (e.g. `200`).
|
|
96
|
+
* @returns `true` if the transition should be taken, `false` otherwise.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const shouldTransition = MapperService.evaluate(
|
|
101
|
+
* { code: 200, match: [{ expected: true, actual: '{data.isReady}' }] },
|
|
102
|
+
* jobState,
|
|
103
|
+
* 200,
|
|
104
|
+
* );
|
|
105
|
+
* ```
|
|
51
106
|
*/
|
|
52
107
|
static evaluate(transitionRule, context, code) {
|
|
53
108
|
if (typeof transitionRule === 'boolean') {
|