@mnci/az-durable 0.1.1 → 0.1.3
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/eslint-plugin.cjs.js +369 -0
- package/dist/index.cjs.js +628 -0
- package/dist/testing.cjs.js +204 -0
- package/package.json +13 -11
- package/dist/eslint-plugin.esm.js +0 -363
- package/dist/index.esm.js +0 -1424
- package/dist/testing.esm.js +0 -225
package/dist/testing.esm.js
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
function _instanceof(left, right) {
|
|
2
|
-
"@swc/helpers - instanceof";
|
|
3
|
-
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
4
|
-
return !!right[Symbol.hasInstance](left);
|
|
5
|
-
} else return left instanceof right;
|
|
6
|
-
}
|
|
7
|
-
function _type_of(obj) {
|
|
8
|
-
"@swc/helpers - typeof";
|
|
9
|
-
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Runs an orchestration against stubbed activities, with no Azure running.
|
|
13
|
-
*
|
|
14
|
-
* @remarks
|
|
15
|
-
* Drives the generator synchronously, feeding each yielded task the stubbed
|
|
16
|
-
* result for that activity's name. There is no host, no emulator and no
|
|
17
|
-
* storage — a three-step workflow with a short-circuit branch is testable in
|
|
18
|
-
* about fifteen lines.
|
|
19
|
-
*
|
|
20
|
-
* **How it intercepts.** The orchestration is driven with a fake
|
|
21
|
-
* `OrchestrationContext`, which works only because every scheduling call in
|
|
22
|
-
* this package goes through `context.df` rather than through the registered
|
|
23
|
-
* callable. The alternative — reading the name off `task.action.functionName` —
|
|
24
|
-
* is an undocumented SDK internal the package's non-goals forbid.
|
|
25
|
-
*
|
|
26
|
-
* **Limits, stated rather than discovered later.** Retry policies are not
|
|
27
|
-
* simulated: a stub returning an `Error` throws once, it does not exhaust
|
|
28
|
-
* attempts. `Task.any` resolves to the FIRST task in the list, since there is
|
|
29
|
-
* no real concurrency to race. Timers complete immediately.
|
|
30
|
-
*
|
|
31
|
-
* @param orchestration - The orchestration to run.
|
|
32
|
-
* @param input - The input, checked against its declared type.
|
|
33
|
-
* @param stub - The activity fakes, clock and instance id.
|
|
34
|
-
* @returns The result, the ordered calls, and the status transitions.
|
|
35
|
-
* @throws Error when an activity is called with no stub registered for it.
|
|
36
|
-
* @typeParam TInput - The orchestration's input type.
|
|
37
|
-
* @typeParam TOutput - The orchestration's output type.
|
|
38
|
-
*/ function runWorkflow(orchestration, input, stub) {
|
|
39
|
-
var _stub_now, _stub_instanceId;
|
|
40
|
-
var calls = [];
|
|
41
|
-
var statuses = [];
|
|
42
|
-
var continuedAsNew;
|
|
43
|
-
var clock = (_stub_now = stub.now) !== null && _stub_now !== void 0 ? _stub_now : new Date(0);
|
|
44
|
-
var schedule = function schedule(name, scheduledInput) {
|
|
45
|
-
calls.push({
|
|
46
|
-
name: name,
|
|
47
|
-
input: scheduledInput
|
|
48
|
-
});
|
|
49
|
-
return {
|
|
50
|
-
isCompleted: false,
|
|
51
|
-
isFaulted: false,
|
|
52
|
-
__name: name,
|
|
53
|
-
__input: scheduledInput
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
var context = {
|
|
57
|
-
df: {
|
|
58
|
-
instanceId: (_stub_instanceId = stub.instanceId) !== null && _stub_instanceId !== void 0 ? _stub_instanceId : 'test-instance',
|
|
59
|
-
isReplaying: false,
|
|
60
|
-
currentUtcDateTime: clock,
|
|
61
|
-
callActivity: schedule,
|
|
62
|
-
callActivityWithRetry: function callActivityWithRetry(name, _retry, i) {
|
|
63
|
-
return schedule(name, i);
|
|
64
|
-
},
|
|
65
|
-
callSubOrchestrator: function callSubOrchestrator(name, i) {
|
|
66
|
-
return schedule(name, i);
|
|
67
|
-
},
|
|
68
|
-
callSubOrchestratorWithRetry: function callSubOrchestratorWithRetry(name, _retry, i) {
|
|
69
|
-
return schedule(name, i);
|
|
70
|
-
},
|
|
71
|
-
waitForExternalEvent: function waitForExternalEvent(name) {
|
|
72
|
-
return schedule(name, undefined);
|
|
73
|
-
},
|
|
74
|
-
// Timers complete immediately: there is no real time to wait for, and a
|
|
75
|
-
// harness that blocked on one would be useless. `cancel` is real,
|
|
76
|
-
// because an orchestration that correctly cancels its losing timer must
|
|
77
|
-
// not crash in a test for doing the right thing.
|
|
78
|
-
createTimer: function createTimer(fireAt) {
|
|
79
|
-
var timer = schedule('__timer', fireAt.toISOString());
|
|
80
|
-
timer.isCanceled = false;
|
|
81
|
-
timer.cancel = function() {
|
|
82
|
-
timer.isCanceled = true;
|
|
83
|
-
};
|
|
84
|
-
return timer;
|
|
85
|
-
},
|
|
86
|
-
setCustomStatus: function setCustomStatus(value) {
|
|
87
|
-
statuses.push(String(value));
|
|
88
|
-
},
|
|
89
|
-
continueAsNew: function continueAsNew(next) {
|
|
90
|
-
continuedAsNew = next;
|
|
91
|
-
},
|
|
92
|
-
Task: {
|
|
93
|
-
all: function all(tasks) {
|
|
94
|
-
return {
|
|
95
|
-
isCompleted: false,
|
|
96
|
-
isFaulted: false,
|
|
97
|
-
__all: tasks
|
|
98
|
-
};
|
|
99
|
-
},
|
|
100
|
-
// A marker, not a winner. `Task.any` resolves to the winning TASK, not
|
|
101
|
-
// to its value, so choosing here would hand the orchestration the
|
|
102
|
-
// wrong kind of thing — which is exactly the bug the reconstructed
|
|
103
|
-
// workflows found.
|
|
104
|
-
any: function any(tasks) {
|
|
105
|
-
return {
|
|
106
|
-
isCompleted: false,
|
|
107
|
-
isFaulted: false,
|
|
108
|
-
__any: tasks
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
var generator = orchestration.handler(context, input);
|
|
115
|
-
var step = generator.next();
|
|
116
|
-
while(!step.done){
|
|
117
|
-
var resumed = resolve(step.value, stub);
|
|
118
|
-
// INTO the generator, not out of the driver. Throwing here instead is the
|
|
119
|
-
// bug the reconstructed workflows found: every compensation branch was
|
|
120
|
-
// unreachable, while the docstring promised the opposite.
|
|
121
|
-
step = isThrowRequest(resumed) ? generator.throw(resumed.__throw) : generator.next(resumed);
|
|
122
|
-
}
|
|
123
|
-
return continuedAsNew === undefined ? {
|
|
124
|
-
result: step.value,
|
|
125
|
-
calls: calls,
|
|
126
|
-
statuses: statuses
|
|
127
|
-
} : {
|
|
128
|
-
result: step.value,
|
|
129
|
-
calls: calls,
|
|
130
|
-
statuses: statuses,
|
|
131
|
-
continuedAsNew: continuedAsNew
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Produces the value the driver resumes a yielded task with.
|
|
136
|
-
*
|
|
137
|
-
* @remarks
|
|
138
|
-
* Separated so the `Task.all` fan-out case — where one yielded task stands for
|
|
139
|
-
* several — is handled in one place rather than inline in the drive loop.
|
|
140
|
-
*
|
|
141
|
-
* @param task - The task the orchestration yielded.
|
|
142
|
-
* @param stub - The stubs to resolve against.
|
|
143
|
-
* @returns The value to resume with, or a {@link ThrowRequest} for the driver to inject.
|
|
144
|
-
* @throws Error naming an activity with no stub registered.
|
|
145
|
-
* @typeParam None - this function has no generic type parameters.
|
|
146
|
-
*/ function resolve(task, stub) {
|
|
147
|
-
var fanOut = task.__all;
|
|
148
|
-
if (fanOut !== undefined) {
|
|
149
|
-
return fanOut.map(function(t) {
|
|
150
|
-
return resolve(t, stub);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
var race = task.__any;
|
|
154
|
-
if (race !== undefined) {
|
|
155
|
-
return resolveRace(race, stub);
|
|
156
|
-
}
|
|
157
|
-
var name = task.__name, input = task.__input;
|
|
158
|
-
if (name === '__timer') {
|
|
159
|
-
return undefined;
|
|
160
|
-
}
|
|
161
|
-
var activity = stub.activities[name];
|
|
162
|
-
if (activity === undefined) {
|
|
163
|
-
// Naming the activity matters: the alternative is `undefined` flowing into
|
|
164
|
-
// the orchestration and failing somewhere unrelated.
|
|
165
|
-
throw new Error("No stub registered for '".concat(name, "'. Add it to stub.activities to run this workflow."));
|
|
166
|
-
}
|
|
167
|
-
var result = activity(input);
|
|
168
|
-
if (_instanceof(result, Error)) {
|
|
169
|
-
// A returned Error becomes a THROWN error inside the orchestration, which
|
|
170
|
-
// is what makes failure branches testable at all. Handed back as a request
|
|
171
|
-
// so the DRIVER injects it; see {@link ThrowRequest}.
|
|
172
|
-
return {
|
|
173
|
-
__throw: result
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
return result;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Settles a `Task.any` race and returns the winning TASK.
|
|
180
|
-
*
|
|
181
|
-
* @remarks
|
|
182
|
-
* The distinction that matters: the SDK's `Task.any` resolves to the winning
|
|
183
|
-
* task object, not to its value, and callers read the value afterwards with
|
|
184
|
-
* `resultOf`. An earlier harness returned the resolved value instead, which
|
|
185
|
-
* made every orchestration using a race fail with "Task.any returned a task
|
|
186
|
-
* that was not one of the inputs" — correct code, rejected by the fake.
|
|
187
|
-
*
|
|
188
|
-
* The winner's `result` is populated and `isCompleted` set, so `resultOf` and
|
|
189
|
-
* an `isCompleted` check on the loser both behave as they do in production.
|
|
190
|
-
*
|
|
191
|
-
* @param candidates - The racing tasks.
|
|
192
|
-
* @param stub - The stubs to resolve the winner against.
|
|
193
|
-
* @returns The winning task, completed and carrying its result.
|
|
194
|
-
* @throws Error when `raceWinner` names a task that is not racing.
|
|
195
|
-
* @typeParam None - this function has no generic type parameters.
|
|
196
|
-
*/ function resolveRace(candidates, stub) {
|
|
197
|
-
var _ref;
|
|
198
|
-
var _stub_raceWinner;
|
|
199
|
-
var names = candidates.map(function(c) {
|
|
200
|
-
return c.__name;
|
|
201
|
-
});
|
|
202
|
-
var chosen = (_ref = (_stub_raceWinner = stub.raceWinner) === null || _stub_raceWinner === void 0 ? void 0 : _stub_raceWinner.call(stub, names)) !== null && _ref !== void 0 ? _ref : names[0];
|
|
203
|
-
var winner = candidates.find(function(c) {
|
|
204
|
-
return c.__name === chosen;
|
|
205
|
-
});
|
|
206
|
-
if (winner === undefined) {
|
|
207
|
-
throw new Error("raceWinner chose '".concat(String(chosen), "', which is not racing. Candidates: ").concat(names.join(', '), "."));
|
|
208
|
-
}
|
|
209
|
-
var mutable = winner;
|
|
210
|
-
mutable.result = winner.__name === '__timer' ? undefined : resolve(winner, stub);
|
|
211
|
-
mutable.isCompleted = true;
|
|
212
|
-
return winner;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Whether a resolved value is a request to throw inside the orchestration.
|
|
216
|
-
*
|
|
217
|
-
* @param value - Whatever `resolve` produced.
|
|
218
|
-
* @returns `true` when the driver should call `generator.throw`.
|
|
219
|
-
* @throws Never - a type guard.
|
|
220
|
-
* @typeParam None - this function has no generic type parameters.
|
|
221
|
-
*/ function isThrowRequest(value) {
|
|
222
|
-
return (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object' && value !== null && '__throw' in value;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export { runWorkflow };
|