@output.ai/core 0.0.16 → 0.1.1

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 (46) hide show
  1. package/README.md +16 -22
  2. package/package.json +19 -7
  3. package/src/consts.js +2 -11
  4. package/src/interface/evaluator.js +8 -4
  5. package/src/interface/step.js +1 -1
  6. package/src/interface/webhook.js +16 -4
  7. package/src/interface/workflow.js +28 -48
  8. package/src/internal_activities/index.js +3 -37
  9. package/src/tracing/index.d.ts +47 -0
  10. package/src/tracing/index.js +45 -0
  11. package/src/tracing/internal_interface.js +66 -0
  12. package/src/tracing/processors/local/index.js +50 -0
  13. package/src/tracing/processors/local/index.spec.js +67 -0
  14. package/src/tracing/processors/s3/index.js +51 -0
  15. package/src/tracing/processors/s3/index.spec.js +64 -0
  16. package/src/tracing/processors/s3/redis_client.js +19 -0
  17. package/src/tracing/processors/s3/redis_client.spec.js +50 -0
  18. package/src/tracing/processors/s3/s3_client.js +33 -0
  19. package/src/tracing/processors/s3/s3_client.spec.js +67 -0
  20. package/src/tracing/tools/build_trace_tree.js +76 -0
  21. package/src/tracing/tools/build_trace_tree.spec.js +99 -0
  22. package/src/tracing/tools/utils.js +28 -0
  23. package/src/tracing/tools/utils.spec.js +14 -0
  24. package/src/tracing/trace_engine.js +63 -0
  25. package/src/tracing/trace_engine.spec.js +91 -0
  26. package/src/utils.js +8 -0
  27. package/src/worker/catalog_workflow/index.js +2 -1
  28. package/src/worker/catalog_workflow/index.spec.js +6 -10
  29. package/src/worker/configs.js +24 -0
  30. package/src/worker/index.js +7 -8
  31. package/src/worker/interceptors/activity.js +15 -17
  32. package/src/worker/interceptors/workflow.js +18 -1
  33. package/src/worker/loader.js +40 -31
  34. package/src/worker/loader.spec.js +22 -29
  35. package/src/worker/loader_tools.js +63 -0
  36. package/src/worker/loader_tools.spec.js +85 -0
  37. package/src/worker/sinks.js +60 -10
  38. package/src/configs.js +0 -36
  39. package/src/configs.spec.js +0 -379
  40. package/src/worker/internal_utils.js +0 -60
  41. package/src/worker/internal_utils.spec.js +0 -134
  42. package/src/worker/tracer/index.js +0 -75
  43. package/src/worker/tracer/index.test.js +0 -102
  44. package/src/worker/tracer/tracer_tree.js +0 -85
  45. package/src/worker/tracer/tracer_tree.test.js +0 -115
  46. /package/src/{worker/async_storage.js → async_storage.js} +0 -0
@@ -1,379 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
-
3
- describe( 'configs', () => {
4
- const originalEnv = process.env;
5
-
6
- beforeEach( () => {
7
- vi.resetModules();
8
- process.env = { ...originalEnv };
9
- } );
10
-
11
- afterEach( () => {
12
- process.env = originalEnv;
13
- } );
14
-
15
- describe( 'Environment Variable Validation', () => {
16
- describe( 'TEMPORAL_ADDRESS', () => {
17
- it( 'should accept string addresses', async () => {
18
- process.env = {
19
- TEMPORAL_ADDRESS: 'localhost:7233',
20
- CATALOG_ID: 'test-catalog'
21
- };
22
-
23
- const { worker } = await import( './configs.js' );
24
- expect( worker.address ).toBe( 'localhost:7233' );
25
- } );
26
-
27
- it( 'should use default when omitted', async () => {
28
- process.env = {
29
- CATALOG_ID: 'test-catalog'
30
- };
31
-
32
- const { worker } = await import( './configs.js' );
33
- expect( worker.address ).toBe( 'localhost:7233' );
34
- } );
35
-
36
- it( 'should reject non-string values', async () => {
37
- process.env = {
38
- TEMPORAL_ADDRESS: '123',
39
- CATALOG_ID: 'test-catalog'
40
- };
41
-
42
- // Convert to number to test non-string
43
- const originalEnv = process.env.TEMPORAL_ADDRESS;
44
- process.env.TEMPORAL_ADDRESS = 123;
45
-
46
- await expect( import( './configs.js' ) ).rejects.toThrow();
47
-
48
- process.env.TEMPORAL_ADDRESS = originalEnv;
49
- } );
50
- } );
51
-
52
- describe( 'CATALOG_ID', () => {
53
- it( 'should accept valid catalog IDs with letters and numbers', async () => {
54
- process.env = {
55
- TEMPORAL_ADDRESS: 'http://localhost:7233',
56
- CATALOG_ID: 'catalog123'
57
- };
58
-
59
- const { worker } = await import( './configs.js' );
60
- expect( worker.catalogId ).toBe( 'catalog123' );
61
- expect( worker.taskQueue ).toBe( 'catalog123' );
62
- } );
63
-
64
- it( 'should accept catalog IDs with dots and hyphens', async () => {
65
- process.env = {
66
- TEMPORAL_ADDRESS: 'http://localhost:7233',
67
- CATALOG_ID: 'my.catalog-id'
68
- };
69
-
70
- const { worker } = await import( './configs.js' );
71
- expect( worker.catalogId ).toBe( 'my.catalog-id' );
72
- } );
73
-
74
- it( 'should accept catalog IDs with underscores', async () => {
75
- process.env = {
76
- TEMPORAL_ADDRESS: 'http://localhost:7233',
77
- CATALOG_ID: 'my_catalog_id'
78
- };
79
-
80
- const { worker } = await import( './configs.js' );
81
- expect( worker.catalogId ).toBe( 'my_catalog_id' );
82
- } );
83
-
84
- it( 'should accept catalog IDs with @ symbol', async () => {
85
- process.env = {
86
- TEMPORAL_ADDRESS: 'http://localhost:7233',
87
- CATALOG_ID: '@my-catalog'
88
- };
89
-
90
- const { worker } = await import( './configs.js' );
91
- expect( worker.catalogId ).toBe( '@my-catalog' );
92
- } );
93
-
94
- it( 'should reject catalog IDs with special characters', async () => {
95
- process.env = {
96
- TEMPORAL_ADDRESS: 'http://localhost:7233',
97
- CATALOG_ID: 'catalog!@#$'
98
- };
99
-
100
- await expect( import( './configs.js' ) ).rejects.toThrow();
101
- } );
102
-
103
- it( 'should reject when CATALOG_ID is missing', async () => {
104
- process.env = {
105
- TEMPORAL_ADDRESS: 'http://localhost:7233'
106
- };
107
-
108
- await expect( import( './configs.js' ) ).rejects.toThrow();
109
- } );
110
-
111
- it( 'should reject empty CATALOG_ID', async () => {
112
- process.env = {
113
- TEMPORAL_ADDRESS: 'http://localhost:7233',
114
- CATALOG_ID: ''
115
- };
116
-
117
- await expect( import( './configs.js' ) ).rejects.toThrow();
118
- } );
119
- } );
120
-
121
- describe( 'Optional Fields', () => {
122
- it( 'should use default namespace when TEMPORAL_NAMESPACE is not provided', async () => {
123
- process.env = {
124
- TEMPORAL_ADDRESS: 'http://localhost:7233',
125
- CATALOG_ID: 'test-catalog'
126
- };
127
-
128
- const { worker } = await import( './configs.js' );
129
- expect( worker.namespace ).toBe( 'default' );
130
- } );
131
-
132
- it( 'should use custom namespace when provided', async () => {
133
- process.env = {
134
- TEMPORAL_ADDRESS: 'http://localhost:7233',
135
- CATALOG_ID: 'test-catalog',
136
- TEMPORAL_NAMESPACE: 'custom-namespace'
137
- };
138
-
139
- const { worker } = await import( './configs.js' );
140
- expect( worker.namespace ).toBe( 'custom-namespace' );
141
- } );
142
-
143
- it( 'should handle TEMPORAL_API_KEY when provided', async () => {
144
- process.env = {
145
- TEMPORAL_ADDRESS: 'http://localhost:7233',
146
- CATALOG_ID: 'test-catalog',
147
- TEMPORAL_API_KEY: 'secret-api-key'
148
- };
149
-
150
- const { worker } = await import( './configs.js' );
151
- expect( worker.apiKey ).toBe( 'secret-api-key' );
152
- } );
153
-
154
- it( 'should handle missing TEMPORAL_API_KEY', async () => {
155
- process.env = {
156
- TEMPORAL_ADDRESS: 'http://localhost:7233',
157
- CATALOG_ID: 'test-catalog'
158
- };
159
-
160
- const { worker } = await import( './configs.js' );
161
- expect( worker.apiKey ).toBeUndefined();
162
- } );
163
-
164
- it( 'should handle API_AUTH_KEY when provided', async () => {
165
- process.env = {
166
- TEMPORAL_ADDRESS: 'http://localhost:7233',
167
- CATALOG_ID: 'test-catalog',
168
- API_AUTH_KEY: 'api-secret-key'
169
- };
170
-
171
- const { api } = await import( './configs.js' );
172
- expect( api.authKey ).toBe( 'api-secret-key' );
173
- } );
174
-
175
- it( 'should handle missing API_AUTH_KEY', async () => {
176
- process.env = {
177
- TEMPORAL_ADDRESS: 'http://localhost:7233',
178
- CATALOG_ID: 'test-catalog'
179
- };
180
-
181
- const { api } = await import( './configs.js' );
182
- expect( api.authKey ).toBeUndefined();
183
- } );
184
-
185
- it( 'should handle TRACING_ENABLED when true', async () => {
186
- process.env = {
187
- TEMPORAL_ADDRESS: 'http://localhost:7233',
188
- CATALOG_ID: 'test-catalog',
189
- TRACING_ENABLED: 'true'
190
- };
191
-
192
- const { tracing } = await import( './configs.js' );
193
- expect( tracing.enabled ).toBe( true );
194
- } );
195
-
196
- it( 'should handle TRACING_ENABLED when false', async () => {
197
- process.env = {
198
- TEMPORAL_ADDRESS: 'http://localhost:7233',
199
- CATALOG_ID: 'test-catalog',
200
- TRACING_ENABLED: 'false'
201
- };
202
-
203
- const { tracing } = await import( './configs.js' );
204
- expect( tracing.enabled ).toBe( false );
205
- } );
206
-
207
- it( 'should handle missing TRACING_ENABLED', async () => {
208
- process.env = {
209
- TEMPORAL_ADDRESS: 'http://localhost:7233',
210
- CATALOG_ID: 'test-catalog'
211
- };
212
-
213
- const { tracing } = await import( './configs.js' );
214
- expect( tracing.enabled ).toBeUndefined();
215
- } );
216
- } );
217
- } );
218
-
219
- describe( 'Exported Config Objects', () => {
220
- it( 'should export worker config with all properties', async () => {
221
- process.env = {
222
- TEMPORAL_ADDRESS: 'http://localhost:7233',
223
- CATALOG_ID: 'test-catalog',
224
- TEMPORAL_NAMESPACE: 'test-namespace',
225
- TEMPORAL_API_KEY: 'test-api-key'
226
- };
227
-
228
- const { worker } = await import( './configs.js' );
229
-
230
- expect( worker ).toEqual( {
231
- address: 'http://localhost:7233',
232
- apiKey: 'test-api-key',
233
- executionTimeout: '1m',
234
- maxActivities: 100,
235
- maxWorkflows: 100,
236
- namespace: 'test-namespace',
237
- taskQueue: 'test-catalog',
238
- catalogId: 'test-catalog'
239
- } );
240
- } );
241
-
242
- it( 'should export api config', async () => {
243
- process.env = {
244
- TEMPORAL_ADDRESS: 'http://localhost:7233',
245
- CATALOG_ID: 'test-catalog',
246
- API_AUTH_KEY: 'test-auth-key'
247
- };
248
-
249
- const { api } = await import( './configs.js' );
250
-
251
- expect( api ).toEqual( {
252
- authKey: 'test-auth-key'
253
- } );
254
- } );
255
-
256
- it( 'should export tracing config', async () => {
257
- process.env = {
258
- TEMPORAL_ADDRESS: 'http://localhost:7233',
259
- CATALOG_ID: 'test-catalog',
260
- TRACING_ENABLED: 'true'
261
- };
262
-
263
- const { tracing } = await import( './configs.js' );
264
-
265
- expect( tracing ).toEqual( {
266
- enabled: true
267
- } );
268
- } );
269
-
270
- it( 'should have correct static worker config values', async () => {
271
- process.env = {
272
- TEMPORAL_ADDRESS: 'http://localhost:7233',
273
- CATALOG_ID: 'test-catalog'
274
- };
275
-
276
- const { worker } = await import( './configs.js' );
277
-
278
- expect( worker.executionTimeout ).toBe( '1m' );
279
- expect( worker.maxActivities ).toBe( 100 );
280
- expect( worker.maxWorkflows ).toBe( 100 );
281
- } );
282
- } );
283
-
284
- describe( 'Error Handling', () => {
285
- it( 'should throw InvalidEnvVarsErrors for invalid configuration', async () => {
286
- process.env = {
287
- TEMPORAL_ADDRESS: 'localhost:7233',
288
- CATALOG_ID: 'invalid!@#'
289
- };
290
-
291
- await expect( import( './configs.js' ) ).rejects.toThrow();
292
- } );
293
-
294
- it( 'should handle multiple validation errors', async () => {
295
- process.env = {
296
- TEMPORAL_ADDRESS: 'localhost:7233',
297
- CATALOG_ID: 'invalid!@#'
298
- };
299
-
300
- await expect( import( './configs.js' ) ).rejects.toThrow();
301
- } );
302
- } );
303
-
304
- describe( 'Edge Cases', () => {
305
- it( 'should handle environment variables with spaces', async () => {
306
- process.env = {
307
- TEMPORAL_ADDRESS: 'http://localhost:7233',
308
- CATALOG_ID: 'test-catalog',
309
- TEMPORAL_NAMESPACE: ' custom-namespace '
310
- };
311
-
312
- const { worker } = await import( './configs.js' );
313
- expect( worker.namespace ).toBe( ' custom-namespace ' );
314
- } );
315
-
316
- it( 'should handle very long catalog IDs', async () => {
317
- process.env = {
318
- TEMPORAL_ADDRESS: 'http://localhost:7233',
319
- CATALOG_ID: 'a'.repeat( 100 )
320
- };
321
-
322
- const { worker } = await import( './configs.js' );
323
- expect( worker.catalogId ).toBe( 'a'.repeat( 100 ) );
324
- } );
325
-
326
- it( 'should handle URLs with ports outside typical range', async () => {
327
- process.env = {
328
- TEMPORAL_ADDRESS: 'http://localhost:65535',
329
- CATALOG_ID: 'test-catalog'
330
- };
331
-
332
- const { worker } = await import( './configs.js' );
333
- expect( worker.address ).toBe( 'http://localhost:65535' );
334
- } );
335
-
336
- it( 'should handle container names with numbers', async () => {
337
- process.env = {
338
- TEMPORAL_ADDRESS: 'temporal123:7233',
339
- CATALOG_ID: 'test-catalog'
340
- };
341
-
342
- const { worker } = await import( './configs.js' );
343
- expect( worker.address ).toBe( 'temporal123:7233' );
344
- } );
345
-
346
- it( 'should handle mixed case in catalog ID', async () => {
347
- process.env = {
348
- TEMPORAL_ADDRESS: 'http://localhost:7233',
349
- CATALOG_ID: 'Test.Catalog-ID_123'
350
- };
351
-
352
- const { worker } = await import( './configs.js' );
353
- expect( worker.catalogId ).toBe( 'Test.Catalog-ID_123' );
354
- } );
355
- } );
356
-
357
- describe( 'Complete Valid Configuration', () => {
358
- it( 'should handle a complete valid configuration with all optional fields', async () => {
359
- process.env = {
360
- TEMPORAL_ADDRESS: 'https://temporal.cloud.example.com',
361
- TEMPORAL_NAMESPACE: 'production',
362
- TEMPORAL_API_KEY: 'prod-api-key-123',
363
- CATALOG_ID: 'prod.catalog@v1',
364
- API_AUTH_KEY: 'secure-auth-key',
365
- TRACING_ENABLED: 'true'
366
- };
367
-
368
- const { worker, api, tracing } = await import( './configs.js' );
369
-
370
- expect( worker.address ).toBe( 'https://temporal.cloud.example.com' );
371
- expect( worker.namespace ).toBe( 'production' );
372
- expect( worker.apiKey ).toBe( 'prod-api-key-123' );
373
- expect( worker.catalogId ).toBe( 'prod.catalog@v1' );
374
- expect( worker.taskQueue ).toBe( 'prod.catalog@v1' );
375
- expect( api.authKey ).toBe( 'secure-auth-key' );
376
- expect( tracing.enabled ).toBe( true );
377
- } );
378
- } );
379
- } );
@@ -1,60 +0,0 @@
1
- /*
2
- * These tools cant be used in sandbox environment!!!
3
- */
4
- import { resolve } from 'path';
5
- import { pathToFileURL } from 'url';
6
- import { METADATA_ACCESS_SYMBOL } from '#consts';
7
- import { writeFileSync, existsSync, readdirSync, mkdirSync } from 'fs';
8
-
9
- /**
10
- * Recursive traverse directories looking for files with given name,
11
- * For each found file, return its path, pathname and URI
12
- *
13
- * @param {string} path - The path to scan
14
- * @param {string[]} filenames - The filenames to look for
15
- * @returns {string[{}]} An array containing an object with path, pathname and URI for each file found
16
- * */
17
- export function recursiveNavigateWhileCollecting( path, filenames, collection = [], ignoreDirNames = [ 'vendor', 'node_modules' ] ) {
18
- for ( const entry of readdirSync( path, { withFileTypes: true } ) ) {
19
- if ( ignoreDirNames.includes( entry.name ) ) {
20
- continue;
21
- }
22
-
23
- const pathname = resolve( path, entry.name );
24
- if ( entry.isDirectory() ) {
25
- recursiveNavigateWhileCollecting( pathname, filenames, collection );
26
- } else if ( filenames.includes( entry.name ) ) {
27
- collection.push( { pathname, path, url: pathToFileURL( pathname ).href } );
28
- }
29
- }
30
-
31
- return collection;
32
- };
33
-
34
- /**
35
- * For each path, dynamic import it, and for each exported component with metadata (step, workflow), yields it.
36
- * @param {string[]} paths - Paths of the files to import
37
- */
38
- export async function *iteratorOverImportedComponents( paths ) {
39
- for ( const { url, path, pathname } of paths ) {
40
- const imported = await import( url );
41
- for ( const component of Object.values( imported ) ) {
42
- const metadata = component[METADATA_ACCESS_SYMBOL];
43
- if ( !metadata ) {
44
- continue;
45
- }
46
- yield { component, metadata, path, pathname };
47
- }
48
- }
49
- };
50
-
51
- /**
52
- * Write a file using the same signature as Node's FS writeFileSync, but recursively creates the necessary directories in the path.
53
- */
54
- export function writeFileOnLocationSync( path, content ) {
55
- const targetDir = path.split( '/' ).slice( 0, -1 ).join( '/' );
56
- if ( targetDir && !existsSync( targetDir ) ) {
57
- mkdirSync( targetDir, { recursive: true } );
58
- }
59
- writeFileSync( path, content, 'utf-8' );
60
- };
@@ -1,134 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, existsSync } from 'node:fs';
3
- import { join, resolve } from 'node:path';
4
- import { tmpdir } from 'node:os';
5
- import { pathToFileURL } from 'node:url';
6
- import { recursiveNavigateWhileCollecting, iteratorOverImportedComponents, writeFileOnLocationSync } from './internal_utils.js';
7
-
8
- function makeTmpRoot( prefix ) {
9
- return mkdtempSync( join( tmpdir(), prefix ) );
10
- }
11
-
12
- describe( '.recursiveNavigateWhileCollecting', () => {
13
- it( 'collects matching files recursively (happy path)', () => {
14
- const root = makeTmpRoot( 'nsu-happy-' );
15
- const target = 'target.txt';
16
-
17
- // layout:
18
- // root/target.txt
19
- // root/a/target.txt
20
- // root/b/c/target.txt
21
- mkdirSync( join( root, 'a' ), { recursive: true } );
22
- mkdirSync( join( root, 'b', 'c' ), { recursive: true } );
23
- writeFileSync( join( root, target ), 'root' );
24
- writeFileSync( join( root, 'a', target ), 'a' );
25
- writeFileSync( join( root, 'b', 'c', target ), 'bc' );
26
-
27
- const results = recursiveNavigateWhileCollecting( root, [ target ] );
28
-
29
- expect( results.length ).toBe( 3 );
30
- for ( const { pathname, path, url } of results ) {
31
- expect( url ).toBe( pathToFileURL( pathname ).href );
32
- expect( resolve( path, target ) ).toBe( pathname );
33
- }
34
-
35
- rmSync( root, { recursive: true, force: true } );
36
- } );
37
-
38
- it( 'skips files inside ignored directories (ignoreDirNames)', () => {
39
- const root = makeTmpRoot( 'nsu-ignore-' );
40
- const target = 'target.txt';
41
-
42
- // layout:
43
- // root/node_modules/target.txt (ignored)
44
- // root/vendor/target.txt (ignored)
45
- // root/ok/target.txt (collected)
46
- mkdirSync( join( root, 'node_modules' ), { recursive: true } );
47
- mkdirSync( join( root, 'vendor' ), { recursive: true } );
48
- mkdirSync( join( root, 'ok' ), { recursive: true } );
49
- writeFileSync( join( root, 'node_modules', target ), 'nm' );
50
- writeFileSync( join( root, 'vendor', target ), 'v' );
51
- writeFileSync( join( root, 'ok', target ), 'ok' );
52
-
53
- const results = recursiveNavigateWhileCollecting( root, [ target ] );
54
-
55
- expect( results.length ).toBe( 1 );
56
- expect( results[0].pathname ).toBe( join( root, 'ok', target ) );
57
- expect( results[0].path ).toBe( join( root, 'ok' ) );
58
- expect( results[0].url ).toBe( pathToFileURL( results[0].pathname ).href );
59
-
60
- rmSync( root, { recursive: true, force: true } );
61
- } );
62
- } );
63
-
64
- describe( '.iteratorOverImportedComponents', () => {
65
- it( 'imports modules and yields metadata from exports tagged with METADATA_ACCESS_SYMBOL', async () => {
66
- const root = join( process.cwd(), 'sdk/core/temp_test_modules', `meta-${Date.now()}` );
67
- mkdirSync( root, { recursive: true } );
68
- const file = join( root, 'meta.module.js' );
69
- writeFileSync( file, [
70
- 'import { METADATA_ACCESS_SYMBOL } from \"#consts\";',
71
- 'export const StepA = () => {};',
72
- 'StepA[METADATA_ACCESS_SYMBOL] = { kind: \"step\", name: \"a\" };',
73
- 'export const FlowB = () => {};',
74
- 'FlowB[METADATA_ACCESS_SYMBOL] = { kind: \"workflow\", name: \"b\" };'
75
- ].join( '\n' ) );
76
-
77
- const paths = recursiveNavigateWhileCollecting( root, [ 'meta.module.js' ] );
78
- const collected = [];
79
- for await ( const m of iteratorOverImportedComponents( paths ) ) {
80
- collected.push( m );
81
- }
82
-
83
- expect( collected.length ).toBe( 2 );
84
- expect( collected.map( m => m.metadata.name ).sort() ).toEqual( [ 'a', 'b' ] );
85
- expect( collected.map( m => m.metadata.kind ).sort() ).toEqual( [ 'step', 'workflow' ] );
86
- for ( const m of collected ) {
87
- expect( m.pathname ).toBe( file );
88
- expect( m.path ).toBe( root );
89
- expect( typeof m.component ).toBe( 'function' );
90
- }
91
-
92
- rmSync( root, { recursive: true, force: true } );
93
- } );
94
-
95
- it( 'ignores exports without metadata symbol', async () => {
96
- const root = join( process.cwd(), 'sdk/core/temp_test_modules', `meta-${Date.now()}-nometa` );
97
- mkdirSync( root, { recursive: true } );
98
- const file = join( root, 'meta.module.js' );
99
- writeFileSync( file, [
100
- 'export const Plain = () => {};',
101
- 'export const AlsoPlain = {}'
102
- ].join( '\n' ) );
103
-
104
- const paths = recursiveNavigateWhileCollecting( root, [ 'meta.module.js' ] );
105
- const collected = [];
106
- for await ( const m of iteratorOverImportedComponents( paths ) ) {
107
- collected.push( m );
108
- }
109
-
110
- expect( collected.length ).toBe( 0 );
111
- rmSync( root, { recursive: true, force: true } );
112
- } );
113
- } );
114
-
115
- describe( '.writeFileOnLocationSync', () => {
116
- it( 'creates missing directories and writes file', () => {
117
- const root = makeTmpRoot( 'nsu-write-' );
118
- const nested = join( root, 'a', 'b', 'c.txt' );
119
- writeFileOnLocationSync( nested, 'hello' );
120
- expect( existsSync( join( root, 'a', 'b' ) ) ).toBe( true );
121
- expect( readFileSync( nested, 'utf-8' ) ).toBe( 'hello' );
122
- rmSync( root, { recursive: true, force: true } );
123
- } );
124
-
125
- it( 'overwrites existing content', () => {
126
- const root = makeTmpRoot( 'nsu-write2-' );
127
- const file = join( root, 'x', 'y.txt' );
128
- mkdirSync( join( root, 'x' ), { recursive: true } );
129
- writeFileSync( file, 'old' );
130
- writeFileOnLocationSync( file, 'new' );
131
- expect( readFileSync( file, 'utf-8' ) ).toBe( 'new' );
132
- rmSync( root, { recursive: true, force: true } );
133
- } );
134
- } );
@@ -1,75 +0,0 @@
1
- import { Storage } from '../async_storage.js';
2
- import { mkdirSync, existsSync, readdirSync, appendFileSync } from 'node:fs';
3
- import { join } from 'path';
4
- import { EOL } from 'os';
5
- import { buildLogTree } from './tracer_tree.js';
6
- import { tracing as tracingConfig } from '#configs';
7
-
8
- const callerDir = process.argv[2];
9
-
10
- /**
11
- * Appends new information to a file
12
- *
13
- * Information has to be a JSON
14
- *
15
- * File is encoded in utf-8
16
- *
17
- * @param {string} path - The full filename
18
- * @param {object} json - The content
19
- */
20
- const flushEntry = ( path, json ) => appendFileSync( path, JSON.stringify( json ) + EOL, 'utf-8' );
21
-
22
- /**
23
- * Add an event to the execution trace file.
24
- *
25
- * Events normally are the result of an operation, either a function call or an IO.
26
- *
27
- * @param {object} options
28
- * @param {string} options.lib - The macro part of the platform that triggered the event
29
- * @param {string} options.event - The name of the event
30
- * @param {any} [options.input] - The input of the operation
31
- * @param {any} [options.output] - The output of the operation
32
- */
33
- export function trace( { lib, event, input = undefined, output = undefined } ) {
34
- const now = Date.now();
35
-
36
- if ( !tracingConfig.enabled ) {
37
- return;
38
- }
39
-
40
- const {
41
- activityId: stepId,
42
- activityType: stepName,
43
- workflowId,
44
- workflowType,
45
- workflowPath,
46
- parentWorkflowId,
47
- rootWorkflowId,
48
- rootWorkflowType
49
- } = Storage.load();
50
-
51
- const entry = { event, input, lib, output, parentWorkflowId, stepId, stepName, timestamp: now, workflowId, workflowPath, workflowType };
52
-
53
- // test for rootWorkflow to append to the same file as the parent/grandparent
54
- const outputDir = join( callerDir, 'logs', 'runs', rootWorkflowType ?? workflowType );
55
- if ( !existsSync( outputDir ) ) {
56
- mkdirSync( outputDir, { recursive: true } );
57
- }
58
-
59
- const suffix = `-${rootWorkflowId ?? workflowId}.raw`;
60
- const logFile = readdirSync( outputDir ).find( f => f.endsWith( suffix ) ) ?? `${new Date( now ).toISOString()}-${suffix}`;
61
- const logPath = join( outputDir, logFile );
62
-
63
- flushEntry( logPath, entry );
64
- buildLogTree( logPath );
65
- };
66
-
67
- /**
68
- * Setup the global tracer function, so it is available to be used by other libraries
69
- *
70
- * It will be situated in the global object, under Symbol.for('__trace')
71
- *
72
- * @returns {object} The assigned globalThis
73
- */
74
- export const setupGlobalTracer = () =>
75
- Object.defineProperty( globalThis, Symbol.for( '__trace' ), { value: trace, writable: false, enumerable: false, configurable: false } );