@workflow/next 5.0.0-beta.4 → 5.0.0-beta.6
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/builder-deferred.d.ts.map +1 -1
- package/dist/builder-deferred.js +230 -304
- package/dist/builder-deferred.js.map +1 -1
- package/dist/builder-eager.d.ts.map +1 -1
- package/dist/builder-eager.js +56 -75
- package/dist/builder-eager.js.map +1 -1
- package/dist/builder.d.ts +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +2 -2
- package/dist/builder.js.map +1 -1
- package/dist/environment-flag.d.ts +2 -0
- package/dist/environment-flag.d.ts.map +1 -0
- package/dist/environment-flag.js +15 -0
- package/dist/environment-flag.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +254 -4
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +31 -6
- package/dist/loader.js.map +1 -1
- package/dist/socket-server.d.ts +20 -0
- package/dist/socket-server.d.ts.map +1 -1
- package/dist/socket-server.js +28 -1
- package/dist/socket-server.js.map +1 -1
- package/docs/api-reference/with-workflow.mdx +32 -0
- package/docs/next.mdx +5 -3
- package/package.json +4 -4
package/dist/builder-deferred.js
CHANGED
|
@@ -7,10 +7,10 @@ exports.getNextBuilderDeferred = getNextBuilderDeferred;
|
|
|
7
7
|
const node_crypto_1 = require("node:crypto");
|
|
8
8
|
const node_fs_1 = require("node:fs");
|
|
9
9
|
const promises_1 = require("node:fs/promises");
|
|
10
|
+
const node_module_1 = require("node:module");
|
|
10
11
|
const node_os_1 = __importDefault(require("node:os"));
|
|
11
12
|
const node_path_1 = require("node:path");
|
|
12
13
|
const socket_server_js_1 = require("./socket-server.js");
|
|
13
|
-
const DEFERRED_STEP_COPY_DIR_NAME = '__workflow_step_files__';
|
|
14
14
|
const ROUTE_STUB_FILE_MARKER = 'WORKFLOW_ROUTE_STUB_FILE';
|
|
15
15
|
const ROUTE_STUB_MARKER_SCAN_BYTES = 4 * 1024;
|
|
16
16
|
let CachedNextBuilderDeferred;
|
|
@@ -21,7 +21,13 @@ async function getNextBuilderDeferred() {
|
|
|
21
21
|
if (CachedNextBuilderDeferred) {
|
|
22
22
|
return CachedNextBuilderDeferred;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
// V2: STEP_QUEUE_TRIGGER, getImportPath, and enhanced-resolve infrastructure
|
|
25
|
+
// were removed because the V2 combined handler eliminates the separate step
|
|
26
|
+
// route/topic. The step copy import rewriting (getRelativeImportSpecifier,
|
|
27
|
+
// getStepCopyFileName, rewriteRelativeImportsForCopiedStep) from main was also
|
|
28
|
+
// removed — V2 doesn't use step copies. If step copy support is needed, it
|
|
29
|
+
// should land as a complete feature set.
|
|
30
|
+
const { BaseBuilder: BaseBuilderClass, WORKFLOW_QUEUE_TRIGGER, detectWorkflowPatterns, applySwcTransform, resolveWorkflowAliasRelativePath,
|
|
25
31
|
// biome-ignore lint/security/noGlobalEval: Need to use eval here to avoid TypeScript from transpiling the import statement into `require()`
|
|
26
32
|
} = (await eval('import("@workflow/builders")'));
|
|
27
33
|
class NextDeferredBuilder extends BaseBuilderClass {
|
|
@@ -35,7 +41,6 @@ async function getNextBuilderDeferred() {
|
|
|
35
41
|
cacheWriteTimer = null;
|
|
36
42
|
deferredRebuildTimer = null;
|
|
37
43
|
lastDeferredBuildSignature = null;
|
|
38
|
-
manifestStepResolveBaseDirs = null;
|
|
39
44
|
async build() {
|
|
40
45
|
const outputDir = await this.findAppDirectory();
|
|
41
46
|
await this.initializeDiscoveryState();
|
|
@@ -99,6 +104,14 @@ async function getNextBuilderDeferred() {
|
|
|
99
104
|
}
|
|
100
105
|
}
|
|
101
106
|
this.lastDeferredBuildSignature = buildSignature;
|
|
107
|
+
if (!this.config.watch) {
|
|
108
|
+
// Production builds can persist newly discovered deferred-entry files to
|
|
109
|
+
// the cache after the first pass completes. Reload that cache before we
|
|
110
|
+
// decide whether the input signature stabilized so staged tarball builds
|
|
111
|
+
// can immediately replay with the expanded step set.
|
|
112
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
113
|
+
await this.loadWorkflowsCache();
|
|
114
|
+
}
|
|
102
115
|
const postBuildInputFiles = this.getCurrentInputFiles(implicitStepFiles);
|
|
103
116
|
const postBuildSignature = await this.createDeferredBuildSignature(postBuildInputFiles);
|
|
104
117
|
if (postBuildSignature === buildSignature) {
|
|
@@ -115,15 +128,11 @@ async function getNextBuilderDeferred() {
|
|
|
115
128
|
const outputDir = await this.findAppDirectory();
|
|
116
129
|
const generatedRouteFiles = [
|
|
117
130
|
(0, node_path_1.join)(outputDir, '.well-known/workflow/v1/flow/route.js'),
|
|
118
|
-
(0, node_path_1.join)(outputDir, '.well-known/workflow/v1/step/route.js'),
|
|
119
131
|
(0, node_path_1.join)(outputDir, '.well-known/workflow/v1/webhook/[token]/route.js'),
|
|
120
132
|
];
|
|
121
133
|
for (const routeFilePath of generatedRouteFiles) {
|
|
122
134
|
const routeState = await this.getGeneratedRouteState(routeFilePath);
|
|
123
|
-
if (routeState === 'missing') {
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
if (routeState === 'stub') {
|
|
135
|
+
if (routeState === 'missing' || routeState === 'stub') {
|
|
127
136
|
return true;
|
|
128
137
|
}
|
|
129
138
|
}
|
|
@@ -341,18 +350,17 @@ async function getNextBuilderDeferred() {
|
|
|
341
350
|
...this.discoveredSerdeFiles,
|
|
342
351
|
...trackedDiscoveredEntries.discoveredSerdeFiles,
|
|
343
352
|
])).sort();
|
|
344
|
-
const discoveredStepFiles = await this.filterExistingFiles(discoveredStepFileCandidates);
|
|
345
353
|
const discoveredWorkflowFiles = await this.filterExistingFiles(discoveredWorkflowFileCandidates);
|
|
354
|
+
const existingStepFileCandidates = await this.filterExistingFiles(discoveredStepFileCandidates);
|
|
355
|
+
const discoveredStepFiles = await this.collectTransitiveStepFiles({
|
|
356
|
+
entryFiles: [...existingStepFileCandidates, ...discoveredWorkflowFiles],
|
|
357
|
+
stepFiles: existingStepFileCandidates,
|
|
358
|
+
});
|
|
346
359
|
const existingSerdeFileCandidates = await this.filterExistingFiles(discoveredSerdeFileCandidates);
|
|
347
360
|
const discoveredSerdeFiles = await this.collectTransitiveSerdeFiles({
|
|
348
361
|
entryFiles: [...discoveredStepFiles, ...discoveredWorkflowFiles],
|
|
349
362
|
serdeFiles: existingSerdeFileCandidates,
|
|
350
363
|
});
|
|
351
|
-
const discoveredEntries = {
|
|
352
|
-
discoveredSteps: new Set(discoveredStepFiles),
|
|
353
|
-
discoveredWorkflows: new Set(discoveredWorkflowFiles),
|
|
354
|
-
discoveredSerdeFiles: new Set(discoveredSerdeFiles),
|
|
355
|
-
};
|
|
356
364
|
const existingInputFiles = await this.filterExistingFiles(inputFiles);
|
|
357
365
|
const buildInputFiles = Array.from(new Set([
|
|
358
366
|
...existingInputFiles,
|
|
@@ -360,38 +368,42 @@ async function getNextBuilderDeferred() {
|
|
|
360
368
|
...discoveredWorkflowFiles,
|
|
361
369
|
...discoveredSerdeFiles,
|
|
362
370
|
])).sort();
|
|
371
|
+
const discoveredEntries = {
|
|
372
|
+
discoveredSteps: new Set(discoveredStepFiles),
|
|
373
|
+
discoveredWorkflows: new Set(discoveredWorkflowFiles),
|
|
374
|
+
discoveredSerdeFiles: new Set(discoveredSerdeFiles),
|
|
375
|
+
};
|
|
363
376
|
// Ensure output directories exist
|
|
364
377
|
await (0, promises_1.mkdir)(workflowGeneratedDir, { recursive: true });
|
|
365
378
|
await this.writeFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, '.gitignore'), '*');
|
|
366
379
|
const tsconfigPath = await this.findTsConfigPath();
|
|
367
|
-
|
|
380
|
+
// V2: Build combined route (replaces separate step + flow routes)
|
|
381
|
+
const flowRouteDir = (0, node_path_1.join)(workflowGeneratedDir, 'flow');
|
|
382
|
+
await (0, promises_1.mkdir)(flowRouteDir, { recursive: true });
|
|
383
|
+
// Write step registrations to final name directly (not temp) so the
|
|
384
|
+
// import path in the flow route is correct. The flow route uses temp
|
|
385
|
+
// naming to avoid HMR churn via copyFileIfChanged, but the step
|
|
386
|
+
// registrations file is a side-effect import and doesn't need that.
|
|
387
|
+
const stepsOutfile = (0, node_path_1.join)(flowRouteDir, '__step_registrations.js');
|
|
388
|
+
const combinedResult = await this.createCombinedBundle({
|
|
389
|
+
format: 'esm',
|
|
368
390
|
inputFiles: buildInputFiles,
|
|
369
|
-
|
|
391
|
+
stepsOutfile,
|
|
392
|
+
flowOutfile: (0, node_path_1.join)(flowRouteDir, tempRouteFileName),
|
|
393
|
+
bundleFinalOutput: false,
|
|
394
|
+
externalizeNonSteps: true,
|
|
370
395
|
tsconfigPath,
|
|
371
|
-
routeFileName: tempRouteFileName,
|
|
372
396
|
discoveredEntries,
|
|
373
|
-
};
|
|
374
|
-
const workflowsBundle = await this.buildWorkflowsFunction(options);
|
|
375
|
-
const { manifest: stepsManifest } = await this.buildStepsFunction({
|
|
376
|
-
...options,
|
|
377
|
-
additionalStepSourceManifest: workflowsBundle?.manifest,
|
|
378
397
|
});
|
|
379
398
|
await this.buildWebhookRoute({
|
|
380
399
|
workflowGeneratedDir,
|
|
381
400
|
routeFileName: tempRouteFileName,
|
|
382
401
|
});
|
|
383
402
|
await this.refreshTrackedDependencyFiles(workflowGeneratedDir, tempRouteFileName);
|
|
384
|
-
// Merge manifests from both bundles
|
|
385
403
|
const manifest = {
|
|
386
|
-
steps: { ...
|
|
387
|
-
workflows: {
|
|
388
|
-
|
|
389
|
-
...workflowsBundle?.manifest?.workflows,
|
|
390
|
-
},
|
|
391
|
-
classes: {
|
|
392
|
-
...stepsManifest.classes,
|
|
393
|
-
...workflowsBundle?.manifest?.classes,
|
|
394
|
-
},
|
|
404
|
+
steps: { ...combinedResult?.manifest?.steps },
|
|
405
|
+
workflows: { ...combinedResult?.manifest?.workflows },
|
|
406
|
+
classes: { ...combinedResult?.manifest?.classes },
|
|
395
407
|
};
|
|
396
408
|
const manifestFilePath = (0, node_path_1.join)(workflowGeneratedDir, 'manifest.json');
|
|
397
409
|
const manifestBuildPath = (0, node_path_1.join)(manifestBuildDir, 'manifest.json');
|
|
@@ -410,8 +422,8 @@ async function getNextBuilderDeferred() {
|
|
|
410
422
|
await (0, promises_1.rm)(manifestFilePath, { force: true });
|
|
411
423
|
}
|
|
412
424
|
await this.writeFunctionsConfig(outputDir);
|
|
425
|
+
// V2: Combined route (flow) — step registrations already at final path
|
|
413
426
|
await this.copyFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, `flow/${tempRouteFileName}`), (0, node_path_1.join)(workflowGeneratedDir, 'flow/route.js'));
|
|
414
|
-
await this.copyFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, `step/${tempRouteFileName}`), (0, node_path_1.join)(workflowGeneratedDir, 'step/route.js'));
|
|
415
427
|
await this.copyFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, `webhook/[token]/${tempRouteFileName}`), (0, node_path_1.join)(workflowGeneratedDir, 'webhook/[token]/route.js'));
|
|
416
428
|
// Expose manifest as a static file when WORKFLOW_PUBLIC_MANIFEST=1.
|
|
417
429
|
// Next.js serves files from public/ at the root URL.
|
|
@@ -432,17 +444,17 @@ async function getNextBuilderDeferred() {
|
|
|
432
444
|
(0, node_path_1.join)(flowRouteDir, 'route.js.temp'),
|
|
433
445
|
(0, node_path_1.join)(flowRouteDir, 'route.js.temp.debug.json'),
|
|
434
446
|
(0, node_path_1.join)(flowRouteDir, 'route.js.debug.json'),
|
|
435
|
-
(0, node_path_1.join)(
|
|
436
|
-
(0, node_path_1.join)(
|
|
437
|
-
|
|
438
|
-
|
|
447
|
+
(0, node_path_1.join)(flowRouteDir, '__step_registrations.route.js.temp'),
|
|
448
|
+
(0, node_path_1.join)(flowRouteDir, '__step_registrations.route.js.temp.debug.json'),
|
|
449
|
+
// V2: clean up stale V1 step route directory
|
|
450
|
+
stepRouteDir,
|
|
439
451
|
(0, node_path_1.join)(webhookRouteDir, 'route.js.temp'),
|
|
440
452
|
(0, node_path_1.join)(workflowGeneratedDir, 'manifest.json'),
|
|
441
453
|
];
|
|
442
|
-
await Promise.all(staleArtifactPaths.map((stalePath) => (0, promises_1.rm)(stalePath, { recursive: true, force: true })));
|
|
443
454
|
await Promise.all([
|
|
455
|
+
...staleArtifactPaths.map((stalePath) => (0, promises_1.rm)(stalePath, { recursive: true, force: true })),
|
|
456
|
+
(0, socket_server_js_1.cleanupStaleSocketInfoFiles)((0, node_path_1.join)(this.config.workingDir, this.getDistDir())),
|
|
444
457
|
this.removeStaleDeferredTempFiles(flowRouteDir),
|
|
445
|
-
this.removeStaleDeferredTempFiles(stepRouteDir),
|
|
446
458
|
this.removeStaleDeferredTempFiles(webhookRouteDir),
|
|
447
459
|
]);
|
|
448
460
|
}
|
|
@@ -503,7 +515,11 @@ async function getNextBuilderDeferred() {
|
|
|
503
515
|
if (hasCacheTrackingChange) {
|
|
504
516
|
this.scheduleWorkflowsCacheWrite();
|
|
505
517
|
}
|
|
506
|
-
if (
|
|
518
|
+
if (hasWorkflow ||
|
|
519
|
+
hasStep ||
|
|
520
|
+
hasSerde ||
|
|
521
|
+
hasCacheTrackingChange ||
|
|
522
|
+
wasTrackedDependency) {
|
|
507
523
|
this.scheduleDeferredRebuild();
|
|
508
524
|
}
|
|
509
525
|
},
|
|
@@ -529,41 +545,68 @@ async function getNextBuilderDeferred() {
|
|
|
529
545
|
return (0, node_path_1.join)(this.config.workingDir, this.getDistDir(), 'cache', 'workflows.json');
|
|
530
546
|
}
|
|
531
547
|
getSocketInfoFilePath() {
|
|
532
|
-
return (0, node_path_1.join)(this.config.workingDir, this.getDistDir(),
|
|
548
|
+
return (0, node_path_1.join)(this.config.workingDir, this.getDistDir(), socket_server_js_1.SOCKET_INFO_FILENAME);
|
|
533
549
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
550
|
+
findPackageJsonPath(filePath) {
|
|
551
|
+
let currentDir = (0, node_path_1.dirname)(filePath);
|
|
552
|
+
let previousDir = '';
|
|
553
|
+
while (currentDir !== previousDir) {
|
|
554
|
+
const packageJsonPath = (0, node_path_1.join)(currentDir, 'package.json');
|
|
555
|
+
if ((0, node_fs_1.existsSync)(packageJsonPath)) {
|
|
556
|
+
return packageJsonPath;
|
|
557
|
+
}
|
|
558
|
+
previousDir = currentDir;
|
|
559
|
+
currentDir = (0, node_path_1.dirname)(currentDir);
|
|
543
560
|
}
|
|
561
|
+
return null;
|
|
544
562
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
563
|
+
shouldPreferSourceBackedPackagePath(filePath) {
|
|
564
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
565
|
+
// Only prefer source for workspace packages (not in node_modules).
|
|
566
|
+
// For tarball-installed packages, using source-backed paths causes
|
|
567
|
+
// esbuild to bundle the full source tree (including world.ts with
|
|
568
|
+
// process.cwd()) instead of externalizing properly.
|
|
569
|
+
if (normalizedPath.includes('/packages/') &&
|
|
570
|
+
!normalizedPath.includes('/node_modules/')) {
|
|
571
|
+
return true;
|
|
548
572
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
resolveBaseDirs.add(this.normalizeDiscoveredFilePath(baseDir));
|
|
552
|
-
};
|
|
553
|
-
if (this.config.projectRoot) {
|
|
554
|
-
addResolveBaseDir(this.config.projectRoot);
|
|
573
|
+
if (!normalizedPath.includes('/node_modules/')) {
|
|
574
|
+
return false;
|
|
555
575
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
576
|
+
const packageJsonPath = this.findPackageJsonPath(filePath);
|
|
577
|
+
if (!packageJsonPath) {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
try {
|
|
581
|
+
const packageJson = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf-8'));
|
|
582
|
+
return (packageJson.name === 'workflow' ||
|
|
583
|
+
(typeof packageJson.name === 'string' &&
|
|
584
|
+
packageJson.name.startsWith('@workflow/')));
|
|
585
|
+
}
|
|
586
|
+
catch {
|
|
587
|
+
return false;
|
|
564
588
|
}
|
|
565
|
-
|
|
566
|
-
|
|
589
|
+
}
|
|
590
|
+
resolveSourceBackedPackagePath(filePath) {
|
|
591
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
592
|
+
if (!normalizedPath.includes('/dist/')) {
|
|
593
|
+
return filePath;
|
|
594
|
+
}
|
|
595
|
+
const sourceCandidate = normalizedPath.replace('/dist/', '/src/');
|
|
596
|
+
const resolvedSourceCandidate = this.resolveCopiedStepImportTargetPath(sourceCandidate);
|
|
597
|
+
if (!(0, node_fs_1.existsSync)(resolvedSourceCandidate) ||
|
|
598
|
+
!this.shouldPreferSourceBackedPackagePath(filePath)) {
|
|
599
|
+
return filePath;
|
|
600
|
+
}
|
|
601
|
+
return (0, node_fs_1.existsSync)(resolvedSourceCandidate)
|
|
602
|
+
? resolvedSourceCandidate
|
|
603
|
+
: filePath;
|
|
604
|
+
}
|
|
605
|
+
normalizeDiscoveredFilePath(filePath) {
|
|
606
|
+
const absolutePath = (0, node_path_1.isAbsolute)(filePath)
|
|
607
|
+
? filePath
|
|
608
|
+
: (0, node_path_1.resolve)(this.config.workingDir, filePath);
|
|
609
|
+
return this.resolveSourceBackedPackagePath(absolutePath);
|
|
567
610
|
}
|
|
568
611
|
async filterExistingFiles(filePaths) {
|
|
569
612
|
const normalizedFilePaths = Array.from(new Set(filePaths.map((filePath) => this.normalizeDiscoveredFilePath(filePath)))).sort();
|
|
@@ -683,9 +726,12 @@ async function getNextBuilderDeferred() {
|
|
|
683
726
|
}
|
|
684
727
|
const normalizedSourcePath = this.normalizeDiscoveredFilePath(resolvedSourcePath);
|
|
685
728
|
const normalizedSourcePathForCheck = normalizedSourcePath.replace(/\\/g, '/');
|
|
729
|
+
const isSourceBackedPackagePath = this.shouldPreferSourceBackedPackagePath(normalizedSourcePath);
|
|
686
730
|
if (normalizedSourcePathForCheck.includes('/.well-known/workflow/') ||
|
|
687
|
-
|
|
688
|
-
|
|
731
|
+
(!isSourceBackedPackagePath &&
|
|
732
|
+
normalizedSourcePathForCheck.includes('/node_modules/')) ||
|
|
733
|
+
(!isSourceBackedPackagePath &&
|
|
734
|
+
normalizedSourcePathForCheck.includes('/.pnpm/')) ||
|
|
689
735
|
normalizedSourcePathForCheck.includes('/.next/') ||
|
|
690
736
|
normalizedSourcePathForCheck.endsWith('/virtual-entry.js')) {
|
|
691
737
|
continue;
|
|
@@ -707,9 +753,6 @@ async function getNextBuilderDeferred() {
|
|
|
707
753
|
}, 50);
|
|
708
754
|
}
|
|
709
755
|
scheduleDeferredRebuild() {
|
|
710
|
-
if (!this.config.watch) {
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
756
|
if (this.deferredRebuildTimer) {
|
|
714
757
|
clearTimeout(this.deferredRebuildTimer);
|
|
715
758
|
}
|
|
@@ -784,35 +827,61 @@ async function getNextBuilderDeferred() {
|
|
|
784
827
|
].join('\n');
|
|
785
828
|
const workflowGeneratedDir = (0, node_path_1.join)(outputDir, '.well-known/workflow/v1');
|
|
786
829
|
await (0, promises_1.mkdir)((0, node_path_1.join)(workflowGeneratedDir, 'flow'), { recursive: true });
|
|
787
|
-
await (0, promises_1.mkdir)((0, node_path_1.join)(workflowGeneratedDir, 'step'), { recursive: true });
|
|
788
830
|
await (0, promises_1.mkdir)((0, node_path_1.join)(workflowGeneratedDir, 'webhook/[token]'), {
|
|
789
831
|
recursive: true,
|
|
790
832
|
});
|
|
791
833
|
await this.writeFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, '.gitignore'), '*');
|
|
792
|
-
//
|
|
793
|
-
//
|
|
834
|
+
// V2: Only flow + webhook stubs needed (no separate step route).
|
|
835
|
+
// Stubs are replaced by generated output once discovery finishes.
|
|
794
836
|
await this.writeFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, 'flow/route.js'), routeStubContent);
|
|
795
|
-
await this.writeFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, 'step/route.js'), routeStubContent);
|
|
796
837
|
await this.writeFileIfChanged((0, node_path_1.join)(workflowGeneratedDir, 'webhook/[token]/route.js'), routeStubContent);
|
|
797
838
|
}
|
|
839
|
+
async getInputFiles() {
|
|
840
|
+
// Read Next.js's app-paths-manifest.json from a previous build to
|
|
841
|
+
// determine which files are actual route entrypoints. This avoids
|
|
842
|
+
// predicting Next.js conventions with regexes and instead reads
|
|
843
|
+
// from Next.js's own output.
|
|
844
|
+
const nextDir = (0, node_path_1.join)(this.config.workingDir, '.next');
|
|
845
|
+
const manifestPath = (0, node_path_1.join)(nextDir, 'app-paths-manifest.json');
|
|
846
|
+
try {
|
|
847
|
+
const manifestContent = (0, node_fs_1.readFileSync)(manifestPath, 'utf-8');
|
|
848
|
+
const manifest = JSON.parse(manifestContent);
|
|
849
|
+
// The manifest maps route paths to their source files.
|
|
850
|
+
// Extract the source file paths and resolve them.
|
|
851
|
+
const manifestFiles = new Set();
|
|
852
|
+
for (const sourcePath of Object.values(manifest)) {
|
|
853
|
+
const resolved = (0, node_path_1.resolve)(nextDir, 'server', sourcePath);
|
|
854
|
+
// The manifest points to built output; find the source file
|
|
855
|
+
// by matching against the base builder's full file list.
|
|
856
|
+
manifestFiles.add(resolved);
|
|
857
|
+
}
|
|
858
|
+
// Use the manifest route paths to filter the input files.
|
|
859
|
+
// A file is included if it matches a known route segment from
|
|
860
|
+
// the manifest (e.g., app/api/route contains 'app/api/route').
|
|
861
|
+
const inputFiles = await super.getInputFiles();
|
|
862
|
+
const routeSegments = Object.keys(manifest).map((route) => route.replace(/^\//, '').replace(/\/route$/, ''));
|
|
863
|
+
return inputFiles.filter((item) => routeSegments.some((segment) => item.includes(segment)));
|
|
864
|
+
}
|
|
865
|
+
catch {
|
|
866
|
+
// No manifest from a previous build — fall back to the base
|
|
867
|
+
// builder's full file scan. This is safe but slower; subsequent
|
|
868
|
+
// builds will use the manifest.
|
|
869
|
+
return super.getInputFiles();
|
|
870
|
+
}
|
|
871
|
+
}
|
|
798
872
|
async writeFunctionsConfig(outputDir) {
|
|
799
873
|
// we don't run this in development mode as it's not needed
|
|
800
874
|
if (process.env.NODE_ENV === 'development') {
|
|
801
875
|
return;
|
|
802
876
|
}
|
|
877
|
+
// V2: Single combined trigger handles both workflow and step execution
|
|
803
878
|
const generatedConfig = {
|
|
804
879
|
version: '0',
|
|
805
|
-
steps: {
|
|
806
|
-
maxDuration: 'max',
|
|
807
|
-
experimentalTriggers: [STEP_QUEUE_TRIGGER],
|
|
808
|
-
},
|
|
809
880
|
workflows: {
|
|
810
881
|
maxDuration: 'max',
|
|
811
882
|
experimentalTriggers: [WORKFLOW_QUEUE_TRIGGER],
|
|
812
883
|
},
|
|
813
884
|
};
|
|
814
|
-
// We write this file to the generated directory for
|
|
815
|
-
// the Next.js builder to consume
|
|
816
885
|
await this.writeFileIfChanged((0, node_path_1.join)(outputDir, '.well-known/workflow/v1/config.json'), JSON.stringify(generatedConfig, null, 2));
|
|
817
886
|
}
|
|
818
887
|
async writeFileIfChanged(filePath, contents) {
|
|
@@ -859,16 +928,56 @@ async function getNextBuilderDeferred() {
|
|
|
859
928
|
// Manifest may not exist (e.g. manifest generation failed); ignore.
|
|
860
929
|
}
|
|
861
930
|
}
|
|
862
|
-
|
|
863
|
-
if (
|
|
864
|
-
|
|
931
|
+
resolveCopiedStepImportTargetPath(targetPath) {
|
|
932
|
+
if ((0, node_fs_1.existsSync)(targetPath)) {
|
|
933
|
+
return targetPath;
|
|
934
|
+
}
|
|
935
|
+
const extensionMatch = targetPath.match(/(\.[^./\\]+)$/);
|
|
936
|
+
const extension = extensionMatch?.[1]?.toLowerCase();
|
|
937
|
+
if (!extension) {
|
|
938
|
+
return targetPath;
|
|
939
|
+
}
|
|
940
|
+
const extensionFallbacks = extension === '.js'
|
|
941
|
+
? ['.ts', '.tsx', '.mts', '.cts']
|
|
942
|
+
: extension === '.mjs'
|
|
943
|
+
? ['.mts']
|
|
944
|
+
: extension === '.cjs'
|
|
945
|
+
? ['.cts']
|
|
946
|
+
: extension === '.jsx'
|
|
947
|
+
? ['.tsx']
|
|
948
|
+
: [];
|
|
949
|
+
if (extensionFallbacks.length === 0) {
|
|
950
|
+
return targetPath;
|
|
865
951
|
}
|
|
866
|
-
|
|
867
|
-
|
|
952
|
+
const targetWithoutExtension = targetPath.slice(0, -extension.length);
|
|
953
|
+
for (const fallbackExtension of extensionFallbacks) {
|
|
954
|
+
const fallbackPath = `${targetWithoutExtension}${fallbackExtension}`;
|
|
955
|
+
if ((0, node_fs_1.existsSync)(fallbackPath)) {
|
|
956
|
+
return fallbackPath;
|
|
957
|
+
}
|
|
868
958
|
}
|
|
869
|
-
|
|
870
|
-
|
|
959
|
+
return targetPath;
|
|
960
|
+
}
|
|
961
|
+
extractRelativeImportSpecifiers(source) {
|
|
962
|
+
return this.extractImportSpecifiers(source).filter((specifier) => specifier.startsWith('.'));
|
|
963
|
+
}
|
|
964
|
+
extractImportSpecifiers(source) {
|
|
965
|
+
const relativeSpecifiers = new Set();
|
|
966
|
+
const importPatterns = [
|
|
967
|
+
/from\s+['"]([^'"]+)['"]/g,
|
|
968
|
+
/import\s+['"]([^'"]+)['"]/g,
|
|
969
|
+
/import\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
970
|
+
/require\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
971
|
+
];
|
|
972
|
+
for (const importPattern of importPatterns) {
|
|
973
|
+
for (const match of source.matchAll(importPattern)) {
|
|
974
|
+
const specifier = match[1];
|
|
975
|
+
if (specifier) {
|
|
976
|
+
relativeSpecifiers.add(specifier);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
871
979
|
}
|
|
980
|
+
return Array.from(relativeSpecifiers);
|
|
872
981
|
}
|
|
873
982
|
async getRelativeFilenameForSwc(filePath) {
|
|
874
983
|
const workingDir = this.config.workingDir;
|
|
@@ -906,13 +1015,6 @@ async function getNextBuilderDeferred() {
|
|
|
906
1015
|
}
|
|
907
1016
|
return relativeFilename;
|
|
908
1017
|
}
|
|
909
|
-
getRelativeImportSpecifier(fromFilePath, toFilePath) {
|
|
910
|
-
let relativePath = (0, node_path_1.relative)((0, node_path_1.dirname)(fromFilePath), toFilePath).replace(/\\/g, '/');
|
|
911
|
-
if (!relativePath.startsWith('.')) {
|
|
912
|
-
relativePath = `./${relativePath}`;
|
|
913
|
-
}
|
|
914
|
-
return relativePath;
|
|
915
|
-
}
|
|
916
1018
|
resolveImportTargetWithExtensionFallbacks(targetPath) {
|
|
917
1019
|
if ((0, node_fs_1.existsSync)(targetPath)) {
|
|
918
1020
|
return targetPath;
|
|
@@ -943,38 +1045,35 @@ async function getNextBuilderDeferred() {
|
|
|
943
1045
|
}
|
|
944
1046
|
return targetPath;
|
|
945
1047
|
}
|
|
946
|
-
extractRelativeImportSpecifiers(source) {
|
|
947
|
-
const relativeSpecifiers = new Set();
|
|
948
|
-
const importPatterns = [
|
|
949
|
-
/from\s+['"]([^'"]+)['"]/g,
|
|
950
|
-
/import\s+['"]([^'"]+)['"]/g,
|
|
951
|
-
/import\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
952
|
-
/require\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
953
|
-
];
|
|
954
|
-
for (const importPattern of importPatterns) {
|
|
955
|
-
for (const match of source.matchAll(importPattern)) {
|
|
956
|
-
const specifier = match[1];
|
|
957
|
-
if (specifier?.startsWith('.')) {
|
|
958
|
-
relativeSpecifiers.add(specifier);
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
return Array.from(relativeSpecifiers);
|
|
963
|
-
}
|
|
964
|
-
isGeneratedWorkflowArtifact(filePath) {
|
|
965
|
-
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
966
|
-
return (normalizedPath.includes('/.well-known/workflow/') ||
|
|
967
|
-
normalizedPath.includes('/.next/'));
|
|
968
|
-
}
|
|
969
1048
|
shouldSkipTransitiveStepFile(filePath) {
|
|
970
1049
|
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
normalizedPath.includes('/.
|
|
1050
|
+
const isSourceBackedPackagePath = this.shouldPreferSourceBackedPackagePath(filePath);
|
|
1051
|
+
return (normalizedPath.includes('/.well-known/workflow/') ||
|
|
1052
|
+
normalizedPath.includes('/.next/') ||
|
|
1053
|
+
(!isSourceBackedPackagePath &&
|
|
1054
|
+
(normalizedPath.includes('/node_modules/') ||
|
|
1055
|
+
normalizedPath.includes('/.pnpm/'))));
|
|
974
1056
|
}
|
|
975
1057
|
async resolveTransitiveStepImportTargetPath(sourceFilePath, specifier) {
|
|
976
1058
|
const specifierMatch = specifier.match(/^([^?#]+)(.*)$/);
|
|
977
1059
|
const importPath = specifierMatch?.[1] ?? specifier;
|
|
1060
|
+
if (!importPath.startsWith('.')) {
|
|
1061
|
+
if (importPath !== 'workflow' && !importPath.startsWith('@workflow/')) {
|
|
1062
|
+
return null;
|
|
1063
|
+
}
|
|
1064
|
+
try {
|
|
1065
|
+
const resolvedPath = (0, node_module_1.createRequire)(sourceFilePath).resolve(importPath);
|
|
1066
|
+
const normalizedResolvedPath = this.normalizeDiscoveredFilePath(resolvedPath);
|
|
1067
|
+
if (this.shouldSkipTransitiveStepFile(normalizedResolvedPath)) {
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
const fileStats = await (0, promises_1.stat)(normalizedResolvedPath);
|
|
1071
|
+
return fileStats.isFile() ? normalizedResolvedPath : null;
|
|
1072
|
+
}
|
|
1073
|
+
catch {
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
978
1077
|
const absoluteTargetPath = (0, node_path_1.resolve)((0, node_path_1.dirname)(sourceFilePath), importPath);
|
|
979
1078
|
const candidatePaths = new Set([
|
|
980
1079
|
this.resolveImportTargetWithExtensionFallbacks(absoluteTargetPath),
|
|
@@ -1013,13 +1112,11 @@ async function getNextBuilderDeferred() {
|
|
|
1013
1112
|
}
|
|
1014
1113
|
return null;
|
|
1015
1114
|
}
|
|
1016
|
-
async collectTransitiveStepFiles({
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
const discoveredStepFiles = new Set();
|
|
1022
|
-
const queuedFiles = [...normalizedSeedFiles];
|
|
1115
|
+
async collectTransitiveStepFiles({ entryFiles, stepFiles, }) {
|
|
1116
|
+
const normalizedEntryFiles = Array.from(new Set(entryFiles.map((entryFile) => this.normalizeDiscoveredFilePath(entryFile)))).sort();
|
|
1117
|
+
const normalizedStepSeedFiles = Array.from(new Set(stepFiles.map((stepFile) => this.normalizeDiscoveredFilePath(stepFile)))).sort();
|
|
1118
|
+
const discoveredStepFiles = new Set(normalizedStepSeedFiles);
|
|
1119
|
+
const queuedFiles = Array.from(new Set([...normalizedEntryFiles, ...normalizedStepSeedFiles]));
|
|
1023
1120
|
const visitedFiles = new Set();
|
|
1024
1121
|
const sourceCache = new Map();
|
|
1025
1122
|
const patternCache = new Map();
|
|
@@ -1060,12 +1157,8 @@ async function getNextBuilderDeferred() {
|
|
|
1060
1157
|
if (currentSource === null) {
|
|
1061
1158
|
continue;
|
|
1062
1159
|
}
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1065
|
-
discoveredStepFiles.add(currentFile);
|
|
1066
|
-
}
|
|
1067
|
-
const relativeImportSpecifiers = this.extractRelativeImportSpecifiers(currentSource);
|
|
1068
|
-
for (const specifier of relativeImportSpecifiers) {
|
|
1160
|
+
const importSpecifiers = this.extractImportSpecifiers(currentSource);
|
|
1161
|
+
for (const specifier of importSpecifiers) {
|
|
1069
1162
|
const resolvedImportPath = await this.resolveTransitiveStepImportTargetPath(currentFile, specifier);
|
|
1070
1163
|
if (!resolvedImportPath) {
|
|
1071
1164
|
continue;
|
|
@@ -1177,173 +1270,6 @@ async function getNextBuilderDeferred() {
|
|
|
1177
1270
|
}));
|
|
1178
1271
|
return verifiedSerdeFiles.sort();
|
|
1179
1272
|
}
|
|
1180
|
-
async createDeferredStepsManifest({ stepFiles, workflowFiles, serdeOnlyFiles, }) {
|
|
1181
|
-
const workflowManifest = {};
|
|
1182
|
-
const filesForStepTransform = Array.from(new Set([...stepFiles, ...serdeOnlyFiles])).sort();
|
|
1183
|
-
await Promise.all(filesForStepTransform.map(async (stepFile) => {
|
|
1184
|
-
const source = await (0, promises_1.readFile)(stepFile, 'utf-8');
|
|
1185
|
-
const relativeFilename = await this.getRelativeFilenameForSwc(stepFile);
|
|
1186
|
-
const { workflowManifest: fileManifest } = await applySwcTransform(relativeFilename, source, 'step', stepFile, this.config.projectRoot || this.config.workingDir);
|
|
1187
|
-
this.mergeWorkflowManifest(workflowManifest, fileManifest);
|
|
1188
|
-
}));
|
|
1189
|
-
const stepFileSet = new Set(stepFiles);
|
|
1190
|
-
const workflowOnlyFiles = workflowFiles
|
|
1191
|
-
.filter((workflowFile) => !stepFileSet.has(workflowFile))
|
|
1192
|
-
.sort();
|
|
1193
|
-
await Promise.all(workflowOnlyFiles.map(async (workflowFile) => {
|
|
1194
|
-
try {
|
|
1195
|
-
const source = await (0, promises_1.readFile)(workflowFile, 'utf-8');
|
|
1196
|
-
const relativeFilename = await this.getRelativeFilenameForSwc(workflowFile);
|
|
1197
|
-
const { workflowManifest: fileManifest } = await applySwcTransform(relativeFilename, source, 'workflow', workflowFile, this.config.projectRoot || this.config.workingDir);
|
|
1198
|
-
this.mergeWorkflowManifest(workflowManifest, {
|
|
1199
|
-
workflows: fileManifest.workflows,
|
|
1200
|
-
classes: fileManifest.classes,
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
|
-
catch (error) {
|
|
1204
|
-
console.log(`Warning: Failed to extract workflow metadata from ${workflowFile}:`, error instanceof Error ? error.message : String(error));
|
|
1205
|
-
}
|
|
1206
|
-
}));
|
|
1207
|
-
return workflowManifest;
|
|
1208
|
-
}
|
|
1209
|
-
async collectManifestStepSourceFiles(manifest) {
|
|
1210
|
-
const manifestStepEntries = Object.keys(manifest.steps || {});
|
|
1211
|
-
if (manifestStepEntries.length === 0) {
|
|
1212
|
-
return [];
|
|
1213
|
-
}
|
|
1214
|
-
const resolveBaseDirs = this.getManifestStepResolveBaseDirs();
|
|
1215
|
-
const candidateFiles = manifestStepEntries
|
|
1216
|
-
.flatMap((stepEntry) => {
|
|
1217
|
-
if ((0, node_path_1.isAbsolute)(stepEntry)) {
|
|
1218
|
-
return [this.normalizeDiscoveredFilePath(stepEntry)];
|
|
1219
|
-
}
|
|
1220
|
-
return resolveBaseDirs.map((baseDir) => this.normalizeDiscoveredFilePath((0, node_path_1.resolve)(baseDir, stepEntry)));
|
|
1221
|
-
})
|
|
1222
|
-
.filter((candidateFile) => !this.isGeneratedWorkflowArtifact(candidateFile));
|
|
1223
|
-
const existingCandidates = await this.filterExistingFiles(candidateFiles);
|
|
1224
|
-
return Array.from(new Set(existingCandidates)).sort();
|
|
1225
|
-
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Resolves the path to the workflow SDK's internal response builtins
|
|
1228
|
-
* step file. Returns the file as a pair of (absolute path, import
|
|
1229
|
-
* specifier) so the caller can include it in both the manifest
|
|
1230
|
-
* (absolute path) and the generated step/route.js (as an import).
|
|
1231
|
-
*/
|
|
1232
|
-
resolveResponseBuiltinsStepSource() {
|
|
1233
|
-
let resolved;
|
|
1234
|
-
try {
|
|
1235
|
-
resolved = require.resolve('workflow/internal/builtins', {
|
|
1236
|
-
paths: [this.config.workingDir],
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
catch {
|
|
1240
|
-
return null;
|
|
1241
|
-
}
|
|
1242
|
-
return {
|
|
1243
|
-
absolutePath: this.normalizeDiscoveredFilePath(resolved),
|
|
1244
|
-
importPath: 'workflow/internal/builtins',
|
|
1245
|
-
};
|
|
1246
|
-
}
|
|
1247
|
-
/**
|
|
1248
|
-
* Builds the import specifier for a given step/serde source file as it
|
|
1249
|
-
* should appear in the generated step/route.js. Package-provided files
|
|
1250
|
-
* are imported via their package specifier so the bundler resolves them
|
|
1251
|
-
* from the app's dependency graph. Local files are imported via a
|
|
1252
|
-
* relative path from the generated route.
|
|
1253
|
-
*/
|
|
1254
|
-
getStepRouteImportSpecifier(stepRouteFile, sourceFilePath) {
|
|
1255
|
-
const { importPath, isPackage } = getImportPath(sourceFilePath, this.config.workingDir);
|
|
1256
|
-
if (isPackage) {
|
|
1257
|
-
return importPath;
|
|
1258
|
-
}
|
|
1259
|
-
return this.getRelativeImportSpecifier(stepRouteFile, sourceFilePath);
|
|
1260
|
-
}
|
|
1261
|
-
async buildStepsFunction({ workflowGeneratedDir, routeFileName = 'route.js', discoveredEntries, additionalStepSourceManifest, }) {
|
|
1262
|
-
const stepsRouteDir = (0, node_path_1.join)(workflowGeneratedDir, 'step');
|
|
1263
|
-
await (0, promises_1.mkdir)(stepsRouteDir, { recursive: true });
|
|
1264
|
-
const discovered = discoveredEntries;
|
|
1265
|
-
const workflowFiles = [...discovered.discoveredWorkflows].sort();
|
|
1266
|
-
const stepFiles = await this.collectTransitiveStepFiles({
|
|
1267
|
-
stepFiles: [...discovered.discoveredSteps].sort(),
|
|
1268
|
-
// Workflow transforms can inline step IDs and remove runtime imports,
|
|
1269
|
-
// so seed transitive traversal with workflow files too.
|
|
1270
|
-
seedFiles: workflowFiles,
|
|
1271
|
-
});
|
|
1272
|
-
const serdeFiles = [...discovered.discoveredSerdeFiles].sort();
|
|
1273
|
-
const stepFileSet = new Set(stepFiles);
|
|
1274
|
-
const serdeOnlyFiles = serdeFiles.filter((file) => !stepFileSet.has(file));
|
|
1275
|
-
const additionalManifestStepFiles = additionalStepSourceManifest
|
|
1276
|
-
? await this.collectManifestStepSourceFiles(additionalStepSourceManifest)
|
|
1277
|
-
: [];
|
|
1278
|
-
const stepFilesWithManifestSources = Array.from(new Set([...stepFiles, ...additionalManifestStepFiles])).sort();
|
|
1279
|
-
const responseBuiltins = this.resolveResponseBuiltinsStepSource();
|
|
1280
|
-
const manifestStepFiles = Array.from(new Set([
|
|
1281
|
-
...stepFilesWithManifestSources,
|
|
1282
|
-
...(responseBuiltins ? [responseBuiltins.absolutePath] : []),
|
|
1283
|
-
])).sort();
|
|
1284
|
-
const manifest = await this.createDeferredStepsManifest({
|
|
1285
|
-
stepFiles: manifestStepFiles,
|
|
1286
|
-
workflowFiles,
|
|
1287
|
-
serdeOnlyFiles,
|
|
1288
|
-
});
|
|
1289
|
-
const manifestDiscoveredStepFiles = await this.collectManifestStepSourceFiles(manifest);
|
|
1290
|
-
// Step source files are imported directly from their original
|
|
1291
|
-
// locations. The workflow loader transforms every file it sees in
|
|
1292
|
-
// step mode, so package-provided sources register their step
|
|
1293
|
-
// functions as module side effects just like local sources do.
|
|
1294
|
-
const stepSourceFiles = Array.from(new Set([
|
|
1295
|
-
...stepFilesWithManifestSources,
|
|
1296
|
-
...manifestDiscoveredStepFiles,
|
|
1297
|
-
])).sort();
|
|
1298
|
-
const stepRouteFile = (0, node_path_1.join)(stepsRouteDir, routeFileName);
|
|
1299
|
-
const stepImportSpecifiers = new Set();
|
|
1300
|
-
if (responseBuiltins) {
|
|
1301
|
-
stepImportSpecifiers.add(responseBuiltins.importPath);
|
|
1302
|
-
}
|
|
1303
|
-
for (const stepSourceFile of stepSourceFiles) {
|
|
1304
|
-
stepImportSpecifiers.add(this.getStepRouteImportSpecifier(stepRouteFile, stepSourceFile));
|
|
1305
|
-
}
|
|
1306
|
-
const stepImports = Array.from(stepImportSpecifiers)
|
|
1307
|
-
.map((specifier) => `import '${specifier}';`)
|
|
1308
|
-
.join('\n');
|
|
1309
|
-
const serdeImports = serdeOnlyFiles
|
|
1310
|
-
.map((serdeFile) => {
|
|
1311
|
-
const normalizedSerdeFile = this.normalizeDiscoveredFilePath(serdeFile);
|
|
1312
|
-
return `import '${this.getStepRouteImportSpecifier(stepRouteFile, normalizedSerdeFile)}';`;
|
|
1313
|
-
})
|
|
1314
|
-
.join('\n');
|
|
1315
|
-
const routeContents = [
|
|
1316
|
-
'// biome-ignore-all lint: generated file',
|
|
1317
|
-
'/* eslint-disable */',
|
|
1318
|
-
stepImports,
|
|
1319
|
-
serdeImports
|
|
1320
|
-
? `// Serde files for cross-context class registration\n${serdeImports}`
|
|
1321
|
-
: '',
|
|
1322
|
-
"export { stepEntrypoint as POST } from 'workflow/runtime';",
|
|
1323
|
-
]
|
|
1324
|
-
.filter(Boolean)
|
|
1325
|
-
.join('\n');
|
|
1326
|
-
await this.writeFileIfChanged(stepRouteFile, routeContents);
|
|
1327
|
-
return {
|
|
1328
|
-
context: undefined,
|
|
1329
|
-
manifest,
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
async buildWorkflowsFunction({ inputFiles, workflowGeneratedDir, tsconfigPath, routeFileName = 'route.js', discoveredEntries, }) {
|
|
1333
|
-
const workflowsRouteDir = (0, node_path_1.join)(workflowGeneratedDir, 'flow');
|
|
1334
|
-
await (0, promises_1.mkdir)(workflowsRouteDir, { recursive: true });
|
|
1335
|
-
return await this.createWorkflowsBundle({
|
|
1336
|
-
format: 'esm',
|
|
1337
|
-
outfile: (0, node_path_1.join)(workflowsRouteDir, routeFileName),
|
|
1338
|
-
bundleFinalOutput: false,
|
|
1339
|
-
// Deferred builds do not reuse the interim esbuild context. Dispose it
|
|
1340
|
-
// after each pass to avoid leaking contexts during watch-mode rebuilds.
|
|
1341
|
-
keepInterimBundleContext: false,
|
|
1342
|
-
inputFiles,
|
|
1343
|
-
tsconfigPath,
|
|
1344
|
-
discoveredEntries,
|
|
1345
|
-
});
|
|
1346
|
-
}
|
|
1347
1273
|
async buildWebhookRoute({ workflowGeneratedDir, routeFileName = 'route.js', }) {
|
|
1348
1274
|
const webhookRouteFile = (0, node_path_1.join)(workflowGeneratedDir, `webhook/[token]/${routeFileName}`);
|
|
1349
1275
|
await this.createWebhookBundle({
|