@workflow/builders 4.0.5 → 4.0.7
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/base-builder.d.ts +23 -4
- package/dist/base-builder.d.ts.map +1 -1
- package/dist/base-builder.js +122 -7
- package/dist/base-builder.js.map +1 -1
- package/dist/discover-entries-esbuild-plugin.d.ts +5 -3
- package/dist/discover-entries-esbuild-plugin.d.ts.map +1 -1
- package/dist/discover-entries-esbuild-plugin.js +32 -8
- package/dist/discover-entries-esbuild-plugin.js.map +1 -1
- package/dist/external-package-warning.test.d.ts +2 -0
- package/dist/external-package-warning.test.d.ts.map +1 -0
- package/dist/external-package-warning.test.js +219 -0
- package/dist/external-package-warning.test.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/request-converter.d.ts +2 -1
- package/dist/request-converter.d.ts.map +1 -1
- package/dist/request-converter.js +19 -1
- package/dist/request-converter.js.map +1 -1
- package/dist/request-converter.test.d.ts +2 -0
- package/dist/request-converter.test.d.ts.map +1 -0
- package/dist/request-converter.test.js +28 -0
- package/dist/request-converter.test.js.map +1 -0
- package/dist/swc-esbuild-plugin.d.ts +9 -0
- package/dist/swc-esbuild-plugin.d.ts.map +1 -1
- package/dist/swc-esbuild-plugin.js +24 -1
- package/dist/swc-esbuild-plugin.js.map +1 -1
- package/dist/swc-esbuild-plugin.test.js +184 -0
- package/dist/swc-esbuild-plugin.test.js.map +1 -1
- package/dist/vercel-build-output-api.d.ts.map +1 -1
- package/dist/vercel-build-output-api.js +3 -0
- package/dist/vercel-build-output-api.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { BaseBuilder } from './base-builder.js';
|
|
6
|
+
/**
|
|
7
|
+
* Minimal subclass to expose the protected `discoverEntries()` for testing.
|
|
8
|
+
*/
|
|
9
|
+
class TestBuilder extends BaseBuilder {
|
|
10
|
+
async build() {
|
|
11
|
+
// no-op
|
|
12
|
+
}
|
|
13
|
+
// Expose for tests
|
|
14
|
+
discoverEntriesPublic(inputs, outdir) {
|
|
15
|
+
return this.discoverEntries(inputs, outdir);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Resolve symlinks in tmpdir to avoid macOS /var -> /private/var issues
|
|
19
|
+
const realTmpdir = realpathSync(tmpdir());
|
|
20
|
+
function writeFile(path, contents) {
|
|
21
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
22
|
+
writeFileSync(path, contents, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
function createBuilder(workingDir, externalPackages) {
|
|
25
|
+
const config = {
|
|
26
|
+
buildTarget: 'standalone',
|
|
27
|
+
workingDir,
|
|
28
|
+
dirs: ['.'],
|
|
29
|
+
externalPackages,
|
|
30
|
+
stepsBundlePath: join(workingDir, 'steps.js'),
|
|
31
|
+
workflowsBundlePath: join(workingDir, 'workflows.js'),
|
|
32
|
+
webhookBundlePath: join(workingDir, 'webhook.js'),
|
|
33
|
+
};
|
|
34
|
+
return new TestBuilder(config);
|
|
35
|
+
}
|
|
36
|
+
describe('warnAboutExternalWorkflowPackages', () => {
|
|
37
|
+
let testRoot;
|
|
38
|
+
let warnSpy;
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
testRoot = mkdtempSync(join(realTmpdir, 'workflow-external-pkg-warning-'));
|
|
41
|
+
warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
42
|
+
});
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
warnSpy.mockRestore();
|
|
45
|
+
rmSync(testRoot, { recursive: true, force: true });
|
|
46
|
+
});
|
|
47
|
+
it('warns when an external package depends on @workflow/serde', async () => {
|
|
48
|
+
// Create a mock project with a node_modules package
|
|
49
|
+
const projectDir = join(testRoot, 'project');
|
|
50
|
+
// Create a minimal entry file for the project
|
|
51
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
52
|
+
// Create the external package with @workflow/serde dependency
|
|
53
|
+
writeFile(join(projectDir, 'node_modules', 'my-serde-pkg', 'package.json'), JSON.stringify({
|
|
54
|
+
name: 'my-serde-pkg',
|
|
55
|
+
version: '1.0.0',
|
|
56
|
+
main: 'index.js',
|
|
57
|
+
dependencies: {
|
|
58
|
+
'@workflow/serde': '^1.0.0',
|
|
59
|
+
},
|
|
60
|
+
}));
|
|
61
|
+
writeFile(join(projectDir, 'node_modules', 'my-serde-pkg', 'index.js'), 'export class Foo {}');
|
|
62
|
+
const builder = createBuilder(projectDir, ['my-serde-pkg']);
|
|
63
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
64
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
65
|
+
const warnMessage = warnSpy.mock.calls[0]?.[0];
|
|
66
|
+
expect(warnMessage).toContain('my-serde-pkg');
|
|
67
|
+
expect(warnMessage).toContain('serverExternalPackages');
|
|
68
|
+
expect(warnMessage).toContain('serialization classes');
|
|
69
|
+
});
|
|
70
|
+
it('warns when an external package source contains serde symbols', async () => {
|
|
71
|
+
const projectDir = join(testRoot, 'project');
|
|
72
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
73
|
+
// Package without @workflow/serde dep but with Symbol.for patterns in source
|
|
74
|
+
writeFile(join(projectDir, 'node_modules', 'my-symbol-pkg', 'package.json'), JSON.stringify({
|
|
75
|
+
name: 'my-symbol-pkg',
|
|
76
|
+
version: '1.0.0',
|
|
77
|
+
main: 'index.js',
|
|
78
|
+
}));
|
|
79
|
+
writeFile(join(projectDir, 'node_modules', 'my-symbol-pkg', 'index.js'), `export class Bar {
|
|
80
|
+
static [Symbol.for('workflow-serialize')](instance) { return {}; }
|
|
81
|
+
static [Symbol.for('workflow-deserialize')](data) { return new Bar(); }
|
|
82
|
+
}`);
|
|
83
|
+
const builder = createBuilder(projectDir, ['my-symbol-pkg']);
|
|
84
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
85
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
86
|
+
const warnMessage = warnSpy.mock.calls[0]?.[0];
|
|
87
|
+
expect(warnMessage).toContain('my-symbol-pkg');
|
|
88
|
+
expect(warnMessage).toContain('serialization classes');
|
|
89
|
+
});
|
|
90
|
+
it('warns when an external package contains "use step" directives', async () => {
|
|
91
|
+
const projectDir = join(testRoot, 'project');
|
|
92
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
93
|
+
writeFile(join(projectDir, 'node_modules', 'my-step-pkg', 'package.json'), JSON.stringify({
|
|
94
|
+
name: 'my-step-pkg',
|
|
95
|
+
version: '1.0.0',
|
|
96
|
+
main: 'index.js',
|
|
97
|
+
}));
|
|
98
|
+
writeFile(join(projectDir, 'node_modules', 'my-step-pkg', 'index.js'), `export async function doWork() {
|
|
99
|
+
"use step";
|
|
100
|
+
return 42;
|
|
101
|
+
}`);
|
|
102
|
+
const builder = createBuilder(projectDir, ['my-step-pkg']);
|
|
103
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
104
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
105
|
+
const warnMessage = warnSpy.mock.calls[0]?.[0];
|
|
106
|
+
expect(warnMessage).toContain('my-step-pkg');
|
|
107
|
+
expect(warnMessage).toContain('"use step" functions');
|
|
108
|
+
});
|
|
109
|
+
it('warns when an external package contains "use workflow" directives', async () => {
|
|
110
|
+
const projectDir = join(testRoot, 'project');
|
|
111
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
112
|
+
writeFile(join(projectDir, 'node_modules', 'my-workflow-pkg', 'package.json'), JSON.stringify({
|
|
113
|
+
name: 'my-workflow-pkg',
|
|
114
|
+
version: '1.0.0',
|
|
115
|
+
main: 'index.js',
|
|
116
|
+
}));
|
|
117
|
+
writeFile(join(projectDir, 'node_modules', 'my-workflow-pkg', 'index.js'), `export async function runJob() {
|
|
118
|
+
"use workflow";
|
|
119
|
+
return "done";
|
|
120
|
+
}`);
|
|
121
|
+
const builder = createBuilder(projectDir, ['my-workflow-pkg']);
|
|
122
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
123
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
124
|
+
const warnMessage = warnSpy.mock.calls[0]?.[0];
|
|
125
|
+
expect(warnMessage).toContain('my-workflow-pkg');
|
|
126
|
+
expect(warnMessage).toContain('"use workflow" functions');
|
|
127
|
+
});
|
|
128
|
+
it('does not warn for packages without workflow patterns', async () => {
|
|
129
|
+
const projectDir = join(testRoot, 'project');
|
|
130
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
131
|
+
writeFile(join(projectDir, 'node_modules', 'plain-pkg', 'package.json'), JSON.stringify({
|
|
132
|
+
name: 'plain-pkg',
|
|
133
|
+
version: '1.0.0',
|
|
134
|
+
main: 'index.js',
|
|
135
|
+
}));
|
|
136
|
+
writeFile(join(projectDir, 'node_modules', 'plain-pkg', 'index.js'), 'export const hello = "world";');
|
|
137
|
+
const builder = createBuilder(projectDir, ['plain-pkg']);
|
|
138
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
139
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
it('does not warn for pseudo-packages (server-only, client-only)', async () => {
|
|
142
|
+
const projectDir = join(testRoot, 'project');
|
|
143
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
144
|
+
const builder = createBuilder(projectDir, ['server-only', 'client-only']);
|
|
145
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
146
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
147
|
+
});
|
|
148
|
+
it('does not warn when externalPackages is empty', async () => {
|
|
149
|
+
const projectDir = join(testRoot, 'project');
|
|
150
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
151
|
+
const builder = createBuilder(projectDir, []);
|
|
152
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
153
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
154
|
+
});
|
|
155
|
+
it('warns only once per package across multiple discoverEntries calls', async () => {
|
|
156
|
+
const projectDir = join(testRoot, 'project');
|
|
157
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
158
|
+
writeFile(join(projectDir, 'other.ts'), 'export const y = 2;');
|
|
159
|
+
writeFile(join(projectDir, 'node_modules', 'my-serde-pkg', 'package.json'), JSON.stringify({
|
|
160
|
+
name: 'my-serde-pkg',
|
|
161
|
+
version: '1.0.0',
|
|
162
|
+
main: 'index.js',
|
|
163
|
+
dependencies: { '@workflow/serde': '^1.0.0' },
|
|
164
|
+
}));
|
|
165
|
+
writeFile(join(projectDir, 'node_modules', 'my-serde-pkg', 'index.js'), 'export class Foo {}');
|
|
166
|
+
const builder = createBuilder(projectDir, ['my-serde-pkg']);
|
|
167
|
+
// Call discoverEntries twice with different inputs
|
|
168
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
169
|
+
await builder.discoverEntriesPublic([join(projectDir, 'other.ts')], join(projectDir, 'out2'));
|
|
170
|
+
// Should only warn once
|
|
171
|
+
const warnCalls = warnSpy.mock.calls.filter((call) => call[0].includes('my-serde-pkg'));
|
|
172
|
+
expect(warnCalls).toHaveLength(1);
|
|
173
|
+
});
|
|
174
|
+
it('lists multiple detected issues in the warning message', async () => {
|
|
175
|
+
const projectDir = join(testRoot, 'project');
|
|
176
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
177
|
+
writeFile(join(projectDir, 'node_modules', 'multi-pkg', 'package.json'), JSON.stringify({
|
|
178
|
+
name: 'multi-pkg',
|
|
179
|
+
version: '1.0.0',
|
|
180
|
+
main: 'index.js',
|
|
181
|
+
dependencies: { '@workflow/serde': '^1.0.0' },
|
|
182
|
+
}));
|
|
183
|
+
writeFile(join(projectDir, 'node_modules', 'multi-pkg', 'index.js'), `export async function doWork() {
|
|
184
|
+
"use step";
|
|
185
|
+
return 42;
|
|
186
|
+
}
|
|
187
|
+
export class Foo {
|
|
188
|
+
static [Symbol.for('workflow-serialize')](instance) { return {}; }
|
|
189
|
+
static [Symbol.for('workflow-deserialize')](data) { return new Foo(); }
|
|
190
|
+
}`);
|
|
191
|
+
const builder = createBuilder(projectDir, ['multi-pkg']);
|
|
192
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
193
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
194
|
+
const warnMessage = warnSpy.mock.calls[0]?.[0];
|
|
195
|
+
expect(warnMessage).toContain('"use step" functions');
|
|
196
|
+
expect(warnMessage).toContain('serialization classes');
|
|
197
|
+
});
|
|
198
|
+
it('warns via entry-file detection when package.json has no serde dep', async () => {
|
|
199
|
+
const projectDir = join(testRoot, 'project');
|
|
200
|
+
writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');
|
|
201
|
+
// Package without @workflow/serde in deps, but entry has "use step"
|
|
202
|
+
writeFile(join(projectDir, 'node_modules', 'no-serde-dep-pkg', 'package.json'), JSON.stringify({
|
|
203
|
+
name: 'no-serde-dep-pkg',
|
|
204
|
+
version: '1.0.0',
|
|
205
|
+
main: 'index.js',
|
|
206
|
+
}));
|
|
207
|
+
writeFile(join(projectDir, 'node_modules', 'no-serde-dep-pkg', 'index.js'), `export async function doWork() {
|
|
208
|
+
"use step";
|
|
209
|
+
return 42;
|
|
210
|
+
}`);
|
|
211
|
+
const builder = createBuilder(projectDir, ['no-serde-dep-pkg']);
|
|
212
|
+
await builder.discoverEntriesPublic([join(projectDir, 'index.ts')], join(projectDir, 'out'));
|
|
213
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
214
|
+
const warnMessage = warnSpy.mock.calls[0]?.[0];
|
|
215
|
+
expect(warnMessage).toContain('no-serde-dep-pkg');
|
|
216
|
+
expect(warnMessage).toContain('"use step" functions');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
//# sourceMappingURL=external-package-warning.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-package-warning.test.js","sourceRoot":"","sources":["../src/external-package-warning.test.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n mkdirSync,\n mkdtempSync,\n realpathSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport { BaseBuilder, type DiscoveredEntries } from './base-builder.js';\nimport type { StandaloneConfig } from './types.js';\n\n/**\n * Minimal subclass to expose the protected `discoverEntries()` for testing.\n */\nclass TestBuilder extends BaseBuilder {\n async build(): Promise<void> {\n // no-op\n }\n\n // Expose for tests\n public discoverEntriesPublic(\n inputs: string[],\n outdir: string\n ): Promise<DiscoveredEntries> {\n return this.discoverEntries(inputs, outdir);\n }\n}\n\n// Resolve symlinks in tmpdir to avoid macOS /var -> /private/var issues\nconst realTmpdir = realpathSync(tmpdir());\n\nfunction writeFile(path: string, contents: string): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, contents, 'utf-8');\n}\n\nfunction createBuilder(\n workingDir: string,\n externalPackages: string[]\n): TestBuilder {\n const config: StandaloneConfig = {\n buildTarget: 'standalone',\n workingDir,\n dirs: ['.'],\n externalPackages,\n stepsBundlePath: join(workingDir, 'steps.js'),\n workflowsBundlePath: join(workingDir, 'workflows.js'),\n webhookBundlePath: join(workingDir, 'webhook.js'),\n };\n return new TestBuilder(config);\n}\n\ndescribe('warnAboutExternalWorkflowPackages', () => {\n let testRoot: string;\n let warnSpy: ReturnType<typeof vi.spyOn>;\n\n beforeEach(() => {\n testRoot = mkdtempSync(join(realTmpdir, 'workflow-external-pkg-warning-'));\n warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});\n });\n\n afterEach(() => {\n warnSpy.mockRestore();\n rmSync(testRoot, { recursive: true, force: true });\n });\n\n it('warns when an external package depends on @workflow/serde', async () => {\n // Create a mock project with a node_modules package\n const projectDir = join(testRoot, 'project');\n\n // Create a minimal entry file for the project\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n // Create the external package with @workflow/serde dependency\n writeFile(\n join(projectDir, 'node_modules', 'my-serde-pkg', 'package.json'),\n JSON.stringify({\n name: 'my-serde-pkg',\n version: '1.0.0',\n main: 'index.js',\n dependencies: {\n '@workflow/serde': '^1.0.0',\n },\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'my-serde-pkg', 'index.js'),\n 'export class Foo {}'\n );\n\n const builder = createBuilder(projectDir, ['my-serde-pkg']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).toHaveBeenCalled();\n const warnMessage = warnSpy.mock.calls[0]?.[0] as string;\n expect(warnMessage).toContain('my-serde-pkg');\n expect(warnMessage).toContain('serverExternalPackages');\n expect(warnMessage).toContain('serialization classes');\n });\n\n it('warns when an external package source contains serde symbols', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n // Package without @workflow/serde dep but with Symbol.for patterns in source\n writeFile(\n join(projectDir, 'node_modules', 'my-symbol-pkg', 'package.json'),\n JSON.stringify({\n name: 'my-symbol-pkg',\n version: '1.0.0',\n main: 'index.js',\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'my-symbol-pkg', 'index.js'),\n `export class Bar {\n static [Symbol.for('workflow-serialize')](instance) { return {}; }\n static [Symbol.for('workflow-deserialize')](data) { return new Bar(); }\n}`\n );\n\n const builder = createBuilder(projectDir, ['my-symbol-pkg']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).toHaveBeenCalled();\n const warnMessage = warnSpy.mock.calls[0]?.[0] as string;\n expect(warnMessage).toContain('my-symbol-pkg');\n expect(warnMessage).toContain('serialization classes');\n });\n\n it('warns when an external package contains \"use step\" directives', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n writeFile(\n join(projectDir, 'node_modules', 'my-step-pkg', 'package.json'),\n JSON.stringify({\n name: 'my-step-pkg',\n version: '1.0.0',\n main: 'index.js',\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'my-step-pkg', 'index.js'),\n `export async function doWork() {\n \"use step\";\n return 42;\n}`\n );\n\n const builder = createBuilder(projectDir, ['my-step-pkg']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).toHaveBeenCalled();\n const warnMessage = warnSpy.mock.calls[0]?.[0] as string;\n expect(warnMessage).toContain('my-step-pkg');\n expect(warnMessage).toContain('\"use step\" functions');\n });\n\n it('warns when an external package contains \"use workflow\" directives', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n writeFile(\n join(projectDir, 'node_modules', 'my-workflow-pkg', 'package.json'),\n JSON.stringify({\n name: 'my-workflow-pkg',\n version: '1.0.0',\n main: 'index.js',\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'my-workflow-pkg', 'index.js'),\n `export async function runJob() {\n \"use workflow\";\n return \"done\";\n}`\n );\n\n const builder = createBuilder(projectDir, ['my-workflow-pkg']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).toHaveBeenCalled();\n const warnMessage = warnSpy.mock.calls[0]?.[0] as string;\n expect(warnMessage).toContain('my-workflow-pkg');\n expect(warnMessage).toContain('\"use workflow\" functions');\n });\n\n it('does not warn for packages without workflow patterns', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n writeFile(\n join(projectDir, 'node_modules', 'plain-pkg', 'package.json'),\n JSON.stringify({\n name: 'plain-pkg',\n version: '1.0.0',\n main: 'index.js',\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'plain-pkg', 'index.js'),\n 'export const hello = \"world\";'\n );\n\n const builder = createBuilder(projectDir, ['plain-pkg']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).not.toHaveBeenCalled();\n });\n\n it('does not warn for pseudo-packages (server-only, client-only)', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n const builder = createBuilder(projectDir, ['server-only', 'client-only']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).not.toHaveBeenCalled();\n });\n\n it('does not warn when externalPackages is empty', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n const builder = createBuilder(projectDir, []);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).not.toHaveBeenCalled();\n });\n\n it('warns only once per package across multiple discoverEntries calls', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n writeFile(join(projectDir, 'other.ts'), 'export const y = 2;');\n\n writeFile(\n join(projectDir, 'node_modules', 'my-serde-pkg', 'package.json'),\n JSON.stringify({\n name: 'my-serde-pkg',\n version: '1.0.0',\n main: 'index.js',\n dependencies: { '@workflow/serde': '^1.0.0' },\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'my-serde-pkg', 'index.js'),\n 'export class Foo {}'\n );\n\n const builder = createBuilder(projectDir, ['my-serde-pkg']);\n\n // Call discoverEntries twice with different inputs\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n await builder.discoverEntriesPublic(\n [join(projectDir, 'other.ts')],\n join(projectDir, 'out2')\n );\n\n // Should only warn once\n const warnCalls = warnSpy.mock.calls.filter((call: unknown[]) =>\n (call[0] as string).includes('my-serde-pkg')\n );\n expect(warnCalls).toHaveLength(1);\n });\n\n it('lists multiple detected issues in the warning message', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n writeFile(\n join(projectDir, 'node_modules', 'multi-pkg', 'package.json'),\n JSON.stringify({\n name: 'multi-pkg',\n version: '1.0.0',\n main: 'index.js',\n dependencies: { '@workflow/serde': '^1.0.0' },\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'multi-pkg', 'index.js'),\n `export async function doWork() {\n \"use step\";\n return 42;\n}\nexport class Foo {\n static [Symbol.for('workflow-serialize')](instance) { return {}; }\n static [Symbol.for('workflow-deserialize')](data) { return new Foo(); }\n}`\n );\n\n const builder = createBuilder(projectDir, ['multi-pkg']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).toHaveBeenCalled();\n const warnMessage = warnSpy.mock.calls[0]?.[0] as string;\n expect(warnMessage).toContain('\"use step\" functions');\n expect(warnMessage).toContain('serialization classes');\n });\n\n it('warns via entry-file detection when package.json has no serde dep', async () => {\n const projectDir = join(testRoot, 'project');\n\n writeFile(join(projectDir, 'index.ts'), 'export const x = 1;');\n\n // Package without @workflow/serde in deps, but entry has \"use step\"\n writeFile(\n join(projectDir, 'node_modules', 'no-serde-dep-pkg', 'package.json'),\n JSON.stringify({\n name: 'no-serde-dep-pkg',\n version: '1.0.0',\n main: 'index.js',\n })\n );\n writeFile(\n join(projectDir, 'node_modules', 'no-serde-dep-pkg', 'index.js'),\n `export async function doWork() {\n \"use step\";\n return 42;\n}`\n );\n\n const builder = createBuilder(projectDir, ['no-serde-dep-pkg']);\n await builder.discoverEntriesPublic(\n [join(projectDir, 'index.ts')],\n join(projectDir, 'out')\n );\n\n expect(warnSpy).toHaveBeenCalled();\n const warnMessage = warnSpy.mock.calls[0]?.[0] as string;\n expect(warnMessage).toContain('no-serde-dep-pkg');\n expect(warnMessage).toContain('\"use step\" functions');\n });\n});\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { createDiscoverEntriesPlugin } from './discover-entries-esbuild-plugin.j
|
|
|
8
8
|
export { clearModuleSpecifierCache, getImportPath, type ImportPathResult, type ModuleSpecifierResult, resolveModuleSpecifier, } from './module-specifier.js';
|
|
9
9
|
export { createNodeModuleErrorPlugin } from './node-module-esbuild-plugin.js';
|
|
10
10
|
export { createPseudoPackagePlugin, PSEUDO_PACKAGES, } from './pseudo-package-esbuild-plugin.js';
|
|
11
|
-
export { NORMALIZE_REQUEST_CODE } from './request-converter.js';
|
|
11
|
+
export { NORMALIZE_REQUEST_CODE, replaceGeneratedRouteExport, } from './request-converter.js';
|
|
12
12
|
export { analyzeSerdeCompliance, extractClassEntries, type SerdeCheckResult, type SerdeClassCheckResult, } from './serde-checker.js';
|
|
13
13
|
export { StandaloneBuilder } from './standalone.js';
|
|
14
14
|
export { createSwcPlugin } from './swc-esbuild-plugin.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,8BAA8B,EACnC,+BAA+B,EAC/B,6CAA6C,GAC9C,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,8BAA8B,EACnC,+BAA+B,EAC/B,6CAA6C,GAC9C,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAClB,KAAK,oBAAoB,EACzB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { createDiscoverEntriesPlugin } from './discover-entries-esbuild-plugin.j
|
|
|
7
7
|
export { clearModuleSpecifierCache, getImportPath, resolveModuleSpecifier, } from './module-specifier.js';
|
|
8
8
|
export { createNodeModuleErrorPlugin } from './node-module-esbuild-plugin.js';
|
|
9
9
|
export { createPseudoPackagePlugin, PSEUDO_PACKAGES, } from './pseudo-package-esbuild-plugin.js';
|
|
10
|
-
export { NORMALIZE_REQUEST_CODE } from './request-converter.js';
|
|
10
|
+
export { NORMALIZE_REQUEST_CODE, replaceGeneratedRouteExport, } from './request-converter.js';
|
|
11
11
|
export { analyzeSerdeCompliance, extractClassEntries, } from './serde-checker.js';
|
|
12
12
|
export { StandaloneBuilder } from './standalone.js';
|
|
13
13
|
export { createSwcPlugin } from './swc-esbuild-plugin.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,uBAAuB,EAGvB,+BAA+B,EAC/B,6CAA6C,GAC9C,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,aAAa,EAGb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,uBAAuB,EAGvB,+BAA+B,EAC/B,6CAA6C,GAC9C,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,aAAa,EAGb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,sBAAsB,EACtB,mBAAmB,GAGpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAElB,sBAAsB,EACtB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAU9B,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,qBAAqB,CAAC","sourcesContent":["export type { WorkflowManifest } from './apply-swc-transform.js';\nexport { applySwcTransform } from './apply-swc-transform.js';\nexport { BaseBuilder } from './base-builder.js';\nexport { createBuildQueue } from './build-queue.js';\nexport {\n createBaseBuilderConfig,\n type DecoratorOptions,\n type DecoratorOptionsWithConfigPath,\n getDecoratorOptionsForDirectory,\n getDecoratorOptionsForDirectoryWithConfigPath,\n} from './config-helpers.js';\nexport { STEP_QUEUE_TRIGGER, WORKFLOW_QUEUE_TRIGGER } from './constants.js';\nexport { createDiscoverEntriesPlugin } from './discover-entries-esbuild-plugin.js';\nexport {\n clearModuleSpecifierCache,\n getImportPath,\n type ImportPathResult,\n type ModuleSpecifierResult,\n resolveModuleSpecifier,\n} from './module-specifier.js';\nexport { createNodeModuleErrorPlugin } from './node-module-esbuild-plugin.js';\nexport {\n createPseudoPackagePlugin,\n PSEUDO_PACKAGES,\n} from './pseudo-package-esbuild-plugin.js';\nexport {\n NORMALIZE_REQUEST_CODE,\n replaceGeneratedRouteExport,\n} from './request-converter.js';\nexport {\n analyzeSerdeCompliance,\n extractClassEntries,\n type SerdeCheckResult,\n type SerdeClassCheckResult,\n} from './serde-checker.js';\nexport { StandaloneBuilder } from './standalone.js';\nexport { createSwcPlugin } from './swc-esbuild-plugin.js';\nexport {\n detectWorkflowPatterns,\n generatedWorkflowPathPattern,\n isGeneratedWorkflowFile,\n isWorkflowSdkFile,\n shouldTransformFile,\n turbopackContentPattern,\n useStepPattern,\n useWorkflowPattern,\n type WorkflowPatternMatch,\n workflowSdkPathPattern,\n workflowSerdeImportPattern,\n workflowSerdeSymbolPattern,\n} from './transform-utils.js';\nexport type {\n AstroConfig,\n BuildTarget,\n NextConfig,\n StandaloneConfig,\n SvelteKitConfig,\n VercelBuildOutputConfig,\n WorkflowConfig,\n} from './types.js';\nexport { isValidBuildTarget, validBuildTargets } from './types.js';\nexport { VercelBuildOutputAPIBuilder } from './vercel-build-output-api.js';\nexport { resolveWorkflowAliasRelativePath } from './workflow-alias.js';\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
declare const NORMALIZE_REQUEST_CODE = "\nasync function normalizeRequest(request) {\n const options = {\n method: request.method,\n headers: new Headers(request.headers)\n };\n if (!['GET', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'].includes(request.method)) {\n options.body = await request.arrayBuffer();\n }\n return new Request(request.url, options);\n}\n";
|
|
2
|
-
|
|
2
|
+
declare function replaceGeneratedRouteExport(content: string, pattern: RegExp, replacement: string, errorMessage: string): string;
|
|
3
|
+
export { NORMALIZE_REQUEST_CODE, replaceGeneratedRouteExport };
|
|
3
4
|
//# sourceMappingURL=request-converter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-converter.d.ts","sourceRoot":"","sources":["../src/request-converter.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,sBAAsB,+UAW3B,CAAC;AAEF,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"request-converter.d.ts","sourceRoot":"","sources":["../src/request-converter.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,sBAAsB,+UAW3B,CAAC;AAEF,iBAAS,2BAA2B,CAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,UAoBrB;AAED,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,CAAC"}
|
|
@@ -10,5 +10,23 @@ async function normalizeRequest(request) {
|
|
|
10
10
|
return new Request(request.url, options);
|
|
11
11
|
}
|
|
12
12
|
`;
|
|
13
|
-
|
|
13
|
+
function replaceGeneratedRouteExport(content, pattern, replacement, errorMessage) {
|
|
14
|
+
const replacedContent = content.replace(pattern, replacement);
|
|
15
|
+
if (replacedContent !== content) {
|
|
16
|
+
return replacedContent;
|
|
17
|
+
}
|
|
18
|
+
const sourceMapMarker = '\n//# sourceMappingURL=';
|
|
19
|
+
const sourceMapIndex = content.lastIndexOf(sourceMapMarker);
|
|
20
|
+
if (sourceMapIndex === -1) {
|
|
21
|
+
throw new Error(errorMessage);
|
|
22
|
+
}
|
|
23
|
+
const routeCode = content.slice(0, sourceMapIndex);
|
|
24
|
+
const sourceMap = content.slice(sourceMapIndex);
|
|
25
|
+
const wrappedRouteCode = routeCode.replace(pattern, replacement);
|
|
26
|
+
if (wrappedRouteCode === routeCode) {
|
|
27
|
+
throw new Error(errorMessage);
|
|
28
|
+
}
|
|
29
|
+
return wrappedRouteCode + sourceMap;
|
|
30
|
+
}
|
|
31
|
+
export { NORMALIZE_REQUEST_CODE, replaceGeneratedRouteExport };
|
|
14
32
|
//# sourceMappingURL=request-converter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-converter.js","sourceRoot":"","sources":["../src/request-converter.ts"],"names":[],"mappings":"AAAA,MAAM,sBAAsB,GAAG;;;;;;;;;;;CAW9B,CAAC;AAEF,OAAO,EAAE,sBAAsB,EAAE,CAAC","sourcesContent":["const NORMALIZE_REQUEST_CODE = `\nasync function normalizeRequest(request) {\n const options = {\n method: request.method,\n headers: new Headers(request.headers)\n };\n if (!['GET', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'].includes(request.method)) {\n options.body = await request.arrayBuffer();\n }\n return new Request(request.url, options);\n}\n`;\n\nexport { NORMALIZE_REQUEST_CODE };\n"]}
|
|
1
|
+
{"version":3,"file":"request-converter.js","sourceRoot":"","sources":["../src/request-converter.ts"],"names":[],"mappings":"AAAA,MAAM,sBAAsB,GAAG;;;;;;;;;;;CAW9B,CAAC;AAEF,SAAS,2BAA2B,CAClC,OAAe,EACf,OAAe,EACf,WAAmB,EACnB,YAAoB;IAEpB,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9D,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,MAAM,eAAe,GAAG,yBAAyB,CAAC;IAClD,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IAC5D,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAChD,MAAM,gBAAgB,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACjE,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,gBAAgB,GAAG,SAAS,CAAC;AACtC,CAAC;AAED,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,CAAC","sourcesContent":["const NORMALIZE_REQUEST_CODE = `\nasync function normalizeRequest(request) {\n const options = {\n method: request.method,\n headers: new Headers(request.headers)\n };\n if (!['GET', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'].includes(request.method)) {\n options.body = await request.arrayBuffer();\n }\n return new Request(request.url, options);\n}\n`;\n\nfunction replaceGeneratedRouteExport(\n content: string,\n pattern: RegExp,\n replacement: string,\n errorMessage: string\n) {\n const replacedContent = content.replace(pattern, replacement);\n if (replacedContent !== content) {\n return replacedContent;\n }\n\n const sourceMapMarker = '\\n//# sourceMappingURL=';\n const sourceMapIndex = content.lastIndexOf(sourceMapMarker);\n if (sourceMapIndex === -1) {\n throw new Error(errorMessage);\n }\n\n const routeCode = content.slice(0, sourceMapIndex);\n const sourceMap = content.slice(sourceMapIndex);\n const wrappedRouteCode = routeCode.replace(pattern, replacement);\n if (wrappedRouteCode === routeCode) {\n throw new Error(errorMessage);\n }\n return wrappedRouteCode + sourceMap;\n}\n\nexport { NORMALIZE_REQUEST_CODE, replaceGeneratedRouteExport };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-converter.test.d.ts","sourceRoot":"","sources":["../src/request-converter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { replaceGeneratedRouteExport } from './request-converter.js';
|
|
3
|
+
describe('replaceGeneratedRouteExport', () => {
|
|
4
|
+
it('replaces route code before an inline source map', () => {
|
|
5
|
+
const result = replaceGeneratedRouteExport('export const POST = handler;\n//# sourceMappingURL=data:application/json;base64,abc', /export const POST = handler;$/, 'export const POST = wrappedHandler;', 'not found');
|
|
6
|
+
expect(result).toBe('export const POST = wrappedHandler;\n//# sourceMappingURL=data:application/json;base64,abc');
|
|
7
|
+
});
|
|
8
|
+
it('ignores source map comments embedded before route exports', () => {
|
|
9
|
+
const result = replaceGeneratedRouteExport([
|
|
10
|
+
'const workflowCode = `',
|
|
11
|
+
'//# sourceMappingURL=data:application/json;base64,inner',
|
|
12
|
+
'`;',
|
|
13
|
+
'const handler = workflowEntrypoint(workflowCode);',
|
|
14
|
+
'export const HEAD = handler;',
|
|
15
|
+
'export const POST = handler;',
|
|
16
|
+
].join('\n'), /const handler = workflowEntrypoint\(workflowCode\);\s*export const HEAD = handler;\s*export const POST = handler;?\s*$/m, 'export const POST = wrappedHandler;', 'not found');
|
|
17
|
+
expect(result).toBe([
|
|
18
|
+
'const workflowCode = `',
|
|
19
|
+
'//# sourceMappingURL=data:application/json;base64,inner',
|
|
20
|
+
'`;',
|
|
21
|
+
'export const POST = wrappedHandler;',
|
|
22
|
+
].join('\n'));
|
|
23
|
+
});
|
|
24
|
+
it('throws when the route export pattern is not found', () => {
|
|
25
|
+
expect(() => replaceGeneratedRouteExport('export const GET = handler;', /export const POST = handler;$/, 'export const POST = wrappedHandler;', 'missing route export')).toThrow('missing route export');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=request-converter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-converter.test.js","sourceRoot":"","sources":["../src/request-converter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAErE,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,MAAM,GAAG,2BAA2B,CACxC,qFAAqF,EACrF,+BAA+B,EAC/B,qCAAqC,EACrC,WAAW,CACZ,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CACjB,4FAA4F,CAC7F,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,MAAM,GAAG,2BAA2B,CACxC;YACE,wBAAwB;YACxB,yDAAyD;YACzD,IAAI;YACJ,mDAAmD;YACnD,8BAA8B;YAC9B,8BAA8B;SAC/B,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,yHAAyH,EACzH,qCAAqC,EACrC,WAAW,CACZ,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CACjB;YACE,wBAAwB;YACxB,yDAAyD;YACzD,IAAI;YACJ,qCAAqC;SACtC,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,GAAG,EAAE,CACV,2BAA2B,CACzB,6BAA6B,EAC7B,+BAA+B,EAC/B,qCAAqC,EACrC,sBAAsB,CACvB,CACF,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { replaceGeneratedRouteExport } from './request-converter.js';\n\ndescribe('replaceGeneratedRouteExport', () => {\n it('replaces route code before an inline source map', () => {\n const result = replaceGeneratedRouteExport(\n 'export const POST = handler;\\n//# sourceMappingURL=data:application/json;base64,abc',\n /export const POST = handler;$/,\n 'export const POST = wrappedHandler;',\n 'not found'\n );\n\n expect(result).toBe(\n 'export const POST = wrappedHandler;\\n//# sourceMappingURL=data:application/json;base64,abc'\n );\n });\n\n it('ignores source map comments embedded before route exports', () => {\n const result = replaceGeneratedRouteExport(\n [\n 'const workflowCode = `',\n '//# sourceMappingURL=data:application/json;base64,inner',\n '`;',\n 'const handler = workflowEntrypoint(workflowCode);',\n 'export const HEAD = handler;',\n 'export const POST = handler;',\n ].join('\\n'),\n /const handler = workflowEntrypoint\\(workflowCode\\);\\s*export const HEAD = handler;\\s*export const POST = handler;?\\s*$/m,\n 'export const POST = wrappedHandler;',\n 'not found'\n );\n\n expect(result).toBe(\n [\n 'const workflowCode = `',\n '//# sourceMappingURL=data:application/json;base64,inner',\n '`;',\n 'export const POST = wrappedHandler;',\n ].join('\\n')\n );\n });\n\n it('throws when the route export pattern is not found', () => {\n expect(() =>\n replaceGeneratedRouteExport(\n 'export const GET = handler;',\n /export const POST = handler;$/,\n 'export const POST = wrappedHandler;',\n 'missing route export'\n )\n ).toThrow('missing route export');\n });\n});\n"]}
|
|
@@ -18,6 +18,15 @@ export interface SwcPluginOptions {
|
|
|
18
18
|
* breaks them because the .js file doesn't exist on disk.
|
|
19
19
|
*/
|
|
20
20
|
rewriteTsExtensions?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Bundle project-local files that are transitively imported by step entries.
|
|
23
|
+
*
|
|
24
|
+
* Keep this disabled when a downstream bundler consumes the generated step
|
|
25
|
+
* bundle because that bundler can resolve the externalized local imports.
|
|
26
|
+
* Enable it for direct runtime loading, where Node imports the generated step
|
|
27
|
+
* bundle from disk without a later bundling pass.
|
|
28
|
+
*/
|
|
29
|
+
bundleTransitiveLocalStepDependencies?: boolean;
|
|
21
30
|
/**
|
|
22
31
|
* Absolute file paths of discovered workflow/step/serde entries whose
|
|
23
32
|
* imports must be treated as side-effectful.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swc-esbuild-plugin.d.ts","sourceRoot":"","sources":["../src/swc-esbuild-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"swc-esbuild-plugin.d.ts","sourceRoot":"","sources":["../src/swc-esbuild-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAQlC,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;IACrC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;OAOG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AA0CD,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAuTjE"}
|
|
@@ -4,6 +4,7 @@ import { promisify } from 'node:util';
|
|
|
4
4
|
import enhancedResolveOrig from 'enhanced-resolve';
|
|
5
5
|
import { applySwcTransform, } from './apply-swc-transform.js';
|
|
6
6
|
import { jsTsRegex, parentHasChild, } from './discover-entries-esbuild-plugin.js';
|
|
7
|
+
import { resolveModuleSpecifier } from './module-specifier.js';
|
|
7
8
|
import { resolveWorkflowAliasRelativePath } from './workflow-alias.js';
|
|
8
9
|
const NODE_RESOLVE_OPTIONS = {
|
|
9
10
|
dependencyType: 'commonjs',
|
|
@@ -39,6 +40,9 @@ const NODE_ESM_RESOLVE_OPTIONS = {
|
|
|
39
40
|
dependencyType: 'esm',
|
|
40
41
|
conditionNames: ['node', 'import'],
|
|
41
42
|
};
|
|
43
|
+
function normalizePath(path) {
|
|
44
|
+
return path.replace(/\\/g, '/');
|
|
45
|
+
}
|
|
42
46
|
export function createSwcPlugin(options) {
|
|
43
47
|
return {
|
|
44
48
|
name: 'swc-workflow-plugin',
|
|
@@ -107,7 +111,9 @@ export function createSwcPlugin(options) {
|
|
|
107
111
|
if (!resolvedPath)
|
|
108
112
|
return null;
|
|
109
113
|
// Normalize to forward slashes for cross-platform comparison
|
|
110
|
-
const normalizedResolvedPath = resolvedPath
|
|
114
|
+
const normalizedResolvedPath = normalizePath(resolvedPath);
|
|
115
|
+
const workingDir = build.initialOptions.absWorkingDir || process.cwd();
|
|
116
|
+
const projectRoot = options.projectRoot || workingDir;
|
|
111
117
|
// Check if this module is a discovered entry whose SWC-transformed
|
|
112
118
|
// code contains side effects (workflow/step/class registration).
|
|
113
119
|
// Override the package.json "sideEffects": false so esbuild does not
|
|
@@ -128,6 +134,17 @@ export function createSwcPlugin(options) {
|
|
|
128
134
|
shouldBundle = true;
|
|
129
135
|
break;
|
|
130
136
|
}
|
|
137
|
+
// Bundle project-local source files that are imported by a
|
|
138
|
+
// step/serde entry so direct runtime loaders do not see raw TS
|
|
139
|
+
// extensionless imports. Keep package dependencies external
|
|
140
|
+
// unless they are themselves in entriesToBundle or are parents
|
|
141
|
+
// of a discovered workflow/step/serde file via the check above.
|
|
142
|
+
if (options.bundleTransitiveLocalStepDependencies &&
|
|
143
|
+
isProjectLocalFile(normalizedResolvedPath, projectRoot) &&
|
|
144
|
+
parentHasChild(normalizedEntry, normalizedResolvedPath)) {
|
|
145
|
+
shouldBundle = true;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
131
148
|
}
|
|
132
149
|
if (shouldBundle) {
|
|
133
150
|
// Let esbuild bundle this entry, but override sideEffects if needed.
|
|
@@ -266,4 +283,10 @@ export function createSwcPlugin(options) {
|
|
|
266
283
|
},
|
|
267
284
|
};
|
|
268
285
|
}
|
|
286
|
+
function isProjectLocalFile(filePath, projectRoot) {
|
|
287
|
+
if (normalizePath(filePath).includes('/node_modules/')) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
return (resolveModuleSpecifier(filePath, projectRoot).moduleSpecifier === undefined);
|
|
291
|
+
}
|
|
269
292
|
//# sourceMappingURL=swc-esbuild-plugin.js.map
|