@outputai/core 0.14.0 → 0.14.1-next.1ec4416.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/dist/credentials/credentials.d.ts +6 -0
- package/dist/credentials/credentials.js +87 -0
- package/dist/credentials/encrypted_yaml_provider.d.ts +2 -0
- package/dist/credentials/encrypted_yaml_provider.js +77 -0
- package/dist/credentials/encryption.d.ts +3 -0
- package/dist/credentials/encryption.js +6 -0
- package/dist/credentials/errors.d.ts +13 -0
- package/dist/credentials/errors.js +39 -0
- package/dist/credentials/index.d.ts +6 -0
- package/dist/credentials/index.js +5 -0
- package/dist/credentials/init.d.ts +1 -0
- package/dist/credentials/init.js +7 -0
- package/dist/credentials/paths.d.ts +7 -0
- package/dist/credentials/paths.js +14 -0
- package/dist/credentials/provider_registry.d.ts +3 -0
- package/dist/credentials/provider_registry.js +6 -0
- package/dist/credentials/types.d.ts +12 -0
- package/dist/credentials/types.js +1 -0
- package/package.json +25 -14
- package/src/async_storage.d.ts +4 -0
- package/src/consts.js +0 -2
- package/src/helpers/object.d.ts +2 -0
- package/src/hooks/index.d.ts +0 -8
- package/src/hooks/index.js +0 -3
- package/src/logger/index.d.ts +4 -0
- package/src/worker/index.js +3 -1
- package/bin/healthcheck.spec.js +0 -90
- package/src/bus.spec.js +0 -196
- package/src/errors.spec.js +0 -19
- package/src/helpers/activity_options.spec.js +0 -55
- package/src/helpers/component.spec.js +0 -54
- package/src/helpers/error_serializer.spec.js +0 -479
- package/src/helpers/errors.spec.js +0 -189
- package/src/helpers/fetch.spec.js +0 -292
- package/src/helpers/function.spec.js +0 -24
- package/src/helpers/object.spec.js +0 -425
- package/src/helpers/promise.spec.js +0 -62
- package/src/helpers/redact.spec.js +0 -66
- package/src/helpers/string.spec.js +0 -99
- package/src/helpers/temporal_context.spec.ts +0 -83
- package/src/helpers/trace_info.spec.js +0 -45
- package/src/helpers/workflow_context.spec.js +0 -46
- package/src/hooks/index.spec.js +0 -265
- package/src/hooks/pending_hooks.spec.js +0 -62
- package/src/interface/evaluator.spec.js +0 -685
- package/src/interface/logger.spec.js +0 -172
- package/src/interface/step.spec.js +0 -128
- package/src/interface/validations/index.spec.js +0 -197
- package/src/interface/validations/schemas.spec.js +0 -229
- package/src/interface/webhook.spec.js +0 -170
- package/src/interface/workflow.spec.js +0 -710
- package/src/interface/workflow_utils.spec.js +0 -271
- package/src/interface/zod_integration.spec.js +0 -646
- package/src/internal_activities/index.spec.js +0 -186
- package/src/logger/development.spec.js +0 -87
- package/src/logger/index.spec.js +0 -27
- package/src/logger/production.spec.js +0 -71
- package/src/sdk/helpers/component_metadata.spec.js +0 -30
- package/src/sdk/helpers/objects.spec.js +0 -16
- package/src/sdk/helpers/path.spec.js +0 -102
- package/src/sdk/runtime/context.spec.js +0 -37
- package/src/sdk/runtime/events.spec.js +0 -40
- package/src/temporal/client.spec.js +0 -124
- package/src/tracing/processors/local/index.spec.js +0 -204
- package/src/tracing/processors/s3/configs.spec.js +0 -64
- package/src/tracing/processors/s3/index.spec.js +0 -185
- package/src/tracing/processors/s3/redis_client.spec.js +0 -179
- package/src/tracing/processors/s3/s3_client.spec.js +0 -68
- package/src/tracing/tools/build_trace_tree.spec.js +0 -216
- package/src/tracing/trace_engine.spec.js +0 -299
- package/src/worker/bundle.spec.js +0 -53
- package/src/worker/bundler_options.spec.js +0 -62
- package/src/worker/catalog_workflow/catalog_publisher.spec.js +0 -317
- package/src/worker/catalog_workflow/index.spec.js +0 -222
- package/src/worker/configs.spec.js +0 -213
- package/src/worker/configs_tuner_schema.spec.js +0 -127
- package/src/worker/connection_monitor.spec.js +0 -328
- package/src/worker/global_functions.spec.js +0 -55
- package/src/worker/index.spec.js +0 -526
- package/src/worker/interceptors/activity.spec.js +0 -369
- package/src/worker/interceptors/headers.spec.js +0 -73
- package/src/worker/interceptors/workflow.spec.js +0 -357
- package/src/worker/interruption.spec.js +0 -177
- package/src/worker/loader/activities.spec.js +0 -212
- package/src/worker/loader/hooks.spec.js +0 -64
- package/src/worker/loader/matchers.spec.js +0 -140
- package/src/worker/loader/tools.spec.js +0 -595
- package/src/worker/loader/workflows.spec.js +0 -287
- package/src/worker/log_hooks.spec.js +0 -303
- package/src/worker/shutdown.spec.js +0 -197
- package/src/worker/sinks.spec.js +0 -220
- package/src/worker/telemetry.spec.js +0 -80
- package/src/worker/temporal_logger.spec.js +0 -90
- package/src/worker/webpack_loaders/tools.spec.js +0 -314
- package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +0 -134
- package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +0 -154
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.spec.js +0 -165
- package/src/worker/webpack_loaders/workflow_validator/index.spec.js +0 -202
- package/src/worker/webpack_loaders/workflow_validator/npm_workflow_export_resolve.spec.js +0 -374
- package/src/worker/worker_runner.spec.js +0 -220
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { FatalError } from '#errors';
|
|
3
|
-
import { ACTIVITY_GET_TRACE_DESTINATIONS, ACTIVITY_SEND_HTTP_REQUEST } from '#consts';
|
|
4
|
-
import { serializeBodyAndInferContentType, serializeResponse } from '#helpers/fetch';
|
|
5
|
-
import { getTraceDestinations, sendHttpRequest } from './index.js';
|
|
6
|
-
|
|
7
|
-
const getDestinationsMock = vi.hoisted( () => vi.fn() );
|
|
8
|
-
const createInternalStepMock = vi.hoisted( () => vi.fn( ( { handler } ) => handler ) );
|
|
9
|
-
const fetchMock = vi.hoisted( () => vi.fn() );
|
|
10
|
-
const EnvHttpProxyAgentMock = vi.hoisted( () => vi.fn( function EnvHttpProxyAgent( options ) {
|
|
11
|
-
this.options = options;
|
|
12
|
-
} ) );
|
|
13
|
-
|
|
14
|
-
vi.mock( 'undici', () => ( {
|
|
15
|
-
EnvHttpProxyAgent: EnvHttpProxyAgentMock,
|
|
16
|
-
fetch: fetchMock
|
|
17
|
-
} ) );
|
|
18
|
-
|
|
19
|
-
vi.mock( '#tracing', () => ( {
|
|
20
|
-
getDestinations: getDestinationsMock
|
|
21
|
-
} ) );
|
|
22
|
-
|
|
23
|
-
vi.mock( '#logger', () => {
|
|
24
|
-
const log = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() };
|
|
25
|
-
return { createChildLogger: vi.fn( () => log ) };
|
|
26
|
-
} );
|
|
27
|
-
|
|
28
|
-
vi.mock( '#helpers/component', () => ( {
|
|
29
|
-
createInternalStep: createInternalStepMock
|
|
30
|
-
} ) );
|
|
31
|
-
|
|
32
|
-
vi.mock( '#helpers/string', () => ( {
|
|
33
|
-
isStringboolTrue: vi.fn( () => false )
|
|
34
|
-
} ) );
|
|
35
|
-
|
|
36
|
-
vi.mock( '#helpers/fetch', () => ( {
|
|
37
|
-
hydrateHeaders: vi.fn( headers => headers ?? {} ),
|
|
38
|
-
serializeBodyAndInferContentType: vi.fn(),
|
|
39
|
-
serializeResponse: vi.fn()
|
|
40
|
-
} ) );
|
|
41
|
-
|
|
42
|
-
const url = 'https://growthx.ai';
|
|
43
|
-
const method = 'GET';
|
|
44
|
-
|
|
45
|
-
const response = ( { ok = true, status = 200, statusText = 'OK', headers = {} } = {} ) => ( {
|
|
46
|
-
ok,
|
|
47
|
-
status,
|
|
48
|
-
statusText,
|
|
49
|
-
headers: new Headers( headers ),
|
|
50
|
-
text: vi.fn()
|
|
51
|
-
} );
|
|
52
|
-
|
|
53
|
-
describe( 'internal_activities component registration', () => {
|
|
54
|
-
it( 'creates internal step components for exported activities', () => {
|
|
55
|
-
expect( EnvHttpProxyAgentMock ).toHaveBeenCalledWith( { allowH2: false } );
|
|
56
|
-
expect( createInternalStepMock ).toHaveBeenNthCalledWith( 1, {
|
|
57
|
-
name: ACTIVITY_SEND_HTTP_REQUEST,
|
|
58
|
-
handler: expect.any( Function )
|
|
59
|
-
} );
|
|
60
|
-
expect( createInternalStepMock ).toHaveBeenNthCalledWith( 2, {
|
|
61
|
-
name: ACTIVITY_GET_TRACE_DESTINATIONS,
|
|
62
|
-
handler: expect.any( Function )
|
|
63
|
-
} );
|
|
64
|
-
expect( sendHttpRequest ).toBe( createInternalStepMock.mock.calls[0][0].handler );
|
|
65
|
-
expect( getTraceDestinations ).toBe( createInternalStepMock.mock.calls[1][0].handler );
|
|
66
|
-
} );
|
|
67
|
-
} );
|
|
68
|
-
|
|
69
|
-
describe( 'internal_activities/sendHttpRequest', () => {
|
|
70
|
-
beforeEach( async () => {
|
|
71
|
-
fetchMock.mockReset();
|
|
72
|
-
serializeBodyAndInferContentType.mockReset();
|
|
73
|
-
serializeResponse.mockReset();
|
|
74
|
-
} );
|
|
75
|
-
|
|
76
|
-
it( 'succeeds and returns serialized JSON response', async () => {
|
|
77
|
-
const payload = { a: 1 };
|
|
78
|
-
const method = 'POST';
|
|
79
|
-
|
|
80
|
-
fetchMock.mockResolvedValueOnce( response( {
|
|
81
|
-
status: 200,
|
|
82
|
-
headers: { 'content-type': 'application/json' }
|
|
83
|
-
} ) );
|
|
84
|
-
|
|
85
|
-
// mock utils
|
|
86
|
-
serializeBodyAndInferContentType.mockReturnValueOnce( {
|
|
87
|
-
body: JSON.stringify( payload ),
|
|
88
|
-
contentType: 'application/json; charset=UTF-8'
|
|
89
|
-
} );
|
|
90
|
-
const fakeSerialized = { sentinel: true };
|
|
91
|
-
serializeResponse.mockResolvedValueOnce( fakeSerialized );
|
|
92
|
-
|
|
93
|
-
const result = await sendHttpRequest( { url, method, payload } );
|
|
94
|
-
|
|
95
|
-
// utils mocked: verify calls and returned value
|
|
96
|
-
expect( serializeBodyAndInferContentType ).toHaveBeenCalledTimes( 1 );
|
|
97
|
-
expect( serializeBodyAndInferContentType ).toHaveBeenCalledWith( payload );
|
|
98
|
-
expect( fetchMock ).toHaveBeenCalledWith( url, expect.objectContaining( {
|
|
99
|
-
method,
|
|
100
|
-
dispatcher: expect.any( EnvHttpProxyAgentMock )
|
|
101
|
-
} ) );
|
|
102
|
-
expect( serializeResponse ).toHaveBeenCalledTimes( 1 );
|
|
103
|
-
const respArg = serializeResponse.mock.calls[0][0];
|
|
104
|
-
expect( respArg && typeof respArg.text ).toBe( 'function' );
|
|
105
|
-
expect( respArg.status ).toBe( 200 );
|
|
106
|
-
expect( respArg.headers.get( 'content-type' ) ).toContain( 'application/json' );
|
|
107
|
-
expect( serializeResponse.mock.calls[0][1] ).toEqual( {} );
|
|
108
|
-
expect( result ).toBe( fakeSerialized );
|
|
109
|
-
} );
|
|
110
|
-
|
|
111
|
-
it( 'passes response options to response serialization', async () => {
|
|
112
|
-
const responseOptions = { includeHeaders: true, includeBody: true };
|
|
113
|
-
const fakeSerialized = { sentinel: true };
|
|
114
|
-
|
|
115
|
-
fetchMock.mockResolvedValueOnce( response( { status: 200 } ) );
|
|
116
|
-
serializeResponse.mockResolvedValueOnce( fakeSerialized );
|
|
117
|
-
|
|
118
|
-
const result = await sendHttpRequest( { url, method, responseOptions } );
|
|
119
|
-
|
|
120
|
-
expect( serializeResponse ).toHaveBeenCalledTimes( 1 );
|
|
121
|
-
expect( serializeResponse.mock.calls[0][1] ).toBe( responseOptions );
|
|
122
|
-
expect( result ).toBe( fakeSerialized );
|
|
123
|
-
} );
|
|
124
|
-
|
|
125
|
-
it( 'throws FatalError when response.ok is false', async () => {
|
|
126
|
-
fetchMock.mockResolvedValueOnce( response( { ok: false, status: 500, statusText: 'Internal Server Error' } ) );
|
|
127
|
-
|
|
128
|
-
await expect( sendHttpRequest( { url, method } ) ).rejects
|
|
129
|
-
.toThrow( new FatalError( 'GET https://growthx.ai 500' ) );
|
|
130
|
-
expect( serializeResponse ).not.toHaveBeenCalled();
|
|
131
|
-
expect( serializeBodyAndInferContentType ).not.toHaveBeenCalled();
|
|
132
|
-
} );
|
|
133
|
-
|
|
134
|
-
it( 'throws FatalError on timeout failure', async () => {
|
|
135
|
-
fetchMock.mockRejectedValueOnce( new Error( 'The operation was aborted due to timeout' ) );
|
|
136
|
-
|
|
137
|
-
await expect( sendHttpRequest( { url, method, timeout: 250 } ) ).rejects
|
|
138
|
-
.toThrow( new FatalError( 'GET https://growthx.ai The operation was aborted due to timeout' ) );
|
|
139
|
-
expect( serializeResponse ).not.toHaveBeenCalled();
|
|
140
|
-
expect( serializeBodyAndInferContentType ).not.toHaveBeenCalled();
|
|
141
|
-
} );
|
|
142
|
-
|
|
143
|
-
it( 'wraps DNS resolution errors (ENOTFOUND) preserving cause message', async () => {
|
|
144
|
-
fetchMock.mockRejectedValueOnce(
|
|
145
|
-
Object.assign( new Error( 'fetch failed' ), { cause: new Error( 'getaddrinfo ENOTFOUND nonexistent.example.test' ) } )
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
await expect( sendHttpRequest( { url, method } ) ).rejects
|
|
149
|
-
.toThrow( new FatalError( 'GET https://growthx.ai Error: getaddrinfo ENOTFOUND nonexistent.example.test' ) );
|
|
150
|
-
expect( serializeResponse ).not.toHaveBeenCalled();
|
|
151
|
-
expect( serializeBodyAndInferContentType ).not.toHaveBeenCalled();
|
|
152
|
-
} );
|
|
153
|
-
|
|
154
|
-
it( 'wraps TCP connection errors (ECONNREFUSED) preserving cause message', async () => {
|
|
155
|
-
fetchMock.mockRejectedValueOnce(
|
|
156
|
-
Object.assign( new Error( 'fetch failed' ), { cause: new Error( 'connect ECONNREFUSED 127.0.0.1:65500' ) } )
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
await expect( sendHttpRequest( { url, method } ) ).rejects
|
|
160
|
-
.toThrow( new FatalError( 'GET https://growthx.ai Error: connect ECONNREFUSED 127.0.0.1:65500' ) );
|
|
161
|
-
expect( serializeResponse ).not.toHaveBeenCalled();
|
|
162
|
-
expect( serializeBodyAndInferContentType ).not.toHaveBeenCalled();
|
|
163
|
-
} );
|
|
164
|
-
} );
|
|
165
|
-
|
|
166
|
-
describe( 'internal_activities/getTraceDestinations', () => {
|
|
167
|
-
beforeEach( () => {
|
|
168
|
-
vi.clearAllMocks();
|
|
169
|
-
} );
|
|
170
|
-
|
|
171
|
-
it( 'returns trace destinations for the given traceInfo', () => {
|
|
172
|
-
const traceInfo = {
|
|
173
|
-
workflowId: 'workflow-id',
|
|
174
|
-
runId: 'run-id',
|
|
175
|
-
workflowType: 'workflow',
|
|
176
|
-
startTime: Date.parse( '2026-06-02T09:00:00.000Z' )
|
|
177
|
-
};
|
|
178
|
-
const destinations = {
|
|
179
|
-
local: '/tmp/project/logs/runs/workflow/trace.json'
|
|
180
|
-
};
|
|
181
|
-
getDestinationsMock.mockReturnValueOnce( destinations );
|
|
182
|
-
|
|
183
|
-
expect( getTraceDestinations( traceInfo ) ).toBe( destinations );
|
|
184
|
-
expect( getDestinationsMock ).toHaveBeenCalledWith( traceInfo );
|
|
185
|
-
} );
|
|
186
|
-
} );
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
const LEVEL = Symbol.for( 'level' );
|
|
4
|
-
const MESSAGE = Symbol.for( 'message' );
|
|
5
|
-
|
|
6
|
-
vi.mock( '#helpers/object', () => ( {
|
|
7
|
-
isPlainObject: v => Object.prototype.toString.call( v ) === '[object Object]',
|
|
8
|
-
shuffleArray: v => v
|
|
9
|
-
} ) );
|
|
10
|
-
|
|
11
|
-
const loadDevelopmentLogger = async () => {
|
|
12
|
-
vi.resetModules();
|
|
13
|
-
return import( './development.js' );
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
describe( 'logger/development', () => {
|
|
17
|
-
afterEach( () => {
|
|
18
|
-
vi.unstubAllEnvs();
|
|
19
|
-
} );
|
|
20
|
-
|
|
21
|
-
describe( 'formatJson', () => {
|
|
22
|
-
it( 'formats nested plain objects and arrays', async () => {
|
|
23
|
-
const { formatJson } = await loadDevelopmentLogger();
|
|
24
|
-
|
|
25
|
-
expect( formatJson( {
|
|
26
|
-
name: 'foo',
|
|
27
|
-
count: 5,
|
|
28
|
-
nested: { ok: true },
|
|
29
|
-
list: [ 1, 'two', { three: 3 } ]
|
|
30
|
-
} ) ).toBe( '{ name: "foo", count: 5, nested: { ok: true }, list: [ 1, "two", { three: 3 } ] }' );
|
|
31
|
-
} );
|
|
32
|
-
|
|
33
|
-
it( 'formats empty objects and arrays', async () => {
|
|
34
|
-
const { formatJson } = await loadDevelopmentLogger();
|
|
35
|
-
|
|
36
|
-
expect( formatJson( { emptyObject: {}, emptyArray: [] } ) ).toBe( '{ emptyObject: {}, emptyArray: [] }' );
|
|
37
|
-
} );
|
|
38
|
-
|
|
39
|
-
it( 'escapes string values', async () => {
|
|
40
|
-
const { formatJson } = await loadDevelopmentLogger();
|
|
41
|
-
|
|
42
|
-
expect( formatJson( { quote: 'hello "world"' } ) ).toBe( '{ quote: "hello \\"world\\"" }' );
|
|
43
|
-
} );
|
|
44
|
-
} );
|
|
45
|
-
|
|
46
|
-
describe( 'options.format', () => {
|
|
47
|
-
it( 'uses debug level by default', async () => {
|
|
48
|
-
const { options } = await loadDevelopmentLogger();
|
|
49
|
-
|
|
50
|
-
expect( options.level ).toBe( 'debug' );
|
|
51
|
-
} );
|
|
52
|
-
|
|
53
|
-
it( 'uses OUTPUT_LOG_LEVEL when configured', async () => {
|
|
54
|
-
vi.stubEnv( 'OUTPUT_LOG_LEVEL', 'http' );
|
|
55
|
-
const { options } = await loadDevelopmentLogger();
|
|
56
|
-
|
|
57
|
-
expect( options.level ).toBe( 'http' );
|
|
58
|
-
} );
|
|
59
|
-
|
|
60
|
-
it( 'formats level, namespace, message, and metadata fields', async () => {
|
|
61
|
-
const { options } = await loadDevelopmentLogger();
|
|
62
|
-
const info = options.format.transform( {
|
|
63
|
-
[LEVEL]: 'info',
|
|
64
|
-
level: 'info',
|
|
65
|
-
message: 'Worker',
|
|
66
|
-
namespace: 'Telemetry',
|
|
67
|
-
status: { runState: 'RUNNING' },
|
|
68
|
-
memory: { heapUsed: 123 }
|
|
69
|
-
} );
|
|
70
|
-
|
|
71
|
-
expect( info[MESSAGE] ).toMatch( /^\[\x1b\[[\d;]+minfo\x1b\[[\d;]+m\] \x1b\[38;5;033mTelemetry: Worker\x1b\[0m /u );
|
|
72
|
-
expect( info[MESSAGE] ).toContain( '{ status: { runState: "RUNNING" }, memory: { heapUsed: 123 } }' );
|
|
73
|
-
} );
|
|
74
|
-
|
|
75
|
-
it( 'does not append metadata text when only namespace is present', async () => {
|
|
76
|
-
const { options } = await loadDevelopmentLogger();
|
|
77
|
-
const info = options.format.transform( {
|
|
78
|
-
[LEVEL]: 'debug',
|
|
79
|
-
level: 'debug',
|
|
80
|
-
message: 'Loading config...',
|
|
81
|
-
namespace: 'Worker'
|
|
82
|
-
} );
|
|
83
|
-
|
|
84
|
-
expect( info[MESSAGE] ).toMatch( /^\[\x1b\[[\d;]+mdebug\x1b\[[\d;]+m\] \x1b\[38;5;033mWorker: Loading config\.\.\.\x1b\[0m$/u );
|
|
85
|
-
} );
|
|
86
|
-
} );
|
|
87
|
-
} );
|
package/src/logger/index.spec.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
const loadLogger = async nodeEnv => {
|
|
4
|
-
vi.resetModules();
|
|
5
|
-
vi.stubEnv( 'NODE_ENV', nodeEnv );
|
|
6
|
-
return import( './index.js' );
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
describe( 'logger/index', () => {
|
|
10
|
-
afterEach( () => {
|
|
11
|
-
vi.unstubAllEnvs();
|
|
12
|
-
} );
|
|
13
|
-
|
|
14
|
-
it( 'loads the development logger options', async () => {
|
|
15
|
-
const { createChildLogger } = await loadLogger( 'development' );
|
|
16
|
-
const log = createChildLogger( 'Test' );
|
|
17
|
-
|
|
18
|
-
expect( typeof log.info ).toBe( 'function' );
|
|
19
|
-
} );
|
|
20
|
-
|
|
21
|
-
it( 'loads the production logger options', async () => {
|
|
22
|
-
const { createChildLogger } = await loadLogger( 'production' );
|
|
23
|
-
const log = createChildLogger( 'Test' );
|
|
24
|
-
|
|
25
|
-
expect( typeof log.info ).toBe( 'function' );
|
|
26
|
-
} );
|
|
27
|
-
} );
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
const LEVEL = Symbol.for( 'level' );
|
|
4
|
-
const MESSAGE = Symbol.for( 'message' );
|
|
5
|
-
|
|
6
|
-
const loadProductionLogger = async () => {
|
|
7
|
-
vi.resetModules();
|
|
8
|
-
return import( './production.js' );
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
describe( 'logger/production', () => {
|
|
12
|
-
afterEach( () => {
|
|
13
|
-
vi.unstubAllEnvs();
|
|
14
|
-
} );
|
|
15
|
-
|
|
16
|
-
it( 'uses info level and default production metadata', async () => {
|
|
17
|
-
const { options } = await loadProductionLogger();
|
|
18
|
-
|
|
19
|
-
expect( options.level ).toBe( 'info' );
|
|
20
|
-
expect( options.defaultMeta ).toEqual( {
|
|
21
|
-
service: 'output-worker',
|
|
22
|
-
environment: 'production'
|
|
23
|
-
} );
|
|
24
|
-
} );
|
|
25
|
-
|
|
26
|
-
it( 'uses OUTPUT_LOG_LEVEL when configured', async () => {
|
|
27
|
-
vi.stubEnv( 'OUTPUT_LOG_LEVEL', 'debug' );
|
|
28
|
-
const { options } = await loadProductionLogger();
|
|
29
|
-
|
|
30
|
-
expect( options.level ).toBe( 'debug' );
|
|
31
|
-
} );
|
|
32
|
-
|
|
33
|
-
it( 'formats logs as JSON with timestamp and metadata fields', async () => {
|
|
34
|
-
const { options } = await loadProductionLogger();
|
|
35
|
-
const info = options.format.transform( {
|
|
36
|
-
[LEVEL]: 'info',
|
|
37
|
-
level: 'info',
|
|
38
|
-
message: 'Worker',
|
|
39
|
-
namespace: 'Telemetry',
|
|
40
|
-
status: { runState: 'RUNNING' }
|
|
41
|
-
} );
|
|
42
|
-
|
|
43
|
-
const output = JSON.parse( info[MESSAGE] );
|
|
44
|
-
|
|
45
|
-
expect( output ).toMatchObject( {
|
|
46
|
-
level: 'info',
|
|
47
|
-
message: 'Worker',
|
|
48
|
-
namespace: 'Telemetry',
|
|
49
|
-
status: { runState: 'RUNNING' }
|
|
50
|
-
} );
|
|
51
|
-
expect( output.timestamp ).toEqual( expect.stringMatching( /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[+-]\d{2}:\d{2}$/u ) );
|
|
52
|
-
} );
|
|
53
|
-
|
|
54
|
-
it( 'includes error stack when formatting Error messages', async () => {
|
|
55
|
-
const { options } = await loadProductionLogger();
|
|
56
|
-
const error = new Error( 'boom' );
|
|
57
|
-
const info = options.format.transform( {
|
|
58
|
-
[LEVEL]: 'error',
|
|
59
|
-
level: 'error',
|
|
60
|
-
message: error
|
|
61
|
-
} );
|
|
62
|
-
|
|
63
|
-
const output = JSON.parse( info[MESSAGE] );
|
|
64
|
-
|
|
65
|
-
expect( output ).toMatchObject( {
|
|
66
|
-
level: 'error',
|
|
67
|
-
message: 'boom'
|
|
68
|
-
} );
|
|
69
|
-
expect( output.stack ).toContain( 'Error: boom' );
|
|
70
|
-
} );
|
|
71
|
-
} );
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { METADATA_ACCESS_SYMBOL } from '#consts';
|
|
3
|
-
import { ComponentMetadata } from './component_metadata.js';
|
|
4
|
-
|
|
5
|
-
describe( 'ComponentMetadata', () => {
|
|
6
|
-
it( 'detects functions tagged with component metadata', () => {
|
|
7
|
-
const component = () => {};
|
|
8
|
-
Object.defineProperty( component, METADATA_ACCESS_SYMBOL, {
|
|
9
|
-
value: { name: 'my_component' }
|
|
10
|
-
} );
|
|
11
|
-
|
|
12
|
-
expect( ComponentMetadata.has( component ) ).toBe( true );
|
|
13
|
-
} );
|
|
14
|
-
|
|
15
|
-
it( 'returns the component metadata name', () => {
|
|
16
|
-
const component = () => {};
|
|
17
|
-
Object.defineProperty( component, METADATA_ACCESS_SYMBOL, {
|
|
18
|
-
value: { name: 'my_component' }
|
|
19
|
-
} );
|
|
20
|
-
|
|
21
|
-
expect( ComponentMetadata.getName( component ) ).toBe( 'my_component' );
|
|
22
|
-
} );
|
|
23
|
-
|
|
24
|
-
it( 'returns false and undefined for untagged functions', () => {
|
|
25
|
-
const fn = () => {};
|
|
26
|
-
|
|
27
|
-
expect( ComponentMetadata.has( fn ) ).toBe( false );
|
|
28
|
-
expect( ComponentMetadata.getName( fn ) ).toBeUndefined();
|
|
29
|
-
} );
|
|
30
|
-
} );
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { Objects } from './objects.js';
|
|
3
|
-
import { Objects as ObjectsFromIndex } from './index.js';
|
|
4
|
-
import { clone, deepMerge, deepMergeWithResolver, isPlainObject } from '#helpers/object';
|
|
5
|
-
|
|
6
|
-
describe( 'Objects', () => {
|
|
7
|
-
it( 'exports the same functions from the object helper module', () => {
|
|
8
|
-
expect( Objects ).toBe( ObjectsFromIndex );
|
|
9
|
-
expect( Objects ).toEqual( {
|
|
10
|
-
clone,
|
|
11
|
-
deepMerge,
|
|
12
|
-
deepMergeWithResolver,
|
|
13
|
-
isPlainObject
|
|
14
|
-
} );
|
|
15
|
-
} );
|
|
16
|
-
} );
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { Path } from './path.js';
|
|
3
|
-
|
|
4
|
-
const OriginalError = Error;
|
|
5
|
-
|
|
6
|
-
describe( 'Resolve Invocation Dir', () => {
|
|
7
|
-
afterEach( () => {
|
|
8
|
-
Error = OriginalError;
|
|
9
|
-
} );
|
|
10
|
-
|
|
11
|
-
it( 'Should detect the invocation dir from the tests workflow', () => {
|
|
12
|
-
const stack = `Error
|
|
13
|
-
at resolveInvocationDir (file:///app/sdk/core/src/sdk/helpers/path.js)
|
|
14
|
-
at fn (file:///app/test_workflows/dist/simple/steps.js:8:21)
|
|
15
|
-
at wrapper (file:///app/sdk/core/src/interface/step.js:12:26)
|
|
16
|
-
at executeNextHandler (/app/node_modules/@temporalio/worker/lib/activity.js:99:54)
|
|
17
|
-
at Storage.runWithContext.parentId (file:///app/sdk/core/src/worker/interceptors/activity.js:31:63)
|
|
18
|
-
at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:63:14)
|
|
19
|
-
at Object.runWithContext (file:///app/sdk/core/src/async_storage.js:12:44)
|
|
20
|
-
at ActivityExecutionInterceptor.execute (file:///app/sdk/core/src/worker/interceptors/activity.js:31:36)
|
|
21
|
-
at next (/app/node_modules/@temporalio/common/lib/interceptors.js:22:51)
|
|
22
|
-
at Activity.execute (/app/node_modules/@temporalio/worker/lib/activity.js:101:26)
|
|
23
|
-
at /app/node_modules/@temporalio/worker/lib/activity.js:149:29`;
|
|
24
|
-
|
|
25
|
-
Error = class extends OriginalError {
|
|
26
|
-
constructor( ...args ) {
|
|
27
|
-
super( ...args );
|
|
28
|
-
this.stack = stack;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
expect( Path.resolveInvocationDir() ).toBe( '/app/test_workflows/dist/simple' );
|
|
33
|
-
} );
|
|
34
|
-
|
|
35
|
-
it( 'Should detect the invocation dir from the sandbox environment at sdk/core', () => {
|
|
36
|
-
const stack = `Error
|
|
37
|
-
at resolveInvocationDir (file:///app/sdk/core/src/sdk/helpers/path.js)
|
|
38
|
-
at workflow (file:///app/sdk/core/src/interface/workflow.js:25:16)
|
|
39
|
-
at file:///app/test_workflows/dist/nested/workflow.js:4:16
|
|
40
|
-
at ModuleJob.run (node:internal/modules/esm/module_job:365:25)
|
|
41
|
-
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:665:26)
|
|
42
|
-
at async importComponents (file:///app/sdk/core/src/worker/loader_tools.js:54:22)
|
|
43
|
-
at async loadWorkflows (file:///app/sdk/core/src/worker/loader.js:64:38)
|
|
44
|
-
at async file:///app/sdk/core/src/worker/index.js:21:21`;
|
|
45
|
-
|
|
46
|
-
Error = class extends OriginalError {
|
|
47
|
-
constructor( ...args ) {
|
|
48
|
-
super( ...args );
|
|
49
|
-
this.stack = stack;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
expect( Path.resolveInvocationDir() ).toBe( '/app/test_workflows/dist/nested' );
|
|
54
|
-
} );
|
|
55
|
-
|
|
56
|
-
it( 'Should detect the invocation dir from workflow loading at core', () => {
|
|
57
|
-
const stack = `Error
|
|
58
|
-
at resolveInvocationDir (/app/sdk/core/src/sdk/helpers/path.js:21:0)
|
|
59
|
-
at workflow (/app/sdk/core/src/interface/workflow.js:22:43)
|
|
60
|
-
at ../../test_workflows/dist/nested/workflow.js (/app/test_workflows/dist/nested/workflow.js:4:24)
|
|
61
|
-
at __webpack_require__ (webpack/bootstrap:19:0)
|
|
62
|
-
at ./src/worker/temp/__workflows_entrypoint.js (null:null:null)
|
|
63
|
-
at __webpack_require__ (webpack/bootstrap:19:0)
|
|
64
|
-
at importWorkflows (/app/sdk/core/src/worker/temp/__workflows_entrypoint-autogenerated-entrypoint.cjs:9:9)
|
|
65
|
-
at Object.initRuntime (/app/node_modules/@temporalio/workflow/src/worker-interface.ts:78:16)
|
|
66
|
-
at __TEMPORAL_CALL_INTO_SCOPE (evalmachine.<anonymous>:30:40)
|
|
67
|
-
at evalmachine.<anonymous>:1:1`;
|
|
68
|
-
|
|
69
|
-
Error = class extends OriginalError {
|
|
70
|
-
constructor( ...args ) {
|
|
71
|
-
super( ...args );
|
|
72
|
-
this.stack = stack;
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
expect( Path.resolveInvocationDir() ).toBe( '/app/test_workflows/dist/nested' );
|
|
77
|
-
} );
|
|
78
|
-
|
|
79
|
-
it( 'Should detect the invocation dir from a workflow using core installed via NPM', () => {
|
|
80
|
-
const stack = `Error
|
|
81
|
-
at resolveInvocationDir (file:///app/node_modules/@outputai/core/src/sdk/helpers/path.js)
|
|
82
|
-
at fn (file:///app/dist/simple/steps.js:8:21)
|
|
83
|
-
at wrapper (file:///app/node_modules/@outputai/core/src/interface/step.js:12:26)
|
|
84
|
-
at executeNextHandler (/app/node_modules/@temporalio/worker/lib/activity.js:99:54)
|
|
85
|
-
at Storage.runWithContext.parentId (file:///app/node_modules/@outputai/core/src/worker/interceptors/activity.js:31:63)
|
|
86
|
-
at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:63:14)
|
|
87
|
-
at Object.runWithContext (file:///app/node_modules/@outputai/core/src/async_storage.js:12:44)
|
|
88
|
-
at ActivityExecutionInterceptor.execute (file:///app/node_modules/@outputai/core/src/worker/interceptors/activity.js:31:36)
|
|
89
|
-
at next (/app/node_modules/@temporalio/common/lib/interceptors.js:22:51)
|
|
90
|
-
at Activity.execute (/app/node_modules/@temporalio/worker/lib/activity.js:101:26)
|
|
91
|
-
at /app/node_modules/@temporalio/worker/lib/activity.js:149:29`;
|
|
92
|
-
|
|
93
|
-
Error = class extends OriginalError {
|
|
94
|
-
constructor( ...args ) {
|
|
95
|
-
super( ...args );
|
|
96
|
-
this.stack = stack;
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
expect( Path.resolveInvocationDir() ).toBe( '/app/dist/simple' );
|
|
101
|
-
} );
|
|
102
|
-
} );
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
const loadMock = vi.fn();
|
|
4
|
-
vi.mock( '#async_storage', () => ( {
|
|
5
|
-
Storage: { load: loadMock }
|
|
6
|
-
} ) );
|
|
7
|
-
|
|
8
|
-
describe( 'Context.getActivityContext', () => {
|
|
9
|
-
beforeEach( () => {
|
|
10
|
-
vi.clearAllMocks();
|
|
11
|
-
vi.resetModules();
|
|
12
|
-
} );
|
|
13
|
-
|
|
14
|
-
it( 'returns null when no context is stored', async () => {
|
|
15
|
-
loadMock.mockReturnValue( undefined );
|
|
16
|
-
const { Context } = await import( './index.js' );
|
|
17
|
-
expect( Context.getActivityContext() ).toBeNull();
|
|
18
|
-
} );
|
|
19
|
-
|
|
20
|
-
it( 'returns activity execution context from storage', async () => {
|
|
21
|
-
const activityInfo = {
|
|
22
|
-
activityId: 'activity-1',
|
|
23
|
-
activityType: 'myActivity',
|
|
24
|
-
workflowExecution: { workflowId: 'wf-1', runId: 'run-1' },
|
|
25
|
-
workflowType: 'myWorkflow'
|
|
26
|
-
};
|
|
27
|
-
loadMock.mockReturnValue( {
|
|
28
|
-
activityInfo,
|
|
29
|
-
workflowFilename: '/workflows/myWorkflow.js'
|
|
30
|
-
} );
|
|
31
|
-
const { Context } = await import( './index.js' );
|
|
32
|
-
expect( Context.getActivityContext() ).toEqual( {
|
|
33
|
-
activityInfo,
|
|
34
|
-
workflowFilename: '/workflows/myWorkflow.js'
|
|
35
|
-
} );
|
|
36
|
-
} );
|
|
37
|
-
} );
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
const emitMock = vi.hoisted( () => vi.fn() );
|
|
4
|
-
|
|
5
|
-
vi.mock( '#bus', () => ( {
|
|
6
|
-
stepEventBus: { emit: emitMock }
|
|
7
|
-
} ) );
|
|
8
|
-
|
|
9
|
-
import { Event } from './events.js';
|
|
10
|
-
|
|
11
|
-
describe( 'Event.emit', () => {
|
|
12
|
-
beforeEach( () => {
|
|
13
|
-
vi.clearAllMocks();
|
|
14
|
-
} );
|
|
15
|
-
|
|
16
|
-
it( 'forwards class instance payloads unchanged', () => {
|
|
17
|
-
class Payload {
|
|
18
|
-
value = 'test';
|
|
19
|
-
}
|
|
20
|
-
const payload = new Payload();
|
|
21
|
-
|
|
22
|
-
Event.emit( 'test:event', payload );
|
|
23
|
-
|
|
24
|
-
expect( emitMock ).toHaveBeenCalledWith( 'sdk:test:event', payload );
|
|
25
|
-
} );
|
|
26
|
-
|
|
27
|
-
it( 'emits plain object payloads on the SDK event channel', () => {
|
|
28
|
-
const payload = { modelId: 'gpt-4o' };
|
|
29
|
-
|
|
30
|
-
Event.emit( 'cost:llm:request', payload );
|
|
31
|
-
|
|
32
|
-
expect( emitMock ).toHaveBeenCalledWith( 'sdk:cost:llm:request', payload );
|
|
33
|
-
} );
|
|
34
|
-
|
|
35
|
-
it( 'forwards a missing payload as undefined', () => {
|
|
36
|
-
Event.emit( 'lifecycle:start' );
|
|
37
|
-
|
|
38
|
-
expect( emitMock ).toHaveBeenCalledWith( 'sdk:lifecycle:start', undefined );
|
|
39
|
-
} );
|
|
40
|
-
} );
|