@workflow/next 5.0.0-beta.2 → 5.0.0-beta.21

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/loader.js CHANGED
@@ -2,48 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = workflowLoader;
4
4
  const node_fs_1 = require("node:fs");
5
- const promises_1 = require("node:fs/promises");
6
- const node_net_1 = require("node:net");
7
5
  const node_path_1 = require("node:path");
8
6
  const core_1 = require("@swc/core");
9
- const socket_server_js_1 = require("./socket-server.js");
10
- const step_copy_utils_js_1 = require("./step-copy-utils.js");
11
7
  // Cache decorator options per working directory to avoid reading tsconfig for every file
12
8
  const decoratorOptionsCache = new Map();
13
9
  // Cache for shared utilities from @workflow/builders (ESM module loaded dynamically in CommonJS context)
14
10
  let cachedBuildersModule = null;
15
11
  let cachedLoaderStaticDependencies = null;
16
- const discoveredPatternStateByFilePath = new Map();
17
- // Cache socket connection to avoid reconnecting on every file.
18
- let socketClientPromise = null;
19
- let socketClient = null;
20
- let socketClientKey = null;
21
- const ROUTE_STUB_FILE_MARKER = 'WORKFLOW_ROUTE_STUB_FILE';
22
- const ROUTE_STUB_BUILD_WAIT_TIMEOUT_MS = 120_000;
23
- let pendingDeferredRouteStubBuildPromise = null;
24
12
  function registerFileDependency(loaderContext, dependencyPath) {
25
13
  loaderContext.addDependency?.(dependencyPath);
26
14
  loaderContext.addBuildDependency?.(dependencyPath);
27
15
  }
28
- function updateDiscoveredPatternState(filePath, nextState) {
29
- const previousState = discoveredPatternStateByFilePath.get(filePath);
30
- const hasAnyPattern = nextState.hasWorkflow || nextState.hasStep || nextState.hasSerde;
31
- if (!hasAnyPattern) {
32
- if (!previousState) {
33
- return { shouldNotify: false };
34
- }
35
- discoveredPatternStateByFilePath.delete(filePath);
36
- return { shouldNotify: true, previousState };
37
- }
38
- if (previousState &&
39
- previousState.hasWorkflow === nextState.hasWorkflow &&
40
- previousState.hasStep === nextState.hasStep &&
41
- previousState.hasSerde === nextState.hasSerde) {
42
- return { shouldNotify: false, previousState };
43
- }
44
- discoveredPatternStateByFilePath.set(filePath, nextState);
45
- return { shouldNotify: true, previousState };
46
- }
47
16
  function addIfExists(files, dependencyPath) {
48
17
  if ((0, node_fs_1.existsSync)(dependencyPath)) {
49
18
  files.add(dependencyPath);
@@ -62,8 +31,6 @@ function resolveLoaderStaticDependencies() {
62
31
  const workflowBuildersPackageJsonPath = (0, node_path_1.join)((0, node_path_1.dirname)(workflowBuildersPath), '../package.json');
63
32
  const files = new Set([
64
33
  __filename,
65
- require.resolve('./socket-server'),
66
- require.resolve('./step-copy-utils'),
67
34
  swcPluginPath,
68
35
  swcPluginBuildHashPath,
69
36
  workflowBuildersPath,
@@ -83,286 +50,6 @@ function registerTransformDependencies(loaderContext) {
83
50
  }
84
51
  return staticDependencies.swcPluginPath;
85
52
  }
86
- function resetSocketClient(cachedSocket) {
87
- if (cachedSocket && socketClient && socketClient !== cachedSocket) {
88
- return;
89
- }
90
- socketClientPromise = null;
91
- socketClient = null;
92
- socketClientKey = null;
93
- }
94
- async function writeSocketMessage(socket, message) {
95
- await new Promise((resolve, reject) => {
96
- socket.write(message, (error) => {
97
- if (error) {
98
- reject(error);
99
- return;
100
- }
101
- resolve();
102
- });
103
- });
104
- }
105
- function getSocketInfoFilePath() {
106
- const configuredPath = process.env.WORKFLOW_SOCKET_INFO_PATH;
107
- if (configuredPath) {
108
- return configuredPath;
109
- }
110
- // Fallback for worker processes that don't inherit dynamic env updates
111
- // from the process that created the socket server.
112
- const distDir = process.env.WORKFLOW_NEXT_DIST_DIR || '.next';
113
- const cwdFallbackPath = (0, node_path_1.join)(process.cwd(), distDir, 'cache', 'workflow-socket.json');
114
- const projectRoot = process.env.WORKFLOW_PROJECT_ROOT;
115
- if (projectRoot) {
116
- const projectRootFallbackPath = (0, node_path_1.join)(projectRoot, distDir, 'cache', 'workflow-socket.json');
117
- if ((0, node_fs_1.existsSync)(projectRootFallbackPath)) {
118
- return projectRootFallbackPath;
119
- }
120
- }
121
- return cwdFallbackPath;
122
- }
123
- function getSocketCredentialsFromEnv() {
124
- const socketPort = process.env.WORKFLOW_SOCKET_PORT;
125
- const authToken = process.env.WORKFLOW_SOCKET_AUTH;
126
- if (!socketPort || !authToken) {
127
- return null;
128
- }
129
- const port = Number.parseInt(socketPort, 10);
130
- if (Number.isNaN(port)) {
131
- return null;
132
- }
133
- return { port, authToken };
134
- }
135
- async function getSocketCredentialsFromFile() {
136
- const socketInfoFilePath = getSocketInfoFilePath();
137
- if (!socketInfoFilePath) {
138
- return null;
139
- }
140
- if (!(0, node_fs_1.existsSync)(socketInfoFilePath)) {
141
- return null;
142
- }
143
- try {
144
- const raw = await (0, promises_1.readFile)(socketInfoFilePath, 'utf8');
145
- const parsed = JSON.parse(raw);
146
- const authToken = typeof parsed.authToken === 'string' ? parsed.authToken : null;
147
- const numericPort = typeof parsed.port === 'number'
148
- ? parsed.port
149
- : Number.parseInt(String(parsed.port), 10);
150
- if (!authToken || Number.isNaN(numericPort)) {
151
- return null;
152
- }
153
- return {
154
- port: numericPort,
155
- authToken,
156
- };
157
- }
158
- catch {
159
- return null;
160
- }
161
- }
162
- async function getSocketCredentials() {
163
- const envCredentials = getSocketCredentialsFromEnv();
164
- if (envCredentials) {
165
- return envCredentials;
166
- }
167
- return await getSocketCredentialsFromFile();
168
- }
169
- async function getSocketClient() {
170
- const socketCredentials = await getSocketCredentials();
171
- if (!socketCredentials) {
172
- return null;
173
- }
174
- if (socketClient?.destroyed) {
175
- resetSocketClient(socketClient);
176
- }
177
- const currentSocketKey = `${socketCredentials.port}:${socketCredentials.authToken}`;
178
- if (socketClientKey && socketClientKey !== currentSocketKey) {
179
- if (socketClient) {
180
- resetSocketClient(socketClient);
181
- }
182
- else {
183
- resetSocketClient();
184
- }
185
- }
186
- if (!socketClientPromise) {
187
- socketClientPromise = (async () => {
188
- try {
189
- const socket = (0, node_net_1.connect)({
190
- port: socketCredentials.port,
191
- host: '127.0.0.1',
192
- });
193
- // Wait for connection
194
- await new Promise((resolve, reject) => {
195
- const onConnect = () => {
196
- socket.setNoDelay(true);
197
- cleanup();
198
- resolve();
199
- };
200
- const onError = (error) => {
201
- cleanup();
202
- reject(error);
203
- };
204
- const timeout = setTimeout(() => {
205
- cleanup();
206
- socket.destroy();
207
- reject(new Error('Socket connection timeout'));
208
- }, 1000);
209
- const cleanup = () => {
210
- clearTimeout(timeout);
211
- socket.off('connect', onConnect);
212
- socket.off('error', onError);
213
- };
214
- socket.on('connect', onConnect);
215
- socket.on('error', onError);
216
- });
217
- socket.on('close', () => {
218
- resetSocketClient(socket);
219
- });
220
- socket.on('error', () => {
221
- resetSocketClient(socket);
222
- });
223
- socketClient = socket;
224
- socketClientKey = currentSocketKey;
225
- return socket;
226
- }
227
- catch (error) {
228
- resetSocketClient();
229
- throw error;
230
- }
231
- })();
232
- }
233
- return socketClientPromise;
234
- }
235
- async function notifySocketServer(filename, hasWorkflow, hasStep, hasSerde) {
236
- const socketCredentials = await getSocketCredentials();
237
- if (!socketCredentials) {
238
- return;
239
- }
240
- const socket = await getSocketClient();
241
- if (!socket) {
242
- throw new Error('Invariant: missing workflow socket connection');
243
- }
244
- const message = {
245
- type: 'file-discovered',
246
- filePath: filename,
247
- hasWorkflow,
248
- hasStep,
249
- hasSerde,
250
- };
251
- const serializedMessage = (0, socket_server_js_1.serializeMessage)(message, socketCredentials.authToken);
252
- try {
253
- await writeSocketMessage(socket, serializedMessage);
254
- }
255
- catch (error) {
256
- resetSocketClient(socket);
257
- const reconnectedSocket = await getSocketClient();
258
- if (!reconnectedSocket) {
259
- throw error;
260
- }
261
- await writeSocketMessage(reconnectedSocket, serializedMessage);
262
- }
263
- }
264
- function isWorkflowRouteStubSource(source) {
265
- return source.includes(ROUTE_STUB_FILE_MARKER);
266
- }
267
- async function createSocketConnection(socketCredentials, timeoutMs = 1_000) {
268
- return await new Promise((resolve, reject) => {
269
- const socket = (0, node_net_1.connect)({
270
- port: socketCredentials.port,
271
- host: '127.0.0.1',
272
- });
273
- const timeout = setTimeout(() => {
274
- cleanup();
275
- socket.destroy();
276
- reject(new Error('Socket connection timeout'));
277
- }, timeoutMs);
278
- const cleanup = () => {
279
- clearTimeout(timeout);
280
- socket.off('connect', onConnect);
281
- socket.off('error', onError);
282
- };
283
- const onConnect = () => {
284
- socket.setNoDelay(true);
285
- cleanup();
286
- resolve(socket);
287
- };
288
- const onError = (error) => {
289
- cleanup();
290
- socket.destroy();
291
- reject(error);
292
- };
293
- socket.on('connect', onConnect);
294
- socket.on('error', onError);
295
- });
296
- }
297
- async function waitForDeferredBuildComplete(socket, authToken, timeoutMs = ROUTE_STUB_BUILD_WAIT_TIMEOUT_MS) {
298
- await new Promise((resolve, reject) => {
299
- let buffer = '';
300
- const timeout = setTimeout(() => {
301
- cleanup();
302
- reject(new Error('Timed out waiting for deferred route build completion'));
303
- }, timeoutMs);
304
- const cleanup = () => {
305
- clearTimeout(timeout);
306
- socket.off('data', onData);
307
- socket.off('error', onError);
308
- socket.off('close', onClose);
309
- socket.off('end', onClose);
310
- };
311
- const onError = (error) => {
312
- cleanup();
313
- reject(error);
314
- };
315
- const onClose = () => {
316
- cleanup();
317
- reject(new Error('Socket closed before deferred route build completed'));
318
- };
319
- const onData = (chunk) => {
320
- buffer += chunk.toString();
321
- let newlineIndex = buffer.indexOf('\n');
322
- while (newlineIndex !== -1) {
323
- const line = buffer.slice(0, newlineIndex);
324
- buffer = buffer.slice(newlineIndex + 1);
325
- newlineIndex = buffer.indexOf('\n');
326
- const message = (0, socket_server_js_1.parseMessage)(line, authToken);
327
- if (message?.type === 'build-complete') {
328
- cleanup();
329
- resolve();
330
- return;
331
- }
332
- }
333
- };
334
- socket.on('data', onData);
335
- socket.on('error', onError);
336
- socket.on('close', onClose);
337
- socket.on('end', onClose);
338
- });
339
- }
340
- async function triggerDeferredRouteStubBuildAndWait() {
341
- const socketCredentials = await getSocketCredentials();
342
- if (!socketCredentials) {
343
- return;
344
- }
345
- const socket = await createSocketConnection(socketCredentials);
346
- try {
347
- await writeSocketMessage(socket, (0, socket_server_js_1.serializeMessage)({ type: 'trigger-build' }, socketCredentials.authToken));
348
- await waitForDeferredBuildComplete(socket, socketCredentials.authToken);
349
- }
350
- finally {
351
- socket.destroy();
352
- }
353
- }
354
- async function ensureDeferredRouteStubBuildAndWait() {
355
- if (pendingDeferredRouteStubBuildPromise) {
356
- return pendingDeferredRouteStubBuildPromise;
357
- }
358
- const pendingPromise = triggerDeferredRouteStubBuildAndWait();
359
- pendingDeferredRouteStubBuildPromise = pendingPromise.finally(() => {
360
- if (pendingDeferredRouteStubBuildPromise === pendingPromise) {
361
- pendingDeferredRouteStubBuildPromise = null;
362
- }
363
- });
364
- return pendingDeferredRouteStubBuildPromise;
365
- }
366
53
  async function getBuildersModule() {
367
54
  if (cachedBuildersModule) {
368
55
  return cachedBuildersModule;
@@ -444,10 +131,6 @@ async function getRelativeFilenameForSwc(filename, workingDir) {
444
131
  }
445
132
  return relativeFilename;
446
133
  }
447
- function stripDeferredStepSourceMetadataComment(source) {
448
- const metadataPattern = new RegExp(`^\\s*//\\s*${step_copy_utils_js_1.DEFERRED_STEP_SOURCE_METADATA_PREFIX}[A-Za-z0-9+/=]+\\s*\\r?\\n?`);
449
- return source.replace(metadataPattern, '');
450
- }
451
134
  function workflowLoader(source, sourceMap) {
452
135
  const callback = this.async?.();
453
136
  const run = async () => {
@@ -455,67 +138,17 @@ function workflowLoader(source, sourceMap) {
455
138
  const normalizedSource = source.toString();
456
139
  const workingDir = process.cwd();
457
140
  const swcPluginPath = registerTransformDependencies(this);
458
- const isDeferredStepCopyFile = (0, step_copy_utils_js_1.isDeferredStepCopyFilePath)(filename);
459
- const deferredStepSourceMetadata = isDeferredStepCopyFile
460
- ? (0, step_copy_utils_js_1.parseDeferredStepSourceMetadata)(normalizedSource)
461
- : null;
462
- const sourceWithoutDeferredMetadata = isDeferredStepCopyFile
463
- ? stripDeferredStepSourceMetadataComment(normalizedSource)
464
- : normalizedSource;
465
- const deferredSourceMapResult = isDeferredStepCopyFile
466
- ? (0, step_copy_utils_js_1.parseInlineSourceMapComment)(sourceWithoutDeferredMetadata)
467
- : {
468
- sourceWithoutMapComment: sourceWithoutDeferredMetadata,
469
- sourceMap: null,
470
- };
471
- const sourceForTransform = deferredSourceMapResult.sourceWithoutMapComment;
472
- const discoveryFilePath = deferredStepSourceMetadata?.absolutePath || filename;
473
- if (deferredStepSourceMetadata?.absolutePath) {
474
- // Ensure edits to the original source invalidate deferred step copies.
475
- registerFileDependency(this, deferredStepSourceMetadata.absolutePath);
476
- }
141
+ const sourceForTransform = normalizedSource;
477
142
  const isGeneratedWorkflowFile = await checkGeneratedFile(filename);
478
- // Skip generated workflow route files to avoid re-processing them, except
479
- // deferred route stubs which must wait for generated route output.
480
- if (isGeneratedWorkflowFile && !isDeferredStepCopyFile) {
481
- if (process.env.WORKFLOW_NEXT_LAZY_DISCOVERY === '1' &&
482
- isWorkflowRouteStubSource(normalizedSource)) {
483
- try {
484
- await ensureDeferredRouteStubBuildAndWait();
485
- const refreshedSource = await (0, promises_1.readFile)(filename, 'utf8');
486
- if (!isWorkflowRouteStubSource(refreshedSource)) {
487
- return { code: refreshedSource, map: sourceMap };
488
- }
489
- }
490
- catch (error) {
491
- console.warn(`[workflow] Failed waiting for deferred route build for ${filename}, using stub output`, error);
492
- }
493
- }
143
+ // Skip generated workflow route files to avoid re-processing them.
144
+ if (isGeneratedWorkflowFile) {
494
145
  return { code: normalizedSource, map: sourceMap };
495
146
  }
496
147
  // Detect workflow patterns in the source code.
497
148
  const patterns = await detectPatterns(sourceForTransform);
498
- // Always notify discovery tracking, even for `false/false`, so files that
499
- // previously had workflow/step usage are removed from the tracked sets.
500
- // Deferred step copy files must report using their original source path so
501
- // deferred rebuilds can react to source edits outside generated artifacts.
502
- if (!isDeferredStepCopyFile || deferredStepSourceMetadata?.absolutePath) {
503
- const hasSerde = patterns.hasSerde;
504
- const nextPatternState = {
505
- hasWorkflow: patterns.hasUseWorkflow,
506
- hasStep: patterns.hasUseStep,
507
- hasSerde,
508
- };
509
- const { shouldNotify } = updateDiscoveredPatternState(discoveryFilePath, nextPatternState);
510
- if (shouldNotify) {
511
- await notifySocketServer(discoveryFilePath, nextPatternState.hasWorkflow, nextPatternState.hasStep, nextPatternState.hasSerde);
512
- }
513
- }
514
- if (!isDeferredStepCopyFile) {
515
- // Check if file needs transformation based on patterns and path
516
- if (!(await checkShouldTransform(filename, patterns))) {
517
- return { code: normalizedSource, map: sourceMap };
518
- }
149
+ // Check if file needs transformation based on patterns and path
150
+ if (!(await checkShouldTransform(filename, patterns))) {
151
+ return { code: normalizedSource, map: sourceMap };
519
152
  }
520
153
  const isTypeScript = filename.endsWith('.ts') ||
521
154
  filename.endsWith('.tsx') ||
@@ -523,16 +156,15 @@ function workflowLoader(source, sourceMap) {
523
156
  filename.endsWith('.cts');
524
157
  // Calculate relative filename for SWC plugin
525
158
  // The SWC plugin uses filename to generate workflowId, so it must be relative
526
- const relativeFilename = deferredStepSourceMetadata?.relativeFilename ||
527
- (await getRelativeFilenameForSwc(filename, workingDir));
159
+ const relativeFilename = await getRelativeFilenameForSwc(filename, workingDir);
528
160
  // Get decorator options from tsconfig (cached per working directory)
529
161
  const { options: decoratorOptions, configPath } = await getDecoratorOptions(workingDir);
530
162
  if (configPath) {
531
163
  registerFileDependency(this, configPath);
532
164
  }
533
165
  // Resolve module specifier for packages (node_modules or workspace packages)
534
- const moduleSpecifier = await getModuleSpecifier(deferredStepSourceMetadata?.absolutePath || filename, workingDir);
535
- const mode = isDeferredStepCopyFile ? 'step' : 'client';
166
+ const moduleSpecifier = await getModuleSpecifier(filename, workingDir);
167
+ const mode = 'step';
536
168
  // Transform with SWC
537
169
  const result = await (0, core_1.transform)(sourceForTransform, {
538
170
  filename: relativeFilename,
@@ -563,9 +195,7 @@ function workflowLoader(source, sourceMap) {
563
195
  },
564
196
  },
565
197
  minify: false,
566
- inputSourceMap: isDeferredStepCopyFile
567
- ? deferredSourceMapResult.sourceMap || sourceMap
568
- : sourceMap,
198
+ inputSourceMap: sourceMap,
569
199
  sourceMaps: true,
570
200
  inlineSourcesContent: true,
571
201
  });
@@ -592,4 +222,4 @@ function workflowLoader(source, sourceMap) {
592
222
  callback(error instanceof Error ? error : new Error(String(error)));
593
223
  });
594
224
  }
595
- //# sourceMappingURL=loader.js.map
225
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2xvYWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQW9OQSxpQ0E2R0M7QUFqVUQscUNBQXFDO0FBQ3JDLHlDQUFvRDtBQUNwRCxvQ0FBc0M7QUFNdEMseUZBQXlGO0FBQ3pGLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxHQUFHLEVBR2xDLENBQUM7QUFDSix5R0FBeUc7QUFDekcsSUFBSSxvQkFBb0IsR0FBK0MsSUFBSSxDQUFDO0FBSzVFLElBQUksOEJBQThCLEdBQW9DLElBQUksQ0FBQztBQUUzRSxTQUFTLHNCQUFzQixDQUM3QixhQUFvQyxFQUNwQyxjQUFzQjtJQUV0QixhQUFhLENBQUMsYUFBYSxFQUFFLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDOUMsYUFBYSxDQUFDLGtCQUFrQixFQUFFLENBQUMsY0FBYyxDQUFDLENBQUM7QUFDckQsQ0FBQztBQUVELFNBQVMsV0FBVyxDQUFDLEtBQWtCLEVBQUUsY0FBc0I7SUFDN0QsSUFBSSxJQUFBLG9CQUFVLEVBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztRQUMvQixLQUFLLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQzVCLENBQUM7QUFDSCxDQUFDO0FBRUQsU0FBUywrQkFBK0I7SUFDdEMsSUFBSSw4QkFBOEIsRUFBRSxDQUFDO1FBQ25DLE9BQU8sOEJBQThCLENBQUM7SUFDeEMsQ0FBQztJQUVELE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUM5RCxNQUFNLHNCQUFzQixHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQzVDLHNDQUFzQyxDQUN2QyxDQUFDO0lBQ0YsTUFBTSxvQkFBb0IsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFFbkUsK0RBQStEO0lBQy9ELG9FQUFvRTtJQUNwRSxNQUFNLHdCQUF3QixHQUFHLElBQUEsZ0JB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aW1wb3J0IHsgZGlybmFtZSwgam9pbiwgcmVsYXRpdmUgfSBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHsgdHJhbnNmb3JtIH0gZnJvbSAnQHN3Yy9jb3JlJztcblxudHlwZSBEZWNvcmF0b3JPcHRpb25zV2l0aENvbmZpZ1BhdGggPVxuICBpbXBvcnQoJ0B3b3JrZmxvdy9idWlsZGVycycpLkRlY29yYXRvck9wdGlvbnNXaXRoQ29uZmlnUGF0aDtcbnR5cGUgV29ya2Zsb3dQYXR0ZXJuTWF0Y2ggPSBpbXBvcnQoJ0B3b3JrZmxvdy9idWlsZGVycycpLldvcmtmbG93UGF0dGVybk1hdGNoO1xuXG4vLyBDYWNoZSBkZWNvcmF0b3Igb3B0aW9ucyBwZXIgd29ya2luZyBkaXJlY3RvcnkgdG8gYXZvaWQgcmVhZGluZyB0c2NvbmZpZyBmb3IgZXZlcnkgZmlsZVxuY29uc3QgZGVjb3JhdG9yT3B0aW9uc0NhY2hlID0gbmV3IE1hcDxcbiAgc3RyaW5nLFxuICBQcm9taXNlPERlY29yYXRvck9wdGlvbnNXaXRoQ29uZmlnUGF0aD5cbj4oKTtcbi8vIENhY2hlIGZvciBzaGFyZWQgdXRpbGl0aWVzIGZyb20gQHdvcmtmbG93L2J1aWxkZXJzIChFU00gbW9kdWxlIGxvYWRlZCBkeW5hbWljYWxseSBpbiBDb21tb25KUyBjb250ZXh0KVxubGV0IGNhY2hlZEJ1aWxkZXJzTW9kdWxlOiB0eXBlb2YgaW1wb3J0KCdAd29ya2Zsb3cvYnVpbGRlcnMnKSB8IG51bGwgPSBudWxsO1xudHlwZSBMb2FkZXJTdGF0aWNEZXBlbmRlbmNpZXMgPSB7XG4gIHN3Y1BsdWdpblBhdGg6IHN0cmluZztcbiAgZmlsZXM6IHN0cmluZ1tdO1xufTtcbmxldCBjYWNoZWRMb2FkZXJTdGF0aWNEZXBlbmRlbmNpZXM6IExvYWRlclN0YXRpY0RlcGVuZGVuY2llcyB8IG51bGwgPSBudWxsO1xuXG5mdW5jdGlvbiByZWdpc3RlckZpbGVEZXBlbmRlbmN5KFxuICBsb2FkZXJDb250ZXh0OiBXb3JrZmxvd0xvYWRlckNvbnRleHQsXG4gIGRlcGVuZGVuY3lQYXRoOiBzdHJpbmdcbik6IHZvaWQge1xuICBsb2FkZXJDb250ZXh0LmFkZERlcGVuZGVuY3k/LihkZXBlbmRlbmN5UGF0aCk7XG4gIGxvYWRlckNvbnRleHQuYWRkQnVpbGREZXBlbmRlbmN5Py4oZGVwZW5kZW5jeVBhdGgpO1xufVxuXG5mdW5jdGlvbiBhZGRJZkV4aXN0cyhmaWxlczogU2V0PHN0cmluZz4sIGRlcGVuZGVuY3lQYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKGV4aXN0c1N5bmMoZGVwZW5kZW5jeVBhdGgpKSB7XG4gICAgZmlsZXMuYWRkKGRlcGVuZGVuY3lQYXRoKTtcbiAgfVxufVxuXG5mdW5jdGlvbiByZXNvbHZlTG9hZGVyU3RhdGljRGVwZW5kZW5jaWVzKCk6IExvYWRlclN0YXRpY0RlcGVuZGVuY2llcyB7XG4gIGlmIChjYWNoZWRMb2FkZXJTdGF0aWNEZXBlbmRlbmNpZXMpIHtcbiAgICByZXR1cm4gY2FjaGVkTG9hZGVyU3RhdGljRGVwZW5kZW5jaWVzO1xuICB9XG5cbiAgY29uc3Qgc3djUGx1Z2luUGF0aCA9IHJlcXVpcmUucmVzb2x2ZSgnQHdvcmtmbG93L3N3Yy1wbHVnaW4nKTtcbiAgY29uc3Qgc3djUGx1Z2luQnVpbGRIYXNoUGF0aCA9IHJlcXVpcmUucmVzb2x2ZShcbiAgICAnQHdvcmtmbG93L3N3Yy1wbHVnaW4vYnVpbGQtaGFzaC5qc29uJ1xuICApO1xuICBjb25zdCB3b3JrZmxvd0J1aWxkZXJzUGF0aCA9IHJlcXVpcmUucmVzb2x2ZSgnQHdvcmtmbG93L2J1aWxkZXJzJyk7XG5cbiAgLy8gRGVyaXZlIHBhY2thZ2UuanNvbiBwYXRocyBmcm9tIHJlc29sdmVkIGVudHJ5cG9pbnRzIHRvIGF2b2lkXG4gIC8vIFR1cmJvcGFjayBsb2FkZXItZXZhbCBmYWlsdXJlcyBhcm91bmQgLi4vcGFja2FnZS5qc29uIHJlc29sdXRpb24uXG4gIGNvbnN0IHN3Y1BsdWdpblBhY2thZ2VKc29uUGF0aCA9IGpvaW4oZGlybmFtZShzd2NQbHVnaW5QYXRoKSwgJ3BhY2thZ2UuanNvbicpO1xuICBjb25zdCB3b3JrZmxvd0J1aWxkZXJzUGFja2FnZUpzb25QYXRoID0gam9pbihcbiAgICBkaXJuYW1lKHdvcmtmbG93QnVpbGRlcnNQYXRoKSxcbiAgICAnLi4vcGFja2FnZS5qc29uJ1xuICApO1xuXG4gIGNvbnN0IGZpbGVzID0gbmV3IFNldDxzdHJpbmc+KFtcbiAgICBfX2ZpbGVuYW1lLFxuICAgIHN3Y1BsdWdpblBhdGgsXG4gICAgc3djUGx1Z2luQnVpbGRIYXNoUGF0aCxcbiAgICB3b3JrZmxvd0J1aWxkZXJzUGF0aCxcbiAgXSk7XG4gIGFkZElmRXhpc3RzKGZpbGVzLCBzd2NQbHVnaW5QYWNrYWdlSnNvblBhdGgpO1xuICBhZGRJZkV4aXN0cyhmaWxlcywgd29ya2Zsb3dCdWlsZGVyc1BhY2thZ2VKc29uUGF0aCk7XG5cbiAgY2FjaGVkTG9hZGVyU3RhdGljRGVwZW5kZW5jaWVzID0ge1xuICAgIHN3Y1BsdWdpblBhdGgsXG4gICAgZmlsZXM6IEFycmF5LmZyb20oZmlsZXMpLFxuICB9O1xuICByZXR1cm4gY2FjaGVkTG9hZGVyU3RhdGljRGVwZW5kZW5jaWVzO1xufVxuXG5mdW5jdGlvbiByZWdpc3RlclRyYW5zZm9ybURlcGVuZGVuY2llcyhcbiAgbG9hZGVyQ29udGV4dDogV29ya2Zsb3dMb2FkZXJDb250ZXh0XG4pOiBzdHJpbmcge1xuICBjb25zdCBzdGF0aWNEZXBlbmRlbmNpZXMgPSByZXNvbHZlTG9hZGVyU3RhdGljRGVwZW5kZW5jaWVzKCk7XG4gIGZvciAoY29uc3QgZGVwZW5kZW5jeVBhdGggb2Ygc3RhdGljRGVwZW5kZW5jaWVzLmZpbGVzKSB7XG4gICAgcmVnaXN0ZXJGaWxlRGVwZW5kZW5jeShsb2FkZXJDb250ZXh0LCBkZXBlbmRlbmN5UGF0aCk7XG4gIH1cblxuICByZXR1cm4gc3RhdGljRGVwZW5kZW5jaWVzLnN3Y1BsdWdpblBhdGg7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEJ1aWxkZXJzTW9kdWxlKCk6IFByb21pc2U8XG4gIHR5cGVvZiBpbXBvcnQoJ0B3b3JrZmxvdy9idWlsZGVycycpXG4+IHtcbiAgaWYgKGNhY2hlZEJ1aWxkZXJzTW9kdWxlKSB7XG4gICAgcmV0dXJuIGNhY2hlZEJ1aWxkZXJzTW9kdWxlO1xuICB9XG4gIC8vIER5bmFtaWMgaW1wb3J0IHRvIGhhbmRsZSBFU00gbW9kdWxlIGZyb20gQ29tbW9uSlMgY29udGV4dFxuICAvLyBiaW9tZS1pZ25vcmUgbGludC9zZWN1cml0eS9ub0dsb2JhbEV2YWw6IE5lZWQgdG8gdXNlIGV2YWwgaGVyZSB0byBhdm9pZCBUeXBlU2NyaXB0IGZyb20gdHJhbnNwaWxpbmcgdGhlIGltcG9ydCBzdGF0ZW1lbnQgaW50byBgcmVxdWlyZSgpYFxuICBjYWNoZWRCdWlsZGVyc01vZHVsZSA9IChhd2FpdCBldmFsKFxuICAgICdpbXBvcnQoXCJAd29ya2Zsb3cvYnVpbGRlcnNcIiknXG4gICkpIGFzIHR5cGVvZiBpbXBvcnQoJ0B3b3JrZmxvdy9idWlsZGVycycpO1xuICByZXR1cm4gY2FjaGVkQnVpbGRlcnNNb2R1bGU7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldERlY29yYXRvck9wdGlvbnMoXG4gIHdvcmtpbmdEaXI6IHN0cmluZ1xuKTogUHJvbWlzZTxEZWNvcmF0b3JPcHRpb25zV2l0aENvbmZpZ1BhdGg+IHtcbiAgY29uc3QgY2FjaGVkID0gZGVjb3JhdG9yT3B0aW9uc0NhY2hlLmdldCh3b3JraW5nRGlyKTtcbiAgaWYgKGNhY2hlZCkge1xuICAgIHJldHVybiBjYWNoZWQ7XG4gIH1cblxuICBjb25zdCBwcm9taXNlID0gKGFzeW5jICgpOiBQcm9taXNlPERlY29yYXRvck9wdGlvbnNXaXRoQ29uZmlnUGF0aD4gPT4ge1xuICAgIGNvbnN0IHsgZ2V0RGVjb3JhdG9yT3B0aW9uc0ZvckRpcmVjdG9yeVdpdGhDb25maWdQYXRoIH0gPVxuICAgICAgYXdhaXQgZ2V0QnVpbGRlcnNNb2R1bGUoKTtcbiAgICByZXR1cm4gZ2V0RGVjb3JhdG9yT3B0aW9uc0ZvckRpcmVjdG9yeVdpdGhDb25maWdQYXRoKHdvcmtpbmdEaXIpO1xuICB9KSgpO1xuXG4gIGRlY29yYXRvck9wdGlvbnNDYWNoZS5zZXQod29ya2luZ0RpciwgcHJvbWlzZSk7XG4gIHJldHVybiBwcm9taXNlO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZXRlY3RQYXR0ZXJucyhzb3VyY2U6IHN0cmluZyk6IFByb21pc2U8V29ya2Zsb3dQYXR0ZXJuTWF0Y2g+IHtcbiAgY29uc3QgeyBkZXRlY3RXb3JrZmxvd1BhdHRlcm5zIH0gPSBhd2FpdCBnZXRCdWlsZGVyc01vZHVsZSgpO1xuICByZXR1cm4gZGV0ZWN0V29ya2Zsb3dQYXR0ZXJucyhzb3VyY2UpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjaGVja0dlbmVyYXRlZEZpbGUoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCB7IGlzR2VuZXJhdGVkV29ya2Zsb3dGaWxlIH0gPSBhd2FpdCBnZXRCdWlsZGVyc01vZHVsZSgpO1xuICByZXR1cm4gaXNHZW5lcmF0ZWRXb3JrZmxvd0ZpbGUoZmlsZVBhdGgpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjaGVja1Nob3VsZFRyYW5zZm9ybShcbiAgZmlsZVBhdGg6IHN0cmluZyxcbiAgcGF0dGVybnM6IFdvcmtmbG93UGF0dGVybk1hdGNoXG4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3QgeyBzaG91bGRUcmFuc2Zvcm1GaWxlIH0gPSBhd2FpdCBnZXRCdWlsZGVyc01vZHVsZSgpO1xuICByZXR1cm4gc2hvdWxkVHJhbnNmb3JtRmlsZShmaWxlUGF0aCwgcGF0dGVybnMpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRNb2R1bGVTcGVjaWZpZXIoXG4gIGZpbGVQYXRoOiBzdHJpbmcsXG4gIHByb2plY3RSb290OiBzdHJpbmdcbik6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IHsgcmVzb2x2ZU1vZHVsZVNwZWNpZmllciB9ID0gYXdhaXQgZ2V0QnVpbGRlcnNNb2R1bGUoKTtcbiAgcmV0dXJuIHJlc29sdmVNb2R1bGVTcGVjaWZpZXIoZmlsZVBhdGgsIHByb2plY3RSb290KS5tb2R1bGVTcGVjaWZpZXI7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVXb3JrZmxvd0FsaWFzUGF0aChcbiAgZmlsZVBhdGg6IHN0cmluZyxcbiAgd29ya2luZ0Rpcjogc3RyaW5nXG4pOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBjb25zdCB7IHJlc29sdmVXb3JrZmxvd0FsaWFzUmVsYXRpdmVQYXRoIH0gPSBhd2FpdCBnZXRCdWlsZGVyc01vZHVsZSgpO1xuICByZXR1cm4gcmVzb2x2ZVdvcmtmbG93QWxpYXNSZWxhdGl2ZVBhdGgoZmlsZVBhdGgsIHdvcmtpbmdEaXIpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRSZWxhdGl2ZUZpbGVuYW1lRm9yU3djKFxuICBmaWxlbmFtZTogc3RyaW5nLFxuICB3b3JraW5nRGlyOiBzdHJpbmdcbik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRXb3JraW5nRGlyID0gd29ya2luZ0RpclxuICAgIC5yZXBsYWNlKC9cXFxcL2csICcvJylcbiAgICAucmVwbGFjZSgvXFwvJC8sICcnKTtcbiAgY29uc3Qgbm9ybWFsaXplZEZpbGVwYXRoID0gZmlsZW5hbWUucmVwbGFjZSgvXFxcXC9nLCAnLycpO1xuXG4gIC8vIFdpbmRvd3MgZml4OiBVc2UgY2FzZS1pbnNlbnNpdGl2ZSBjb21wYXJpc29uIHRvIHdvcmsgYXJvdW5kIGRyaXZlIGxldHRlciBjYXNpbmcgaXNzdWVzXG4gIGNvbnN0IGxvd2VyV2QgPSBub3JtYWxpemVkV29ya2luZ0Rpci50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCBsb3dlclBhdGggPSBub3JtYWxpemVkRmlsZXBhdGgudG9Mb3dlckNhc2UoKTtcblxuICBsZXQgcmVsYXRpdmVGaWxlbmFtZTogc3RyaW5nO1xuICBpZiAobG93ZXJQYXRoLnN0YXJ0c1dpdGgoYCR7bG93ZXJXZH0vYCkpIHtcbiAgICAvLyBGaWxlIGlzIHVuZGVyIHdvcmtpbmcgZGlyZWN0b3J5IC0gbWFudWFsbHkgY2FsY3VsYXRlIHJlbGF0aXZlIHBhdGhcbiAgICByZWxhdGl2ZUZpbGVuYW1lID0gbm9ybWFsaXplZEZpbGVwYXRoLnN1YnN0cmluZyhcbiAgICAgIG5vcm1hbGl6ZWRXb3JraW5nRGlyLmxlbmd0aCArIDFcbiAgICApO1xuICB9IGVsc2UgaWYgKGxvd2VyUGF0aCA9PT0gbG93ZXJXZCkge1xuICAgIC8vIEZpbGUgSVMgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IChzaG91bGRuJ3QgaGFwcGVuKVxuICAgIHJlbGF0aXZlRmlsZW5hbWUgPSAnLic7XG4gIH0gZWxzZSB7XG4gICAgLy8gVXNlIHJlbGF0aXZlKCkgZm9yIGZpbGVzIG91dHNpZGUgd29ya2luZyBkaXJlY3RvcnlcbiAgICByZWxhdGl2ZUZpbGVuYW1lID0gcmVsYXRpdmUod29ya2luZ0RpciwgZmlsZW5hbWUpLnJlcGxhY2UoL1xcXFwvZywgJy8nKTtcblxuICAgIGlmIChyZWxhdGl2ZUZpbGVuYW1lLnN0YXJ0c1dpdGgoJy4uLycpKSB7XG4gICAgICBjb25zdCBhbGlhc2VkUmVsYXRpdmVQYXRoID0gYXdhaXQgcmVzb2x2ZVdvcmtmbG93QWxpYXNQYXRoKFxuICAgICAgICBmaWxlbmFtZSxcbiAgICAgICAgd29ya2luZ0RpclxuICAgICAgKTtcbiAgICAgIGlmIChhbGlhc2VkUmVsYXRpdmVQYXRoKSB7XG4gICAgICAgIHJlbGF0aXZlRmlsZW5hbWUgPSBhbGlhc2VkUmVsYXRpdmVQYXRoO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVsYXRpdmVGaWxlbmFtZSA9IHJlbGF0aXZlRmlsZW5hbWVcbiAgICAgICAgICAuc3BsaXQoJy8nKVxuICAgICAgICAgIC5maWx0ZXIoKHBhcnQpID0+IHBhcnQgIT09ICcuLicpXG4gICAgICAgICAgLmpvaW4oJy8nKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBGaW5hbCBzYWZldHkgY2hlY2sgLSBlbnN1cmUgd2UgbmV2ZXIgcGFzcyBhbiBhYnNvbHV0ZSBwYXRoIHRvIFNXQ1xuICBpZiAocmVsYXRpdmVGaWxlbmFtZS5pbmNsdWRlcygnOicpIHx8IHJlbGF0aXZlRmlsZW5hbWUuc3RhcnRzV2l0aCgnLycpKSB7XG4gICAgLy8gVGhpcyBzaG91bGQgcmFyZWx5IGhhcHBlbiwgYnV0IHVzZSBmaWxlbmFtZSBzcGxpdCBhcyBsYXN0IHJlc29ydFxuICAgIHJlbGF0aXZlRmlsZW5hbWUgPSBub3JtYWxpemVkRmlsZXBhdGguc3BsaXQoJy8nKS5wb3AoKSB8fCAndW5rbm93bi50cyc7XG4gIH1cblxuICByZXR1cm4gcmVsYXRpdmVGaWxlbmFtZTtcbn1cblxuLy8gVGhpcyBsb2FkZXIgYXBwbGllcyB0aGUgXCJ1c2Ugd29ya2Zsb3dcIi9cInVzZSBzdGVwXCIgdHJhbnNmb3JtLlxuLy8gQWxsIGZpbGVzIHVzZSBzdGVwIG1vZGU7IHRoZSBTV0MgcGx1Z2luIGRlY2lkZXMgcGVyLWZ1bmN0aW9uIHdoZXRoZXJcbi8vIHRvIGVtaXQgd29ya2Zsb3cgb3Igc3RlcCBiaW5kaW5ncyBiYXNlZCBvbiB0aGUgc291cmNlJ3MgZGlyZWN0aXZlcy5cbnR5cGUgV29ya2Zsb3dMb2FkZXJDb250ZXh0ID0ge1xuICByZXNvdXJjZVBhdGg6IHN0cmluZztcbiAgYXN5bmM/OiAoKSA9PiAoXG4gICAgZXJyb3I6IEVycm9yIHwgbnVsbCxcbiAgICBjb250ZW50Pzogc3RyaW5nLFxuICAgIHNvdXJjZU1hcD86IGFueVxuICApID0+IHZvaWQ7XG4gIGFkZERlcGVuZGVuY3k/OiAoZGVwZW5kZW5jeTogc3RyaW5nKSA9PiB2b2lkO1xuICBhZGRCdWlsZERlcGVuZGVuY3k/OiAoZGVwZW5kZW5jeTogc3RyaW5nKSA9PiB2b2lkO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gd29ya2Zsb3dMb2FkZXIoXG4gIHRoaXM6IFdvcmtmbG93TG9hZGVyQ29udGV4dCxcbiAgc291cmNlOiBzdHJpbmcgfCBCdWZmZXIsXG4gIHNvdXJjZU1hcDogYW55XG4pOiBzdHJpbmcgfCBQcm9taXNlPHN0cmluZz4gfCB2b2lkIHtcbiAgY29uc3QgY2FsbGJhY2sgPSB0aGlzLmFzeW5jPy4oKTtcbiAgY29uc3QgcnVuID0gYXN5bmMgKCk6IFByb21pc2U8eyBjb2RlOiBzdHJpbmc7IG1hcDogYW55IH0+ID0+IHtcbiAgICBjb25zdCBmaWxlbmFtZSA9IHRoaXMucmVzb3VyY2VQYXRoO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRTb3VyY2UgPSBzb3VyY2UudG9TdHJpbmcoKTtcbiAgICBjb25zdCB3b3JraW5nRGlyID0gcHJvY2Vzcy5jd2QoKTtcbiAgICBjb25zdCBzd2NQbHVnaW5QYXRoID0gcmVnaXN0ZXJUcmFuc2Zvcm1EZXBlbmRlbmNpZXModGhpcyk7XG4gICAgY29uc3Qgc291cmNlRm9yVHJhbnNmb3JtID0gbm9ybWFsaXplZFNvdXJjZTtcblxuICAgIGNvbnN0IGlzR2VuZXJhdGVkV29ya2Zsb3dGaWxlID0gYXdhaXQgY2hlY2tHZW5lcmF0ZWRGaWxlKGZpbGVuYW1lKTtcbiAgICAvLyBTa2lwIGdlbmVyYXRlZCB3b3JrZmxvdyByb3V0ZSBmaWxlcyB0byBhdm9pZCByZS1wcm9jZXNzaW5nIHRoZW0uXG4gICAgaWYgKGlzR2VuZXJhdGVkV29ya2Zsb3dGaWxlKSB7XG4gICAgICByZXR1cm4geyBjb2RlOiBub3JtYWxpemVkU291cmNlLCBtYXA6IHNvdXJjZU1hcCB9O1xuICAgIH1cblxuICAgIC8vIERldGVjdCB3b3JrZmxvdyBwYXR0ZXJucyBpbiB0aGUgc291cmNlIGNvZGUuXG4gICAgY29uc3QgcGF0dGVybnMgPSBhd2FpdCBkZXRlY3RQYXR0ZXJucyhzb3VyY2VGb3JUcmFuc2Zvcm0pO1xuXG4gICAgLy8gQ2hlY2sgaWYgZmlsZSBuZWVkcyB0cmFuc2Zvcm1hdGlvbiBiYXNlZCBvbiBwYXR0ZXJucyBhbmQgcGF0aFxuICAgIGlmICghKGF3YWl0IGNoZWNrU2hvdWxkVHJhbnNmb3JtKGZpbGVuYW1lLCBwYXR0ZXJucykpKSB7XG4gICAgICByZXR1cm4geyBjb2RlOiBub3JtYWxpemVkU291cmNlLCBtYXA6IHNvdXJjZU1hcCB9O1xuICAgIH1cblxuICAgIGNvbnN0IGlzVHlwZVNjcmlwdCA9XG4gICAgICBmaWxlbmFtZS5lbmRzV2l0aCgnLnRzJykgfHxcbiAgICAgIGZpbGVuYW1lLmVuZHNXaXRoKCcudHN4JykgfHxcbiAgICAgIGZpbGVuYW1lLmVuZHNXaXRoKCcubXRzJykgfHxcbiAgICAgIGZpbGVuYW1lLmVuZHNXaXRoKCcuY3RzJyk7XG5cbiAgICAvLyBDYWxjdWxhdGUgcmVsYXRpdmUgZmlsZW5hbWUgZm9yIFNXQyBwbHVnaW5cbiAgICAvLyBUaGUgU1dDIHBsdWdpbiB1c2VzIGZpbGVuYW1lIHRvIGdlbmVyYXRlIHdvcmtmbG93SWQsIHNvIGl0IG11c3QgYmUgcmVsYXRpdmVcbiAgICBjb25zdCByZWxhdGl2ZUZpbGVuYW1lID0gYXdhaXQgZ2V0UmVsYXRpdmVGaWxlbmFtZUZvclN3YyhcbiAgICAgIGZpbGVuYW1lLFxuICAgICAgd29ya2luZ0RpclxuICAgICk7XG5cbiAgICAvLyBHZXQgZGVjb3JhdG9yIG9wdGlvbnMgZnJvbSB0c2NvbmZpZyAoY2FjaGVkIHBlciB3b3JraW5nIGRpcmVjdG9yeSlcbiAgICBjb25zdCB7IG9wdGlvbnM6IGRlY29yYXRvck9wdGlvbnMsIGNvbmZpZ1BhdGggfSA9XG4gICAgICBhd2FpdCBnZXREZWNvcmF0b3JPcHRpb25zKHdvcmtpbmdEaXIpO1xuICAgIGlmIChjb25maWdQYXRoKSB7XG4gICAgICByZWdpc3RlckZpbGVEZXBlbmRlbmN5KHRoaXMsIGNvbmZpZ1BhdGgpO1xuICAgIH1cblxuICAgIC8vIFJlc29sdmUgbW9kdWxlIHNwZWNpZmllciBmb3IgcGFja2FnZXMgKG5vZGVfbW9kdWxlcyBvciB3b3Jrc3BhY2UgcGFja2FnZXMpXG4gICAgY29uc3QgbW9kdWxlU3BlY2lmaWVyID0gYXdhaXQgZ2V0TW9kdWxlU3BlY2lmaWVyKGZpbGVuYW1lLCB3b3JraW5nRGlyKTtcbiAgICBjb25zdCBtb2RlID0gJ3N0ZXAnO1xuXG4gICAgLy8gVHJhbnNmb3JtIHdpdGggU1dDXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdHJhbnNmb3JtKHNvdXJjZUZvclRyYW5zZm9ybSwge1xuICAgICAgZmlsZW5hbWU6IHJlbGF0aXZlRmlsZW5hbWUsXG4gICAgICBqc2M6IHtcbiAgICAgICAgcGFyc2VyOiB7XG4gICAgICAgICAgLi4uKGlzVHlwZVNjcmlwdFxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgc3ludGF4OiAndHlwZXNjcmlwdCcsXG4gICAgICAgICAgICAgICAgdHN4OiBmaWxlbmFtZS5lbmRzV2l0aCgnLnRzeCcpLFxuICAgICAgICAgICAgICAgIGRlY29yYXRvcnM6IGRlY29yYXRvck9wdGlvbnMuZGVjb3JhdG9ycyxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgc3ludGF4OiAnZWNtYXNjcmlwdCcsXG4gICAgICAgICAgICAgICAganN4OiBmaWxlbmFtZS5lbmRzV2l0aCgnLmpzeCcpLFxuICAgICAgICAgICAgICAgIGRlY29yYXRvcnM6IGRlY29yYXRvck9wdGlvbnMuZGVjb3JhdG9ycyxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgIH0sXG4gICAgICAgIHRhcmdldDogJ2VzMjAyMicsXG4gICAgICAgIGV4cGVyaW1lbnRhbDoge1xuICAgICAgICAgIHBsdWdpbnM6IFtbc3djUGx1Z2luUGF0aCwgeyBtb2RlLCBtb2R1bGVTcGVjaWZpZXIgfV1dLFxuICAgICAgICB9LFxuICAgICAgICB0cmFuc2Zvcm06IHtcbiAgICAgICAgICByZWFjdDoge1xuICAgICAgICAgICAgcnVudGltZTogJ3ByZXNlcnZlJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGxlZ2FjeURlY29yYXRvcjogZGVjb3JhdG9yT3B0aW9ucy5sZWdhY3lEZWNvcmF0b3IsXG4gICAgICAgICAgZGVjb3JhdG9yTWV0YWRhdGE6IGRlY29yYXRvck9wdGlvbnMuZGVjb3JhdG9yTWV0YWRhdGEsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgbWluaWZ5OiBmYWxzZSxcbiAgICAgIGlucHV0U291cmNlTWFwOiBzb3VyY2VNYXAsXG4gICAgICBzb3VyY2VNYXBzOiB0cnVlLFxuICAgICAgaW5saW5lU291cmNlc0NvbnRlbnQ6IHRydWUsXG4gICAgfSk7XG5cbiAgICBsZXQgdHJhbnNmb3JtZWRNYXAgPSBzb3VyY2VNYXA7XG4gICAgaWYgKHR5cGVvZiByZXN1bHQubWFwID09PSAnc3RyaW5nJykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdHJhbnNmb3JtZWRNYXAgPSBKU09OLnBhcnNlKHJlc3VsdC5tYXApO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHRyYW5zZm9ybWVkTWFwID0gcmVzdWx0Lm1hcDtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHJlc3VsdC5tYXApIHtcbiAgICAgIHRyYW5zZm9ybWVkTWFwID0gcmVzdWx0Lm1hcDtcbiAgICB9XG5cbiAgICByZXR1cm4geyBjb2RlOiByZXN1bHQuY29kZSwgbWFwOiB0cmFuc2Zvcm1lZE1hcCB9O1xuICB9O1xuXG4gIGlmICghY2FsbGJhY2spIHtcbiAgICByZXR1cm4gcnVuKCkudGhlbigocmVzdWx0KSA9PiByZXN1bHQuY29kZSk7XG4gIH1cblxuICB2b2lkIHJ1bigpXG4gICAgLnRoZW4oKHJlc3VsdCkgPT4gY2FsbGJhY2sobnVsbCwgcmVzdWx0LmNvZGUsIHJlc3VsdC5tYXApKVxuICAgIC5jYXRjaCgoZXJyb3I6IHVua25vd24pID0+IHtcbiAgICAgIGNhbGxiYWNrKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSk7XG4gICAgfSk7XG59XG4iXX0=
package/dist/runtime.js CHANGED
@@ -18,4 +18,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  // require @workflow/core be a dependency as well as
19
19
  // @workflow/next
20
20
  __exportStar(require("@workflow/core/dist/runtime"), exports);
21
- //# sourceMappingURL=runtime.js.map
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxpREFBaUQ7QUFDakQsb0RBQW9EO0FBQ3BELGlCQUFpQjtBQUNqQiw4REFBNEMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyByZS1leHBvcnQgcnVudGltZSBhcyBzdHViIGZvciByZXNvbHZpbmcgdG8gbm90XG4vLyByZXF1aXJlIEB3b3JrZmxvdy9jb3JlIGJlIGEgZGVwZW5kZW5jeSBhcyB3ZWxsIGFzXG4vLyBAd29ya2Zsb3cvbmV4dFxuZXhwb3J0ICogZnJvbSAnQHdvcmtmbG93L2NvcmUvZGlzdC9ydW50aW1lJztcbiJdfQ==
@@ -27,6 +27,39 @@ const workflowConfig = {}
27
27
  export default withWorkflow(nextConfig, workflowConfig); // [!code highlight]
28
28
  ```
29
29
 
30
+ <Callout type="warn">
31
+ If a package in `serverExternalPackages` contains workflow code (`"use step"`,
32
+ `"use workflow"`, or serialization classes), `withWorkflow()` automatically
33
+ removes it from `serverExternalPackages` for the current build and prints a
34
+ warning. Workflow still compiles the package so its directives are transformed.
35
+ Remove that package from `serverExternalPackages` in your
36
+ `next.config` to silence the warning.
37
+ </Callout>
38
+
39
+ ### Workflow Discovery in Next.js
40
+
41
+ `withWorkflow()` discovers workflows by scanning your Next.js entrypoints — App
42
+ Router `route`, `page`, and `layout` files (under `app/` or `src/app/`) and any
43
+ file under `pages/` or `src/pages/` — for `start()` calls imported from
44
+ `workflow/api`. The workflow and step files themselves can live anywhere (for
45
+ example `src/workflows/`); they are discovered transitively through imports, as
46
+ long as a `start()` call in an entrypoint statically reaches them.
47
+
48
+ <Callout type="info">
49
+ Call `start()` from server-side entrypoints, including Route Handlers and Server
50
+ Actions. Don't call workflow functions directly — that bypasses the workflow
51
+ runtime.
52
+ </Callout>
53
+
54
+ ### Next.js Server Actions and `"use server"`
55
+
56
+ Don't put a top-level `"use server"` directive in modules imported by workflow
57
+ or step functions. Workflow transformation wraps imported modules in synchronous
58
+ initializers, and Next.js rejects a `"use server"` directive inside that wrapper
59
+ with errors like `Server Actions must be async functions`. Keep `"use server"`
60
+ on the files that define your Server Actions, and move shared logic into
61
+ separate modules that don't carry the directive.
62
+
30
63
  ### Monorepos and Workspace Imports
31
64
 
32
65
  By default, Next.js detects the correct workspace root automatically. If your Next.js app lives in a subdirectory such as `apps/web` and workspace resolution is not working correctly, you can set `outputFileTracingRoot` as a workaround:
@@ -59,18 +92,38 @@ const nextConfig: NextConfig = {};
59
92
 
60
93
  export default withWorkflow(nextConfig, {
61
94
  workflows: {
62
- lazyDiscovery: true,
63
95
  local: {
64
96
  port: 4000,
65
97
  },
98
+ sourcemap: false,
66
99
  },
67
100
  });
68
101
  ```
69
102
 
70
103
  | Option | Type | Default | Description |
71
104
  | --- | --- | --- | --- |
72
- | `workflows.lazyDiscovery` | `boolean` | `false` | When `true`, defers workflow discovery until files are requested instead of scanning eagerly at startup. Useful for large projects where startup time matters. |
73
105
  | `workflows.local.port` | `number` | — | Overrides the `PORT` environment variable for local development. Has no effect when deployed to Vercel. |
106
+ | `workflows.sourcemap` | `boolean \| 'inline' \| 'linked' \| 'external' \| 'both'` | `'inline'` (dev) / `false` (prod) | Controls source maps on generated workflow bundles. See [Source maps](#source-maps) below. |
107
+
108
+ ### Source maps
109
+
110
+ The step bundle and intermediate workflow bundle default to `'inline'` source maps **in development** — so stack traces from step errors and workflow VM errors point at your source files — and to **`false` in production**, so function bundles stay small. The `sourcemap` option lets you change that:
111
+
112
+ | Value | Behavior |
113
+ | --- | --- |
114
+ | `true` / `'inline'` | Base64-encode the source map and append it to the bundle (default in development). |
115
+ | `'linked'` | Write a separate `.map` file and add a `sourceMappingURL` comment. |
116
+ | `'external'` | Write a separate `.map` file without the comment. |
117
+ | `'both'` | Emit both inline and external source maps. |
118
+ | `false` | Omit source maps entirely. |
119
+
120
+ In production, source maps are already off by default. Setting `sourcemap: false` explicitly also turns them off in development, and it drops the inline source map from every bundle while skipping the source-map-support runtime shim on the Vercel step function (the same behavior production gets by default) — the main lever for staying under the Vercel 250MB function size limit. The tradeoff is that workflow VM stack traces will reference generated code (e.g. `evalmachine.<anonymous>`) rather than your source files.
121
+
122
+ <Callout type="info">
123
+ Setting `sourcemap` explicitly affects **all** generated bundles (steps, workflows, webhook). The legacy `WORKFLOW_EMIT_SOURCEMAPS_FOR_DEBUGGING=1` environment variable is narrower — it only toggles source maps on the final workflow wrapper and webhook bundle (which default to off). It continues to work, but new code should use the `sourcemap` option or the `WORKFLOW_SOURCEMAP` environment variable instead.
124
+ </Callout>
125
+
126
+ The option can also be set via the `WORKFLOW_SOURCEMAP` environment variable, which accepts the same values plus `'0'` / `'1'` as aliases for `false` / `true`. Precedence is: explicit config > `WORKFLOW_SOURCEMAP` > the environment-aware default (`'inline'` in development, `false` in production). Development is detected from `next dev` / `NODE_ENV=development`, so the config option and the env var both let you force either behavior in either environment.
74
127
 
75
128
  <Callout type="info">
76
129
  The `workflows.local` options only affect local development. When deployed to Vercel, the runtime ignores `local` settings and uses the Vercel world automatically.
@@ -78,6 +131,7 @@ The `workflows.local` options only affect local development. When deployed to Ve
78
131
 
79
132
  ## Exporting a Function
80
133
 
134
+
81
135
  If you are exporting a function in your `next.config` you will need to ensure you call the function returned from `withWorkflow`.
82
136
 
83
137
  ```typescript title="next.config.ts" lineNumbers
package/docs/next.mdx CHANGED
@@ -75,9 +75,9 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json
75
75
  </Accordion>
76
76
 
77
77
  <Accordion type="single" collapsible>
78
- <AccordionItem value="typescript-intellisense" className="[&_h3]:my-0">
78
+ <AccordionItem value="configure-proxy-handler" className="[&_h3]:my-0">
79
79
  <AccordionTrigger className="text-sm">
80
- ### Configure Proxy Handler (if applicable)
80
+ <h3 id="configure-proxy-handler">Configure Proxy Handler (if applicable)</h3>
81
81
  </AccordionTrigger>
82
82
  <AccordionContent className="[&_p]:my-2">
83
83
 
@@ -85,7 +85,9 @@ If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-refere
85
85
  (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's
86
86
  internal paths to prevent the proxy handler from running on them.
87
87
 
88
- Add `.well-known/workflow/*` to your middleware's exclusion list:
88
+ If you see `[local world] Queue operation failed` with `Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer`, your proxy matcher is still intercepting Workflow's internal `POST /.well-known/workflow/v1/flow` request. This is especially easy to miss in Next.js 16, where `proxy.ts` replaced `middleware.ts`.
89
+
90
+ Add `.well-known/workflow/*` to your matcher exclusion list:
89
91
 
90
92
  ```typescript title="proxy.ts" lineNumbers
91
93
  import { NextResponse } from "next/server";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workflow/next",
3
- "version": "5.0.0-beta.2",
3
+ "version": "5.0.0-beta.21",
4
4
  "description": "Next.js integration for Workflow SDK",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",
@@ -27,12 +27,11 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@swc/core": "1.15.3",
30
- "enhanced-resolve": "5.19.0",
31
30
  "semver": "7.7.4",
32
31
  "watchpack": "2.5.1",
33
- "@workflow/builders": "5.0.0-beta.2",
34
- "@workflow/core": "5.0.0-beta.2",
35
- "@workflow/swc-plugin": "5.0.0-beta.2"
32
+ "@workflow/builders": "5.0.0-beta.21",
33
+ "@workflow/core": "5.0.0-beta.21",
34
+ "@workflow/swc-plugin": "5.0.0-beta.5"
36
35
  },
37
36
  "devDependencies": {
38
37
  "@types/node": "22.19.0",
@@ -1,2 +0,0 @@
1
- export declare function getNextBuilderDeferred(): Promise<any>;
2
- //# sourceMappingURL=builder-deferred.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"builder-deferred.d.ts","sourceRoot":"","sources":["../src/builder-deferred.ts"],"names":[],"mappings":"AAkDA,wBAAsB,sBAAsB,iBAosE3C"}