@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.
@@ -0,0 +1,204 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Runs an orchestration against stubbed activities, with no Azure running.
5
+ *
6
+ * @remarks
7
+ * Drives the generator synchronously, feeding each yielded task the stubbed
8
+ * result for that activity's name. There is no host, no emulator and no
9
+ * storage — a three-step workflow with a short-circuit branch is testable in
10
+ * about fifteen lines.
11
+ *
12
+ * **How it intercepts.** The orchestration is driven with a fake
13
+ * `OrchestrationContext`, which works only because every scheduling call in
14
+ * this package goes through `context.df` rather than through the registered
15
+ * callable. The alternative — reading the name off `task.action.functionName` —
16
+ * is an undocumented SDK internal the package's non-goals forbid.
17
+ *
18
+ * **Limits, stated rather than discovered later.** Retry policies are not
19
+ * simulated: a stub returning an `Error` throws once, it does not exhaust
20
+ * attempts. `Task.any` resolves to the FIRST task in the list, since there is
21
+ * no real concurrency to race. Timers complete immediately.
22
+ *
23
+ * @param orchestration - The orchestration to run.
24
+ * @param input - The input, checked against its declared type.
25
+ * @param stub - The activity fakes, clock and instance id.
26
+ * @returns The result, the ordered calls, and the status transitions.
27
+ * @throws Error when an activity is called with no stub registered for it.
28
+ * @typeParam TInput - The orchestration's input type.
29
+ * @typeParam TOutput - The orchestration's output type.
30
+ */
31
+ function runWorkflow(orchestration, input, stub) {
32
+ const calls = [];
33
+ const statuses = [];
34
+ let continuedAsNew;
35
+ const clock = stub.now ?? new Date(0);
36
+ const schedule = (name, scheduledInput) => {
37
+ calls.push({
38
+ name,
39
+ input: scheduledInput
40
+ });
41
+ return {
42
+ isCompleted: false,
43
+ isFaulted: false,
44
+ __name: name,
45
+ __input: scheduledInput
46
+ };
47
+ };
48
+ const context = {
49
+ df: {
50
+ instanceId: stub.instanceId ?? 'test-instance',
51
+ isReplaying: false,
52
+ currentUtcDateTime: clock,
53
+ callActivity: schedule,
54
+ callActivityWithRetry: (name, _retry, i) => schedule(name, i),
55
+ callSubOrchestrator: (name, i) => schedule(name, i),
56
+ callSubOrchestratorWithRetry: (name, _retry, i) => schedule(name, i),
57
+ waitForExternalEvent: name => schedule(name, undefined),
58
+ // Timers complete immediately: there is no real time to wait for, and a
59
+ // harness that blocked on one would be useless. `cancel` is real,
60
+ // because an orchestration that correctly cancels its losing timer must
61
+ // not crash in a test for doing the right thing.
62
+ createTimer: fireAt => {
63
+ const timer = schedule('__timer', fireAt.toISOString());
64
+ timer.isCanceled = false;
65
+ timer.cancel = () => {
66
+ timer.isCanceled = true;
67
+ };
68
+ return timer;
69
+ },
70
+ setCustomStatus: value => {
71
+ statuses.push(String(value));
72
+ },
73
+ continueAsNew: next => {
74
+ continuedAsNew = next;
75
+ },
76
+ Task: {
77
+ all: tasks => ({
78
+ isCompleted: false,
79
+ isFaulted: false,
80
+ __all: tasks
81
+ }),
82
+ // A marker, not a winner. `Task.any` resolves to the winning TASK, not
83
+ // to its value, so choosing here would hand the orchestration the
84
+ // wrong kind of thing — which is exactly the bug the reconstructed
85
+ // workflows found.
86
+ any: tasks => ({
87
+ isCompleted: false,
88
+ isFaulted: false,
89
+ __any: tasks
90
+ })
91
+ }
92
+ }
93
+ };
94
+ const generator = orchestration.handler(context, input);
95
+ let step = generator.next();
96
+ while (!step.done) {
97
+ const resumed = resolve(step.value, stub);
98
+ // INTO the generator, not out of the driver. Throwing here instead is the
99
+ // bug the reconstructed workflows found: every compensation branch was
100
+ // unreachable, while the docstring promised the opposite.
101
+ step = isThrowRequest(resumed) ? generator.throw(resumed.__throw) : generator.next(resumed);
102
+ }
103
+ return continuedAsNew === undefined ? {
104
+ result: step.value,
105
+ calls,
106
+ statuses
107
+ } : {
108
+ result: step.value,
109
+ calls,
110
+ statuses,
111
+ continuedAsNew
112
+ };
113
+ }
114
+ /**
115
+ * Produces the value the driver resumes a yielded task with.
116
+ *
117
+ * @remarks
118
+ * Separated so the `Task.all` fan-out case — where one yielded task stands for
119
+ * several — is handled in one place rather than inline in the drive loop.
120
+ *
121
+ * @param task - The task the orchestration yielded.
122
+ * @param stub - The stubs to resolve against.
123
+ * @returns The value to resume with, or a {@link ThrowRequest} for the driver to inject.
124
+ * @throws Error naming an activity with no stub registered.
125
+ * @typeParam None - this function has no generic type parameters.
126
+ */
127
+ function resolve(task, stub) {
128
+ const fanOut = task.__all;
129
+ if (fanOut !== undefined) {
130
+ return fanOut.map(t => resolve(t, stub));
131
+ }
132
+ const race = task.__any;
133
+ if (race !== undefined) {
134
+ return resolveRace(race, stub);
135
+ }
136
+ const {
137
+ __name: name,
138
+ __input: input
139
+ } = task;
140
+ if (name === '__timer') {
141
+ return undefined;
142
+ }
143
+ const activity = stub.activities[name];
144
+ if (activity === undefined) {
145
+ // Naming the activity matters: the alternative is `undefined` flowing into
146
+ // the orchestration and failing somewhere unrelated.
147
+ throw new Error(`No stub registered for '${name}'. Add it to stub.activities to run this workflow.`);
148
+ }
149
+ const result = activity(input);
150
+ if (result instanceof Error) {
151
+ // A returned Error becomes a THROWN error inside the orchestration, which
152
+ // is what makes failure branches testable at all. Handed back as a request
153
+ // so the DRIVER injects it; see {@link ThrowRequest}.
154
+ return {
155
+ __throw: result
156
+ };
157
+ }
158
+ return result;
159
+ }
160
+ /**
161
+ * Settles a `Task.any` race and returns the winning TASK.
162
+ *
163
+ * @remarks
164
+ * The distinction that matters: the SDK's `Task.any` resolves to the winning
165
+ * task object, not to its value, and callers read the value afterwards with
166
+ * `resultOf`. An earlier harness returned the resolved value instead, which
167
+ * made every orchestration using a race fail with "Task.any returned a task
168
+ * that was not one of the inputs" — correct code, rejected by the fake.
169
+ *
170
+ * The winner's `result` is populated and `isCompleted` set, so `resultOf` and
171
+ * an `isCompleted` check on the loser both behave as they do in production.
172
+ *
173
+ * @param candidates - The racing tasks.
174
+ * @param stub - The stubs to resolve the winner against.
175
+ * @returns The winning task, completed and carrying its result.
176
+ * @throws Error when `raceWinner` names a task that is not racing.
177
+ * @typeParam None - this function has no generic type parameters.
178
+ */
179
+ function resolveRace(candidates, stub) {
180
+ const names = candidates.map(c => c.__name);
181
+ const chosen = stub.raceWinner?.(names) ?? names[0];
182
+ const winner = candidates.find(c => c.__name === chosen);
183
+ if (winner === undefined) {
184
+ throw new Error(`raceWinner chose '${String(chosen)}', which is not racing. Candidates: ${names.join(', ')}.`);
185
+ }
186
+ const mutable = winner;
187
+ mutable.result = winner.__name === '__timer' ? undefined : resolve(winner, stub);
188
+ mutable.isCompleted = true;
189
+ return winner;
190
+ }
191
+ /**
192
+ * Whether a resolved value is a request to throw inside the orchestration.
193
+ *
194
+ * @param value - Whatever `resolve` produced.
195
+ * @returns `true` when the driver should call `generator.throw`.
196
+ * @throws Never - a type guard.
197
+ * @typeParam None - this function has no generic type parameters.
198
+ */
199
+ function isThrowRequest(value) {
200
+ return typeof value === 'object' && value !== null && '__throw' in value;
201
+ }
202
+
203
+ exports.runWorkflow = runWorkflow;
204
+ //# sourceMappingURL=testing.cjs.js.map
package/package.json CHANGED
@@ -1,32 +1,34 @@
1
1
  {
2
2
  "name": "@mnci/az-durable",
3
- "version": "0.1.1",
4
- "type": "module",
5
- "main": "./dist/index.esm.js",
6
- "module": "./dist/index.esm.js",
3
+ "version": "0.1.3",
4
+ "main": "./dist/index.cjs.js",
7
5
  "types": "./dist/src/index.d.ts",
8
6
  "exports": {
9
7
  "./package.json": "./package.json",
10
8
  ".": {
11
9
  "types": "./dist/src/index.d.ts",
12
- "import": "./dist/index.esm.js",
13
- "default": "./dist/index.esm.js"
10
+ "require": "./dist/index.cjs.js",
11
+ "import": "./dist/index.cjs.js",
12
+ "default": "./dist/index.cjs.js"
14
13
  },
15
14
  "./testing": {
16
15
  "types": "./dist/src/testing.d.ts",
17
- "import": "./dist/testing.esm.js",
18
- "default": "./dist/testing.esm.js"
16
+ "require": "./dist/testing.cjs.js",
17
+ "import": "./dist/testing.cjs.js",
18
+ "default": "./dist/testing.cjs.js"
19
19
  },
20
20
  "./eslint-plugin": {
21
21
  "types": "./dist/src/eslint-plugin.d.ts",
22
- "import": "./dist/eslint-plugin.esm.js",
23
- "default": "./dist/eslint-plugin.esm.js"
22
+ "require": "./dist/eslint-plugin.cjs.js",
23
+ "import": "./dist/eslint-plugin.cjs.js",
24
+ "default": "./dist/eslint-plugin.cjs.js"
24
25
  }
25
26
  },
26
27
  "files": [
27
28
  "dist",
28
29
  "!**/*.tsbuildinfo",
29
- "!**/*.d.ts.map"
30
+ "!**/*.d.ts.map",
31
+ "!**/*.js.map"
30
32
  ],
31
33
  "publishConfig": {
32
34
  "access": "public"
@@ -1,363 +0,0 @@
1
- /**
2
- * Minimal ESLint rule shapes, declared locally.
3
- *
4
- * @remarks
5
- * Declared here rather than imported from `@types/eslint` or
6
- * `@typescript-eslint/utils` because this package ships **zero runtime
7
- * dependencies**, and a type-only dependency is still a dependency a consumer
8
- * must be able to resolve. These cover exactly what the three rules use.
9
- */ /**
10
- * Whether a call expression registers an orchestration.
11
- *
12
- * @remarks
13
- * Matches both `defineOrchestration(...)` and the raw
14
- * `df.app.orchestration(...)`, since an orchestration written either way has
15
- * the same determinism constraints.
16
- *
17
- * **Heuristic, by construction.** These rules match on call-site SHAPE, so an
18
- * orchestration body extracted into a helper function is not caught. That is a
19
- * documented limit rather than a defect: following the value would require type
20
- * information the rule deliberately does not depend on.
21
- *
22
- * @param node - A `CallExpression` node.
23
- * @returns `true` when the call registers an orchestration.
24
- * @throws Never - pure inspection.
25
- * @typeParam None - this function has no generic type parameters.
26
- */ function isOrchestrationRegistration(node) {
27
- var callee = node.callee;
28
- if (callee === undefined) {
29
- return false;
30
- }
31
- if (callee.type === 'Identifier' && callee.name === 'defineOrchestration') {
32
- return true;
33
- }
34
- // df.app.orchestration(...) — match on the trailing property, so any local
35
- // alias for the namespace still matches.
36
- if (callee.type === 'MemberExpression') {
37
- var property = callee.property;
38
- return (property === null || property === void 0 ? void 0 : property.type) === 'Identifier' && property.name === 'orchestration';
39
- }
40
- return false;
41
- }
42
- /**
43
- * The name a callee refers to, if it is a plain identifier or member access.
44
- *
45
- * @remarks
46
- * For a member expression this returns the TRAILING property, so `df.now()`
47
- * and `context.df.now()` both read as `now`. Callers that must distinguish a
48
- * bare call from a member call check `node.type` themselves - `require-yield-star`
49
- * does exactly that, because `yield c.df.callActivity(...)` is the correct raw
50
- * SDK call and must not be flagged.
51
- *
52
- * @param node - A callee node.
53
- * @returns The identifier or property name, or `undefined`.
54
- * @throws Never - pure inspection.
55
- * @typeParam None - this function has no generic type parameters.
56
- */ function calleeName(node) {
57
- if (node === undefined) {
58
- return undefined;
59
- }
60
- if (node.type === 'Identifier') {
61
- return node.name;
62
- }
63
- if (node.type === 'MemberExpression') {
64
- var property = node.property;
65
- if ((property === null || property === void 0 ? void 0 : property.type) === 'Identifier') {
66
- return property.name;
67
- }
68
- }
69
- return undefined;
70
- }
71
-
72
- /** Global reads that differ on every replay, with the replacement to suggest. */ var FORBIDDEN_CALLS = {
73
- 'Date.now': 'now(context).getTime()',
74
- 'Math.random': 'context.df.newGuid(...) or an activity',
75
- 'crypto.randomUUID': 'context.df.newGuid(...)',
76
- fetch: 'an activity — network calls must not run in an orchestrator',
77
- axios: 'an activity — network calls must not run in an orchestrator'
78
- };
79
- /**
80
- * Flags non-deterministic operations inside an orchestration body.
81
- *
82
- * @remarks
83
- * The highest-value rule in the package. Each of these returns a DIFFERENT
84
- * value on every replay, and the failure is silent: the orchestration still
85
- * completes, it just produces output that disagrees with its own history.
86
- * Nothing in the runtime reports it.
87
- *
88
- * Every message names the replacement, because "this is non-deterministic" is
89
- * only half of what a reader needs.
90
- *
91
- * Heuristic by design — see {@link isOrchestrationRegistration}.
92
- */ var noNondeterministicOrchestrator = {
93
- meta: {
94
- type: 'problem',
95
- docs: {
96
- description: 'Disallow non-deterministic operations inside an orchestration.'
97
- },
98
- schema: [],
99
- messages: {
100
- forbidden: '{{what}} is non-deterministic on replay. Use {{fix}} instead.',
101
- newDate: 'new Date() is non-deterministic on replay. Use now(context) instead.',
102
- processEnv: 'process.env is read at replay time and may differ between deploys. ' + 'Read it in an activity, or pass it as orchestration input.'
103
- }
104
- },
105
- create: function create(context) {
106
- var depth = 0;
107
- var enter = function enter(node) {
108
- if (isOrchestrationRegistration(node)) {
109
- depth += 1;
110
- }
111
- };
112
- var exit = function exit(node) {
113
- if (isOrchestrationRegistration(node)) {
114
- depth -= 1;
115
- }
116
- };
117
- return {
118
- CallExpression: function CallExpression(node) {
119
- var _calleeName;
120
- enter(node);
121
- if (depth === 0) {
122
- return;
123
- }
124
- var callee = node.callee;
125
- var object = callee === null || callee === void 0 ? void 0 : callee.object;
126
- var full = (object === null || object === void 0 ? void 0 : object.type) === 'Identifier' ? "".concat(String(object.name), ".").concat(String(calleeName(callee))) : (_calleeName = calleeName(callee)) !== null && _calleeName !== void 0 ? _calleeName : '';
127
- var fix = FORBIDDEN_CALLS[full];
128
- if (fix !== undefined) {
129
- context.report({
130
- node: node,
131
- messageId: 'forbidden',
132
- data: {
133
- what: full,
134
- fix: fix
135
- }
136
- });
137
- }
138
- },
139
- 'CallExpression:exit': exit,
140
- NewExpression: function NewExpression(node) {
141
- var _ref;
142
- if (depth === 0) {
143
- return;
144
- }
145
- var callee = node.callee;
146
- var args = node.arguments;
147
- // `new Date(someInstant)` is fine and common — only the argument-less
148
- // form reads the wall clock.
149
- if ((callee === null || callee === void 0 ? void 0 : callee.type) === 'Identifier' && callee.name === 'Date' && ((_ref = args === null || args === void 0 ? void 0 : args.length) !== null && _ref !== void 0 ? _ref : 0) === 0) {
150
- context.report({
151
- node: node,
152
- messageId: 'newDate'
153
- });
154
- }
155
- },
156
- MemberExpression: function MemberExpression(node) {
157
- if (depth === 0) {
158
- return;
159
- }
160
- var object = node.object;
161
- var property = node.property;
162
- if ((object === null || object === void 0 ? void 0 : object.type) === 'Identifier' && object.name === 'process' && (property === null || property === void 0 ? void 0 : property.type) === 'Identifier' && property.name === 'env') {
163
- context.report({
164
- node: node,
165
- messageId: 'processEnv'
166
- });
167
- }
168
- }
169
- };
170
- }
171
- };
172
-
173
- /** SDK handler aliases that erase a handler's real signature. */ var ERASING_TYPES = new Set([
174
- 'ActivityHandler',
175
- 'OrchestrationHandler',
176
- 'FunctionHandler'
177
- ]);
178
- /**
179
- * The annotation's type name, if it is a bare type reference.
180
- *
181
- * @param annotation - A node carrying a `typeAnnotation`, or `undefined`.
182
- * @returns The referenced type's name, or `undefined` when it is not a bare reference.
183
- * @throws Never - pure inspection.
184
- * @typeParam None - this function has no generic type parameters.
185
- */ function referencedName(annotation) {
186
- var typeAnnotation = annotation === null || annotation === void 0 ? void 0 : annotation.typeAnnotation;
187
- if ((typeAnnotation === null || typeAnnotation === void 0 ? void 0 : typeAnnotation.type) !== 'TSTypeReference') {
188
- return undefined;
189
- }
190
- var typeName = typeAnnotation.typeName;
191
- return (typeName === null || typeName === void 0 ? void 0 : typeName.type) === 'Identifier' ? typeName.name : undefined;
192
- }
193
- /**
194
- * Flags annotations that collapse a typed handler back to `any`.
195
- *
196
- * @remarks
197
- * **The rule that actually earns its keep**, because TypeScript cannot catch
198
- * this: the annotation is legal, so nothing errors — the types simply stop
199
- * meaning anything.
200
- *
201
- * `ActivityHandler` is an alias for `FunctionHandler`, which the SDK declares as
202
- * `(triggerInput: any, context: InvocationContext) => FunctionResult<any>`. So
203
- * annotating a handler with it discards the very signature `defineActivity`
204
- * exists to capture, and the activity silently becomes `any` in, `any` out. The
205
- * package then appears to work — every call compiles — while checking nothing.
206
- *
207
- * The second, nastier form is a middleware wrapper typed
208
- * `(h: ActivityHandler) => ActivityHandler`. That collapses EVERY handler it
209
- * wraps, so one `injectLogger` helper can quietly disable type safety across a
210
- * whole Function App. The fix is to make the wrapper generic:
211
- *
212
- * ```ts
213
- * const withLogging = <I, O>(h: (i: I, c: InvocationContext) => O) =>
214
- * (i: I, c: InvocationContext): O => { c.log('...'); return h(i, c) }
215
- * ```
216
- */ var noUntypedActivityHandler = {
217
- meta: {
218
- type: 'problem',
219
- docs: {
220
- description: 'Disallow handler annotations that erase inferred types.'
221
- },
222
- schema: [],
223
- messages: {
224
- erased: "Annotating with '{{name}}' erases the handler's real signature — it is an alias for " + '(triggerInput: any, context) => any, so the activity becomes `any` in and `any` out. ' + 'Drop the annotation and let defineActivity infer it.',
225
- erasedWrapper: "A wrapper typed '{{name}}' collapses every handler it wraps to `any`. " + 'Make it generic: <I, O>(h: (i: I, c: InvocationContext) => O) => (i: I, c: InvocationContext): O.'
226
- }
227
- },
228
- create: function create(context) {
229
- return {
230
- // const handler: ActivityHandler = ...
231
- Identifier: function Identifier(node) {
232
- var _node_parent_type, _node_parent, _node_parent_params, _node_parent1;
233
- var name = referencedName(node.typeAnnotation);
234
- if (name === undefined || !ERASING_TYPES.has(name)) {
235
- return;
236
- }
237
- // A function PARAMETER annotated this way is the middleware form, which
238
- // is worse: it erases every handler passed through it, not just one.
239
- var isParameter = ((_node_parent = node.parent) === null || _node_parent === void 0 ? void 0 : (_node_parent_type = _node_parent.type) === null || _node_parent_type === void 0 ? void 0 : _node_parent_type.startsWith('TS')) === false && ((_node_parent1 = node.parent) === null || _node_parent1 === void 0 ? void 0 : (_node_parent_params = _node_parent1.params) === null || _node_parent_params === void 0 ? void 0 : _node_parent_params.includes(node)) === true;
240
- context.report({
241
- node: node,
242
- messageId: isParameter ? 'erasedWrapper' : 'erased',
243
- data: {
244
- name: name
245
- }
246
- });
247
- }
248
- };
249
- }
250
- };
251
-
252
- /** The wrapper calls that must be delegated to, not yielded. */ var DELEGATED = new Set([
253
- 'callActivity',
254
- 'callSubOrchestration',
255
- 'all',
256
- 'any',
257
- 'waitForEvent',
258
- 'sleepFor',
259
- 'sleepUntil'
260
- ]);
261
- /**
262
- * Flags `yield callActivity(...)` where `yield *` is meant.
263
- *
264
- * @remarks
265
- * **A convenience, not a safety net — and the build plan was wrong about this.**
266
- * The plan described bare `yield` as compiling silently to `any`, "the
267
- * difference between the package working and appearing to work". Measured
268
- * against the real typings, it is a COMPILE ERROR in both registration paths:
269
- * `TS2345` through `defineOrchestration` and `TS2322` through the SDK's own
270
- * `OrchestrationHandler`, because these helpers return a `Generator` and
271
- * yielding one where a `Task` is expected does not typecheck.
272
- *
273
- * The genuinely silent case is the RAW SDK — `yield context.df.callActivity(...)`
274
- * returns `any` and compiles — which is the baseline this package replaces.
275
- *
276
- * So this rule earns its place only by reporting a clearer message than
277
- * `TS2345` does. It is in `recommended` for that reason, not because anything
278
- * depends on it.
279
- */ var requireYieldStar = {
280
- meta: {
281
- type: 'suggestion',
282
- docs: {
283
- description: 'Require `yield *` when calling a delegating helper.'
284
- },
285
- schema: [],
286
- messages: {
287
- useYieldStar: "Use 'yield *' rather than 'yield' with {{name}}(). Delegation is what carries the " + 'result type; a bare yield does not typecheck, but the compiler error is obscure.'
288
- }
289
- },
290
- create: function create(context) {
291
- return {
292
- YieldExpression: function YieldExpression(node) {
293
- if (node.delegate === true) {
294
- return;
295
- }
296
- var argument = node.argument;
297
- if ((argument === null || argument === void 0 ? void 0 : argument.type) !== 'CallExpression') {
298
- return;
299
- }
300
- // A BARE IDENTIFIER only. `c.df.callActivity(...)` is the raw SDK call,
301
- // which is correct code and must not be flagged — matching the trailing
302
- // property of a member expression would flag it, which a negative
303
- // fixture caught.
304
- var callee = argument.callee;
305
- if ((callee === null || callee === void 0 ? void 0 : callee.type) !== 'Identifier') {
306
- return;
307
- }
308
- var name = callee.name;
309
- if (DELEGATED.has(name)) {
310
- context.report({
311
- node: node,
312
- messageId: 'useYieldStar',
313
- data: {
314
- name: name
315
- }
316
- });
317
- }
318
- }
319
- };
320
- }
321
- };
322
-
323
- /**
324
- * Every rule this plugin ships, by name.
325
- *
326
- * @remarks
327
- * The keys are the names a config writes after the `az-durable/` prefix, so
328
- * renaming one is a breaking change for any consumer's config.
329
- */ var rules = {
330
- 'no-nondeterministic-orchestrator': noNondeterministicOrchestrator,
331
- 'no-untyped-activity-handler': noUntypedActivityHandler,
332
- 'require-yield-star': requireYieldStar
333
- };
334
- /**
335
- * The plugin object, for a flat config's `plugins` map.
336
- *
337
- * @remarks
338
- * Shipped from a separate entry point so lint rules are never a runtime import
339
- * of the wrapper itself.
340
- */ var plugin = {
341
- rules: rules
342
- };
343
- /**
344
- * The recommended rule set.
345
- *
346
- * @remarks
347
- * Two errors and one warning, and the split is deliberate.
348
- * `no-nondeterministic-orchestrator` and `no-untyped-activity-handler` catch
349
- * failures nothing else does — silent replay corruption, and a type collapse
350
- * TypeScript accepts as legal. `require-yield-star` is a warning because the
351
- * compiler already rejects the code it flags; it only improves the message.
352
- */ var recommended = {
353
- plugins: {
354
- 'az-durable': plugin
355
- },
356
- rules: {
357
- 'az-durable/no-nondeterministic-orchestrator': 'error',
358
- 'az-durable/no-untyped-activity-handler': 'error',
359
- 'az-durable/require-yield-star': 'warn'
360
- }
361
- };
362
-
363
- export { noNondeterministicOrchestrator, noUntypedActivityHandler, plugin, recommended, requireYieldStar, rules };