@outputai/core 0.14.0 → 0.14.1-next.51e8690.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.
Files changed (100) hide show
  1. package/dist/credentials/credentials.d.ts +6 -0
  2. package/dist/credentials/credentials.js +87 -0
  3. package/dist/credentials/encrypted_yaml_provider.d.ts +2 -0
  4. package/dist/credentials/encrypted_yaml_provider.js +77 -0
  5. package/dist/credentials/encryption.d.ts +3 -0
  6. package/dist/credentials/encryption.js +6 -0
  7. package/dist/credentials/errors.d.ts +13 -0
  8. package/dist/credentials/errors.js +39 -0
  9. package/dist/credentials/index.d.ts +6 -0
  10. package/dist/credentials/index.js +5 -0
  11. package/dist/credentials/init.d.ts +1 -0
  12. package/dist/credentials/init.js +7 -0
  13. package/dist/credentials/paths.d.ts +7 -0
  14. package/dist/credentials/paths.js +14 -0
  15. package/dist/credentials/provider_registry.d.ts +3 -0
  16. package/dist/credentials/provider_registry.js +6 -0
  17. package/dist/credentials/types.d.ts +12 -0
  18. package/dist/credentials/types.js +1 -0
  19. package/package.json +14 -3
  20. package/src/async_storage.d.ts +4 -0
  21. package/src/consts.js +0 -2
  22. package/src/helpers/object.d.ts +2 -0
  23. package/src/hooks/index.d.ts +0 -8
  24. package/src/hooks/index.js +0 -3
  25. package/src/logger/index.d.ts +4 -0
  26. package/src/worker/index.js +3 -1
  27. package/bin/healthcheck.spec.js +0 -90
  28. package/src/bus.spec.js +0 -196
  29. package/src/errors.spec.js +0 -19
  30. package/src/helpers/activity_options.spec.js +0 -55
  31. package/src/helpers/component.spec.js +0 -54
  32. package/src/helpers/error_serializer.spec.js +0 -479
  33. package/src/helpers/errors.spec.js +0 -189
  34. package/src/helpers/fetch.spec.js +0 -292
  35. package/src/helpers/function.spec.js +0 -24
  36. package/src/helpers/object.spec.js +0 -425
  37. package/src/helpers/promise.spec.js +0 -62
  38. package/src/helpers/redact.spec.js +0 -66
  39. package/src/helpers/string.spec.js +0 -99
  40. package/src/helpers/temporal_context.spec.ts +0 -83
  41. package/src/helpers/trace_info.spec.js +0 -45
  42. package/src/helpers/workflow_context.spec.js +0 -46
  43. package/src/hooks/index.spec.js +0 -265
  44. package/src/hooks/pending_hooks.spec.js +0 -62
  45. package/src/interface/evaluator.spec.js +0 -685
  46. package/src/interface/logger.spec.js +0 -172
  47. package/src/interface/step.spec.js +0 -128
  48. package/src/interface/validations/index.spec.js +0 -197
  49. package/src/interface/validations/schemas.spec.js +0 -229
  50. package/src/interface/webhook.spec.js +0 -170
  51. package/src/interface/workflow.spec.js +0 -710
  52. package/src/interface/workflow_utils.spec.js +0 -271
  53. package/src/interface/zod_integration.spec.js +0 -646
  54. package/src/internal_activities/index.spec.js +0 -186
  55. package/src/logger/development.spec.js +0 -87
  56. package/src/logger/index.spec.js +0 -27
  57. package/src/logger/production.spec.js +0 -71
  58. package/src/sdk/helpers/component_metadata.spec.js +0 -30
  59. package/src/sdk/helpers/objects.spec.js +0 -16
  60. package/src/sdk/helpers/path.spec.js +0 -102
  61. package/src/sdk/runtime/context.spec.js +0 -37
  62. package/src/sdk/runtime/events.spec.js +0 -40
  63. package/src/temporal/client.spec.js +0 -124
  64. package/src/tracing/processors/local/index.spec.js +0 -204
  65. package/src/tracing/processors/s3/configs.spec.js +0 -64
  66. package/src/tracing/processors/s3/index.spec.js +0 -185
  67. package/src/tracing/processors/s3/redis_client.spec.js +0 -179
  68. package/src/tracing/processors/s3/s3_client.spec.js +0 -68
  69. package/src/tracing/tools/build_trace_tree.spec.js +0 -216
  70. package/src/tracing/trace_engine.spec.js +0 -299
  71. package/src/worker/bundle.spec.js +0 -53
  72. package/src/worker/bundler_options.spec.js +0 -62
  73. package/src/worker/catalog_workflow/catalog_publisher.spec.js +0 -317
  74. package/src/worker/catalog_workflow/index.spec.js +0 -222
  75. package/src/worker/configs.spec.js +0 -213
  76. package/src/worker/configs_tuner_schema.spec.js +0 -127
  77. package/src/worker/connection_monitor.spec.js +0 -328
  78. package/src/worker/global_functions.spec.js +0 -55
  79. package/src/worker/index.spec.js +0 -526
  80. package/src/worker/interceptors/activity.spec.js +0 -369
  81. package/src/worker/interceptors/headers.spec.js +0 -73
  82. package/src/worker/interceptors/workflow.spec.js +0 -357
  83. package/src/worker/interruption.spec.js +0 -177
  84. package/src/worker/loader/activities.spec.js +0 -212
  85. package/src/worker/loader/hooks.spec.js +0 -64
  86. package/src/worker/loader/matchers.spec.js +0 -140
  87. package/src/worker/loader/tools.spec.js +0 -595
  88. package/src/worker/loader/workflows.spec.js +0 -287
  89. package/src/worker/log_hooks.spec.js +0 -303
  90. package/src/worker/shutdown.spec.js +0 -197
  91. package/src/worker/sinks.spec.js +0 -220
  92. package/src/worker/telemetry.spec.js +0 -80
  93. package/src/worker/temporal_logger.spec.js +0 -90
  94. package/src/worker/webpack_loaders/tools.spec.js +0 -314
  95. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +0 -134
  96. package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +0 -154
  97. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.spec.js +0 -165
  98. package/src/worker/webpack_loaders/workflow_validator/index.spec.js +0 -202
  99. package/src/worker/webpack_loaders/workflow_validator/npm_workflow_export_resolve.spec.js +0 -374
  100. package/src/worker/worker_runner.spec.js +0 -220
@@ -1,374 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { dirname, join } from 'node:path';
5
- import { parse } from '../tools.js';
6
- import {
7
- isBareNpmSpecifier,
8
- resolveBareImportSpecifiersAsWorkflows,
9
- resolveBareDestructuredRequireAsWorkflows,
10
- resolveBareDefaultRequireAsWorkflow
11
- } from './npm_workflow_export_resolve.js';
12
-
13
- /**
14
- * @param {(dir: string) => void} fn
15
- */
16
- const withTempProjectDir = fn => {
17
- const dir = mkdtempSync( join( tmpdir(), 'npm-resolve-' ) );
18
- try {
19
- fn( dir );
20
- } finally {
21
- rmSync( dir, { recursive: true, force: true } );
22
- }
23
- };
24
-
25
- /**
26
- * @param {string} source - Single import declaration source line (no newline required).
27
- * @returns {import('@babel/types').ImportDeclaration['specifiers']}
28
- */
29
- const importSpecifiersFromSource = source => {
30
- const ast = parse( `${source}\n`, 'stub.js' );
31
- const decl = ast.program.body[0];
32
- if ( decl.type !== 'ImportDeclaration' ) {
33
- throw new Error( 'expected ImportDeclaration' );
34
- }
35
- return decl.specifiers;
36
- };
37
-
38
- /**
39
- * @param {string} source - `const { ... } = require('...');`
40
- */
41
- const destructuredRequirePropertiesFromSource = source => {
42
- const ast = parse( `${source}\n`, 'stub.js' );
43
- const stmt = ast.program.body[0];
44
- if ( stmt.type !== 'VariableDeclaration' || !stmt.declarations[0] ) {
45
- throw new Error( 'expected VariableDeclaration' );
46
- }
47
- const pat = stmt.declarations[0].id;
48
- if ( pat.type !== 'ObjectPattern' ) {
49
- throw new Error( 'expected ObjectPattern' );
50
- }
51
- return pat.properties;
52
- };
53
-
54
- /**
55
- * Writes a minimal package under `root/node_modules/<name>` with given files (relative paths).
56
- *
57
- * @param {string} root - Project root containing `node_modules`.
58
- * @param {string} name - Package name e.g. `@test/catalog`.
59
- * @param {string} main - Relative main entry from package root.
60
- * @param {Record<string, string>} files - Relative path -> file contents.
61
- * @param {object} [extraPackageJson] - Extra fields to merge into package.json.
62
- */
63
- const writeNodeModulesPackage = ( root, name, main, files, extraPackageJson = {} ) => {
64
- const pkgRoot = name.startsWith( '@' ) ?
65
- join( root, 'node_modules', ...name.split( '/' ) ) :
66
- join( root, 'node_modules', name );
67
- mkdirSync( pkgRoot, { recursive: true } );
68
- writeFileSync(
69
- join( pkgRoot, 'package.json' ),
70
- JSON.stringify( { name, version: '1.0.0', main, ...extraPackageJson }, null, 2 )
71
- );
72
- for ( const [ rel, content ] of Object.entries( files ) ) {
73
- const abs = join( pkgRoot, rel );
74
- mkdirSync( dirname( abs ), { recursive: true } );
75
- writeFileSync( abs, content );
76
- }
77
- return pkgRoot;
78
- };
79
-
80
- describe( 'isBareNpmSpecifier', () => {
81
- it( 'returns false for empty or non-string', () => {
82
- expect( isBareNpmSpecifier( '' ) ).toBe( false );
83
- expect( isBareNpmSpecifier( undefined ) ).toBe( false );
84
- } );
85
-
86
- it( 'returns false for relative and absolute paths', () => {
87
- expect( isBareNpmSpecifier( './x' ) ).toBe( false );
88
- expect( isBareNpmSpecifier( '../x' ) ).toBe( false );
89
- expect( isBareNpmSpecifier( '/abs' ) ).toBe( false );
90
- } );
91
-
92
- it( 'returns false for node:, file:, data:, http(s):', () => {
93
- expect( isBareNpmSpecifier( 'node:fs' ) ).toBe( false );
94
- expect( isBareNpmSpecifier( 'file:///x' ) ).toBe( false );
95
- expect( isBareNpmSpecifier( 'data:,x' ) ).toBe( false );
96
- expect( isBareNpmSpecifier( 'http://x' ) ).toBe( false );
97
- expect( isBareNpmSpecifier( 'https://x' ) ).toBe( false );
98
- } );
99
-
100
- it( 'returns true for bare package names', () => {
101
- expect( isBareNpmSpecifier( 'lodash' ) ).toBe( true );
102
- expect( isBareNpmSpecifier( '@scope/pkg' ) ).toBe( true );
103
- } );
104
- } );
105
-
106
- describe( 'resolveBareImportSpecifiersAsWorkflows', () => {
107
- it( 'returns none when the specifier does not resolve', () => {
108
- withTempProjectDir( dir => {
109
- const wf = join( dir, 'workflow.js' );
110
- writeFileSync( wf, 'export default workflow({ name: \'local\' });\n' );
111
-
112
- const out = resolveBareImportSpecifiersAsWorkflows( {
113
- fromAbsoluteFile: wf,
114
- specifier: '@missing-scope/missing-pkg-xyz',
115
- specifiers: importSpecifiersFromSource( 'import x from \'@missing-scope/missing-pkg-xyz\'' ),
116
- workflowNameCache: new Map()
117
- } );
118
- expect( out ).toEqual( { type: 'none' } );
119
- } );
120
- } );
121
-
122
- it( 'throws for namespace imports from workflow packages', () => {
123
- withTempProjectDir( dir => {
124
- const wf = join( dir, 'workflow.js' );
125
- writeFileSync( wf, 'export default workflow({ name: \'local\' });\n' );
126
- writeNodeModulesPackage( dir, '@test/ns', './index.js', {
127
- 'index.js': 'export { default as nsWorkflow } from \'./workflow.js\';\n',
128
- 'workflow.js': 'export default workflow({ name: \'ns.wf\' });\n'
129
- } );
130
-
131
- expect( () => resolveBareImportSpecifiersAsWorkflows( {
132
- fromAbsoluteFile: wf,
133
- specifier: '@test/ns',
134
- specifiers: importSpecifiersFromSource( 'import * as ns from \'@test/ns\'' ),
135
- workflowNameCache: new Map()
136
- } ) ).toThrow(
137
- 'Namespace imports from workflow package "@test/ns" are not supported. ' +
138
- 'Use named imports instead, e.g. import { myWorkflow } from \'@test/ns\'.'
139
- );
140
- } );
141
- } );
142
-
143
- it( 'returns none for namespace imports from non-workflow packages', () => {
144
- withTempProjectDir( dir => {
145
- const wf = join( dir, 'workflow.js' );
146
- writeFileSync( wf, 'export default workflow({ name: \'local\' });\n' );
147
- writeNodeModulesPackage( dir, '@test/helper', './index.js', {
148
- 'index.js': 'export const helper = () => 1;\n'
149
- } );
150
-
151
- const out = resolveBareImportSpecifiersAsWorkflows( {
152
- fromAbsoluteFile: wf,
153
- specifier: '@test/helper',
154
- specifiers: importSpecifiersFromSource( 'import * as helper from \'@test/helper\'' ),
155
- workflowNameCache: new Map()
156
- } );
157
- expect( out ).toEqual( { type: 'none' } );
158
- } );
159
- } );
160
-
161
- it( 'resolves default import to the package default workflow name', () => {
162
- withTempProjectDir( dir => {
163
- const importing = join( dir, 'workflow.js' );
164
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
165
- writeNodeModulesPackage( dir, '@test/wfdef', './workflow.js', {
166
- 'workflow.js': 'export default workflow({ name: \'pkg.default\' });\n'
167
- } );
168
-
169
- const out = resolveBareImportSpecifiersAsWorkflows( {
170
- fromAbsoluteFile: importing,
171
- specifier: '@test/wfdef',
172
- specifiers: importSpecifiersFromSource( 'import PkgDef from \'@test/wfdef\'' ),
173
- workflowNameCache: new Map()
174
- } );
175
- expect( out ).toEqual( {
176
- type: 'all',
177
- bindings: [ { localName: 'PkgDef', workflowName: 'pkg.default' } ]
178
- } );
179
- } );
180
- } );
181
-
182
- it( 'prefers the output workflow bundle export condition over the default entry', () => {
183
- withTempProjectDir( dir => {
184
- const importing = join( dir, 'workflow.js' );
185
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
186
- writeNodeModulesPackage( dir, '@test/conditional', './node-entry.js', {
187
- 'node-entry.js': 'export const helper = () => 1;\n',
188
- 'bundle/workflow.js': 'export default workflow({ name: \'bundle.workflow\' });\n'
189
- }, {
190
- exports: {
191
- '.': {
192
- 'output-workflow-bundle': './bundle/workflow.js',
193
- default: './node-entry.js'
194
- }
195
- }
196
- } );
197
-
198
- const out = resolveBareImportSpecifiersAsWorkflows( {
199
- fromAbsoluteFile: importing,
200
- specifier: '@test/conditional',
201
- specifiers: importSpecifiersFromSource( 'import BundleWorkflow from \'@test/conditional\'' ),
202
- workflowNameCache: new Map()
203
- } );
204
- expect( out ).toEqual( {
205
- type: 'all',
206
- bindings: [ { localName: 'BundleWorkflow', workflowName: 'bundle.workflow' } ]
207
- } );
208
- } );
209
- } );
210
-
211
- it( 'supports root conditional exports without an explicit dot key', () => {
212
- withTempProjectDir( dir => {
213
- const importing = join( dir, 'workflow.js' );
214
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
215
- writeNodeModulesPackage( dir, '@test/root-conditional', './node-entry.js', {
216
- 'node-entry.js': 'export const helper = () => 1;\n',
217
- 'workflow.js': 'export default workflow({ name: \'root.conditional\' });\n'
218
- }, {
219
- exports: {
220
- 'output-workflow-bundle': './workflow.js',
221
- default: './node-entry.js'
222
- }
223
- } );
224
-
225
- const out = resolveBareImportSpecifiersAsWorkflows( {
226
- fromAbsoluteFile: importing,
227
- specifier: '@test/root-conditional',
228
- specifiers: importSpecifiersFromSource( 'import RootWorkflow from \'@test/root-conditional\'' ),
229
- workflowNameCache: new Map()
230
- } );
231
- expect( out ).toEqual( {
232
- type: 'all',
233
- bindings: [ { localName: 'RootWorkflow', workflowName: 'root.conditional' } ]
234
- } );
235
- } );
236
- } );
237
-
238
- it( 'uses webpack export condition when workflow bundle condition is absent', () => {
239
- withTempProjectDir( dir => {
240
- const importing = join( dir, 'workflow.js' );
241
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
242
- writeNodeModulesPackage( dir, '@test/webpack-conditional', './node-entry.js', {
243
- 'node-entry.js': 'export const helper = () => 1;\n',
244
- 'webpack/workflow.js': 'export default workflow({ name: \'webpack.workflow\' });\n'
245
- }, {
246
- exports: {
247
- '.': {
248
- webpack: './webpack/workflow.js',
249
- default: './node-entry.js'
250
- }
251
- }
252
- } );
253
-
254
- const out = resolveBareImportSpecifiersAsWorkflows( {
255
- fromAbsoluteFile: importing,
256
- specifier: '@test/webpack-conditional',
257
- specifiers: importSpecifiersFromSource( 'import WebpackWorkflow from \'@test/webpack-conditional\'' ),
258
- workflowNameCache: new Map()
259
- } );
260
- expect( out ).toEqual( {
261
- type: 'all',
262
- bindings: [ { localName: 'WebpackWorkflow', workflowName: 'webpack.workflow' } ]
263
- } );
264
- } );
265
- } );
266
-
267
- it( 'follows re-exports to workflow.js for a named import', () => {
268
- withTempProjectDir( dir => {
269
- const importing = join( dir, 'workflow.js' );
270
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
271
- writeNodeModulesPackage( dir, '@test/catalog', './src/index.js', {
272
- 'src/index.js': 'export { default as sumNumbers } from \'./wf/workflow.js\';\n',
273
- 'src/wf/workflow.js': 'export default workflow({ name: \'sum.numbers\' });\n'
274
- } );
275
-
276
- const out = resolveBareImportSpecifiersAsWorkflows( {
277
- fromAbsoluteFile: importing,
278
- specifier: '@test/catalog',
279
- specifiers: importSpecifiersFromSource( 'import { sumNumbers } from \'@test/catalog\'' ),
280
- workflowNameCache: new Map()
281
- } );
282
- expect( out ).toEqual( {
283
- type: 'all',
284
- bindings: [ { localName: 'sumNumbers', workflowName: 'sum.numbers' } ]
285
- } );
286
- } );
287
- } );
288
-
289
- it( 'returns partial when one named import does not resolve to a workflow', () => {
290
- withTempProjectDir( dir => {
291
- const importing = join( dir, 'workflow.js' );
292
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
293
- writeNodeModulesPackage( dir, '@test/partial', './index.js', {
294
- 'index.js': 'export { default as Good } from \'./wf/workflow.js\';\n',
295
- 'wf/workflow.js': 'export default workflow({ name: \'good.def\' });\n'
296
- } );
297
-
298
- const out = resolveBareImportSpecifiersAsWorkflows( {
299
- fromAbsoluteFile: importing,
300
- specifier: '@test/partial',
301
- specifiers: importSpecifiersFromSource( 'import { Good, MissingExport } from \'@test/partial\'' ),
302
- workflowNameCache: new Map()
303
- } );
304
- expect( out.type ).toBe( 'partial' );
305
- } );
306
- } );
307
- } );
308
-
309
- describe( 'resolveBareDestructuredRequireAsWorkflows', () => {
310
- it( 'resolves destructured keys to workflow names', () => {
311
- withTempProjectDir( dir => {
312
- const importing = join( dir, 'workflow.js' );
313
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
314
- writeNodeModulesPackage( dir, '@test/destr', './index.js', {
315
- 'index.js': 'export { default as alpha } from \'./wf/workflow.js\';\n',
316
- 'wf/workflow.js': 'export default workflow({ name: \'alpha.wf\' });\n'
317
- } );
318
-
319
- const props = destructuredRequirePropertiesFromSource(
320
- 'const { alpha: A } = require(\'@test/destr\');'
321
- );
322
- const out = resolveBareDestructuredRequireAsWorkflows( {
323
- fromAbsoluteFile: importing,
324
- specifier: '@test/destr',
325
- properties: props,
326
- workflowNameCache: new Map()
327
- } );
328
- expect( out ).toEqual( {
329
- type: 'all',
330
- bindings: [ { localName: 'A', workflowName: 'alpha.wf' } ]
331
- } );
332
- } );
333
- } );
334
- } );
335
-
336
- describe( 'resolveBareDefaultRequireAsWorkflow', () => {
337
- it( 'returns binding when default resolves to a workflow', () => {
338
- withTempProjectDir( dir => {
339
- const importing = join( dir, 'workflow.js' );
340
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
341
- writeNodeModulesPackage( dir, '@test/defreq', './entry.js', {
342
- 'entry.js': 'export { default } from \'./wf/workflow.js\';\n',
343
- 'wf/workflow.js': 'export default workflow({ name: \'chain.def\' });\n'
344
- } );
345
-
346
- const out = resolveBareDefaultRequireAsWorkflow(
347
- importing,
348
- '@test/defreq',
349
- 'Cat',
350
- new Map()
351
- );
352
- expect( out ).toEqual( {
353
- type: 'binding',
354
- localName: 'Cat',
355
- workflowName: 'chain.def'
356
- } );
357
- } );
358
- } );
359
-
360
- it( 'returns none when nothing resolves', () => {
361
- withTempProjectDir( dir => {
362
- const importing = join( dir, 'workflow.js' );
363
- writeFileSync( importing, 'export default workflow({ name: \'local\' });\n' );
364
-
365
- const out = resolveBareDefaultRequireAsWorkflow(
366
- importing,
367
- '@ghost/no-such-pkg',
368
- 'X',
369
- new Map()
370
- );
371
- expect( out ).toEqual( { type: 'none' } );
372
- } );
373
- } );
374
- } );
@@ -1,220 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { WorkerRunner } from './worker_runner.js';
3
-
4
- /**
5
- * Stands in for a Temporal worker: run() only settles once the drain finishes,
6
- * and shutdown() moves the run state out of RUNNING the way the SDK does.
7
- */
8
- const createWorker = () => {
9
- const state = { runState: 'INITIALIZED', resolve: null, reject: null };
10
-
11
- const worker = {
12
- run: vi.fn( () => {
13
- state.runState = 'RUNNING';
14
- return new Promise( ( resolve, reject ) => {
15
- state.resolve = resolve;
16
- state.reject = reject;
17
- } );
18
- } ),
19
- shutdown: vi.fn( () => {
20
- state.runState = 'STOPPING';
21
- } ),
22
- getStatus: vi.fn( () => ( { runState: state.runState } ) )
23
- };
24
-
25
- return {
26
- worker,
27
- drain: () => {
28
- state.runState = 'STOPPED';
29
- state.resolve();
30
- },
31
- fail: error => {
32
- state.runState = 'STOPPED';
33
- state.reject( error );
34
- }
35
- };
36
- };
37
-
38
- const createRunner = ( worker, signal = new AbortController().signal ) => new WorkerRunner( { worker, signal } );
39
-
40
- describe( 'WorkerRunner', () => {
41
- it( 'polls the task queue and reports running until the worker settles', async () => {
42
- const { worker, drain } = createWorker();
43
- const runner = createRunner( worker );
44
-
45
- const run = runner.start();
46
-
47
- expect( worker.run ).toHaveBeenCalledOnce();
48
- expect( runner.running ).toBe( true );
49
-
50
- drain();
51
- await run;
52
-
53
- expect( runner.running ).toBe( false );
54
- } );
55
-
56
- it( 'returns the same execution when started more than once', async () => {
57
- const { worker, drain } = createWorker();
58
- const runner = createRunner( worker );
59
-
60
- const first = runner.start();
61
- const second = runner.start();
62
-
63
- expect( second ).toBe( first );
64
- expect( worker.run ).toHaveBeenCalledOnce();
65
-
66
- drain();
67
- await first;
68
- } );
69
-
70
- it( 'never polls when the signal is already aborted', async () => {
71
- const controller = new AbortController();
72
- controller.abort();
73
- const { worker } = createWorker();
74
- const runner = createRunner( worker, controller.signal );
75
-
76
- await expect( runner.start() ).resolves.toBeUndefined();
77
-
78
- expect( worker.run ).not.toHaveBeenCalled();
79
- expect( worker.shutdown ).not.toHaveBeenCalled();
80
- expect( runner.running ).toBe( false );
81
- } );
82
-
83
- it( 'drains the worker when the signal aborts', async () => {
84
- const controller = new AbortController();
85
- const { worker, drain } = createWorker();
86
- const runner = createRunner( worker, controller.signal );
87
-
88
- const run = runner.start();
89
- controller.abort();
90
-
91
- expect( worker.shutdown ).toHaveBeenCalledOnce();
92
- expect( runner.running ).toBe( true );
93
-
94
- drain();
95
- await run;
96
-
97
- expect( runner.running ).toBe( false );
98
- } );
99
-
100
- it( 'drains on stop and resolves once the worker settles', async () => {
101
- const { worker, drain } = createWorker();
102
- const runner = createRunner( worker );
103
-
104
- const run = runner.start();
105
- const stopped = runner.stop();
106
-
107
- expect( worker.shutdown ).toHaveBeenCalledOnce();
108
- expect( runner.running ).toBe( true );
109
-
110
- drain();
111
-
112
- await expect( stopped ).resolves.toBeUndefined();
113
- await run;
114
-
115
- expect( runner.running ).toBe( false );
116
- } );
117
-
118
- it( 'does not shut down a worker that is not running', async () => {
119
- const { worker } = createWorker();
120
- const runner = createRunner( worker );
121
-
122
- await expect( runner.stop() ).resolves.toBeUndefined();
123
-
124
- expect( worker.run ).not.toHaveBeenCalled();
125
- expect( worker.shutdown ).not.toHaveBeenCalled();
126
- } );
127
-
128
- it( 'shuts the worker down once when stopped twice', async () => {
129
- const { worker, drain } = createWorker();
130
- const runner = createRunner( worker );
131
-
132
- const run = runner.start();
133
- runner.stop();
134
- runner.stop();
135
-
136
- expect( worker.shutdown ).toHaveBeenCalledOnce();
137
-
138
- drain();
139
- await run;
140
- } );
141
-
142
- it( 'shuts the worker down once when aborted and then stopped', async () => {
143
- const controller = new AbortController();
144
- const { worker, drain } = createWorker();
145
- const runner = createRunner( worker, controller.signal );
146
-
147
- const run = runner.start();
148
- controller.abort();
149
- const stopped = runner.stop();
150
-
151
- expect( worker.shutdown ).toHaveBeenCalledOnce();
152
-
153
- drain();
154
-
155
- await expect( stopped ).resolves.toBeUndefined();
156
- await run;
157
- } );
158
-
159
- it( 'rejects when the worker fails', async () => {
160
- const error = new Error( 'poll failed' );
161
- const { worker, fail } = createWorker();
162
- const runner = createRunner( worker );
163
-
164
- const run = runner.start();
165
- const rejection = expect( run ).rejects.toBe( error );
166
-
167
- fail( error );
168
- await rejection;
169
-
170
- expect( runner.running ).toBe( false );
171
- } );
172
-
173
- it( 'reports the failure through stop so a drain error is never silent', async () => {
174
- const error = new Error( 'poll failed' );
175
- const { worker, fail } = createWorker();
176
- const runner = createRunner( worker );
177
-
178
- const run = runner.start();
179
- const rejection = expect( run ).rejects.toBe( error );
180
-
181
- fail( error );
182
- await rejection;
183
-
184
- await expect( runner.stop() ).rejects.toBe( error );
185
- expect( worker.shutdown ).not.toHaveBeenCalled();
186
- } );
187
-
188
- it( 'never rethrows a drain that fails after the signal aborted', async () => {
189
- const error = new Error( 'drain failed' );
190
- const controller = new AbortController();
191
- const { worker, fail } = createWorker();
192
- const runner = createRunner( worker, controller.signal );
193
-
194
- const run = runner.start();
195
- const rejection = expect( run ).rejects.toBe( error );
196
-
197
- // Node rethrows a rejected promise returned by an event listener, so the abort listener must not return one
198
- controller.abort();
199
- fail( error );
200
-
201
- await rejection;
202
-
203
- expect( runner.running ).toBe( false );
204
- } );
205
-
206
- it( 'reports a drain that fails after stop was called', async () => {
207
- const error = new Error( 'drain failed' );
208
- const { worker, fail } = createWorker();
209
- const runner = createRunner( worker );
210
-
211
- const run = runner.start();
212
- const rejection = expect( run ).rejects.toBe( error );
213
- const stopped = runner.stop();
214
-
215
- fail( error );
216
-
217
- await expect( stopped ).rejects.toBe( error );
218
- await rejection;
219
- } );
220
- } );