@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@output.ai/core",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "The core module of the output framework",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
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.union( [
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.enum( [ 'true', 'false' ] ).optional()
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( JSON.stringify( error.format(), null, 2 ) );
16
+ throw new InvalidEnvVarsErrors( z.prettifyError( error ) );
59
17
  }
60
18
 
61
19
  export const worker = {
@@ -14,139 +14,38 @@ describe( 'configs', () => {
14
14
 
15
15
  describe( 'Environment Variable Validation', () => {
16
16
  describe( 'TEMPORAL_ADDRESS', () => {
17
- it( 'should accept valid http URLs', async () => {
17
+ it( 'should accept string addresses', async () => {
18
18
  process.env = {
19
- TEMPORAL_ADDRESS: 'http://localhost:7233',
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( '[2001:db8::1]:7233' );
24
+ expect( worker.address ).toBe( 'localhost:7233' );
95
25
  } );
96
26
 
97
- it( 'should accept IPv6 addresses with HTTP', async () => {
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( 'http://[2001:db8::1]:7233' );
33
+ expect( worker.address ).toBe( 'localhost:7233' );
105
34
  } );
106
35
 
107
- it( 'should accept IPv6 addresses with HTTPS', async () => {
36
+ it( 'should reject non-string values', async () => {
108
37
  process.env = {
109
- TEMPORAL_ADDRESS: 'https://[::1]:7233',
38
+ TEMPORAL_ADDRESS: '123',
110
39
  CATALOG_ID: 'test-catalog'
111
40
  };
112
41
 
113
- const { worker } = await import( './configs.js' );
114
- expect( worker.address ).toBe( 'https://[::1]:7233' );
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
- it( 'should reject addresses without ports in container format', async () => {
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( 'true' );
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( 'false' );
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: 'true'
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: 'invalid',
389
- CATALOG_ID: 'test-catalog'
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: 'invalid',
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( 'true' );
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 file = join( dir, readdirSync( dir ).find( f => f.endsWith( suffix ) ) );
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
- return existsSync( file ) ? readFileSync( file, 'utf-8' ).split( '\n' ) : null;
65
+ const file = join( dir, matchingFile );
66
+ return existsSync( file ) ? readFileSync( file, 'utf-8' ).split( '\n' ) : [];
55
67
  };