@workflow/next 5.0.0-beta.20 → 5.0.0-beta.22

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.
@@ -1,2 +0,0 @@
1
- export declare function parseEnvironmentFlag(rawValue: string | undefined): boolean | undefined;
2
- //# sourceMappingURL=environment-flag.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"environment-flag.d.ts","sourceRoot":"","sources":["../src/environment-flag.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,GAAG,SAAS,CAWrB"}
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseEnvironmentFlag = parseEnvironmentFlag;
4
- const FALSE_ENV_VALUES = new Set(['0', 'false', 'no', 'off']);
5
- function parseEnvironmentFlag(rawValue) {
6
- const normalizedValue = rawValue?.trim().toLowerCase();
7
- if (!normalizedValue) {
8
- return undefined;
9
- }
10
- if (FALSE_ENV_VALUES.has(normalizedValue)) {
11
- return false;
12
- }
13
- return true;
14
- }
15
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52aXJvbm1lbnQtZmxhZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9lbnZpcm9ubWVudC1mbGFnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBRUEsb0RBYUM7QUFmRCxNQUFNLGdCQUFnQixHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUU5RCxTQUFnQixvQkFBb0IsQ0FDbEMsUUFBNEI7SUFFNUIsTUFBTSxlQUFlLEdBQUcsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3ZELElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUNyQixPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQsSUFBSSxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUMxQyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBGQUxTRV9FTlZfVkFMVUVTID0gbmV3IFNldChbJzAnLCAnZmFsc2UnLCAnbm8nLCAnb2ZmJ10pO1xuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VFbnZpcm9ubWVudEZsYWcoXG4gIHJhd1ZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWRcbik6IGJvb2xlYW4gfCB1bmRlZmluZWQge1xuICBjb25zdCBub3JtYWxpemVkVmFsdWUgPSByYXdWYWx1ZT8udHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gIGlmICghbm9ybWFsaXplZFZhbHVlKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmIChGQUxTRV9FTlZfVkFMVUVTLmhhcyhub3JtYWxpemVkVmFsdWUpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIHRydWU7XG59XG4iXX0=
@@ -1,68 +0,0 @@
1
- /**
2
- * Message types that can be sent between loader and builder
3
- */
4
- export type SocketMessage = {
5
- type: 'file-discovered';
6
- filePath: string;
7
- hasWorkflow: boolean;
8
- hasStep: boolean;
9
- hasSerde: boolean;
10
- } | {
11
- type: 'trigger-build';
12
- } | {
13
- type: 'build-complete';
14
- };
15
- /**
16
- * Configuration for the socket server
17
- */
18
- export interface SocketServerConfig {
19
- isDevServer: boolean;
20
- onFileDiscovered: (filePath: string, hasWorkflow: boolean, hasStep: boolean, hasSerde: boolean) => void;
21
- onTriggerBuild: () => void;
22
- socketInfoFilePath?: string;
23
- }
24
- /**
25
- * Interface for the socket IO instance returned by createSocketServer
26
- */
27
- export interface SocketIO {
28
- emit(event: 'build-complete'): void;
29
- getAuthToken(): string;
30
- }
31
- /**
32
- * Filename for the socket-info file.
33
- */
34
- export declare const SOCKET_INFO_FILENAME = "workflow-socket.json";
35
- /**
36
- * Previous filesystem location for the socket-info file. This file lives
37
- * inside `.next/cache/`, which Vercel and Turborepo preserve across builds —
38
- * a stale file from a prior build would cause the loader to attempt to
39
- * connect to a dead port (ECONNREFUSED). The current location is a sibling
40
- * of `cache/` so it isn't preserved.
41
- *
42
- * Exported so the builders can unlink the legacy path at boot, cleaning up
43
- * any leftover file written by older versions of the SDK.
44
- */
45
- export declare const LEGACY_SOCKET_INFO_RELATIVE_PATH: string;
46
- /**
47
- * Remove any stale socket-info files at boot.
48
- * @param distDir absolute path to the project's `.next` directory.
49
- */
50
- export declare function cleanupStaleSocketInfoFiles(distDir: string): Promise<void>;
51
- /**
52
- * Serialize a message with authentication preamble
53
- */
54
- export declare function serializeMessage(message: SocketMessage, authToken: string): string;
55
- /**
56
- * Parse and authenticate a message from the socket
57
- * Returns the parsed message if valid, null otherwise
58
- */
59
- export declare function parseMessage(line: string, authToken: string): SocketMessage | null;
60
- /**
61
- * Create a TCP socket server for loader<->builder communication.
62
- * Returns a SocketIO interface for broadcasting messages and the auth token.
63
- *
64
- * SECURITY: Server listens on 127.0.0.1 (localhost only) and uses
65
- * message authentication to prevent processing of unauthorized messages.
66
- */
67
- export declare function createSocketServer(config: SocketServerConfig): Promise<SocketIO>;
68
- //# sourceMappingURL=socket-server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"socket-server.d.ts","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"AAmBA;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB,GACD;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE/B;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,OAAO,EACpB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,KACd,IAAI,CAAC;IACV,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,YAAY,IAAI,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAE3D;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC,QAG5C,CAAC;AAMF;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,aAAa,GAAG,IAAI,CAoCtB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,QAAQ,CAAC,CAoGnB"}
@@ -1,181 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LEGACY_SOCKET_INFO_RELATIVE_PATH = exports.SOCKET_INFO_FILENAME = void 0;
4
- exports.cleanupStaleSocketInfoFiles = cleanupStaleSocketInfoFiles;
5
- exports.serializeMessage = serializeMessage;
6
- exports.parseMessage = parseMessage;
7
- exports.createSocketServer = createSocketServer;
8
- const node_crypto_1 = require("node:crypto");
9
- const promises_1 = require("node:fs/promises");
10
- const node_net_1 = require("node:net");
11
- const node_path_1 = require("node:path");
12
- /**
13
- * Magic preamble that must prefix all messages to authenticate them as workflow messages.
14
- * This prevents accidental processing of messages from port scanners or other local processes.
15
- */
16
- const MESSAGE_PREAMBLE = 'WF:';
17
- /**
18
- * Generate a random authentication token for this server session.
19
- * Clients must include this token in all messages.
20
- */
21
- function generateAuthToken() {
22
- return (0, node_crypto_1.randomBytes)(16).toString('hex');
23
- }
24
- /**
25
- * Filename for the socket-info file.
26
- */
27
- exports.SOCKET_INFO_FILENAME = 'workflow-socket.json';
28
- /**
29
- * Previous filesystem location for the socket-info file. This file lives
30
- * inside `.next/cache/`, which Vercel and Turborepo preserve across builds —
31
- * a stale file from a prior build would cause the loader to attempt to
32
- * connect to a dead port (ECONNREFUSED). The current location is a sibling
33
- * of `cache/` so it isn't preserved.
34
- *
35
- * Exported so the builders can unlink the legacy path at boot, cleaning up
36
- * any leftover file written by older versions of the SDK.
37
- */
38
- exports.LEGACY_SOCKET_INFO_RELATIVE_PATH = (0, node_path_1.join)('cache', exports.SOCKET_INFO_FILENAME);
39
- function getDefaultSocketInfoFilePath() {
40
- return (0, node_path_1.join)(process.cwd(), '.next', exports.SOCKET_INFO_FILENAME);
41
- }
42
- /**
43
- * Remove any stale socket-info files at boot.
44
- * @param distDir absolute path to the project's `.next` directory.
45
- */
46
- async function cleanupStaleSocketInfoFiles(distDir) {
47
- await Promise.all([
48
- (0, promises_1.rm)((0, node_path_1.join)(distDir, exports.SOCKET_INFO_FILENAME), { force: true }),
49
- (0, promises_1.rm)((0, node_path_1.join)(distDir, exports.LEGACY_SOCKET_INFO_RELATIVE_PATH), { force: true }),
50
- ]);
51
- }
52
- /**
53
- * Serialize a message with authentication preamble
54
- */
55
- function serializeMessage(message, authToken) {
56
- return `${MESSAGE_PREAMBLE}${authToken}:${JSON.stringify(message)}\n`;
57
- }
58
- /**
59
- * Parse and authenticate a message from the socket
60
- * Returns the parsed message if valid, null otherwise
61
- */
62
- function parseMessage(line, authToken) {
63
- const trimmed = line.trim();
64
- if (!trimmed) {
65
- return null;
66
- }
67
- // Check for preamble
68
- if (!trimmed.startsWith(MESSAGE_PREAMBLE)) {
69
- console.warn('Received message without valid preamble, ignoring');
70
- return null;
71
- }
72
- // Extract auth token and payload
73
- const withoutPreamble = trimmed.slice(MESSAGE_PREAMBLE.length);
74
- const colonIndex = withoutPreamble.indexOf(':');
75
- if (colonIndex === -1) {
76
- console.warn('Received message without auth token separator, ignoring');
77
- return null;
78
- }
79
- const messageToken = withoutPreamble.slice(0, colonIndex);
80
- const payload = withoutPreamble.slice(colonIndex + 1);
81
- // Verify auth token
82
- if (messageToken !== authToken) {
83
- console.warn('Received message with invalid auth token, ignoring');
84
- return null;
85
- }
86
- // Parse JSON payload
87
- try {
88
- return JSON.parse(payload);
89
- }
90
- catch (error) {
91
- console.error('Failed to parse socket message JSON:', error);
92
- return null;
93
- }
94
- }
95
- /**
96
- * Create a TCP socket server for loader<->builder communication.
97
- * Returns a SocketIO interface for broadcasting messages and the auth token.
98
- *
99
- * SECURITY: Server listens on 127.0.0.1 (localhost only) and uses
100
- * message authentication to prevent processing of unauthorized messages.
101
- */
102
- async function createSocketServer(config) {
103
- const authToken = generateAuthToken();
104
- const clients = new Set();
105
- let buildTriggered = false;
106
- const server = (0, node_net_1.createServer)((socket) => {
107
- socket.setNoDelay(true);
108
- clients.add(socket);
109
- // Send build-complete if build already finished (production mode)
110
- if (buildTriggered && !config.isDevServer) {
111
- socket.write(serializeMessage({ type: 'build-complete' }, authToken));
112
- }
113
- let buffer = '';
114
- socket.on('data', (data) => {
115
- buffer += data.toString();
116
- // Process complete messages (newline-delimited)
117
- let newlineIndex = buffer.indexOf('\n');
118
- while (newlineIndex !== -1) {
119
- const line = buffer.slice(0, newlineIndex);
120
- buffer = buffer.slice(newlineIndex + 1);
121
- newlineIndex = buffer.indexOf('\n');
122
- const message = parseMessage(line, authToken);
123
- if (!message) {
124
- continue;
125
- }
126
- if (message.type === 'file-discovered') {
127
- config.onFileDiscovered(message.filePath, message.hasWorkflow, message.hasStep, message.hasSerde);
128
- }
129
- else if (message.type === 'trigger-build') {
130
- config.onTriggerBuild();
131
- }
132
- }
133
- });
134
- socket.on('end', () => {
135
- clients.delete(socket);
136
- });
137
- socket.on('error', (err) => {
138
- console.error('Socket error:', err);
139
- clients.delete(socket);
140
- });
141
- });
142
- // Listen on random available port (localhost only)
143
- await new Promise((resolve, reject) => {
144
- server.once('error', reject);
145
- server.listen(0, '127.0.0.1', () => {
146
- const address = server.address();
147
- if (address && typeof address === 'object') {
148
- const socketInfoFilePath = config.socketInfoFilePath || getDefaultSocketInfoFilePath();
149
- void (async () => {
150
- try {
151
- await (0, promises_1.mkdir)((0, node_path_1.dirname)(socketInfoFilePath), { recursive: true });
152
- await (0, promises_1.writeFile)(socketInfoFilePath, JSON.stringify({
153
- port: address.port,
154
- authToken,
155
- }, null, 2));
156
- process.env.WORKFLOW_SOCKET_INFO_PATH = socketInfoFilePath;
157
- process.env.WORKFLOW_SOCKET_PORT = String(address.port);
158
- process.env.WORKFLOW_SOCKET_AUTH = authToken;
159
- resolve();
160
- }
161
- catch (error) {
162
- reject(error);
163
- }
164
- })();
165
- return;
166
- }
167
- reject(new Error('Failed to obtain workflow socket server address'));
168
- });
169
- });
170
- return {
171
- emit: (_event) => {
172
- buildTriggered = true;
173
- const message = serializeMessage({ type: 'build-complete' }, authToken);
174
- for (const client of clients) {
175
- client.write(message);
176
- }
177
- },
178
- getAuthToken: () => authToken,
179
- };
180
- }
181
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0LXNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zb2NrZXQtc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQW9GQSxrRUFPQztBQUtELDRDQUtDO0FBTUQsb0NBdUNDO0FBU0QsZ0RBc0dDO0FBalFELDZDQUEwQztBQUMxQywrQ0FBd0Q7QUFDeEQsdUNBQWtFO0FBQ2xFLHlDQUEwQztBQUUxQzs7O0dBR0c7QUFDSCxNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQztBQUUvQjs7O0dBR0c7QUFDSCxTQUFTLGlCQUFpQjtJQUN4QixPQUFPLElBQUEseUJBQVcsRUFBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDekMsQ0FBQztBQXVDRDs7R0FFRztBQUNVLFFBQUEsb0JBQW9CLEdBQUcsc0JBQXNCLENBQUM7QUFFM0Q7Ozs7Ozs7OztHQVNHO0FBQ1UsUUFBQSxnQ0FBZ0MsR0FBRyxJQUFBLGdCQUFJLEVBQ2xELE9BQU8sRUFDUCw0QkFBb0IsQ0FDckIsQ0FBQztBQUVGLFNBQVMsNEJBQTRCO0lBQ25DLE9BQU8sSUFBQSxnQkFBSSxFQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUUsNEJBQW9CLENBQUMsQ0FBQztBQUM1RCxDQUFDO0FBRUQ7OztHQUdHO0FBQ0ksS0FBSyxVQUFVLDJCQUEyQixDQUMvQyxPQUFlO0lBRWYsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDO1FBQ2hCLElBQUEsYUFBRSxFQUFDLElBQUEsZ0JBQUksRUFBQyxPQUFPLEVBQUUsNEJBQW9CLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUN4RCxJQUFBLGFBQUUsRUFBQyxJQUFBLGdCQUFJLEVBQUMsT0FBTyxFQUFFLHdDQUFnQyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUM7S0FDckUsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztB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LENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQ2hCLENBQUM7Z0JBQ0gsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDTCxPQUFPO1lBQ1QsQ0FBQztZQUNELE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxpREFBaUQsQ0FBQyxDQUFDLENBQUM7UUFDdkUsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILE9BQU87UUFDTCxJQUFJLEVBQUUsQ0FBQyxNQUF3QixFQUFFLEVBQUU7WUFDakMsY0FBYyxHQUFHLElBQUksQ0FBQztZQUN0QixNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQ3hFLEtBQUssTUFBTSxNQUFNLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQzdCLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDeEIsQ0FBQztRQUNILENBQUM7UUFDRCxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsU0FBUztLQUM5QixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJhbmRvbUJ5dGVzIH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0IHsgbWtkaXIsIHJtLCB3cml0ZUZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJztcbmltcG9ydCB7IGNyZWF0ZVNlcnZlciwgdHlwZSBTZXJ2ZXIsIHR5cGUgU29ja2V0IH0gZnJvbSAnbm9kZTpuZXQnO1xuaW1wb3J0IHsgZGlybmFtZSwgam9pbiB9IGZyb20gJ25vZGU6cGF0aCc7XG5cbi8qKlxuICogTWFnaWMgcHJlYW1ibGUgdGhhdCBtdXN0IHByZWZpeCBhbGwgbWVzc2FnZXMgdG8gYXV0aGVudGljYXRlIHRoZW0gYXMgd29ya2Zsb3cgbWVzc2FnZXMuXG4gKiBUaGlzIHByZXZlbnRzIGFjY2lkZW50YWwgcHJvY2Vzc2luZyBvZiBtZXNzYWdlcyBmcm9tIHBvcnQgc2Nhbm5lcnMgb3Igb3RoZXIgbG9jYWwgcHJvY2Vzc2VzLlxuICovXG5jb25zdCBNRVNTQUdFX1BSRUFNQkxFID0gJ1dGOic7XG5cbi8qKlxuICogR2VuZXJhdGUgYSByYW5kb20gYXV0aGVudGljYXRpb24gdG9rZW4gZm9yIHRoaXMgc2VydmVyIHNlc3Npb24uXG4gKiBDbGllbnRzIG11c3QgaW5jbHVkZSB0aGlzIHRva2VuIGluIGFsbCBtZXNzYWdlcy5cbiAqL1xuZnVuY3Rpb24gZ2VuZXJhdGVBdXRoVG9rZW4oKTogc3RyaW5nIHtcbiAgcmV0dXJuIHJhbmRvbUJ5dGVzKDE2KS50b1N0cmluZygnaGV4Jyk7XG59XG5cbi8qKlxuICogTWVzc2FnZSB0eXBlcyB0aGF0IGNhbiBiZSBzZW50IGJldHdlZW4gbG9hZGVyIGFuZCBidWlsZGVyXG4gKi9cbmV4cG9ydCB0eXBlIFNvY2tldE1lc3NhZ2UgPVxuICB8IHtcbiAgICAgIHR5cGU6ICdmaWxlLWRpc2NvdmVyZWQnO1xuICAgICAgZmlsZVBhdGg6IHN0cmluZztcbiAgICAgIGhhc1dvcmtmbG93OiBib29sZWFuO1xuICAgICAgaGFzU3RlcDogYm9vbGVhbjtcbiAgICAgIGhhc1NlcmRlOiBib29sZWFuO1xuICAgIH1cbiAgfCB7IHR5cGU6ICd0cmlnZ2VyLWJ1aWxkJyB9XG4gIHwgeyB0eXBlOiAnYnVpbGQtY29tcGxldGUnIH07XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgdGhlIHNvY2tldCBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTb2NrZXRTZXJ2ZXJDb25maWcge1xuICBpc0RldlNlcnZlcjogYm9vbGVhbjtcbiAgb25GaWxlRGlzY292ZXJlZDogKFxuICAgIGZpbGVQYXRoOiBzdHJpbmcsXG4gICAgaGFzV29ya2Zsb3c6IGJvb2xlYW4sXG4gICAgaGFzU3RlcDogYm9vbGVhbixcbiAgICBoYXNTZXJkZTogYm9vbGVhblxuICApID0+IHZvaWQ7XG4gIG9uVHJpZ2dlckJ1aWxkOiAoKSA9PiB2b2lkO1xuICBzb2NrZXRJbmZvRmlsZVBhdGg/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogSW50ZXJmYWNlIGZvciB0aGUgc29ja2V0IElPIGluc3RhbmNlIHJldHVybmVkIGJ5IGNyZWF0ZVNvY2tldFNlcnZlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNvY2tldElPIHtcbiAgZW1pdChldmVudDogJ2J1aWxkLWNvbXBsZXRlJyk6IHZvaWQ7XG4gIGdldEF1dGhUb2tlbigpOiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmlsZW5hbWUgZm9yIHRoZSBzb2NrZXQtaW5mbyBmaWxlLlxuICovXG5leHBvcnQgY29uc3QgU09DS0VUX0lORk9fRklMRU5BTUUgPSAnd29ya2Zsb3ctc29ja2V0Lmpzb24nO1xuXG4vKipcbiAqIFByZXZpb3VzIGZpbGVzeXN0ZW0gbG9jYXRpb24gZm9yIHRoZSBzb2NrZXQtaW5mbyBmaWxlLiBUaGlzIGZpbGUgbGl2ZXNcbiAqIGluc2lkZSBgLm5leHQvY2FjaGUvYCwgd2hpY2ggVmVyY2VsIGFuZCBUdXJib3JlcG8gcHJlc2VydmUgYWNyb3NzIGJ1aWxkcyDigJRcbiAqIGEgc3RhbGUgZmlsZSBmcm9tIGEgcHJpb3IgYnVpbGQgd291bGQgY2F1c2UgdGhlIGxvYWRlciB0byBhdHRlbXB0IHRvXG4gKiBjb25uZWN0IHRvIGEgZGVhZCBwb3J0IChFQ09OTlJFRlVTRUQpLiBUaGUgY3VycmVudCBsb2NhdGlvbiBpcyBhIHNpYmxpbmdcbiAqIG9mIGBjYWNoZS9gIHNvIGl0IGlzbid0IHByZXNlcnZlZC5cbiAqXG4gKiBFeHBvcnRlZCBzbyB0aGUgYnVpbGRlcnMgY2FuIHVubGluayB0aGUgbGVnYWN5IHBhdGggYXQgYm9vdCwgY2xlYW5pbmcgdXBcbiAqIGFueSBsZWZ0b3ZlciBmaWxlIHdyaXR0ZW4gYnkgb2xkZXIgdmVyc2lvbnMgb2YgdGhlIFNESy5cbiAqL1xuZXhwb3J0IGNvbnN0IExFR0FDWV9TT0NLRVRfSU5GT19SRUxBVElWRV9QQVRIID0gam9pbihcbiAgJ2NhY2hlJyxcbiAgU09DS0VUX0lORk9fRklMRU5BTUVcbik7XG5cbmZ1bmN0aW9uIGdldERlZmF1bHRTb2NrZXRJbmZvRmlsZVBhdGgoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGpvaW4ocHJvY2Vzcy5jd2QoKSwgJy5uZXh0JywgU09DS0VUX0lORk9fRklMRU5BTUUpO1xufVxuXG4vKipcbiAqIFJlbW92ZSBhbnkgc3RhbGUgc29ja2V0LWluZm8gZmlsZXMgYXQgYm9vdC5cbiAqIEBwYXJhbSBkaXN0RGlyIGFic29sdXRlIHBhdGggdG8gdGhlIHByb2plY3QncyBgLm5leHRgIGRpcmVjdG9yeS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFudXBTdGFsZVNvY2tldEluZm9GaWxlcyhcbiAgZGlzdERpcjogc3RyaW5nXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIHJtKGpvaW4oZGlzdERpciwgU09DS0VUX0lORk9fRklMRU5BTUUpLCB7IGZvcmNlOiB0cnVlIH0pLFxuICAgIHJtKGpvaW4oZGlzdERpciwgTEVHQUNZX1NPQ0tFVF9JTkZPX1JFTEFUSVZFX1BBVEgpLCB7IGZvcmNlOiB0cnVlIH0pLFxuICBdKTtcbn1cblxuLyoqXG4gKiBTZXJpYWxpemUgYSBtZXNzYWdlIHdpdGggYXV0aGVudGljYXRpb24gcHJlYW1ibGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlcmlhbGl6ZU1lc3NhZ2UoXG4gIG1lc3NhZ2U6IFNvY2tldE1lc3NhZ2UsXG4gIGF1dGhUb2tlbjogc3RyaW5nXG4pOiBzdHJpbmcge1xuICByZXR1cm4gYCR7TUVTU0FHRV9QUkVBTUJMRX0ke2F1dGhUb2tlbn06JHtKU09OLnN0cmluZ2lmeShtZXNzYWdlKX1cXG5gO1xufVxuXG4vKipcbiAqIFBhcnNlIGFuZCBhdXRoZW50aWNhdGUgYSBtZXNzYWdlIGZyb20gdGhlIHNvY2tldFxuICogUmV0dXJucyB0aGUgcGFyc2VkIG1lc3NhZ2UgaWYgdmFsaWQsIG51bGwgb3RoZXJ3aXNlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZU1lc3NhZ2UoXG4gIGxpbmU6IHN0cmluZyxcbiAgYXV0aFRva2VuOiBzdHJpbmdcbik6IFNvY2tldE1lc3NhZ2UgfCBudWxsIHtcbiAgY29uc3QgdHJpbW1lZCA9IGxpbmUudHJpbSgpO1xuICBpZiAoIXRyaW1tZWQpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8vIENoZWNrIGZvciBwcmVhbWJsZVxuICBpZiAoIXRyaW1tZWQuc3RhcnRzV2l0aChNRVNTQUdFX1BSRUFNQkxFKSkge1xuICAgIGNvbnNvbGUud2FybignUmVjZWl2ZWQgbWVzc2FnZSB3aXRob3V0IHZhbGlkIHByZWFtYmxlLCBpZ25vcmluZycpO1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLy8gRXh0cmFjdCBhdXRoIHRva2VuIGFuZCBwYXlsb2FkXG4gIGNvbnN0IHdpdGhvdXRQcmVhbWJsZSA9IHRyaW1tZWQuc2xpY2UoTUVTU0FHRV9QUkVBTUJMRS5sZW5ndGgpO1xuICBjb25zdCBjb2xvbkluZGV4ID0gd2l0aG91dFByZWFtYmxlLmluZGV4T2YoJzonKTtcbiAgaWYgKGNvbG9uSW5kZXggPT09IC0xKSB7XG4gICAgY29uc29sZS53YXJuKCdSZWNlaXZlZCBtZXNzYWdlIHdpdGhvdXQgYXV0aCB0b2tlbiBzZXBhcmF0b3IsIGlnbm9yaW5nJyk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBtZXNzYWdlVG9rZW4gPSB3aXRob3V0UHJlYW1ibGUuc2xpY2UoMCwgY29sb25JbmRleCk7XG4gIGNvbnN0IHBheWxvYWQgPSB3aXRob3V0UHJlYW1ibGUuc2xpY2UoY29sb25JbmRleCArIDEpO1xuXG4gIC8vIFZlcmlmeSBhdXRoIHRva2VuXG4gIGlmIChtZXNzYWdlVG9rZW4gIT09IGF1dGhUb2tlbikge1xuICAgIGNvbnNvbGUud2FybignUmVjZWl2ZWQgbWVzc2FnZSB3aXRoIGludmFsaWQgYXV0aCB0b2tlbiwgaWdub3JpbmcnKTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8vIFBhcnNlIEpTT04gcGF5bG9hZFxuICB0cnkge1xuICAgIHJldHVybiBKU09OLnBhcnNlKHBheWxvYWQpIGFzIFNvY2tldE1lc3NhZ2U7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHBhcnNlIHNvY2tldCBtZXNzYWdlIEpTT046JywgZXJyb3IpO1xuICAgIHJldHVybiBudWxsO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgVENQIHNvY2tldCBzZXJ2ZXIgZm9yIGxvYWRlcjwtPmJ1aWxkZXIgY29tbXVuaWNhdGlvbi5cbiAqIFJldHVybnMgYSBTb2NrZXRJTyBpbnRlcmZhY2UgZm9yIGJyb2FkY2FzdGluZyBtZXNzYWdlcyBhbmQgdGhlIGF1dGggdG9rZW4uXG4gKlxuICogU0VDVVJJVFk6IFNlcnZlciBsaXN0ZW5zIG9uIDEyNy4wLjAuMSAobG9jYWxob3N0IG9ubHkpIGFuZCB1c2VzXG4gKiBtZXNzYWdlIGF1dGhlbnRpY2F0aW9uIHRvIHByZXZlbnQgcHJvY2Vzc2luZyBvZiB1bmF1dGhvcml6ZWQgbWVzc2FnZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVTb2NrZXRTZXJ2ZXIoXG4gIGNvbmZpZzogU29ja2V0U2VydmVyQ29uZmlnXG4pOiBQcm9taXNlPFNvY2tldElPPiB7XG4gIGNvbnN0IGF1dGhUb2tlbiA9IGdlbmVyYXRlQXV0aFRva2VuKCk7XG4gIGNvbnN0IGNsaWVudHMgPSBuZXcgU2V0PFNvY2tldD4oKTtcbiAgbGV0IGJ1aWxkVHJpZ2dlcmVkID0gZmFsc2U7XG5cbiAgY29uc3Qgc2VydmVyOiBTZXJ2ZXIgPSBjcmVhdGVTZXJ2ZXIoKHNvY2tldDogU29ja2V0KSA9PiB7XG4gICAgc29ja2V0LnNldE5vRGVsYXkodHJ1ZSk7XG4gICAgY2xpZW50cy5hZGQoc29ja2V0KTtcblxuICAgIC8vIFNlbmQgYnVpbGQtY29tcGxldGUgaWYgYnVpbGQgYWxyZWFkeSBmaW5pc2hlZCAocHJvZHVjdGlvbiBtb2RlKVxuICAgIGlmIChidWlsZFRyaWdnZXJlZCAmJiAhY29uZmlnLmlzRGV2U2VydmVyKSB7XG4gICAgICBzb2NrZXQud3JpdGUoc2VyaWFsaXplTWVzc2FnZSh7IHR5cGU6ICdidWlsZC1jb21wbGV0ZScgfSwgYXV0aFRva2VuKSk7XG4gICAgfVxuXG4gICAgbGV0IGJ1ZmZlciA9ICcnO1xuXG4gICAgc29ja2V0Lm9uKCdkYXRhJywgKGRhdGE6IEJ1ZmZlcikgPT4ge1xuICAgICAgYnVmZmVyICs9IGRhdGEudG9TdHJpbmcoKTtcblxuICAgICAgLy8gUHJvY2VzcyBjb21wbGV0ZSBtZXNzYWdlcyAobmV3bGluZS1kZWxpbWl0ZWQpXG4gICAgICBsZXQgbmV3bGluZUluZGV4ID0gYnVmZmVyLmluZGV4T2YoJ1xcbicpO1xuICAgICAgd2hpbGUgKG5ld2xpbmVJbmRleCAhPT0gLTEpIHtcbiAgICAgICAgY29uc3QgbGluZSA9IGJ1ZmZlci5zbGljZSgwLCBuZXdsaW5lSW5kZXgpO1xuICAgICAgICBidWZmZXIgPSBidWZmZXIuc2xpY2UobmV3bGluZUluZGV4ICsgMSk7XG4gICAgICAgIG5ld2xpbmVJbmRleCA9IGJ1ZmZlci5pbmRleE9mKCdcXG4nKTtcblxuICAgICAgICBjb25zdCBtZXNzYWdlID0gcGFyc2VNZXNzYWdlKGxpbmUsIGF1dGhUb2tlbik7XG4gICAgICAgIGlmICghbWVzc2FnZSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gJ2ZpbGUtZGlzY292ZXJlZCcpIHtcbiAgICAgICAgICBjb25maWcub25GaWxlRGlzY292ZXJlZChcbiAgICAgICAgICAgIG1lc3NhZ2UuZmlsZVBhdGgsXG4gICAgICAgICAgICBtZXNzYWdlLmhhc1dvcmtmbG93LFxuICAgICAgICAgICAgbWVzc2FnZS5oYXNTdGVwLFxuICAgICAgICAgICAgbWVzc2FnZS5oYXNTZXJkZVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSAndHJpZ2dlci1idWlsZCcpIHtcbiAgICAgICAgICBjb25maWcub25UcmlnZ2VyQnVpbGQoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgc29ja2V0Lm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICBjbGllbnRzLmRlbGV0ZShzb2NrZXQpO1xuICAgIH0pO1xuXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnI6IEVycm9yKSA9PiB7XG4gICAgICBjb25zb2xlLmVycm9yKCdTb2NrZXQgZXJyb3I6JywgZXJyKTtcbiAgICAgIGNsaWVudHMuZGVsZXRlKHNvY2tldCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vIExpc3RlbiBvbiByYW5kb20gYXZhaWxhYmxlIHBvcnQgKGxvY2FsaG9zdCBvbmx5KVxuICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgc2VydmVyLm9uY2UoJ2Vycm9yJywgcmVqZWN0KTtcbiAgICBzZXJ2ZXIubGlzdGVuKDAsICcxMjcuMC4wLjEnLCAoKSA9PiB7XG4gICAgICBjb25zdCBhZGRyZXNzID0gc2VydmVyLmFkZHJlc3MoKTtcbiAgICAgIGlmIChhZGRyZXNzICYmIHR5cGVvZiBhZGRyZXNzID09PSAnb2JqZWN0Jykge1xuICAgICAgICBjb25zdCBzb2NrZXRJbmZvRmlsZVBhdGggPVxuICAgICAgICAgIGNvbmZpZy5zb2NrZXRJbmZvRmlsZVBhdGggfHwgZ2V0RGVmYXVsdFNvY2tldEluZm9GaWxlUGF0aCgpO1xuICAgICAgICB2b2lkIChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IG1rZGlyKGRpcm5hbWUoc29ja2V0SW5mb0ZpbGVQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICAgICAgICAgIHNvY2tldEluZm9GaWxlUGF0aCxcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgcG9ydDogYWRkcmVzcy5wb3J0LFxuICAgICAgICAgICAgICAgICAgYXV0aFRva2VuLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAyXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBwcm9jZXNzLmVudi5XT1JLRkxPV19TT0NLRVRfSU5GT19QQVRIID0gc29ja2V0SW5mb0ZpbGVQYXRoO1xuICAgICAgICAgICAgcHJvY2Vzcy5lbnYuV09SS0ZMT1dfU09DS0VUX1BPUlQgPSBTdHJpbmcoYWRkcmVzcy5wb3J0KTtcbiAgICAgICAgICAgIHByb2Nlc3MuZW52LldPUktGTE9XX1NPQ0tFVF9BVVRIID0gYXV0aFRva2VuO1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgcmVqZWN0KG5ldyBFcnJvcignRmFpbGVkIHRvIG9idGFpbiB3b3JrZmxvdyBzb2NrZXQgc2VydmVyIGFkZHJlc3MnKSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIHJldHVybiB7XG4gICAgZW1pdDogKF9ldmVudDogJ2J1aWxkLWNvbXBsZXRlJykgPT4ge1xuICAgICAgYnVpbGRUcmlnZ2VyZWQgPSB0cnVlO1xuICAgICAgY29uc3QgbWVzc2FnZSA9IHNlcmlhbGl6ZU1lc3NhZ2UoeyB0eXBlOiAnYnVpbGQtY29tcGxldGUnIH0sIGF1dGhUb2tlbik7XG4gICAgICBmb3IgKGNvbnN0IGNsaWVudCBvZiBjbGllbnRzKSB7XG4gICAgICAgIGNsaWVudC53cml0ZShtZXNzYWdlKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIGdldEF1dGhUb2tlbjogKCkgPT4gYXV0aFRva2VuLFxuICB9O1xufVxuIl19