@outputai/core 0.8.2-next.013689b.0 → 0.8.2-next.0f9af4b.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 (72) hide show
  1. package/package.json +3 -8
  2. package/src/bus.js +1 -1
  3. package/src/consts.js +5 -2
  4. package/src/helpers/component.js +12 -0
  5. package/src/helpers/component.spec.js +54 -0
  6. package/src/helpers/fetch.js +105 -0
  7. package/src/helpers/fetch.spec.js +203 -0
  8. package/src/helpers/function.js +15 -0
  9. package/src/helpers/function.spec.js +48 -0
  10. package/src/helpers/object.js +98 -0
  11. package/src/helpers/object.spec.js +377 -0
  12. package/src/helpers/promise.js +29 -0
  13. package/src/helpers/promise.spec.js +35 -0
  14. package/src/helpers/string.js +30 -0
  15. package/src/helpers/string.spec.js +64 -0
  16. package/src/interface/evaluator.js +14 -12
  17. package/src/interface/evaluator.spec.js +10 -6
  18. package/src/interface/index.d.ts +7 -6
  19. package/src/interface/index.js +2 -0
  20. package/src/interface/logger.d.ts +53 -0
  21. package/src/interface/logger.js +68 -0
  22. package/src/interface/logger.spec.js +138 -0
  23. package/src/interface/step.js +15 -12
  24. package/src/interface/step.spec.js +10 -6
  25. package/src/interface/webhook.d.ts +21 -2
  26. package/src/interface/workflow.js +85 -79
  27. package/src/interface/workflow.spec.js +11 -4
  28. package/src/internal_activities/index.js +38 -36
  29. package/src/internal_activities/index.spec.js +27 -4
  30. package/src/logger/development.js +2 -2
  31. package/src/logger/development.spec.js +19 -2
  32. package/src/logger/production.js +1 -1
  33. package/src/logger/production.spec.js +24 -5
  34. package/src/sdk/helpers/index.d.ts +1 -0
  35. package/src/sdk/helpers/index.js +1 -0
  36. package/src/sdk/helpers/objects.d.ts +51 -0
  37. package/src/sdk/helpers/objects.js +8 -0
  38. package/src/sdk/helpers/objects.spec.js +16 -0
  39. package/src/tracing/processors/s3/redis_client.spec.js +0 -6
  40. package/src/tracing/processors/s3/s3_client.spec.js +0 -6
  41. package/src/tracing/trace_engine.js +1 -1
  42. package/src/worker/catalog_workflow/catalog_job.js +1 -1
  43. package/src/worker/catalog_workflow/index.spec.js +8 -11
  44. package/src/worker/configs.js +1 -1
  45. package/src/worker/connection_monitor.js +1 -1
  46. package/src/worker/global_functions.js +14 -0
  47. package/src/worker/global_functions.spec.js +55 -0
  48. package/src/worker/index.js +4 -1
  49. package/src/worker/index.spec.js +7 -0
  50. package/src/worker/interceptors/activity.js +2 -2
  51. package/src/worker/interceptors/workflow.js +3 -3
  52. package/src/worker/interceptors/workflow.spec.js +1 -1
  53. package/src/worker/loader/matchers.js +1 -1
  54. package/src/worker/log_hooks.js +14 -0
  55. package/src/worker/log_hooks.spec.js +83 -2
  56. package/src/worker/sinks.js +7 -1
  57. package/src/worker/sinks.spec.js +203 -0
  58. package/src/internal_utils/component.js +0 -9
  59. package/src/utils/index.d.ts +0 -148
  60. package/src/utils/index.js +0 -1
  61. package/src/utils/utils.js +0 -307
  62. package/src/utils/utils.spec.js +0 -723
  63. /package/src/{internal_utils → helpers}/aggregations.js +0 -0
  64. /package/src/{internal_utils → helpers}/aggregations.spec.js +0 -0
  65. /package/src/{internal_utils → helpers}/errors.js +0 -0
  66. /package/src/{internal_utils → helpers}/errors.spec.js +0 -0
  67. /package/src/{internal_utils → helpers}/temporal_context.js +0 -0
  68. /package/src/{internal_utils → helpers}/temporal_context.spec.ts +0 -0
  69. /package/src/{internal_utils → helpers}/trace_info.js +0 -0
  70. /package/src/{internal_utils → helpers}/trace_info.spec.js +0 -0
  71. /package/src/{internal_utils → helpers}/workflow_context.js +0 -0
  72. /package/src/{internal_utils → helpers}/workflow_context.spec.js +0 -0
@@ -47,6 +47,13 @@ messageBus.on( BusEventType.ACTIVITY_ERROR, ( { activityInfo, outputActivityKind
47
47
  } )
48
48
  );
49
49
 
50
+ messageBus.on( BusEventType.ACTIVITY_LOG, ( { level, message, metadata, activityInfo } ) =>
51
+ activityLog[level]( message, {
52
+ ...metadata ?? {},
53
+ ...serializedActivityFields( activityInfo )
54
+ } )
55
+ );
56
+
50
57
  /*
51
58
  ╔═════════════════╗
52
59
  ║ Workflow events ║
@@ -82,3 +89,10 @@ messageBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, error } ) =>
82
89
  error: error.message
83
90
  } )
84
91
  );
92
+
93
+ messageBus.on( BusEventType.WORKFLOW_LOG, ( { level, message, metadata, workflowDetails } ) =>
94
+ workflowLog[level]( message, {
95
+ ...metadata ?? {},
96
+ ...serializeWorkflowFields( workflowDetails )
97
+ } )
98
+ );
@@ -6,8 +6,17 @@ import {
6
6
  WORKFLOW_CATALOG
7
7
  } from '#consts';
8
8
 
9
- const activityLogMock = vi.hoisted( () => ( { info: vi.fn(), error: vi.fn() } ) );
10
- const workflowLogMock = vi.hoisted( () => ( { info: vi.fn(), error: vi.fn() } ) );
9
+ const createLoggerMock = vi.hoisted( () => () => ( {
10
+ error: vi.fn(),
11
+ warn: vi.fn(),
12
+ info: vi.fn(),
13
+ http: vi.fn(),
14
+ verbose: vi.fn(),
15
+ debug: vi.fn(),
16
+ silly: vi.fn()
17
+ } ) );
18
+ const activityLogMock = vi.hoisted( () => createLoggerMock() );
19
+ const workflowLogMock = vi.hoisted( () => createLoggerMock() );
11
20
  const createChildLoggerMock = vi.hoisted( () =>
12
21
  vi.fn( name => ( name === 'Activity' ? activityLogMock : workflowLogMock ) )
13
22
  );
@@ -125,6 +134,44 @@ describe( 'log_hooks', () => {
125
134
 
126
135
  expect( activityLogMock.error ).not.toHaveBeenCalled();
127
136
  } );
137
+
138
+ it( 'ACTIVITY_LOG logs dynamic levels with metadata and serialized activity fields', () => {
139
+ onHandlers[BusEventType.ACTIVITY_LOG]( {
140
+ activityInfo,
141
+ level: 'debug',
142
+ message: 'activity detail',
143
+ metadata: {
144
+ custom: 'value',
145
+ workflowId: 'metadata-workflow-id'
146
+ }
147
+ } );
148
+
149
+ expect( activityLogMock.debug ).toHaveBeenCalledTimes( 1 );
150
+ expect( activityLogMock.debug ).toHaveBeenCalledWith( 'activity detail', {
151
+ custom: 'value',
152
+ activityId: 'act-1',
153
+ activityType: 'myWorkflow#myStep',
154
+ workflowId: 'wf-1',
155
+ workflowType: 'myWorkflow',
156
+ runId: 'run-1'
157
+ } );
158
+ } );
159
+
160
+ it( 'ACTIVITY_LOG accepts omitted metadata', () => {
161
+ onHandlers[BusEventType.ACTIVITY_LOG]( {
162
+ activityInfo,
163
+ level: 'info',
164
+ message: 'activity detail'
165
+ } );
166
+
167
+ expect( activityLogMock.info ).toHaveBeenCalledWith( 'activity detail', {
168
+ activityId: 'act-1',
169
+ activityType: 'myWorkflow#myStep',
170
+ workflowId: 'wf-1',
171
+ workflowType: 'myWorkflow',
172
+ runId: 'run-1'
173
+ } );
174
+ } );
128
175
  } );
129
176
 
130
177
  describe( 'workflow events', () => {
@@ -210,5 +257,39 @@ describe( 'log_hooks', () => {
210
257
 
211
258
  expect( workflowLogMock.error ).not.toHaveBeenCalled();
212
259
  } );
260
+
261
+ it( 'WORKFLOW_LOG logs dynamic levels with metadata and serialized workflow fields', () => {
262
+ onHandlers[BusEventType.WORKFLOW_LOG]( {
263
+ workflowDetails,
264
+ level: 'warn',
265
+ message: 'workflow detail',
266
+ metadata: {
267
+ custom: 'value',
268
+ runId: 'metadata-run-id'
269
+ }
270
+ } );
271
+
272
+ expect( workflowLogMock.warn ).toHaveBeenCalledTimes( 1 );
273
+ expect( workflowLogMock.warn ).toHaveBeenCalledWith( 'workflow detail', {
274
+ custom: 'value',
275
+ workflowId: 'wf-1',
276
+ workflowType: 'myWorkflow',
277
+ runId: 'run-1'
278
+ } );
279
+ } );
280
+
281
+ it( 'WORKFLOW_LOG accepts omitted metadata', () => {
282
+ onHandlers[BusEventType.WORKFLOW_LOG]( {
283
+ workflowDetails,
284
+ level: 'info',
285
+ message: 'workflow detail'
286
+ } );
287
+
288
+ expect( workflowLogMock.info ).toHaveBeenCalledWith( 'workflow detail', {
289
+ workflowId: 'wf-1',
290
+ workflowType: 'myWorkflow',
291
+ runId: 'run-1'
292
+ } );
293
+ } );
213
294
  } );
214
295
  } );
@@ -1,7 +1,7 @@
1
1
  import { BusEventType, ComponentType } from '#consts';
2
2
  import * as Tracing from '#tracing';
3
3
  import { messageBus } from '#bus';
4
- import { createWorkflowDetails } from '#internal_utils/temporal_context';
4
+ import { createWorkflowDetails } from '#helpers/temporal_context';
5
5
 
6
6
  // This sink allow for sandbox Temporal environment to send trace logs back to the main thread.
7
7
  export const sinks = {
@@ -10,6 +10,12 @@ export const sinks = {
10
10
  * Workflow lifecycle sinks
11
11
  */
12
12
  workflow: {
13
+ log: {
14
+ fn: ( workflowInfo, { level, message, metadata } ) => {
15
+ messageBus.emit( BusEventType.WORKFLOW_LOG, { level, message, metadata, workflowDetails: createWorkflowDetails( workflowInfo ) } );
16
+ },
17
+ callDuringReplay: false
18
+ },
13
19
  start: {
14
20
  fn: ( workflowInfo, input ) => {
15
21
  const { runId, workflowType, memo: { traceInfo }, parent } = workflowInfo;
@@ -0,0 +1,203 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { BusEventType, ComponentType } from '#consts';
3
+
4
+ const messageBusMock = vi.hoisted( () => ( {
5
+ emit: vi.fn()
6
+ } ) );
7
+
8
+ const addEventStartMock = vi.hoisted( () => vi.fn() );
9
+ const addEventEndMock = vi.hoisted( () => vi.fn() );
10
+ const addEventErrorMock = vi.hoisted( () => vi.fn() );
11
+
12
+ const createWorkflowDetailsMock = vi.hoisted( () => vi.fn( workflowInfo => ( {
13
+ workflowId: workflowInfo.workflowId,
14
+ workflowType: workflowInfo.workflowType,
15
+ runId: workflowInfo.runId
16
+ } ) ) );
17
+
18
+ vi.mock( '#bus', () => ( { messageBus: messageBusMock } ) );
19
+ vi.mock( '#tracing', () => ( {
20
+ addEventStart: addEventStartMock,
21
+ addEventEnd: addEventEndMock,
22
+ addEventError: addEventErrorMock
23
+ } ) );
24
+ vi.mock( '#helpers/temporal_context', () => ( {
25
+ createWorkflowDetails: createWorkflowDetailsMock
26
+ } ) );
27
+
28
+ describe( 'worker/sinks', () => {
29
+ const workflowInfo = {
30
+ workflowId: 'wf-1',
31
+ workflowType: 'myWorkflow',
32
+ runId: 'run-1',
33
+ memo: {
34
+ traceInfo: { traceId: 'trace-1' }
35
+ },
36
+ parent: {
37
+ runId: 'parent-run-1'
38
+ }
39
+ };
40
+ const workflowDetails = {
41
+ workflowId: 'wf-1',
42
+ workflowType: 'myWorkflow',
43
+ runId: 'run-1'
44
+ };
45
+
46
+ beforeEach( () => {
47
+ vi.clearAllMocks();
48
+ } );
49
+
50
+ it( 'disables replay calls for side-effecting sinks', async () => {
51
+ const { sinks } = await import( './sinks.js' );
52
+
53
+ expect( sinks.workflow.start.callDuringReplay ).toBe( false );
54
+ expect( sinks.workflow.end.callDuringReplay ).toBe( false );
55
+ expect( sinks.workflow.error.callDuringReplay ).toBe( false );
56
+ expect( sinks.trace.start.callDuringReplay ).toBe( false );
57
+ expect( sinks.trace.end.callDuringReplay ).toBe( false );
58
+ expect( sinks.trace.error.callDuringReplay ).toBe( false );
59
+ } );
60
+
61
+ it( 'workflow.log emits workflow log events with metadata and workflow details', async () => {
62
+ const { sinks } = await import( './sinks.js' );
63
+ const metadata = { requestId: 'req-1' };
64
+
65
+ sinks.workflow.log.fn( workflowInfo, {
66
+ level: 'info',
67
+ message: 'workflow detail',
68
+ metadata
69
+ } );
70
+
71
+ expect( createWorkflowDetailsMock ).toHaveBeenCalledWith( workflowInfo );
72
+ expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_LOG, {
73
+ level: 'info',
74
+ message: 'workflow detail',
75
+ metadata,
76
+ workflowDetails
77
+ } );
78
+ } );
79
+
80
+ it( 'workflow.start emits workflow start events and trace start events', async () => {
81
+ const { sinks } = await import( './sinks.js' );
82
+ const input = { value: 'input' };
83
+
84
+ sinks.workflow.start.fn( workflowInfo, input );
85
+
86
+ expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_START, { workflowDetails } );
87
+ expect( addEventStartMock ).toHaveBeenCalledWith( {
88
+ id: 'run-1',
89
+ kind: ComponentType.WORKFLOW,
90
+ name: 'myWorkflow',
91
+ details: input,
92
+ parentId: 'parent-run-1',
93
+ traceInfo: { traceId: 'trace-1' }
94
+ } );
95
+ } );
96
+
97
+ it( 'workflow.start skips tracing when trace info is absent', async () => {
98
+ const { sinks } = await import( './sinks.js' );
99
+
100
+ sinks.workflow.start.fn( { ...workflowInfo, memo: {} }, { value: 'input' } );
101
+
102
+ expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_START, { workflowDetails } );
103
+ expect( addEventStartMock ).not.toHaveBeenCalled();
104
+ } );
105
+
106
+ it( 'workflow.end emits workflow end events and trace end events', async () => {
107
+ const { sinks } = await import( './sinks.js' );
108
+ const output = { value: 'output' };
109
+
110
+ sinks.workflow.end.fn( workflowInfo, output );
111
+
112
+ expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_END, { workflowDetails } );
113
+ expect( addEventEndMock ).toHaveBeenCalledWith( {
114
+ id: 'run-1',
115
+ details: output,
116
+ traceInfo: { traceId: 'trace-1' }
117
+ } );
118
+ } );
119
+
120
+ it( 'workflow.end skips tracing when trace info is absent', async () => {
121
+ const { sinks } = await import( './sinks.js' );
122
+
123
+ sinks.workflow.end.fn( { ...workflowInfo, memo: {} }, { value: 'output' } );
124
+
125
+ expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_END, { workflowDetails } );
126
+ expect( addEventEndMock ).not.toHaveBeenCalled();
127
+ } );
128
+
129
+ it( 'workflow.error emits workflow error events and trace error events', async () => {
130
+ const { sinks } = await import( './sinks.js' );
131
+ const error = new Error( 'workflow failed' );
132
+
133
+ sinks.workflow.error.fn( workflowInfo, error );
134
+
135
+ expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, { workflowDetails, error } );
136
+ expect( addEventErrorMock ).toHaveBeenCalledWith( {
137
+ id: 'run-1',
138
+ details: error,
139
+ traceInfo: { traceId: 'trace-1' }
140
+ } );
141
+ } );
142
+
143
+ it( 'workflow.error skips tracing when trace info is absent', async () => {
144
+ const { sinks } = await import( './sinks.js' );
145
+ const error = new Error( 'workflow failed' );
146
+
147
+ sinks.workflow.error.fn( { ...workflowInfo, memo: {} }, error );
148
+
149
+ expect( messageBusMock.emit ).toHaveBeenCalledWith( BusEventType.WORKFLOW_ERROR, { workflowDetails, error } );
150
+ expect( addEventErrorMock ).not.toHaveBeenCalled();
151
+ } );
152
+
153
+ it( 'trace.start records trace start events with workflow parent context', async () => {
154
+ const { sinks } = await import( './sinks.js' );
155
+
156
+ sinks.trace.start.fn( workflowInfo, {
157
+ id: 'step-1',
158
+ kind: ComponentType.STEP,
159
+ name: 'myStep',
160
+ details: { input: true }
161
+ } );
162
+
163
+ expect( addEventStartMock ).toHaveBeenCalledWith( {
164
+ id: 'step-1',
165
+ kind: ComponentType.STEP,
166
+ name: 'myStep',
167
+ details: { input: true },
168
+ parentId: 'parent-run-1',
169
+ traceInfo: { traceId: 'trace-1' }
170
+ } );
171
+ } );
172
+
173
+ it( 'trace.end records trace end events', async () => {
174
+ const { sinks } = await import( './sinks.js' );
175
+
176
+ sinks.trace.end.fn( workflowInfo, {
177
+ id: 'step-1',
178
+ details: { output: true }
179
+ } );
180
+
181
+ expect( addEventEndMock ).toHaveBeenCalledWith( {
182
+ id: 'step-1',
183
+ details: { output: true },
184
+ traceInfo: { traceId: 'trace-1' }
185
+ } );
186
+ } );
187
+
188
+ it( 'trace.error records trace error events', async () => {
189
+ const { sinks } = await import( './sinks.js' );
190
+ const error = new Error( 'step failed' );
191
+
192
+ sinks.trace.error.fn( workflowInfo, {
193
+ id: 'step-1',
194
+ details: error
195
+ } );
196
+
197
+ expect( addEventErrorMock ).toHaveBeenCalledWith( {
198
+ id: 'step-1',
199
+ details: error,
200
+ traceInfo: { traceId: 'trace-1' }
201
+ } );
202
+ } );
203
+ } );
@@ -1,9 +0,0 @@
1
- import { METADATA_ACCESS_SYMBOL } from '#consts';
2
-
3
- /**
4
- * Add metadata "values" property to a given object
5
- * @param {object} target
6
- * @param {object} values
7
- */
8
- export const setMetadata = ( target, values ) =>
9
- Object.defineProperty( target, METADATA_ACCESS_SYMBOL, { value: values, writable: false, enumerable: false, configurable: false } );
@@ -1,148 +0,0 @@
1
- /**
2
- * > [!WARNING]
3
- * > **Internal use only.** Not part of the public API; may change without notice.
4
- *
5
- * @packageDocumentation
6
- */
7
-
8
- /**
9
- * Node safe clone implementation that doesn't use global structuredClone().
10
- *
11
- * Returns a cloned version of the object.
12
- *
13
- * Only clones static properties. Getters become static properties.
14
- *
15
- * @param object
16
- */
17
- export function clone( object: object ): object;
18
-
19
- /** Represents a {Response} serialized to plain object */
20
- export type SerializedFetchResponse = {
21
- /** The response url */
22
- url: string,
23
-
24
- /** The response status code */
25
- status: number,
26
-
27
- /** The response status text */
28
- statusText: string,
29
-
30
- /** Flag indicating if the request succeeded */
31
- ok: boolean,
32
-
33
- /** Object with response headers */
34
- headers: Record<string, string>,
35
-
36
- /** Response body, either JSON, text or arrayBuffer converter to base64 */
37
- body: object | string
38
- };
39
-
40
- /**
41
- * Consumes an HTTP `Response` and serializes it to a plain object.
42
- *
43
- * @param response - The response to serialize.
44
- * @returns SerializedFetchResponse
45
- */
46
- export function serializeFetchResponse( response: Response ): SerializedFetchResponse;
47
-
48
- export type SerializedBodyAndContentType = {
49
- /** The body as a string when possible; otherwise the original value */
50
- body: string | unknown,
51
- /** The inferred `Content-Type` header value, if any */
52
- contentType: string | undefined
53
- };
54
-
55
- /**
56
- * Serializes a payload for use as a fetch POST body and infers its `Content-Type`.
57
- *
58
- * @param body - The payload to serialize.
59
- * @returns The serialized body and inferred `Content-Type`.
60
- */
61
- export function serializeBodyAndInferContentType( body: unknown ): SerializedBodyAndContentType;
62
-
63
- /**
64
- * Returns true if the value is a plain object:
65
- * - `{}`
66
- * - `new Object()`
67
- * - `Object.create(null)`
68
- *
69
- * @param object - The value to check.
70
- * @returns Whether the value is a plain object.
71
- */
72
- export function isPlainObject( object: unknown ): boolean;
73
-
74
- /**
75
- * Returns a copy of an array with its content shuffled.
76
- *
77
- * @param arr - The array to shuffle
78
- * @returns A shuffled array copy
79
- */
80
- export function shuffleArray( arr: unknown[] ): unknown[];
81
-
82
- /**
83
- * Creates a new object by merging object `b` onto object `a`, biased toward `b`:
84
- * - Fields in `b` overwrite fields in `a`.
85
- * - Fields in `b` that don't exist in `a` are created.
86
- * - Fields in `a` that don't exist in `b` are left unchanged.
87
- *
88
- * @param a - The base object.
89
- * @param b - The overriding object.
90
- * @throws {Error} If either `a` or `b` is not a plain object.
91
- * @returns A new merged object.
92
- */
93
- export function deepMerge( a: object, b: object | null | undefined ): object;
94
-
95
- /**
96
- * Creates a new object by merging object `b` onto object `a`, biased toward `b`:
97
- * - Fields in `b` that don't exist in `a` are created.
98
- * - Fields in `a` that don't exist in `b` are left unchanged.
99
- * - Fields in `a` and `b` are passed as arguments to the resolve function (a,b) and its return assigns the new value.
100
- *
101
- * @param a - The base object.
102
- * @param b - The overriding object.
103
- * @param resolver - The resolver function.
104
- * @throws {Error} If either `a` or `b` is not a plain object.
105
- * @returns A new merged object.
106
- */
107
- export function deepMergeWithResolver( a: object, b: object | null | undefined, resolver: function ): object;
108
-
109
- /**
110
- * Shortens a UUID to a url-safe base64-like string (custom 64-char alphabet).
111
- * Temporal-friendly: no Buffer or crypto; safe to use inside workflows.
112
- *
113
- * @param uuid - Standard UUID (e.g. `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`).
114
- * @returns Short string using A–Z, a–z, 0–9, `_`, `-` (typically 21–22 chars).
115
- */
116
- export function toUrlSafeBase64( uuid: string ): string;
117
-
118
- /**
119
- * Similar to native Promise.allSettled, but rejects with `{ isTimeout: true }`
120
- * if the execution exceeds the given timeout.
121
- *
122
- * @param promises - Values or promises to wait for.
123
- * @param timeoutMs - Maximum wait time in milliseconds.
124
- * @returns Native Promise.allSettled-style results.
125
- */
126
- export function allSettledWithTimeout<T>(
127
- promises: Array<T | PromiseLike<T>>,
128
- timeoutMs: number
129
- ): Promise<PromiseSettledResult<Awaited<T>>[]>;
130
-
131
- /**
132
- * Promise wrapper that can be resolved externally.
133
- */
134
- export class CancellablePromise {
135
- /** The internal promise */
136
- readonly promise: Promise<void>;
137
- /** Whether the promise is already resolved or not */
138
- readonly completed: boolean;
139
- /** Resolves the promise */
140
- complete(): void;
141
- }
142
-
143
- /**
144
- * Returns a function that invokes the wrapped function once.
145
- */
146
- export function runOnce<Args extends unknown[], Return>(
147
- fn: ( ...args: Args ) => Return
148
- ): ( ...args: Args ) => Return;
@@ -1 +0,0 @@
1
- export * from './utils.js';