@output.ai/core 0.2.4 → 0.3.0-dev.pr263-8f8e94a
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/consts.js +1 -1
- package/src/interface/workflow.js +3 -4
- package/src/worker/index.js +1 -1
- package/src/worker/loader.js +58 -17
- package/src/worker/loader.spec.js +106 -5
- package/src/worker/loader_tools.js +80 -11
- package/src/worker/loader_tools.spec.js +33 -4
- package/src/worker/webpack_loaders/consts.js +0 -1
- package/src/worker/webpack_loaders/tools.js +70 -21
- package/src/worker/webpack_loaders/tools.spec.js +65 -14
- package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +17 -11
- package/src/worker/webpack_loaders/workflow_validator/index.mjs +109 -27
- package/src/worker/webpack_loaders/workflow_validator/index.spec.js +429 -62
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
|
2
|
+
import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import validatorLoader from './index.mjs';
|
|
@@ -17,16 +17,14 @@ function runLoader( filename, source ) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
describe( 'workflow_validator loader', () => {
|
|
20
|
-
it( 'workflow.js: allows imports from steps/
|
|
20
|
+
it( 'workflow.js: allows imports from steps/evaluators/workflow', async () => {
|
|
21
21
|
const dir = mkdtempSync( join( tmpdir(), 'wf-allow-' ) );
|
|
22
22
|
writeFileSync( join( dir, 'steps.js' ), 'export const S = step({ name: "s" })\n' );
|
|
23
|
-
writeFileSync( join( dir, 'shared_steps.js' ), 'export const SS = step({ name: "ss" })\n' );
|
|
24
23
|
writeFileSync( join( dir, 'evaluators.js' ), 'export const E = evaluator({ name: "e" })\n' );
|
|
25
24
|
writeFileSync( join( dir, 'workflow.js' ), 'export const W = workflow({ name: "w" })\n' );
|
|
26
25
|
|
|
27
26
|
const src = [
|
|
28
27
|
'import { S } from "./steps.js";',
|
|
29
|
-
'import { SS } from "./shared_steps.js";',
|
|
30
28
|
'import { E } from "./evaluators.js";',
|
|
31
29
|
'import { W } from "./workflow.js";',
|
|
32
30
|
'const x = 1;'
|
|
@@ -36,6 +34,13 @@ describe( 'workflow_validator loader', () => {
|
|
|
36
34
|
rmSync( dir, { recursive: true, force: true } );
|
|
37
35
|
} );
|
|
38
36
|
|
|
37
|
+
it( 'workflow.js: allows imports from any non-component file', async () => {
|
|
38
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-any-allow-' ) );
|
|
39
|
+
const src = 'import x from "./foo.js";';
|
|
40
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
41
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
42
|
+
} );
|
|
43
|
+
|
|
39
44
|
it( 'workflow.js: allows imports from @output.ai/core and local_core', async () => {
|
|
40
45
|
const dir = mkdtempSync( join( tmpdir(), 'wf-allow-external-' ) );
|
|
41
46
|
const src = [
|
|
@@ -47,7 +52,7 @@ describe( 'workflow_validator loader', () => {
|
|
|
47
52
|
rmSync( dir, { recursive: true, force: true } );
|
|
48
53
|
} );
|
|
49
54
|
|
|
50
|
-
it( 'steps.js: rejects importing steps/
|
|
55
|
+
it( 'steps.js: rejects importing steps/evaluators/workflow', async () => {
|
|
51
56
|
const dir = mkdtempSync( join( tmpdir(), 'steps-reject-' ) );
|
|
52
57
|
const src = 'import { S } from "./steps.js";';
|
|
53
58
|
await expect( runLoader( join( dir, 'steps.js' ), src ) ).rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
@@ -61,44 +66,34 @@ describe( 'workflow_validator loader', () => {
|
|
|
61
66
|
rmSync( dir, { recursive: true, force: true } );
|
|
62
67
|
} );
|
|
63
68
|
|
|
64
|
-
it( 'evaluators.js: rejects importing evaluators/steps/
|
|
69
|
+
it( 'evaluators.js: rejects importing evaluators/steps/workflow', async () => {
|
|
65
70
|
const dir = mkdtempSync( join( tmpdir(), 'evals-reject-' ) );
|
|
66
71
|
const src = 'import { E } from "./evaluators.js";';
|
|
67
72
|
await expect( runLoader( join( dir, 'evaluators.js' ), src ) ).rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
68
73
|
rmSync( dir, { recursive: true, force: true } );
|
|
69
74
|
} );
|
|
70
75
|
|
|
71
|
-
it( 'steps.js: rejects calling another step
|
|
76
|
+
it( 'steps.js: rejects calling another step inside fn', async () => {
|
|
72
77
|
const dir = mkdtempSync( join( tmpdir(), 'steps-call-reject-' ) );
|
|
78
|
+
// Can only test same-type components since cross-type declarations are now blocked by instantiation validation
|
|
73
79
|
const src = [
|
|
74
80
|
'const A = step({ name: "a" });',
|
|
75
81
|
'const B = step({ name: "b" });',
|
|
76
82
|
'const obj = { fn: function() { B(); } };'
|
|
77
83
|
].join( '\n' );
|
|
78
84
|
await expect( runLoader( join( dir, 'steps.js' ), src ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
79
|
-
|
|
80
|
-
const src2 = [
|
|
81
|
-
'const E = evaluator({ name: "e" });',
|
|
82
|
-
'const obj = { fn: () => { E(); } };'
|
|
83
|
-
].join( '\n' );
|
|
84
|
-
await expect( runLoader( join( dir, 'steps.js' ), src2 ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
85
85
|
rmSync( dir, { recursive: true, force: true } );
|
|
86
86
|
} );
|
|
87
87
|
|
|
88
|
-
it( 'evaluators.js: rejects calling another evaluator
|
|
88
|
+
it( 'evaluators.js: rejects calling another evaluator inside fn', async () => {
|
|
89
89
|
const dir = mkdtempSync( join( tmpdir(), 'evals-call-reject-' ) );
|
|
90
|
+
// Can only test same-type components since cross-type declarations are now blocked by instantiation validation
|
|
90
91
|
const src = [
|
|
91
92
|
'const E1 = evaluator({ name: "e1" });',
|
|
92
93
|
'const E2 = evaluator({ name: "e2" });',
|
|
93
94
|
'const obj = { fn: function() { E2(); } };'
|
|
94
95
|
].join( '\n' );
|
|
95
96
|
await expect( runLoader( join( dir, 'evaluators.js' ), src ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
96
|
-
|
|
97
|
-
const src2 = [
|
|
98
|
-
'const S = step({ name: "s" });',
|
|
99
|
-
'const obj = { fn: () => { S(); } };'
|
|
100
|
-
].join( '\n' );
|
|
101
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), src2 ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
102
97
|
rmSync( dir, { recursive: true, force: true } );
|
|
103
98
|
} );
|
|
104
99
|
|
|
@@ -118,10 +113,25 @@ describe( 'workflow_validator loader', () => {
|
|
|
118
113
|
rmSync( dir, { recursive: true, force: true } );
|
|
119
114
|
} );
|
|
120
115
|
|
|
121
|
-
it( '
|
|
116
|
+
it( 'workflow.js: allows require from steps/evaluators/workflow; allows other require', async () => {
|
|
117
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-req-' ) );
|
|
118
|
+
writeFileSync( join( dir, 'steps.js' ), 'export const S = step({ name: "s" })\n' );
|
|
119
|
+
writeFileSync( join( dir, 'evaluators.js' ), 'export const E = evaluator({ name: "e" })\n' );
|
|
120
|
+
writeFileSync( join( dir, 'workflow.js' ), 'export default workflow({ name: "w" })\n' );
|
|
121
|
+
const ok = [
|
|
122
|
+
'const { S } = require("./steps.js");',
|
|
123
|
+
'const { E } = require("./evaluators.js");',
|
|
124
|
+
'const W = require("./workflow.js");'
|
|
125
|
+
].join( '\n' );
|
|
126
|
+
await expect( runLoader( join( dir, 'workflow.js' ), ok ) ).resolves.toBeTruthy();
|
|
127
|
+
// Also allow random files (not rejected anymore)
|
|
128
|
+
const ok2 = 'const X = require("./random_file.js");';
|
|
129
|
+
await expect( runLoader( join( dir, 'workflow.js' ), ok2 ) ).resolves.toBeTruthy();
|
|
130
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
131
|
+
} );
|
|
132
|
+
|
|
133
|
+
it( 'steps.js: rejects importing evaluators/workflow variants', async () => {
|
|
122
134
|
const dir = mkdtempSync( join( tmpdir(), 'steps-reject2-' ) );
|
|
123
|
-
await expect( runLoader( join( dir, 'steps.js' ), 'import { SS } from "./shared_steps.js";' ) )
|
|
124
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
125
135
|
await expect( runLoader( join( dir, 'steps.js' ), 'import { E } from "./evaluators.js";' ) )
|
|
126
136
|
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
127
137
|
await expect( runLoader( join( dir, 'steps.js' ), 'import WF from "./workflow.js";' ) )
|
|
@@ -129,12 +139,10 @@ describe( 'workflow_validator loader', () => {
|
|
|
129
139
|
rmSync( dir, { recursive: true, force: true } );
|
|
130
140
|
} );
|
|
131
141
|
|
|
132
|
-
it( 'evaluators.js: rejects importing steps/
|
|
142
|
+
it( 'evaluators.js: rejects importing steps/workflow variants', async () => {
|
|
133
143
|
const dir = mkdtempSync( join( tmpdir(), 'evals-reject2-' ) );
|
|
134
144
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'import { S } from "./steps.js";' ) )
|
|
135
145
|
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
136
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), 'import { SS } from "./shared_steps.js";' ) )
|
|
137
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
138
146
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'import WF from "./workflow.js";' ) )
|
|
139
147
|
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
140
148
|
rmSync( dir, { recursive: true, force: true } );
|
|
@@ -149,48 +157,29 @@ describe( 'workflow_validator loader', () => {
|
|
|
149
157
|
rmSync( dir, { recursive: true, force: true } );
|
|
150
158
|
} );
|
|
151
159
|
|
|
152
|
-
it( '
|
|
153
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
await expect( runLoader( join( dir, '
|
|
157
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in shared_steps\.js/ );
|
|
158
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), 'import { E } from "./evaluators.js";' ) )
|
|
159
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in shared_steps\.js/ );
|
|
160
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), 'import WF from "./workflow.js";' ) )
|
|
161
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in shared_steps\.js/ );
|
|
160
|
+
it( 'workflow.js: allows importing ./types.js and bare types', async () => {
|
|
161
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-types-allow-' ) );
|
|
162
|
+
writeFileSync( join( dir, 'types.js' ), 'export const T = {}\n' );
|
|
163
|
+
const src1 = 'import { T } from "./types.js";';
|
|
164
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src1 ) ).resolves.toBeTruthy();
|
|
162
165
|
rmSync( dir, { recursive: true, force: true } );
|
|
163
166
|
} );
|
|
164
167
|
|
|
165
|
-
it( '
|
|
166
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const src2 = [
|
|
174
|
-
'const E = evaluator({ name: "e" });',
|
|
175
|
-
'const obj = { fn: () => { E(); } };'
|
|
176
|
-
].join( '\n' );
|
|
177
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), src2 ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
178
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
179
|
-
} );
|
|
180
|
-
|
|
181
|
-
it( 'shared_steps.js: top-level calls outside fn are allowed', async () => {
|
|
182
|
-
const dir = mkdtempSync( join( tmpdir(), 'shared-toplevel-allowed-' ) );
|
|
183
|
-
const src = [ 'const A = step({ name: "a" });', 'A();' ].join( '\n' );
|
|
184
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), src ) ).resolves.toBeTruthy();
|
|
168
|
+
it( 'workflow.js: allows importing any file (consts/constants/vars/variables/random)', async () => {
|
|
169
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-extra-allow-' ) );
|
|
170
|
+
const bases = [ 'consts', 'constants', 'vars', 'variables', 'random', 'anything' ];
|
|
171
|
+
for ( const base of bases ) {
|
|
172
|
+
writeFileSync( join( dir, `${base}.js` ), 'export const X = 1\n' );
|
|
173
|
+
const src = `import x from "./${base}.js";`;
|
|
174
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
175
|
+
}
|
|
185
176
|
rmSync( dir, { recursive: true, force: true } );
|
|
186
177
|
} );
|
|
187
178
|
|
|
188
|
-
it( 'steps.js: rejects require of steps/
|
|
179
|
+
it( 'steps.js: rejects require of steps/evaluators/workflow; allows other require', async () => {
|
|
189
180
|
const dir = mkdtempSync( join( tmpdir(), 'steps-require-' ) );
|
|
190
181
|
await expect( runLoader( join( dir, 'steps.js' ), 'const { S } = require("./steps.js");' ) )
|
|
191
182
|
.rejects.toThrow( /Invalid (require|dependency) in steps\.js/ );
|
|
192
|
-
await expect( runLoader( join( dir, 'steps.js' ), 'const { SS } = require("./shared_steps.js");' ) )
|
|
193
|
-
.rejects.toThrow( /Invalid (require|dependency) in steps\.js/ );
|
|
194
183
|
await expect( runLoader( join( dir, 'steps.js' ), 'const { E } = require("./evaluators.js");' ) )
|
|
195
184
|
.rejects.toThrow( /Invalid (require|dependency) in steps\.js/ );
|
|
196
185
|
await expect( runLoader( join( dir, 'steps.js' ), 'const W = require("./workflow.js");' ) )
|
|
@@ -200,16 +189,394 @@ describe( 'workflow_validator loader', () => {
|
|
|
200
189
|
rmSync( dir, { recursive: true, force: true } );
|
|
201
190
|
} );
|
|
202
191
|
|
|
203
|
-
it( 'evaluators.js: rejects require of steps/
|
|
192
|
+
it( 'evaluators.js: rejects require of steps/workflow; allows other require', async () => {
|
|
204
193
|
const dir = mkdtempSync( join( tmpdir(), 'evals-require-' ) );
|
|
205
194
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'const { S } = require("./steps.js");' ) )
|
|
206
195
|
.rejects.toThrow( /Invalid (require|dependency) in evaluators\.js/ );
|
|
207
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), 'const { SS } = require("./shared_steps.js");' ) )
|
|
208
|
-
.rejects.toThrow( /Invalid (require|dependency) in evaluators\.js/ );
|
|
209
196
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'const W = require("./workflow.js");' ) )
|
|
210
197
|
.rejects.toThrow( /Invalid (require|dependency) in evaluators\.js/ );
|
|
211
198
|
const ok = 'const util = require("./util.js");';
|
|
212
199
|
await expect( runLoader( join( dir, 'evaluators.js' ), ok ) ).resolves.toBeTruthy();
|
|
213
200
|
rmSync( dir, { recursive: true, force: true } );
|
|
214
201
|
} );
|
|
202
|
+
|
|
203
|
+
// =====================================================
|
|
204
|
+
// Folder-based utilities and shared directory
|
|
205
|
+
// =====================================================
|
|
206
|
+
|
|
207
|
+
describe( 'folder-based utilities', () => {
|
|
208
|
+
it( 'workflow.js: allows imports from ./utils/helper.js (folder-based utils)', async () => {
|
|
209
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-folder-utils-' ) );
|
|
210
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
211
|
+
writeFileSync( join( dir, 'utils', 'helper.js' ), 'export const helper = () => 1;\n' );
|
|
212
|
+
const src = 'import { helper } from "./utils/helper.js";';
|
|
213
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
214
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
215
|
+
} );
|
|
216
|
+
|
|
217
|
+
it( 'workflow.js: allows imports from ./clients/redis.js (folder-based clients)', async () => {
|
|
218
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-folder-clients-' ) );
|
|
219
|
+
mkdirSync( join( dir, 'clients' ) );
|
|
220
|
+
writeFileSync( join( dir, 'clients', 'redis.js' ), 'export const client = {};\n' );
|
|
221
|
+
const src = 'import { client } from "./clients/redis.js";';
|
|
222
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
223
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
224
|
+
} );
|
|
225
|
+
|
|
226
|
+
it( 'steps/fetch_data.js: allows imports from ../utils/http.js', async () => {
|
|
227
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-folder-utils-' ) );
|
|
228
|
+
mkdirSync( join( dir, 'steps' ) );
|
|
229
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
230
|
+
writeFileSync( join( dir, 'utils', 'http.js' ), 'export const get = () => {};\n' );
|
|
231
|
+
const src = 'import { get } from "../utils/http.js";';
|
|
232
|
+
await expect( runLoader( join( dir, 'steps', 'fetch_data.js' ), src ) ).resolves.toBeTruthy();
|
|
233
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
234
|
+
} );
|
|
235
|
+
|
|
236
|
+
it( 'evaluators/quality.js: allows imports from ../utils/metrics.js', async () => {
|
|
237
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-folder-utils-' ) );
|
|
238
|
+
mkdirSync( join( dir, 'evaluators' ) );
|
|
239
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
240
|
+
writeFileSync( join( dir, 'utils', 'metrics.js' ), 'export const compute = () => {};\n' );
|
|
241
|
+
const src = 'import { compute } from "../utils/metrics.js";';
|
|
242
|
+
await expect( runLoader( join( dir, 'evaluators', 'quality.js' ), src ) ).resolves.toBeTruthy();
|
|
243
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
244
|
+
} );
|
|
245
|
+
} );
|
|
246
|
+
|
|
247
|
+
describe( 'shared directory imports', () => {
|
|
248
|
+
it( 'workflow.js: allows imports from ../../shared/utils/keys.js', async () => {
|
|
249
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-utils-' ) );
|
|
250
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
251
|
+
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
252
|
+
writeFileSync( join( dir, 'shared', 'utils', 'keys.js' ), 'export const KEY = "test";\n' );
|
|
253
|
+
const src = 'import { KEY } from "../../shared/utils/keys.js";';
|
|
254
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
255
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
256
|
+
} );
|
|
257
|
+
|
|
258
|
+
it( 'workflow.js: allows imports from ../../shared/steps/common.js', async () => {
|
|
259
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-steps-' ) );
|
|
260
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
261
|
+
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
262
|
+
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
263
|
+
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
264
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
265
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
266
|
+
} );
|
|
267
|
+
|
|
268
|
+
it( 'workflow.js: allows imports from ../../shared/evaluators/quality.js', async () => {
|
|
269
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-evals-' ) );
|
|
270
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
271
|
+
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
272
|
+
writeFileSync( join( dir, 'shared', 'evaluators', 'quality.js' ), 'export const qualityEval = evaluator({ name: "quality" });\n' );
|
|
273
|
+
const src = 'import { qualityEval } from "../../shared/evaluators/quality.js";';
|
|
274
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
275
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
276
|
+
} );
|
|
277
|
+
|
|
278
|
+
it( 'workflow.js: allows imports from ../../shared/clients/pokeapi.js', async () => {
|
|
279
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-clients-' ) );
|
|
280
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
281
|
+
mkdirSync( join( dir, 'shared', 'clients' ), { recursive: true } );
|
|
282
|
+
writeFileSync( join( dir, 'shared', 'clients', 'pokeapi.js' ), 'export const getPokemon = () => {};\n' );
|
|
283
|
+
const src = 'import { getPokemon } from "../../shared/clients/pokeapi.js";';
|
|
284
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
285
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
286
|
+
} );
|
|
287
|
+
|
|
288
|
+
it( 'steps.ts: allows imports from ../../shared/utils/keys.js', async () => {
|
|
289
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-utils-' ) );
|
|
290
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
291
|
+
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
292
|
+
writeFileSync( join( dir, 'shared', 'utils', 'keys.js' ), 'export const KEY = "test";\n' );
|
|
293
|
+
const src = 'import { KEY } from "../../shared/utils/keys.js";';
|
|
294
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
295
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
296
|
+
} );
|
|
297
|
+
|
|
298
|
+
it( 'steps.ts: allows imports from ../../shared/clients/redis.js', async () => {
|
|
299
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-clients-' ) );
|
|
300
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
301
|
+
mkdirSync( join( dir, 'shared', 'clients' ), { recursive: true } );
|
|
302
|
+
writeFileSync( join( dir, 'shared', 'clients', 'redis.js' ), 'export const client = {};\n' );
|
|
303
|
+
const src = 'import { client } from "../../shared/clients/redis.js";';
|
|
304
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
305
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
306
|
+
} );
|
|
307
|
+
|
|
308
|
+
it( 'evaluators.ts: allows imports from ../../shared/utils/helpers.js', async () => {
|
|
309
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-utils-' ) );
|
|
310
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
311
|
+
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
312
|
+
writeFileSync( join( dir, 'shared', 'utils', 'helpers.js' ), 'export const helper = () => 1;\n' );
|
|
313
|
+
const src = 'import { helper } from "../../shared/utils/helpers.js";';
|
|
314
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src ) ).resolves.toBeTruthy();
|
|
315
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
316
|
+
} );
|
|
317
|
+
} );
|
|
318
|
+
|
|
319
|
+
describe( 'activity isolation - shared imports', () => {
|
|
320
|
+
it( 'steps.ts: rejects imports from ../../shared/steps/common.js (activity isolation)', async () => {
|
|
321
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-steps-reject-' ) );
|
|
322
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
323
|
+
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
324
|
+
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
325
|
+
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
326
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) )
|
|
327
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
328
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
329
|
+
} );
|
|
330
|
+
|
|
331
|
+
it( 'steps.ts: rejects imports from ../../shared/evaluators/quality.js (activity isolation)', async () => {
|
|
332
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-evals-reject-' ) );
|
|
333
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
334
|
+
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
335
|
+
writeFileSync( join( dir, 'shared', 'evaluators', 'quality.js' ), 'export const qualityEval = evaluator({ name: "quality" });\n' );
|
|
336
|
+
const src = 'import { qualityEval } from "../../shared/evaluators/quality.js";';
|
|
337
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) )
|
|
338
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
339
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
340
|
+
} );
|
|
341
|
+
|
|
342
|
+
it( 'evaluators.ts: rejects imports from ../../shared/steps/common.js (activity isolation)', async () => {
|
|
343
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-steps-reject-' ) );
|
|
344
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
345
|
+
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
346
|
+
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
347
|
+
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
348
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src ) )
|
|
349
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
350
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
351
|
+
} );
|
|
352
|
+
|
|
353
|
+
it( 'evaluators.ts: rejects imports from ../../shared/evaluators/other.js (activity isolation)', async () => {
|
|
354
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-evals-reject-' ) );
|
|
355
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
356
|
+
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
357
|
+
writeFileSync( join( dir, 'shared', 'evaluators', 'other.js' ), 'export const otherEval = evaluator({ name: "other" });\n' );
|
|
358
|
+
const src = 'import { otherEval } from "../../shared/evaluators/other.js";';
|
|
359
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src ) )
|
|
360
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
361
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
362
|
+
} );
|
|
363
|
+
} );
|
|
364
|
+
|
|
365
|
+
describe( 'workflow import scope', () => {
|
|
366
|
+
it( 'workflow.js: allows imports from other workflow directories (cross-workflow)', async () => {
|
|
367
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-cross-allow-' ) );
|
|
368
|
+
mkdirSync( join( dir, 'workflows', 'workflow_a' ), { recursive: true } );
|
|
369
|
+
mkdirSync( join( dir, 'workflows', 'workflow_b' ), { recursive: true } );
|
|
370
|
+
writeFileSync( join( dir, 'workflows', 'workflow_b', 'steps.js' ), 'export const S = step({ name: "s" });\n' );
|
|
371
|
+
// Cross-workflow imports are allowed for workflows (they can import steps from other workflows)
|
|
372
|
+
const src = 'import { S } from "../workflow_b/steps.js";';
|
|
373
|
+
await expect( runLoader( join( dir, 'workflows', 'workflow_a', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
374
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
375
|
+
} );
|
|
376
|
+
|
|
377
|
+
it( 'workflow.js: allows imports from utils with relative parent paths', async () => {
|
|
378
|
+
// The validator does not enforce strict scope boundaries, it validates by file type patterns
|
|
379
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-parent-utils-' ) );
|
|
380
|
+
mkdirSync( join( dir, 'src', 'workflows', 'my_workflow' ), { recursive: true } );
|
|
381
|
+
mkdirSync( join( dir, 'utils' ), { recursive: true } );
|
|
382
|
+
writeFileSync( join( dir, 'utils', 'helpers.js' ), 'export const helper = () => 1;\n' );
|
|
383
|
+
const src = 'import { helper } from "../../../utils/helpers.js";';
|
|
384
|
+
// This should pass because it's not a component file
|
|
385
|
+
await expect( runLoader( join( dir, 'src', 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
386
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
387
|
+
} );
|
|
388
|
+
} );
|
|
389
|
+
|
|
390
|
+
// =====================================================
|
|
391
|
+
// Arbitrary path imports (proving any folder name works)
|
|
392
|
+
// =====================================================
|
|
393
|
+
|
|
394
|
+
describe( 'arbitrary path imports', () => {
|
|
395
|
+
it( 'workflow.js: allows imports from ./foobar.js', async () => {
|
|
396
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-1-' ) );
|
|
397
|
+
const src = 'import { foo } from "./foobar.js";';
|
|
398
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
399
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
400
|
+
} );
|
|
401
|
+
|
|
402
|
+
it( 'workflow.js: allows imports from ./foobar/baz.js', async () => {
|
|
403
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-2-' ) );
|
|
404
|
+
mkdirSync( join( dir, 'foobar' ) );
|
|
405
|
+
writeFileSync( join( dir, 'foobar', 'baz.js' ), 'export const baz = 1;\n' );
|
|
406
|
+
const src = 'import { baz } from "./foobar/baz.js";';
|
|
407
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
408
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
409
|
+
} );
|
|
410
|
+
|
|
411
|
+
it( 'workflow.js: allows imports from ../../shared/foobar.js', async () => {
|
|
412
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-3-' ) );
|
|
413
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
414
|
+
mkdirSync( join( dir, 'shared' ), { recursive: true } );
|
|
415
|
+
writeFileSync( join( dir, 'shared', 'foobar.js' ), 'export const foobar = 1;\n' );
|
|
416
|
+
const src = 'import { foobar } from "../../shared/foobar.js";';
|
|
417
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
418
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
419
|
+
} );
|
|
420
|
+
|
|
421
|
+
it( 'workflow.js: allows imports from ../../shared/foobar/baz.js', async () => {
|
|
422
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-4-' ) );
|
|
423
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
424
|
+
mkdirSync( join( dir, 'shared', 'foobar' ), { recursive: true } );
|
|
425
|
+
writeFileSync( join( dir, 'shared', 'foobar', 'baz.js' ), 'export const baz = 1;\n' );
|
|
426
|
+
const src = 'import { baz } from "../../shared/foobar/baz.js";';
|
|
427
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
428
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
429
|
+
} );
|
|
430
|
+
|
|
431
|
+
it( 'steps.js: allows imports from ./helpers/anything.js', async () => {
|
|
432
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-arbitrary-1-' ) );
|
|
433
|
+
mkdirSync( join( dir, 'helpers' ) );
|
|
434
|
+
writeFileSync( join( dir, 'helpers', 'anything.js' ), 'export const anything = 1;\n' );
|
|
435
|
+
const src = 'import { anything } from "./helpers/anything.js";';
|
|
436
|
+
await expect( runLoader( join( dir, 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
437
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
438
|
+
} );
|
|
439
|
+
|
|
440
|
+
it( 'evaluators.js: allows imports from ./my_custom_lib/tools.js', async () => {
|
|
441
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-arbitrary-1-' ) );
|
|
442
|
+
mkdirSync( join( dir, 'my_custom_lib' ) );
|
|
443
|
+
writeFileSync( join( dir, 'my_custom_lib', 'tools.js' ), 'export const tools = {};\n' );
|
|
444
|
+
const src = 'import { tools } from "./my_custom_lib/tools.js";';
|
|
445
|
+
await expect( runLoader( join( dir, 'evaluators.js' ), src ) ).resolves.toBeTruthy();
|
|
446
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
447
|
+
} );
|
|
448
|
+
} );
|
|
449
|
+
|
|
450
|
+
// =====================================================
|
|
451
|
+
// Instantiation location validation
|
|
452
|
+
// =====================================================
|
|
453
|
+
|
|
454
|
+
describe( 'instantiation location tests - correct locations', () => {
|
|
455
|
+
it( 'step() called in steps/fetch_data.js is allowed', async () => {
|
|
456
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-folder-allowed-' ) );
|
|
457
|
+
mkdirSync( join( dir, 'steps' ) );
|
|
458
|
+
const src = [
|
|
459
|
+
'import { step } from "@output.ai/core";',
|
|
460
|
+
'export const fetchData = step({ name: "fetch_data", fn: async () => ({}) });'
|
|
461
|
+
].join( '\n' );
|
|
462
|
+
await expect( runLoader( join( dir, 'steps', 'fetch_data.js' ), src ) ).resolves.toBeTruthy();
|
|
463
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
464
|
+
} );
|
|
465
|
+
|
|
466
|
+
it( 'step() called in src/shared/steps/common.js is allowed', async () => {
|
|
467
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-shared-allowed-' ) );
|
|
468
|
+
mkdirSync( join( dir, 'src', 'shared', 'steps' ), { recursive: true } );
|
|
469
|
+
const src = [
|
|
470
|
+
'import { step } from "@output.ai/core";',
|
|
471
|
+
'export const commonStep = step({ name: "common_step", fn: async () => ({}) });'
|
|
472
|
+
].join( '\n' );
|
|
473
|
+
await expect( runLoader( join( dir, 'src', 'shared', 'steps', 'common.js' ), src ) ).resolves.toBeTruthy();
|
|
474
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
475
|
+
} );
|
|
476
|
+
|
|
477
|
+
it( 'evaluator() called in evaluators/quality.js is allowed', async () => {
|
|
478
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-folder-allowed-' ) );
|
|
479
|
+
mkdirSync( join( dir, 'evaluators' ) );
|
|
480
|
+
const src = [
|
|
481
|
+
'import { evaluator } from "@output.ai/core";',
|
|
482
|
+
'export const quality = evaluator({ name: "quality", fn: async () => ({ value: 1 }) });'
|
|
483
|
+
].join( '\n' );
|
|
484
|
+
await expect( runLoader( join( dir, 'evaluators', 'quality.js' ), src ) ).resolves.toBeTruthy();
|
|
485
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
486
|
+
} );
|
|
487
|
+
|
|
488
|
+
it( 'evaluator() called in src/shared/evaluators/metrics.js is allowed', async () => {
|
|
489
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-shared-allowed-' ) );
|
|
490
|
+
mkdirSync( join( dir, 'src', 'shared', 'evaluators' ), { recursive: true } );
|
|
491
|
+
const src = [
|
|
492
|
+
'import { evaluator } from "@output.ai/core";',
|
|
493
|
+
'export const metrics = evaluator({ name: "metrics", fn: async () => ({ value: 1 }) });'
|
|
494
|
+
].join( '\n' );
|
|
495
|
+
await expect( runLoader( join( dir, 'src', 'shared', 'evaluators', 'metrics.js' ), src ) ).resolves.toBeTruthy();
|
|
496
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
497
|
+
} );
|
|
498
|
+
} );
|
|
499
|
+
|
|
500
|
+
describe( 'instantiation location tests - wrong locations', () => {
|
|
501
|
+
it( 'step() called in utils.js is blocked by validator', async () => {
|
|
502
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-utils-fail-' ) );
|
|
503
|
+
const src = [
|
|
504
|
+
'import { step } from "@output.ai/core";',
|
|
505
|
+
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
506
|
+
].join( '\n' );
|
|
507
|
+
await expect( runLoader( join( dir, 'utils.js' ), src ) )
|
|
508
|
+
.rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
509
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
510
|
+
} );
|
|
511
|
+
|
|
512
|
+
it( 'step() called in clients/api.js is blocked by validator', async () => {
|
|
513
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-clients-fail-' ) );
|
|
514
|
+
mkdirSync( join( dir, 'clients' ) );
|
|
515
|
+
const src = [
|
|
516
|
+
'import { step } from "@output.ai/core";',
|
|
517
|
+
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
518
|
+
].join( '\n' );
|
|
519
|
+
await expect( runLoader( join( dir, 'clients', 'api.js' ), src ) )
|
|
520
|
+
.rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
521
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
522
|
+
} );
|
|
523
|
+
|
|
524
|
+
it( 'evaluator() called in utils.js is blocked by validator', async () => {
|
|
525
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-utils-fail-' ) );
|
|
526
|
+
const src = [
|
|
527
|
+
'import { evaluator } from "@output.ai/core";',
|
|
528
|
+
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
529
|
+
].join( '\n' );
|
|
530
|
+
await expect( runLoader( join( dir, 'utils.js' ), src ) )
|
|
531
|
+
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
532
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
533
|
+
} );
|
|
534
|
+
|
|
535
|
+
it( 'evaluator() called in clients/api.js is blocked by validator', async () => {
|
|
536
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-clients-fail-' ) );
|
|
537
|
+
mkdirSync( join( dir, 'clients' ) );
|
|
538
|
+
const src = [
|
|
539
|
+
'import { evaluator } from "@output.ai/core";',
|
|
540
|
+
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
541
|
+
].join( '\n' );
|
|
542
|
+
await expect( runLoader( join( dir, 'clients', 'api.js' ), src ) )
|
|
543
|
+
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
544
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
545
|
+
} );
|
|
546
|
+
|
|
547
|
+
it( 'evaluator() called in helpers.js is blocked by validator', async () => {
|
|
548
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-helpers-fail-' ) );
|
|
549
|
+
const src = [
|
|
550
|
+
'import { evaluator } from "@output.ai/core";',
|
|
551
|
+
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
552
|
+
].join( '\n' );
|
|
553
|
+
await expect( runLoader( join( dir, 'helpers.js' ), src ) )
|
|
554
|
+
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
555
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
556
|
+
} );
|
|
557
|
+
|
|
558
|
+
it( 'workflow() called in shared/common.js is blocked by validator', async () => {
|
|
559
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-fail-' ) );
|
|
560
|
+
mkdirSync( join( dir, 'shared' ) );
|
|
561
|
+
const src = [
|
|
562
|
+
'import { workflow } from "@output.ai/core";',
|
|
563
|
+
'export const badWf = workflow({ name: "bad", fn: async () => ({}) });'
|
|
564
|
+
].join( '\n' );
|
|
565
|
+
await expect( runLoader( join( dir, 'shared', 'common.js' ), src ) )
|
|
566
|
+
.rejects.toThrow( /Invalid instantiation location.*workflow\(\).*workflow/ );
|
|
567
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
568
|
+
} );
|
|
569
|
+
|
|
570
|
+
it( 'workflow() called in utils/index.js is blocked by validator', async () => {
|
|
571
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-utils-fail-' ) );
|
|
572
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
573
|
+
const src = [
|
|
574
|
+
'import { workflow } from "@output.ai/core";',
|
|
575
|
+
'export const badWf = workflow({ name: "bad", fn: async () => ({}) });'
|
|
576
|
+
].join( '\n' );
|
|
577
|
+
await expect( runLoader( join( dir, 'utils', 'index.js' ), src ) )
|
|
578
|
+
.rejects.toThrow( /Invalid instantiation location.*workflow\(\).*workflow/ );
|
|
579
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
580
|
+
} );
|
|
581
|
+
} );
|
|
215
582
|
} );
|