@output.ai/core 0.0.11 → 0.0.13
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 +1 -1
- package/src/configs.js +4 -46
- package/src/configs.spec.js +18 -119
- package/src/internal_activities/index.js +14 -2
package/package.json
CHANGED
package/src/configs.js
CHANGED
|
@@ -1,61 +1,19 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
2
|
|
|
3
|
-
class InvalidEnvVarsErrors extends Error {}
|
|
4
|
-
|
|
5
|
-
const ipv4Validator = z.ipv4();
|
|
6
|
-
const ipv6Validator = z.ipv6();
|
|
7
|
-
const portValidator = z.number().int().min( 10 ).max( 65535 ).optional();
|
|
8
|
-
|
|
9
|
-
const ipValidator = z.union( [ ipv4Validator, ipv6Validator ] );
|
|
10
|
-
|
|
11
|
-
const likelyIpv6 = val => val.startsWith( '[' );
|
|
12
|
-
|
|
13
|
-
const splitIpWithPort = val => {
|
|
14
|
-
// ipv6
|
|
15
|
-
if ( likelyIpv6( val ) ) {
|
|
16
|
-
const address = val.slice( 1, val.lastIndexOf( ']' ) );
|
|
17
|
-
const portString = val.split( ']' )[1].slice( 1 ); // remove the :
|
|
18
|
-
const port = portString ? parseInt( portString, 10 ) : undefined;
|
|
19
|
-
return { address, port };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// ipv4
|
|
23
|
-
const parts = val.split( ':' );
|
|
24
|
-
if ( parts.length !== 2 ) {
|
|
25
|
-
return { address: val, port: undefined };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const [ address, portString ] = parts;
|
|
29
|
-
const port = portString ? parseInt( portString, 10 ) : undefined;
|
|
30
|
-
return { address, port };
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const ipWithOptionalPort = z.string().refine(
|
|
34
|
-
val => {
|
|
35
|
-
const { address, port } = splitIpWithPort( val );
|
|
36
|
-
return ipValidator.safeParse( address ).success && portValidator.safeParse( port ).success;
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
message: 'Must be a valid IP address'
|
|
40
|
-
}
|
|
41
|
-
);
|
|
3
|
+
class InvalidEnvVarsErrors extends Error { }
|
|
42
4
|
|
|
43
5
|
const envVarSchema = z.object( {
|
|
44
|
-
TEMPORAL_ADDRESS: z.
|
|
45
|
-
z.string().regex( /^https?:\/\/.+/ ), // HTTP or HTTPS URLs
|
|
46
|
-
z.string().regex( /^[a-z0-9_-]+:\d{2,5}$/i ), // local docker container name like worker:7233
|
|
47
|
-
ipWithOptionalPort // IP address (IPv4 or IPv6) with port
|
|
48
|
-
] ),
|
|
6
|
+
TEMPORAL_ADDRESS: z.string().optional().default( 'localhost:7233' ),
|
|
49
7
|
TEMPORAL_NAMESPACE: z.string().optional().default( 'default' ),
|
|
50
8
|
TEMPORAL_API_KEY: z.string().optional(),
|
|
51
9
|
CATALOG_ID: z.string().regex( /^[a-z0-9_.@-]+$/i ),
|
|
52
10
|
API_AUTH_KEY: z.string().optional(),
|
|
53
|
-
TRACING_ENABLED: z.
|
|
11
|
+
TRACING_ENABLED: z.stringbool().optional()
|
|
54
12
|
} );
|
|
55
13
|
|
|
56
14
|
const { data: safeEnvVar, error } = envVarSchema.safeParse( process.env );
|
|
57
15
|
if ( error ) {
|
|
58
|
-
throw new InvalidEnvVarsErrors(
|
|
16
|
+
throw new InvalidEnvVarsErrors( z.prettifyError( error ) );
|
|
59
17
|
}
|
|
60
18
|
|
|
61
19
|
export const worker = {
|
package/src/configs.spec.js
CHANGED
|
@@ -14,139 +14,38 @@ describe( 'configs', () => {
|
|
|
14
14
|
|
|
15
15
|
describe( 'Environment Variable Validation', () => {
|
|
16
16
|
describe( 'TEMPORAL_ADDRESS', () => {
|
|
17
|
-
it( 'should accept
|
|
17
|
+
it( 'should accept string addresses', async () => {
|
|
18
18
|
process.env = {
|
|
19
|
-
TEMPORAL_ADDRESS: '
|
|
20
|
-
CATALOG_ID: 'test-catalog'
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const { worker } = await import( './configs.js' );
|
|
24
|
-
expect( worker.address ).toBe( 'http://localhost:7233' );
|
|
25
|
-
} );
|
|
26
|
-
|
|
27
|
-
it( 'should accept valid https URLs', async () => {
|
|
28
|
-
process.env = {
|
|
29
|
-
TEMPORAL_ADDRESS: 'https://temporal.example.com',
|
|
30
|
-
CATALOG_ID: 'test-catalog'
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const { worker } = await import( './configs.js' );
|
|
34
|
-
expect( worker.address ).toBe( 'https://temporal.example.com' );
|
|
35
|
-
} );
|
|
36
|
-
|
|
37
|
-
it( 'should accept docker container names with ports', async () => {
|
|
38
|
-
process.env = {
|
|
39
|
-
TEMPORAL_ADDRESS: 'temporal-server:7233',
|
|
40
|
-
CATALOG_ID: 'test-catalog'
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const { worker } = await import( './configs.js' );
|
|
44
|
-
expect( worker.address ).toBe( 'temporal-server:7233' );
|
|
45
|
-
} );
|
|
46
|
-
|
|
47
|
-
it( 'should accept container names with underscores and hyphens', async () => {
|
|
48
|
-
process.env = {
|
|
49
|
-
TEMPORAL_ADDRESS: 'my_temporal-server:7233',
|
|
50
|
-
CATALOG_ID: 'test-catalog'
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const { worker } = await import( './configs.js' );
|
|
54
|
-
expect( worker.address ).toBe( 'my_temporal-server:7233' );
|
|
55
|
-
} );
|
|
56
|
-
|
|
57
|
-
it( 'should accept IP addresses with HTTP', async () => {
|
|
58
|
-
process.env = {
|
|
59
|
-
TEMPORAL_ADDRESS: 'http://192.168.1.100:7233',
|
|
60
|
-
CATALOG_ID: 'test-catalog'
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const { worker } = await import( './configs.js' );
|
|
64
|
-
expect( worker.address ).toBe( 'http://192.168.1.100:7233' );
|
|
65
|
-
} );
|
|
66
|
-
|
|
67
|
-
it( 'should accept IP addresses with HTTPS', async () => {
|
|
68
|
-
process.env = {
|
|
69
|
-
TEMPORAL_ADDRESS: 'https://10.0.0.1:7233',
|
|
70
|
-
CATALOG_ID: 'test-catalog'
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const { worker } = await import( './configs.js' );
|
|
74
|
-
expect( worker.address ).toBe( 'https://10.0.0.1:7233' );
|
|
75
|
-
} );
|
|
76
|
-
|
|
77
|
-
it( 'should accept IP addresses without protocol for docker format', async () => {
|
|
78
|
-
process.env = {
|
|
79
|
-
TEMPORAL_ADDRESS: '172.17.0.2:7233',
|
|
80
|
-
CATALOG_ID: 'test-catalog'
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const { worker } = await import( './configs.js' );
|
|
84
|
-
expect( worker.address ).toBe( '172.17.0.2:7233' );
|
|
85
|
-
} );
|
|
86
|
-
|
|
87
|
-
it( 'should accept IPv6 addresses with brackets and port', async () => {
|
|
88
|
-
process.env = {
|
|
89
|
-
TEMPORAL_ADDRESS: '[2001:db8::1]:7233',
|
|
19
|
+
TEMPORAL_ADDRESS: 'localhost:7233',
|
|
90
20
|
CATALOG_ID: 'test-catalog'
|
|
91
21
|
};
|
|
92
22
|
|
|
93
23
|
const { worker } = await import( './configs.js' );
|
|
94
|
-
expect( worker.address ).toBe( '
|
|
24
|
+
expect( worker.address ).toBe( 'localhost:7233' );
|
|
95
25
|
} );
|
|
96
26
|
|
|
97
|
-
it( 'should
|
|
27
|
+
it( 'should use default when omitted', async () => {
|
|
98
28
|
process.env = {
|
|
99
|
-
TEMPORAL_ADDRESS: 'http://[2001:db8::1]:7233',
|
|
100
29
|
CATALOG_ID: 'test-catalog'
|
|
101
30
|
};
|
|
102
31
|
|
|
103
32
|
const { worker } = await import( './configs.js' );
|
|
104
|
-
expect( worker.address ).toBe( '
|
|
33
|
+
expect( worker.address ).toBe( 'localhost:7233' );
|
|
105
34
|
} );
|
|
106
35
|
|
|
107
|
-
it( 'should
|
|
36
|
+
it( 'should reject non-string values', async () => {
|
|
108
37
|
process.env = {
|
|
109
|
-
TEMPORAL_ADDRESS: '
|
|
38
|
+
TEMPORAL_ADDRESS: '123',
|
|
110
39
|
CATALOG_ID: 'test-catalog'
|
|
111
40
|
};
|
|
112
41
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
it( 'should reject invalid addresses', async () => {
|
|
118
|
-
process.env = {
|
|
119
|
-
TEMPORAL_ADDRESS: 'not-a-valid-address',
|
|
120
|
-
CATALOG_ID: 'test-catalog'
|
|
121
|
-
};
|
|
42
|
+
// Convert to number to test non-string
|
|
43
|
+
const originalEnv = process.env.TEMPORAL_ADDRESS;
|
|
44
|
+
process.env.TEMPORAL_ADDRESS = 123;
|
|
122
45
|
|
|
123
46
|
await expect( import( './configs.js' ) ).rejects.toThrow();
|
|
124
|
-
} );
|
|
125
47
|
|
|
126
|
-
|
|
127
|
-
process.env = {
|
|
128
|
-
TEMPORAL_ADDRESS: 'temporal-server',
|
|
129
|
-
CATALOG_ID: 'test-catalog'
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
await expect( import( './configs.js' ) ).rejects.toThrow();
|
|
133
|
-
} );
|
|
134
|
-
|
|
135
|
-
it( 'should reject addresses with single digit port numbers', async () => {
|
|
136
|
-
process.env = {
|
|
137
|
-
TEMPORAL_ADDRESS: 'temporal-server:1',
|
|
138
|
-
CATALOG_ID: 'test-catalog'
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
await expect( import( './configs.js' ) ).rejects.toThrow();
|
|
142
|
-
} );
|
|
143
|
-
|
|
144
|
-
it( 'should reject when TEMPORAL_ADDRESS is missing', async () => {
|
|
145
|
-
process.env = {
|
|
146
|
-
CATALOG_ID: 'test-catalog'
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
await expect( import( './configs.js' ) ).rejects.toThrow();
|
|
48
|
+
process.env.TEMPORAL_ADDRESS = originalEnv;
|
|
150
49
|
} );
|
|
151
50
|
} );
|
|
152
51
|
|
|
@@ -291,7 +190,7 @@ describe( 'configs', () => {
|
|
|
291
190
|
};
|
|
292
191
|
|
|
293
192
|
const { tracing } = await import( './configs.js' );
|
|
294
|
-
expect( tracing.enabled ).toBe(
|
|
193
|
+
expect( tracing.enabled ).toBe( true );
|
|
295
194
|
} );
|
|
296
195
|
|
|
297
196
|
it( 'should handle TRACING_ENABLED when false', async () => {
|
|
@@ -302,7 +201,7 @@ describe( 'configs', () => {
|
|
|
302
201
|
};
|
|
303
202
|
|
|
304
203
|
const { tracing } = await import( './configs.js' );
|
|
305
|
-
expect( tracing.enabled ).toBe(
|
|
204
|
+
expect( tracing.enabled ).toBe( false );
|
|
306
205
|
} );
|
|
307
206
|
|
|
308
207
|
it( 'should handle missing TRACING_ENABLED', async () => {
|
|
@@ -364,7 +263,7 @@ describe( 'configs', () => {
|
|
|
364
263
|
const { tracing } = await import( './configs.js' );
|
|
365
264
|
|
|
366
265
|
expect( tracing ).toEqual( {
|
|
367
|
-
enabled:
|
|
266
|
+
enabled: true
|
|
368
267
|
} );
|
|
369
268
|
} );
|
|
370
269
|
|
|
@@ -385,8 +284,8 @@ describe( 'configs', () => {
|
|
|
385
284
|
describe( 'Error Handling', () => {
|
|
386
285
|
it( 'should throw InvalidEnvVarsErrors for invalid configuration', async () => {
|
|
387
286
|
process.env = {
|
|
388
|
-
TEMPORAL_ADDRESS: '
|
|
389
|
-
CATALOG_ID: '
|
|
287
|
+
TEMPORAL_ADDRESS: 'localhost:7233',
|
|
288
|
+
CATALOG_ID: 'invalid!@#'
|
|
390
289
|
};
|
|
391
290
|
|
|
392
291
|
await expect( import( './configs.js' ) ).rejects.toThrow();
|
|
@@ -394,7 +293,7 @@ describe( 'configs', () => {
|
|
|
394
293
|
|
|
395
294
|
it( 'should handle multiple validation errors', async () => {
|
|
396
295
|
process.env = {
|
|
397
|
-
TEMPORAL_ADDRESS: '
|
|
296
|
+
TEMPORAL_ADDRESS: 'localhost:7233',
|
|
398
297
|
CATALOG_ID: 'invalid!@#'
|
|
399
298
|
};
|
|
400
299
|
|
|
@@ -474,7 +373,7 @@ describe( 'configs', () => {
|
|
|
474
373
|
expect( worker.catalogId ).toBe( 'prod.catalog@v1' );
|
|
475
374
|
expect( worker.taskQueue ).toBe( 'prod.catalog@v1' );
|
|
476
375
|
expect( api.authKey ).toBe( 'secure-auth-key' );
|
|
477
|
-
expect( tracing.enabled ).toBe(
|
|
376
|
+
expect( tracing.enabled ).toBe( true );
|
|
478
377
|
} );
|
|
479
378
|
} );
|
|
480
379
|
} );
|
|
@@ -48,8 +48,20 @@ export const sendWebhookPost = async ( { url, workflowId, payload } ) => {
|
|
|
48
48
|
*/
|
|
49
49
|
export const readTraceFile = async ( { workflowType, workflowId } ) => {
|
|
50
50
|
const dir = join( callerDir, 'logs', 'runs', workflowType );
|
|
51
|
+
|
|
52
|
+
if ( !existsSync( dir ) ) {
|
|
53
|
+
console.log( '[Core.ReadTraceFile]', 'Trace folder not found', dir );
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
|
|
51
57
|
const suffix = `-${workflowId}.raw`;
|
|
52
|
-
const
|
|
58
|
+
const matchingFile = readdirSync( dir ).find( f => f.endsWith( suffix ) );
|
|
59
|
+
|
|
60
|
+
if ( !matchingFile ) {
|
|
61
|
+
console.log( '[Core.ReadTraceFile]', 'Trace file not found', dir, suffix );
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
const file = join( dir, matchingFile );
|
|
66
|
+
return existsSync( file ) ? readFileSync( file, 'utf-8' ).split( '\n' ) : [];
|
|
55
67
|
};
|