@btravstack/temporal-worker 0.16.0 → 0.18.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.
- package/dist/index.cjs +18 -72
- package/dist/index.d.cts +5 -48
- package/dist/index.d.mts +5 -48
- package/dist/index.mjs +18 -72
- package/package.json +24 -23
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _btravstack_core = require("@btravstack/core");
|
|
2
3
|
let _btravstack_di = require("@btravstack/di");
|
|
3
4
|
let _btravstack_config = require("@btravstack/config");
|
|
4
|
-
let _btravstack_core = require("@btravstack/core");
|
|
5
5
|
let _temporal_contract_worker_activity = require("@temporal-contract/worker/activity");
|
|
6
6
|
let _temporalio_common = require("@temporalio/common");
|
|
7
7
|
let _temporalio_worker = require("@temporalio/worker");
|
|
@@ -9,47 +9,12 @@ let unthrown = require("unthrown");
|
|
|
9
9
|
let _temporalio_activity = require("@temporalio/activity");
|
|
10
10
|
//#region src/unit.ts
|
|
11
11
|
/**
|
|
12
|
-
* Where `activityUnits` leaves the forked context for the piece wrappers to
|
|
13
|
-
* read. A symbol rather than a name: the middleware merges it into the context
|
|
14
|
-
* every activity sees, and a string key would appear on the record an activity
|
|
15
|
-
* written against the `{ inject, sync }` arm destructures.
|
|
16
|
-
*/
|
|
17
|
-
const UNIT_SCOPE = Symbol("@btravstack/temporal-worker/unit-scope");
|
|
18
|
-
/**
|
|
19
|
-
* The declared record, as a getter per name resolved on read out of the fork.
|
|
20
|
-
* Neither writable nor configurable — an activity reads what the fork holds, and
|
|
21
|
-
* cannot reshape the record under the next attempt. With no `unit.activity`
|
|
22
|
-
* bound there is nothing to resolve from, so the record is empty whatever was
|
|
23
|
-
* declared.
|
|
24
|
-
*/
|
|
25
|
-
const unitRecordOf = (forked, record) => {
|
|
26
|
-
const unit = {};
|
|
27
|
-
if (forked === void 0) return unit;
|
|
28
|
-
for (const [name, port] of Object.entries(record)) Object.defineProperty(unit, name, {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
get: () => forked.get(port)
|
|
31
|
-
});
|
|
32
|
-
return unit;
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
12
|
* One entry of the activities record — a contract-global activity's own
|
|
36
13
|
* implementation, or the record of them a workflow key carries — with its
|
|
37
14
|
* piece's declared record put on `context.unit`. Applied once per piece as di
|
|
38
15
|
* constructs it, so an attempt costs one record and one context object.
|
|
39
16
|
*/
|
|
40
|
-
const withUnit = (record, entry) =>
|
|
41
|
-
const wrap = (implementation) => (helpers, input) => {
|
|
42
|
-
const { [UNIT_SCOPE]: forked, ...rest } = helpers.context ?? {};
|
|
43
|
-
return implementation({
|
|
44
|
-
...helpers,
|
|
45
|
-
context: {
|
|
46
|
-
...rest,
|
|
47
|
-
unit: unitRecordOf(forked, record)
|
|
48
|
-
}
|
|
49
|
-
}, input);
|
|
50
|
-
};
|
|
51
|
-
return typeof entry === "function" ? wrap(entry) : Object.fromEntries(Object.entries(entry).map(([name, implementation]) => [name, wrap(implementation)]));
|
|
52
|
-
};
|
|
17
|
+
const withUnit = (record, entry) => typeof entry === "function" ? (0, _btravstack_core.withUnitRecord)(record, entry) : Object.fromEntries(Object.entries(entry).map(([name, implementation]) => [name, (0, _btravstack_core.withUnitRecord)(record, implementation)]));
|
|
53
18
|
//#endregion
|
|
54
19
|
//#region src/workflow-activities.ts
|
|
55
20
|
/** One id, declared once, so no contract instantiating it warns about a duplicate. */
|
|
@@ -99,13 +64,8 @@ const WORKFLOW_ACTIVITIES_PREFIX = "TemporalWorkflowActivities:";
|
|
|
99
64
|
*/
|
|
100
65
|
const TemporalWorkflowActivities = (contract, key) => {
|
|
101
66
|
const port = class extends (0, _btravstack_di.Port)(`${WORKFLOW_ACTIVITIES_PREFIX}${key}`) {};
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return Object.assign((0, _btravstack_di.Provider)(port)({
|
|
105
|
-
inject: options.inject,
|
|
106
|
-
sync: (services) => withUnit(record, options.sync(services))
|
|
107
|
-
}), { unit: record });
|
|
108
|
-
};
|
|
67
|
+
const mint = (0, _btravstack_core.mintPiece)(port, withUnit);
|
|
68
|
+
return (options) => mint(options);
|
|
109
69
|
};
|
|
110
70
|
//#endregion
|
|
111
71
|
//#region src/activity-units.ts
|
|
@@ -118,9 +78,8 @@ const TemporalWorkflowActivities = (contract, key) => {
|
|
|
118
78
|
* bound, `next()` runs unchanged, so the ambient `currentUnit()` record is what
|
|
119
79
|
* an adapter reads.
|
|
120
80
|
*
|
|
121
|
-
* The forked context rides the invocation's context
|
|
122
|
-
*
|
|
123
|
-
* that piece declared — the records live with the pieces, so a hand-composed
|
|
81
|
+
* The forked context rides the invocation's context, where each piece's own
|
|
82
|
+
* wrapper turns it into the typed `context.unit` record that piece declared — the records live with the pieces, so a hand-composed
|
|
124
83
|
* `temporal()` gets them without threading a second option through the starter,
|
|
125
84
|
* and the middleware never has to map Temporal's FLAT activity name back to the
|
|
126
85
|
* workflow key its piece was minted under.
|
|
@@ -133,17 +92,19 @@ const TemporalWorkflowActivities = (contract, key) => {
|
|
|
133
92
|
* No `Result`-unwrapping boundary, deliberately: `declareActivitiesHandler` owns
|
|
134
93
|
* the mapping from a settled `Result` to an activity failure.
|
|
135
94
|
*/
|
|
136
|
-
const activityUnits = (host, observers, unit) => (invocation, next) => {
|
|
137
|
-
|
|
95
|
+
const activityUnits = (host, observers, unit) => (invocation, next) => (0, _btravstack_core.dispatchUnit)({
|
|
96
|
+
host,
|
|
97
|
+
observers,
|
|
98
|
+
operation: {
|
|
138
99
|
component: "temporal",
|
|
139
100
|
name: "attempt",
|
|
140
101
|
attributes: { activity: (0, _temporalio_activity.activityInfo)().activityType }
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
};
|
|
102
|
+
},
|
|
103
|
+
meta: metaFor(),
|
|
104
|
+
unit,
|
|
105
|
+
seed: [ActivityInputPort, invocation.input],
|
|
106
|
+
next
|
|
107
|
+
});
|
|
147
108
|
/**
|
|
148
109
|
* `UnitMeta.id` must be unique per unit, and a workflow id is **not** one: an
|
|
149
110
|
* activity is retried under the same execution. A task token identifies one
|
|
@@ -252,10 +213,7 @@ const temporal = (options) => {
|
|
|
252
213
|
})),
|
|
253
214
|
release: (connection) => connection.close().catch((cause) => heldByWorker(cause) ? void 0 : Promise.reject(cause))
|
|
254
215
|
}),
|
|
255
|
-
|
|
256
|
-
inject: {},
|
|
257
|
-
value: _btravstack_core.noObserver
|
|
258
|
-
}),
|
|
216
|
+
_btravstack_core.noObserverMember,
|
|
259
217
|
(0, _btravstack_di.Provider)(TemporalRuntime)({
|
|
260
218
|
inject: {
|
|
261
219
|
connection: TemporalConnection,
|
|
@@ -383,19 +341,7 @@ const TemporalModule = (name) => (options) => {
|
|
|
383
341
|
* and two slices claiming one key are di's duplicate-provider defect at build.
|
|
384
342
|
*/
|
|
385
343
|
const TemporalActivities = (contract) => {
|
|
386
|
-
|
|
387
|
-
const compose = (pieces) => build({
|
|
388
|
-
inject: Object.fromEntries(pieces.map((piece) => [piece.port.portId.slice(27), piece.port])),
|
|
389
|
-
sync: (services) => services
|
|
390
|
-
});
|
|
391
|
-
const whole = (options) => {
|
|
392
|
-
const record = options.unit ?? {};
|
|
393
|
-
return build({
|
|
394
|
-
inject: options.inject,
|
|
395
|
-
sync: (services) => Object.fromEntries(Object.entries(options.sync(services)).map(([key, entry]) => [key, withUnit(record, entry)]))
|
|
396
|
-
});
|
|
397
|
-
};
|
|
398
|
-
return ((first) => Array.isArray(first) ? compose(first) : whole(first));
|
|
344
|
+
return (0, _btravstack_core.composeByPrefix)(TemporalActivitiesPort, WORKFLOW_ACTIVITIES_PREFIX, withUnit);
|
|
399
345
|
};
|
|
400
346
|
//#endregion
|
|
401
347
|
exports.ActivityInput = ActivityInput;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { ConfigInvalid, Env } from "@btravstack/config";
|
|
2
|
+
import { AnyUnitModule, Refuse, Runtime, RuntimePort, UnitGate, UnitNeedsOf, UnitRecordOf } from "@btravstack/core";
|
|
2
3
|
import { AnyModule, AnyPort, AnyProvider, Exportable, Module, NeedsGate, PortClassOf, PortInstance, Provider, Scope, ServiceOf } from "@btravstack/di";
|
|
3
4
|
import { ContractDefinition } from "@temporal-contract/contract";
|
|
4
|
-
import { Runtime, RuntimePort } from "@btravstack/core";
|
|
5
5
|
import { DeclareActivitiesHandlerOptions, EmptyContext } from "@temporal-contract/worker/activity";
|
|
6
6
|
import { Duration } from "@temporalio/common";
|
|
7
7
|
import { NativeConnection, WorkflowBundleWithSourceMap } from "@temporalio/worker";
|
|
8
|
-
//#region src/unit.d.ts
|
|
9
|
-
/** What a bound unit module exports — the port instances an activity of that kind may read. */
|
|
10
|
-
type UnitExportsOf<M> = M extends Module<infer X, never, unknown> ? X : never;
|
|
11
|
-
/** The declared `unit:` record, as the services an activity reads off `context.unit`. */
|
|
12
|
-
type UnitRecordOf<U extends Readonly<Record<string, AnyPort>>> = { readonly [N in keyof U]: ServiceOf<InstanceType<U[N]>>; };
|
|
13
|
-
/**
|
|
14
|
-
* A piece injecting a port the bound `unit.activity` module does not export.
|
|
15
|
-
* `unknown` when every declared port is covered — including the empty case, so
|
|
16
|
-
* a worker whose pieces declare no `unit:` is gated on nothing.
|
|
17
|
-
*/
|
|
18
|
-
type UnitGate<Unit, Declared> = [Exclude<NonNullable<Declared>, UnitExportsOf<Unit>>] extends [never] ? unknown : {
|
|
19
|
-
readonly "UNIT DOES NOT PROVIDE — a piece injects a port the bound unit module does not export": Exclude<NonNullable<Declared>, UnitExportsOf<Unit>>;
|
|
20
|
-
};
|
|
21
|
-
//#endregion
|
|
22
8
|
//#region src/workflow-activities.d.ts
|
|
23
9
|
/**
|
|
24
10
|
* `ActivitiesOf<C, …>` is a `NoInfer`-wrapped conditional TypeScript refuses to
|
|
@@ -76,8 +62,6 @@ type WorkflowActivitiesPortOf<C extends ContractDefinition, K extends Activities
|
|
|
76
62
|
/** What a minted piece returns. */
|
|
77
63
|
type MintedActivities<C extends ContractDefinition, K extends ActivitiesKeyOf<C>, N, U extends Readonly<Record<string, AnyPort>>> = Provider<InstanceType<WorkflowActivitiesPortOf<C, K>>, never, N> & {
|
|
78
64
|
readonly port: WorkflowActivitiesPortOf<C, K>;
|
|
79
|
-
/** The declared `unit:` record, which the wrapper resolves against. */
|
|
80
|
-
readonly unit: U;
|
|
81
65
|
/** Phantom: the ports this piece injects, which the root's `unit.activity` must export. */
|
|
82
66
|
readonly _declared?: InstanceType<U[keyof U]>;
|
|
83
67
|
};
|
|
@@ -167,22 +151,8 @@ export declare class TemporalUnreachable extends TemporalUnreachable_base<{
|
|
|
167
151
|
}
|
|
168
152
|
/** The runtime's port: what `temporal()` provides, and what the module `start` boots must export. */
|
|
169
153
|
export declare class TemporalRuntime extends RuntimePort<Runtime<never, TemporalInfo>> {}
|
|
170
|
-
/**
|
|
171
|
-
|
|
172
|
-
* constrains its own `Unit` type parameter to. `Module`'s `_exports` channel
|
|
173
|
-
* is contravariant, so `Exports = never` — never `unknown` — is what makes a
|
|
174
|
-
* REAL module's own (necessarily narrower) export type assignable to this
|
|
175
|
-
* bound: `(x: Concrete) => void` is assignable to `(x: never) => void`, not
|
|
176
|
-
* to `(x: unknown) => void`.
|
|
177
|
-
*/
|
|
178
|
-
type AnyUnitModule = Module<never, never, unknown>;
|
|
179
|
-
/**
|
|
180
|
-
* The needs a bound `unit.activity` module still owes, or `never` when none is
|
|
181
|
-
* bound. `Scope` is excluded, since nothing can ever provide it — the same
|
|
182
|
-
* exemption `NeedsGate` itself carries — and so is the activity input, which
|
|
183
|
-
* the fork's own seed discharges.
|
|
184
|
-
*/
|
|
185
|
-
type UnitNeedsOf<Unit> = Unit extends Module<never, never, infer N> ? Exclude<N, Scope | ActivityInputInstance> : never;
|
|
154
|
+
/** The needs a bound `unit.activity` module still owes, less the input the fork's seed discharges. */
|
|
155
|
+
type UnitNeedsOf$1<Unit> = UnitNeedsOf<Unit, ActivityInputInstance>;
|
|
186
156
|
/**
|
|
187
157
|
* The activity implementations `declareActivitiesHandler` takes for `C`.
|
|
188
158
|
* `TContext` is what an implementation reads off `helpers.context` — left
|
|
@@ -250,11 +220,11 @@ type Provided = TemporalRuntime | TemporalConfig | TemporalConnection;
|
|
|
250
220
|
* Each configuration field is pinned on its own: a pinned field reads nothing
|
|
251
221
|
* from the environment, and a field left unpinned still does.
|
|
252
222
|
*/
|
|
253
|
-
export declare const temporal: <C extends ContractDefinition, Unit extends AnyUnitModule | undefined = undefined>(options: TemporalOptions<C, Unit>) => Module<Provided, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf<Unit>>;
|
|
223
|
+
export declare const temporal: <C extends ContractDefinition, Unit extends AnyUnitModule | undefined = undefined>(options: TemporalOptions<C, Unit>) => Module<Provided, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf$1<Unit>>;
|
|
254
224
|
//#endregion
|
|
255
225
|
//#region src/temporal-module.d.ts
|
|
256
226
|
/** The starter's own module, as the sugar adds it to the application's imports. */
|
|
257
|
-
type TemporalStarter<C extends ContractDefinition, Unit extends AnyUnitModule | undefined> = Module<TemporalRuntime | TemporalConfig | TemporalConnection, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf<Unit>>;
|
|
227
|
+
type TemporalStarter<C extends ContractDefinition, Unit extends AnyUnitModule | undefined> = Module<TemporalRuntime | TemporalConfig | TemporalConnection, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf$1<Unit>>;
|
|
258
228
|
/** The application's imports plus the starter — the tuple `Module(name)` is handed. */
|
|
259
229
|
type Imports<I extends readonly AnyModule[], C extends ContractDefinition, Unit extends AnyUnitModule | undefined> = readonly [...I, TemporalStarter<C, Unit>];
|
|
260
230
|
/** The activities provider plus the application's own — the tuple `Module(name)` is handed. */
|
|
@@ -318,19 +288,6 @@ type KeyOfPiece<P> = P extends {
|
|
|
318
288
|
} ? K : never;
|
|
319
289
|
/** The record's top-level keys no piece in `T` covers. */
|
|
320
290
|
type Uncovered<C extends ContractDefinition, T extends readonly PieceOf<C>[]> = Exclude<ActivitiesKeyOf<C>, KeyOfPiece<T[number]>>;
|
|
321
|
-
/**
|
|
322
|
-
* A refused array: as long as the array the caller wrote, its head the caller's
|
|
323
|
-
* own elements — which match — and its LAST element the marker paired with what
|
|
324
|
-
* is wrong.
|
|
325
|
-
*
|
|
326
|
-
* TypeScript compares two equal-length tuples element by element, so the extra
|
|
327
|
-
* diagnostic it reports lands on the trailing element and carries both the
|
|
328
|
-
* sentence and the missing key. A fixed two-element tuple named the key only
|
|
329
|
-
* when the array happened to be two elements long; every other arity was a
|
|
330
|
-
* length mismatch, and the developer diffed the contract against the array by
|
|
331
|
-
* hand.
|
|
332
|
-
*/
|
|
333
|
-
type Refuse<T extends readonly unknown[], Marker extends string, Detail> = T extends readonly [...infer Head, unknown] ? readonly [...Head, readonly [Marker, Detail]] : readonly [readonly [Marker, Detail]];
|
|
334
291
|
/**
|
|
335
292
|
* The record arm: the whole activities record from one `sync`, with one `unit:`
|
|
336
293
|
* record shared by every entry in it.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
|
+
import { AnyUnitModule, Refuse, Runtime, RuntimePort, UnitGate, UnitNeedsOf, UnitRecordOf } from "@btravstack/core";
|
|
1
2
|
import { AnyModule, AnyPort, AnyProvider, Exportable, Module, NeedsGate, PortClassOf, PortInstance, Provider, Scope, ServiceOf } from "@btravstack/di";
|
|
2
3
|
import { ConfigInvalid, Env } from "@btravstack/config";
|
|
3
|
-
import { Runtime, RuntimePort } from "@btravstack/core";
|
|
4
4
|
import { DeclareActivitiesHandlerOptions, EmptyContext } from "@temporal-contract/worker/activity";
|
|
5
5
|
import { Duration } from "@temporalio/common";
|
|
6
6
|
import { NativeConnection, Worker, WorkflowBundleWithSourceMap } from "@temporalio/worker";
|
|
7
7
|
import { ContractDefinition } from "@temporal-contract/contract";
|
|
8
|
-
//#region src/unit.d.ts
|
|
9
|
-
/** What a bound unit module exports — the port instances an activity of that kind may read. */
|
|
10
|
-
type UnitExportsOf<M> = M extends Module<infer X, never, unknown> ? X : never;
|
|
11
|
-
/** The declared `unit:` record, as the services an activity reads off `context.unit`. */
|
|
12
|
-
type UnitRecordOf<U extends Readonly<Record<string, AnyPort>>> = { readonly [N in keyof U]: ServiceOf<InstanceType<U[N]>>; };
|
|
13
|
-
/**
|
|
14
|
-
* A piece injecting a port the bound `unit.activity` module does not export.
|
|
15
|
-
* `unknown` when every declared port is covered — including the empty case, so
|
|
16
|
-
* a worker whose pieces declare no `unit:` is gated on nothing.
|
|
17
|
-
*/
|
|
18
|
-
type UnitGate<Unit, Declared> = [Exclude<NonNullable<Declared>, UnitExportsOf<Unit>>] extends [never] ? unknown : {
|
|
19
|
-
readonly "UNIT DOES NOT PROVIDE — a piece injects a port the bound unit module does not export": Exclude<NonNullable<Declared>, UnitExportsOf<Unit>>;
|
|
20
|
-
};
|
|
21
|
-
//#endregion
|
|
22
8
|
//#region src/workflow-activities.d.ts
|
|
23
9
|
/**
|
|
24
10
|
* `ActivitiesOf<C, …>` is a `NoInfer`-wrapped conditional TypeScript refuses to
|
|
@@ -76,8 +62,6 @@ type WorkflowActivitiesPortOf<C extends ContractDefinition, K extends Activities
|
|
|
76
62
|
/** What a minted piece returns. */
|
|
77
63
|
type MintedActivities<C extends ContractDefinition, K extends ActivitiesKeyOf<C>, N, U extends Readonly<Record<string, AnyPort>>> = Provider<InstanceType<WorkflowActivitiesPortOf<C, K>>, never, N> & {
|
|
78
64
|
readonly port: WorkflowActivitiesPortOf<C, K>;
|
|
79
|
-
/** The declared `unit:` record, which the wrapper resolves against. */
|
|
80
|
-
readonly unit: U;
|
|
81
65
|
/** Phantom: the ports this piece injects, which the root's `unit.activity` must export. */
|
|
82
66
|
readonly _declared?: InstanceType<U[keyof U]>;
|
|
83
67
|
};
|
|
@@ -167,22 +151,8 @@ export declare class TemporalUnreachable extends TemporalUnreachable_base<{
|
|
|
167
151
|
}
|
|
168
152
|
/** The runtime's port: what `temporal()` provides, and what the module `start` boots must export. */
|
|
169
153
|
export declare class TemporalRuntime extends RuntimePort<Runtime<never, TemporalInfo>> {}
|
|
170
|
-
/**
|
|
171
|
-
|
|
172
|
-
* constrains its own `Unit` type parameter to. `Module`'s `_exports` channel
|
|
173
|
-
* is contravariant, so `Exports = never` — never `unknown` — is what makes a
|
|
174
|
-
* REAL module's own (necessarily narrower) export type assignable to this
|
|
175
|
-
* bound: `(x: Concrete) => void` is assignable to `(x: never) => void`, not
|
|
176
|
-
* to `(x: unknown) => void`.
|
|
177
|
-
*/
|
|
178
|
-
type AnyUnitModule = Module<never, never, unknown>;
|
|
179
|
-
/**
|
|
180
|
-
* The needs a bound `unit.activity` module still owes, or `never` when none is
|
|
181
|
-
* bound. `Scope` is excluded, since nothing can ever provide it — the same
|
|
182
|
-
* exemption `NeedsGate` itself carries — and so is the activity input, which
|
|
183
|
-
* the fork's own seed discharges.
|
|
184
|
-
*/
|
|
185
|
-
type UnitNeedsOf<Unit> = Unit extends Module<never, never, infer N> ? Exclude<N, Scope | ActivityInputInstance> : never;
|
|
154
|
+
/** The needs a bound `unit.activity` module still owes, less the input the fork's seed discharges. */
|
|
155
|
+
type UnitNeedsOf$1<Unit> = UnitNeedsOf<Unit, ActivityInputInstance>;
|
|
186
156
|
/**
|
|
187
157
|
* The activity implementations `declareActivitiesHandler` takes for `C`.
|
|
188
158
|
* `TContext` is what an implementation reads off `helpers.context` — left
|
|
@@ -250,11 +220,11 @@ type Provided = TemporalRuntime | TemporalConfig | TemporalConnection;
|
|
|
250
220
|
* Each configuration field is pinned on its own: a pinned field reads nothing
|
|
251
221
|
* from the environment, and a field left unpinned still does.
|
|
252
222
|
*/
|
|
253
|
-
export declare const temporal: <C extends ContractDefinition, Unit extends AnyUnitModule | undefined = undefined>(options: TemporalOptions<C, Unit>) => Module<Provided, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf<Unit>>;
|
|
223
|
+
export declare const temporal: <C extends ContractDefinition, Unit extends AnyUnitModule | undefined = undefined>(options: TemporalOptions<C, Unit>) => Module<Provided, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf$1<Unit>>;
|
|
254
224
|
//#endregion
|
|
255
225
|
//#region src/temporal-module.d.ts
|
|
256
226
|
/** The starter's own module, as the sugar adds it to the application's imports. */
|
|
257
|
-
type TemporalStarter<C extends ContractDefinition, Unit extends AnyUnitModule | undefined> = Module<TemporalRuntime | TemporalConfig | TemporalConnection, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf<Unit>>;
|
|
227
|
+
type TemporalStarter<C extends ContractDefinition, Unit extends AnyUnitModule | undefined> = Module<TemporalRuntime | TemporalConfig | TemporalConnection, ConfigInvalid | TemporalUnreachable, Env | Scope | ActivitiesInstanceOf<C> | UnitNeedsOf$1<Unit>>;
|
|
258
228
|
/** The application's imports plus the starter — the tuple `Module(name)` is handed. */
|
|
259
229
|
type Imports<I extends readonly AnyModule[], C extends ContractDefinition, Unit extends AnyUnitModule | undefined> = readonly [...I, TemporalStarter<C, Unit>];
|
|
260
230
|
/** The activities provider plus the application's own — the tuple `Module(name)` is handed. */
|
|
@@ -318,19 +288,6 @@ type KeyOfPiece<P> = P extends {
|
|
|
318
288
|
} ? K : never;
|
|
319
289
|
/** The record's top-level keys no piece in `T` covers. */
|
|
320
290
|
type Uncovered<C extends ContractDefinition, T extends readonly PieceOf<C>[]> = Exclude<ActivitiesKeyOf<C>, KeyOfPiece<T[number]>>;
|
|
321
|
-
/**
|
|
322
|
-
* A refused array: as long as the array the caller wrote, its head the caller's
|
|
323
|
-
* own elements — which match — and its LAST element the marker paired with what
|
|
324
|
-
* is wrong.
|
|
325
|
-
*
|
|
326
|
-
* TypeScript compares two equal-length tuples element by element, so the extra
|
|
327
|
-
* diagnostic it reports lands on the trailing element and carries both the
|
|
328
|
-
* sentence and the missing key. A fixed two-element tuple named the key only
|
|
329
|
-
* when the array happened to be two elements long; every other arity was a
|
|
330
|
-
* length mismatch, and the developer diffed the contract against the array by
|
|
331
|
-
* hand.
|
|
332
|
-
*/
|
|
333
|
-
type Refuse<T extends readonly unknown[], Marker extends string, Detail> = T extends readonly [...infer Head, unknown] ? readonly [...Head, readonly [Marker, Detail]] : readonly [readonly [Marker, Detail]];
|
|
334
291
|
/**
|
|
335
292
|
* The record arm: the whole activities record from one `sync`, with one `unit:`
|
|
336
293
|
* record shared by every entry in it.
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { Observers, RuntimePort, RuntimeStartFailed, composeByPrefix, dispatchUnit, mintPiece, noObserverMember, releasedBy, withUnitRecord } from "@btravstack/core";
|
|
1
2
|
import { Module, Port, Provider } from "@btravstack/di";
|
|
2
3
|
import { Config, Env } from "@btravstack/config";
|
|
3
|
-
import { Observers, RuntimePort, RuntimeStartFailed, noObserver, observe, releasedBy } from "@btravstack/core";
|
|
4
4
|
import { declareActivitiesHandler } from "@temporal-contract/worker/activity";
|
|
5
5
|
import { msToNumber } from "@temporalio/common";
|
|
6
6
|
import { NativeConnection, Worker } from "@temporalio/worker";
|
|
@@ -8,47 +8,12 @@ import { Ok, OkAsync, TaggedError, fromPromise, fromSafePromise, fromThrowable }
|
|
|
8
8
|
import { activityInfo } from "@temporalio/activity";
|
|
9
9
|
//#region src/unit.ts
|
|
10
10
|
/**
|
|
11
|
-
* Where `activityUnits` leaves the forked context for the piece wrappers to
|
|
12
|
-
* read. A symbol rather than a name: the middleware merges it into the context
|
|
13
|
-
* every activity sees, and a string key would appear on the record an activity
|
|
14
|
-
* written against the `{ inject, sync }` arm destructures.
|
|
15
|
-
*/
|
|
16
|
-
const UNIT_SCOPE = Symbol("@btravstack/temporal-worker/unit-scope");
|
|
17
|
-
/**
|
|
18
|
-
* The declared record, as a getter per name resolved on read out of the fork.
|
|
19
|
-
* Neither writable nor configurable — an activity reads what the fork holds, and
|
|
20
|
-
* cannot reshape the record under the next attempt. With no `unit.activity`
|
|
21
|
-
* bound there is nothing to resolve from, so the record is empty whatever was
|
|
22
|
-
* declared.
|
|
23
|
-
*/
|
|
24
|
-
const unitRecordOf = (forked, record) => {
|
|
25
|
-
const unit = {};
|
|
26
|
-
if (forked === void 0) return unit;
|
|
27
|
-
for (const [name, port] of Object.entries(record)) Object.defineProperty(unit, name, {
|
|
28
|
-
enumerable: true,
|
|
29
|
-
get: () => forked.get(port)
|
|
30
|
-
});
|
|
31
|
-
return unit;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
11
|
* One entry of the activities record — a contract-global activity's own
|
|
35
12
|
* implementation, or the record of them a workflow key carries — with its
|
|
36
13
|
* piece's declared record put on `context.unit`. Applied once per piece as di
|
|
37
14
|
* constructs it, so an attempt costs one record and one context object.
|
|
38
15
|
*/
|
|
39
|
-
const withUnit = (record, entry) =>
|
|
40
|
-
const wrap = (implementation) => (helpers, input) => {
|
|
41
|
-
const { [UNIT_SCOPE]: forked, ...rest } = helpers.context ?? {};
|
|
42
|
-
return implementation({
|
|
43
|
-
...helpers,
|
|
44
|
-
context: {
|
|
45
|
-
...rest,
|
|
46
|
-
unit: unitRecordOf(forked, record)
|
|
47
|
-
}
|
|
48
|
-
}, input);
|
|
49
|
-
};
|
|
50
|
-
return typeof entry === "function" ? wrap(entry) : Object.fromEntries(Object.entries(entry).map(([name, implementation]) => [name, wrap(implementation)]));
|
|
51
|
-
};
|
|
16
|
+
const withUnit = (record, entry) => typeof entry === "function" ? withUnitRecord(record, entry) : Object.fromEntries(Object.entries(entry).map(([name, implementation]) => [name, withUnitRecord(record, implementation)]));
|
|
52
17
|
//#endregion
|
|
53
18
|
//#region src/workflow-activities.ts
|
|
54
19
|
/** One id, declared once, so no contract instantiating it warns about a duplicate. */
|
|
@@ -98,13 +63,8 @@ const WORKFLOW_ACTIVITIES_PREFIX = "TemporalWorkflowActivities:";
|
|
|
98
63
|
*/
|
|
99
64
|
const TemporalWorkflowActivities = (contract, key) => {
|
|
100
65
|
const port = class extends Port(`${WORKFLOW_ACTIVITIES_PREFIX}${key}`) {};
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return Object.assign(Provider(port)({
|
|
104
|
-
inject: options.inject,
|
|
105
|
-
sync: (services) => withUnit(record, options.sync(services))
|
|
106
|
-
}), { unit: record });
|
|
107
|
-
};
|
|
66
|
+
const mint = mintPiece(port, withUnit);
|
|
67
|
+
return (options) => mint(options);
|
|
108
68
|
};
|
|
109
69
|
//#endregion
|
|
110
70
|
//#region src/activity-units.ts
|
|
@@ -117,9 +77,8 @@ const TemporalWorkflowActivities = (contract, key) => {
|
|
|
117
77
|
* bound, `next()` runs unchanged, so the ambient `currentUnit()` record is what
|
|
118
78
|
* an adapter reads.
|
|
119
79
|
*
|
|
120
|
-
* The forked context rides the invocation's context
|
|
121
|
-
*
|
|
122
|
-
* that piece declared — the records live with the pieces, so a hand-composed
|
|
80
|
+
* The forked context rides the invocation's context, where each piece's own
|
|
81
|
+
* wrapper turns it into the typed `context.unit` record that piece declared — the records live with the pieces, so a hand-composed
|
|
123
82
|
* `temporal()` gets them without threading a second option through the starter,
|
|
124
83
|
* and the middleware never has to map Temporal's FLAT activity name back to the
|
|
125
84
|
* workflow key its piece was minted under.
|
|
@@ -132,17 +91,19 @@ const TemporalWorkflowActivities = (contract, key) => {
|
|
|
132
91
|
* No `Result`-unwrapping boundary, deliberately: `declareActivitiesHandler` owns
|
|
133
92
|
* the mapping from a settled `Result` to an activity failure.
|
|
134
93
|
*/
|
|
135
|
-
const activityUnits = (host, observers, unit) => (invocation, next) => {
|
|
136
|
-
|
|
94
|
+
const activityUnits = (host, observers, unit) => (invocation, next) => dispatchUnit({
|
|
95
|
+
host,
|
|
96
|
+
observers,
|
|
97
|
+
operation: {
|
|
137
98
|
component: "temporal",
|
|
138
99
|
name: "attempt",
|
|
139
100
|
attributes: { activity: activityInfo().activityType }
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
};
|
|
101
|
+
},
|
|
102
|
+
meta: metaFor(),
|
|
103
|
+
unit,
|
|
104
|
+
seed: [ActivityInputPort, invocation.input],
|
|
105
|
+
next
|
|
106
|
+
});
|
|
146
107
|
/**
|
|
147
108
|
* `UnitMeta.id` must be unique per unit, and a workflow id is **not** one: an
|
|
148
109
|
* activity is retried under the same execution. A task token identifies one
|
|
@@ -251,10 +212,7 @@ const temporal = (options) => {
|
|
|
251
212
|
})),
|
|
252
213
|
release: (connection) => connection.close().catch((cause) => heldByWorker(cause) ? void 0 : Promise.reject(cause))
|
|
253
214
|
}),
|
|
254
|
-
|
|
255
|
-
inject: {},
|
|
256
|
-
value: noObserver
|
|
257
|
-
}),
|
|
215
|
+
noObserverMember,
|
|
258
216
|
Provider(TemporalRuntime)({
|
|
259
217
|
inject: {
|
|
260
218
|
connection: TemporalConnection,
|
|
@@ -382,19 +340,7 @@ const TemporalModule = (name) => (options) => {
|
|
|
382
340
|
* and two slices claiming one key are di's duplicate-provider defect at build.
|
|
383
341
|
*/
|
|
384
342
|
const TemporalActivities = (contract) => {
|
|
385
|
-
|
|
386
|
-
const compose = (pieces) => build({
|
|
387
|
-
inject: Object.fromEntries(pieces.map((piece) => [piece.port.portId.slice(27), piece.port])),
|
|
388
|
-
sync: (services) => services
|
|
389
|
-
});
|
|
390
|
-
const whole = (options) => {
|
|
391
|
-
const record = options.unit ?? {};
|
|
392
|
-
return build({
|
|
393
|
-
inject: options.inject,
|
|
394
|
-
sync: (services) => Object.fromEntries(Object.entries(options.sync(services)).map(([key, entry]) => [key, withUnit(record, entry)]))
|
|
395
|
-
});
|
|
396
|
-
};
|
|
397
|
-
return ((first) => Array.isArray(first) ? compose(first) : whole(first));
|
|
343
|
+
return composeByPrefix(TemporalActivitiesPort, WORKFLOW_ACTIVITIES_PREFIX, withUnit);
|
|
398
344
|
};
|
|
399
345
|
//#endregion
|
|
400
346
|
export { ActivityInput, TemporalActivities, TemporalConfig, TemporalConnection, TemporalModule, TemporalRuntime, TemporalUnreachable, TemporalWorkflowActivities, temporal };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/temporal-worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "The Temporal worker runtime for @btravstack/core: one unit per activity attempt, and a drain that honours the kernel's deadline",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graceful-shutdown",
|
|
@@ -54,33 +54,34 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@btravstack/config": "0.
|
|
58
|
-
"@btravstack/core": "0.
|
|
59
|
-
"@btravstack/di": "0.
|
|
57
|
+
"@btravstack/config": "0.18.0",
|
|
58
|
+
"@btravstack/core": "0.18.0",
|
|
59
|
+
"@btravstack/di": "0.18.0",
|
|
60
60
|
"@btravstack/internal-test-infra": "0.0.0",
|
|
61
|
-
"@btravstack/testing": "0.
|
|
61
|
+
"@btravstack/testing": "0.18.0",
|
|
62
62
|
"@btravstack/tsconfig": "0.4.0",
|
|
63
|
-
"@temporal-contract/client": "8.0.0-beta.
|
|
64
|
-
"@temporal-contract/contract": "8.0.0-beta.
|
|
65
|
-
"@temporal-contract/worker": "8.0.0-beta.
|
|
66
|
-
"@temporalio/activity": "1.
|
|
67
|
-
"@temporalio/client": "1.
|
|
68
|
-
"@temporalio/common": "1.
|
|
69
|
-
"@temporalio/worker": "1.
|
|
70
|
-
"@temporalio/workflow": "1.
|
|
71
|
-
"@types/node": "26.4
|
|
72
|
-
"@unthrown/vitest": "5.
|
|
73
|
-
"@vitest/coverage-v8": "
|
|
63
|
+
"@temporal-contract/client": "8.0.0-beta.11",
|
|
64
|
+
"@temporal-contract/contract": "8.0.0-beta.11",
|
|
65
|
+
"@temporal-contract/worker": "8.0.0-beta.11",
|
|
66
|
+
"@temporalio/activity": "1.24.0",
|
|
67
|
+
"@temporalio/client": "1.24.0",
|
|
68
|
+
"@temporalio/common": "1.24.0",
|
|
69
|
+
"@temporalio/worker": "1.24.0",
|
|
70
|
+
"@temporalio/workflow": "1.24.0",
|
|
71
|
+
"@types/node": "26.6.4",
|
|
72
|
+
"@unthrown/vitest": "5.12.0",
|
|
73
|
+
"@vitest/coverage-v8": "5.0.3",
|
|
74
74
|
"tsdown": "0.23.0",
|
|
75
75
|
"typescript": "7.0.2",
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
76
|
+
"typescript-consumer": "npm:typescript@5.9.3",
|
|
77
|
+
"unthrown": "5.12.0",
|
|
78
|
+
"vitest": "5.0.3",
|
|
79
|
+
"zod": "4.6.5"
|
|
79
80
|
},
|
|
80
81
|
"peerDependencies": {
|
|
81
|
-
"@btravstack/config": "^0.
|
|
82
|
-
"@btravstack/core": "^0.
|
|
83
|
-
"@btravstack/di": "^0.
|
|
82
|
+
"@btravstack/config": "^0.18.0",
|
|
83
|
+
"@btravstack/core": "^0.18.0",
|
|
84
|
+
"@btravstack/di": "^0.18.0",
|
|
84
85
|
"@temporal-contract/client": "^8.0.0-beta.9",
|
|
85
86
|
"@temporal-contract/contract": "^8.0.0-beta.9",
|
|
86
87
|
"@temporal-contract/worker": "^8.0.0-beta.9",
|
|
@@ -101,6 +102,6 @@
|
|
|
101
102
|
"build": "tsdown src/index.ts src/schedule.ts --format cjs,esm --dts --clean",
|
|
102
103
|
"dev": "tsdown src/index.ts src/schedule.ts --format cjs,esm --dts --watch",
|
|
103
104
|
"test": "vitest run --coverage",
|
|
104
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test-d.json"
|
|
105
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test-d.json && node ./node_modules/typescript-consumer/bin/tsc --noEmit -p tsconfig.test-d.json"
|
|
105
106
|
}
|
|
106
107
|
}
|