@outputai/core 0.10.1-next.be4ec7f.0 → 0.10.1-next.c717e35.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outputai/core",
3
- "version": "0.10.1-next.be4ec7f.0",
3
+ "version": "0.10.1-next.c717e35.0",
4
4
  "description": "The core module of the output framework",
5
5
  "type": "module",
6
6
  "engines": {
@@ -41,17 +41,17 @@
41
41
  "@babel/parser": "7.29.2",
42
42
  "@babel/traverse": "7.29.0",
43
43
  "@babel/types": "7.29.0",
44
- "@temporalio/activity": "1.17.0",
45
- "@temporalio/client": "1.17.0",
46
- "@temporalio/common": "1.17.0",
47
- "@temporalio/worker": "1.17.0",
48
- "@temporalio/workflow": "1.17.0",
44
+ "@temporalio/activity": "1.20.3",
45
+ "@temporalio/client": "1.20.3",
46
+ "@temporalio/common": "1.20.3",
47
+ "@temporalio/worker": "1.20.3",
48
+ "@temporalio/workflow": "1.20.3",
49
49
  "decimal.js": "10.6.0",
50
50
  "folder-hash": "4.1.3",
51
51
  "json-stream-stringify": "3.1.6",
52
52
  "redis": "5.12.1",
53
53
  "stacktrace-parser": "0.1.11",
54
- "undici": "8.5.0",
54
+ "undici": "8.9.0",
55
55
  "winston": "3.19.0"
56
56
  },
57
57
  "peerDependencies": {
@@ -8,7 +8,7 @@ import {
8
8
  import { evaluator } from './evaluator.js';
9
9
  import { step } from './step.js';
10
10
  import { workflow } from './workflow.js';
11
- import { executeInParallel } from './workflow_utils.js';
11
+ import { executeInParallel, hasErrorType } from './workflow_utils.js';
12
12
  import { sendHttpRequest, sendPostRequestAndAwaitWebhook } from './webhook.js';
13
13
  import { Logger } from './logger.js';
14
14
 
@@ -23,6 +23,7 @@ export {
23
23
  EvaluationVerdictResult,
24
24
  EvaluationFeedback,
25
25
  executeInParallel,
26
+ hasErrorType,
26
27
  sendHttpRequest,
27
28
  sendPostRequestAndAwaitWebhook
28
29
  };
@@ -74,3 +74,18 @@ export declare function executeInParallel<T extends readonly ( () => Promise<unk
74
74
  onJobCompleted?: ( result: ParallelResults<T>[number] ) => void;
75
75
  }
76
76
  ): Promise<ParallelResults<T>>;
77
+
78
+ /**
79
+ * Checks whether an error or any error in its cause chain matches an Error class.
80
+ *
81
+ * Temporal Application Failures are matched through their serialized `type`,
82
+ * in addition to standard `instanceof` and `name` checks.
83
+ *
84
+ * @param error - Error or failure chain to inspect
85
+ * @param ErrorType - Error class to match
86
+ * @returns Whether the Error class appears in the chain
87
+ */
88
+ export declare function hasErrorType<T extends Error>(
89
+ error: unknown,
90
+ ErrorType: abstract new ( ...args: never[] ) => T
91
+ ): boolean;
@@ -48,3 +48,22 @@ export const executeInParallel = async ( { jobs, concurrency = Infinity, onJobCo
48
48
 
49
49
  return results.sort( ( a, b ) => a.index - b.index );
50
50
  };
51
+
52
+ /**
53
+ * Check if an error, or any parts of its cause chain are instances of a given Error class.
54
+ * Also check .name and .type
55
+ *
56
+ * @param {Error} error
57
+ * @param {Error} ErrorType
58
+ * @returns {boolean}
59
+ */
60
+ export const hasErrorType = ( error, ErrorType, depth = 0 ) => {
61
+ if ( depth > 20 || typeof ErrorType !== 'function' ) {
62
+ return false;
63
+ }
64
+ const expectedType = ErrorType.name;
65
+ if ( error instanceof ErrorType || error?.type === expectedType || error?.name === expectedType || error === expectedType ) {
66
+ return true;
67
+ }
68
+ return error?.cause ? hasErrorType( error.cause, ErrorType, depth + 1 ) : false;
69
+ };
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
- import { executeInParallel } from './workflow_utils.js';
2
+ import { hasErrorType, executeInParallel } from './workflow_utils.js';
3
3
 
4
4
  describe( 'executeInParallel', () => {
5
5
  it( 'returns empty array for empty jobs', async () => {
@@ -188,3 +188,84 @@ describe( 'executeInParallel', () => {
188
188
  ] );
189
189
  } );
190
190
  } );
191
+
192
+ describe( 'hasErrorType', () => {
193
+ class FooError extends Error {}
194
+
195
+ it( 'matches a direct error instance', () => {
196
+ expect( hasErrorType( new FooError( 'foo' ), FooError ) ).toBe( true );
197
+ } );
198
+
199
+ it( 'matches an error instance in the cause chain', () => {
200
+ const error = new Error( 'outer', {
201
+ cause: new Error( 'middle', {
202
+ cause: new FooError( 'foo' )
203
+ } )
204
+ } );
205
+
206
+ expect( hasErrorType( error, FooError ) ).toBe( true );
207
+ } );
208
+
209
+ it( 'matches Temporal ApplicationFailure type in the cause chain', () => {
210
+ const applicationFailure = Object.assign( new Error( 'foo' ), {
211
+ name: 'ApplicationFailure',
212
+ type: 'FooError'
213
+ } );
214
+ const activityFailure = Object.assign( new Error( 'Activity execution failed', {
215
+ cause: applicationFailure
216
+ } ), {
217
+ name: 'ActivityFailure'
218
+ } );
219
+
220
+ expect( hasErrorType( activityFailure, FooError ) ).toBe( true );
221
+ } );
222
+
223
+ it( 'matches a serialized error name', () => {
224
+ const error = Object.assign( new Error( 'foo' ), { name: 'FooError' } );
225
+
226
+ expect( hasErrorType( error, FooError ) ).toBe( true );
227
+ } );
228
+
229
+ it( 'matches an error serialized as its type name', () => {
230
+ expect( hasErrorType( 'FooError', FooError ) ).toBe( true );
231
+ } );
232
+
233
+ it( 'matches an error type in a plain object cause chain', () => {
234
+ const error = {
235
+ name: 'ActivityFailure',
236
+ cause: {
237
+ name: 'ApplicationFailure',
238
+ type: 'FooError'
239
+ }
240
+ };
241
+
242
+ expect( hasErrorType( error, FooError ) ).toBe( true );
243
+ } );
244
+
245
+ it.each( [ null, undefined, '', 42, false ] )( 'returns false for unsupported error value %j', error => {
246
+ expect( hasErrorType( error, FooError ) ).toBe( false );
247
+ } );
248
+
249
+ it( 'returns false when ErrorType is not a class', () => {
250
+ expect( hasErrorType( new FooError( 'foo' ), null ) ).toBe( false );
251
+ } );
252
+
253
+ it( 'returns false when the requested error type is absent', () => {
254
+ const error = new Error( 'outer', { cause: new TypeError( 'inner' ) } );
255
+
256
+ expect( hasErrorType( error, FooError ) ).toBe( false );
257
+ } );
258
+
259
+ it( 'keeps plain Error matching backwards compatible', () => {
260
+ expect( hasErrorType( new Error( 'foo' ), Error ) ).toBe( true );
261
+ } );
262
+
263
+ it( 'stops traversing cause chains after the depth limit', () => {
264
+ const createCauseChain = depth => depth === 20 ?
265
+ new FooError( 'foo' ) :
266
+ new Error( `depth-${depth}`, { cause: createCauseChain( depth + 1 ) } );
267
+ const root = new Error( 'root', { cause: createCauseChain( 0 ) } );
268
+
269
+ expect( hasErrorType( root, FooError ) ).toBe( false );
270
+ } );
271
+ } );