@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.
@@ -1,48 +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
- * Serialize a message with authentication preamble
33
- */
34
- export declare function serializeMessage(message: SocketMessage, authToken: string): string;
35
- /**
36
- * Parse and authenticate a message from the socket
37
- * Returns the parsed message if valid, null otherwise
38
- */
39
- export declare function parseMessage(line: string, authToken: string): SocketMessage | null;
40
- /**
41
- * Create a TCP socket server for loader<->builder communication.
42
- * Returns a SocketIO interface for broadcasting messages and the auth token.
43
- *
44
- * SECURITY: Server listens on 127.0.0.1 (localhost only) and uses
45
- * message authentication to prevent processing of unauthorized messages.
46
- */
47
- export declare function createSocketServer(config: SocketServerConfig): Promise<SocketIO>;
48
- //# 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;AAMD;;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,154 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.serializeMessage = serializeMessage;
4
- exports.parseMessage = parseMessage;
5
- exports.createSocketServer = createSocketServer;
6
- const node_crypto_1 = require("node:crypto");
7
- const promises_1 = require("node:fs/promises");
8
- const node_net_1 = require("node:net");
9
- const node_path_1 = require("node:path");
10
- /**
11
- * Magic preamble that must prefix all messages to authenticate them as workflow messages.
12
- * This prevents accidental processing of messages from port scanners or other local processes.
13
- */
14
- const MESSAGE_PREAMBLE = 'WF:';
15
- /**
16
- * Generate a random authentication token for this server session.
17
- * Clients must include this token in all messages.
18
- */
19
- function generateAuthToken() {
20
- return (0, node_crypto_1.randomBytes)(16).toString('hex');
21
- }
22
- function getDefaultSocketInfoFilePath() {
23
- return (0, node_path_1.join)(process.cwd(), '.next', 'cache', 'workflow-socket.json');
24
- }
25
- /**
26
- * Serialize a message with authentication preamble
27
- */
28
- function serializeMessage(message, authToken) {
29
- return `${MESSAGE_PREAMBLE}${authToken}:${JSON.stringify(message)}\n`;
30
- }
31
- /**
32
- * Parse and authenticate a message from the socket
33
- * Returns the parsed message if valid, null otherwise
34
- */
35
- function parseMessage(line, authToken) {
36
- const trimmed = line.trim();
37
- if (!trimmed) {
38
- return null;
39
- }
40
- // Check for preamble
41
- if (!trimmed.startsWith(MESSAGE_PREAMBLE)) {
42
- console.warn('Received message without valid preamble, ignoring');
43
- return null;
44
- }
45
- // Extract auth token and payload
46
- const withoutPreamble = trimmed.slice(MESSAGE_PREAMBLE.length);
47
- const colonIndex = withoutPreamble.indexOf(':');
48
- if (colonIndex === -1) {
49
- console.warn('Received message without auth token separator, ignoring');
50
- return null;
51
- }
52
- const messageToken = withoutPreamble.slice(0, colonIndex);
53
- const payload = withoutPreamble.slice(colonIndex + 1);
54
- // Verify auth token
55
- if (messageToken !== authToken) {
56
- console.warn('Received message with invalid auth token, ignoring');
57
- return null;
58
- }
59
- // Parse JSON payload
60
- try {
61
- return JSON.parse(payload);
62
- }
63
- catch (error) {
64
- console.error('Failed to parse socket message JSON:', error);
65
- return null;
66
- }
67
- }
68
- /**
69
- * Create a TCP socket server for loader<->builder communication.
70
- * Returns a SocketIO interface for broadcasting messages and the auth token.
71
- *
72
- * SECURITY: Server listens on 127.0.0.1 (localhost only) and uses
73
- * message authentication to prevent processing of unauthorized messages.
74
- */
75
- async function createSocketServer(config) {
76
- const authToken = generateAuthToken();
77
- const clients = new Set();
78
- let buildTriggered = false;
79
- const server = (0, node_net_1.createServer)((socket) => {
80
- socket.setNoDelay(true);
81
- clients.add(socket);
82
- // Send build-complete if build already finished (production mode)
83
- if (buildTriggered && !config.isDevServer) {
84
- socket.write(serializeMessage({ type: 'build-complete' }, authToken));
85
- }
86
- let buffer = '';
87
- socket.on('data', (data) => {
88
- buffer += data.toString();
89
- // Process complete messages (newline-delimited)
90
- let newlineIndex = buffer.indexOf('\n');
91
- while (newlineIndex !== -1) {
92
- const line = buffer.slice(0, newlineIndex);
93
- buffer = buffer.slice(newlineIndex + 1);
94
- newlineIndex = buffer.indexOf('\n');
95
- const message = parseMessage(line, authToken);
96
- if (!message) {
97
- continue;
98
- }
99
- if (message.type === 'file-discovered') {
100
- config.onFileDiscovered(message.filePath, message.hasWorkflow, message.hasStep, message.hasSerde);
101
- }
102
- else if (message.type === 'trigger-build') {
103
- config.onTriggerBuild();
104
- }
105
- }
106
- });
107
- socket.on('end', () => {
108
- clients.delete(socket);
109
- });
110
- socket.on('error', (err) => {
111
- console.error('Socket error:', err);
112
- clients.delete(socket);
113
- });
114
- });
115
- // Listen on random available port (localhost only)
116
- await new Promise((resolve, reject) => {
117
- server.once('error', reject);
118
- server.listen(0, '127.0.0.1', () => {
119
- const address = server.address();
120
- if (address && typeof address === 'object') {
121
- const socketInfoFilePath = config.socketInfoFilePath || getDefaultSocketInfoFilePath();
122
- void (async () => {
123
- try {
124
- await (0, promises_1.mkdir)((0, node_path_1.dirname)(socketInfoFilePath), { recursive: true });
125
- await (0, promises_1.writeFile)(socketInfoFilePath, JSON.stringify({
126
- port: address.port,
127
- authToken,
128
- }, null, 2));
129
- process.env.WORKFLOW_SOCKET_INFO_PATH = socketInfoFilePath;
130
- process.env.WORKFLOW_SOCKET_PORT = String(address.port);
131
- process.env.WORKFLOW_SOCKET_AUTH = authToken;
132
- resolve();
133
- }
134
- catch (error) {
135
- reject(error);
136
- }
137
- })();
138
- return;
139
- }
140
- reject(new Error('Failed to obtain workflow socket server address'));
141
- });
142
- });
143
- return {
144
- emit: (_event) => {
145
- buildTriggered = true;
146
- const message = serializeMessage({ type: 'build-complete' }, authToken);
147
- for (const client of clients) {
148
- client.write(message);
149
- }
150
- },
151
- getAuthToken: () => authToken,
152
- };
153
- }
154
- //# sourceMappingURL=socket-server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"socket-server.js","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":";;AA+DA,4CAKC;AAMD,oCAuCC;AASD,gDAsGC;AAhOD,6CAA0C;AAC1C,+CAAoD;AACpD,uCAAkE;AAClE,yCAA0C;AAE1C;;;GAGG;AACH,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;;;GAGG;AACH,SAAS,iBAAiB;IACxB,OAAO,IAAA,yBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAuCD,SAAS,4BAA4B;IACnC,OAAO,IAAA,gBAAI,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAC9B,OAAsB,EACtB,SAAiB;IAEjB,OAAO,GAAG,gBAAgB,GAAG,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAC1B,IAAY,EACZ,SAAiB;IAEjB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qBAAqB;IACrB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iCAAiC;IACjC,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IAEtD,oBAAoB;IACpB,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qBAAqB;IACrB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAkB,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,kBAAkB,CACtC,MAA0B;IAE1B,MAAM,SAAS,GAAG,iBAAiB,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,MAAM,MAAM,GAAW,IAAA,uBAAY,EAAC,CAAC,MAAc,EAAE,EAAE;QACrD,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEpB,kEAAkE;QAClE,IAAI,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC1C,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACjC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAE1B,gDAAgD;YAChD,IAAI,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxC,OAAO,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;gBAC3C,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;gBACxC,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAEpC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,SAAS;gBACX,CAAC;gBAED,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;oBACvC,MAAM,CAAC,gBAAgB,CACrB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,QAAQ,CACjB,CAAC;gBACJ,CAAC;qBAAM,IAAI,OAAO,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;oBAC5C,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACpB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YAChC,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;YACpC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,mDAAmD;IACnD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC3C,MAAM,kBAAkB,GACtB,MAAM,CAAC,kBAAkB,IAAI,4BAA4B,EAAE,CAAC;gBAC9D,KAAK,CAAC,KAAK,IAAI,EAAE;oBACf,IAAI,CAAC;wBACH,MAAM,IAAA,gBAAK,EAAC,IAAA,mBAAO,EAAC,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;wBAC9D,MAAM,IAAA,oBAAS,EACb,kBAAkB,EAClB,IAAI,CAAC,SAAS,CACZ;4BACE,IAAI,EAAE,OAAO,CAAC,IAAI;4BAClB,SAAS;yBACV,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;wBACF,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,kBAAkB,CAAC;wBAC3D,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;wBACxD,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,SAAS,CAAC;wBAC7C,OAAO,EAAE,CAAC;oBACZ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,KAAK,CAAC,CAAC;oBAChB,CAAC;gBACH,CAAC,CAAC,EAAE,CAAC;gBACL,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,CAAC,MAAwB,EAAE,EAAE;YACjC,cAAc,GAAG,IAAI,CAAC;YACtB,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,SAAS,CAAC,CAAC;YACxE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS;KAC9B,CAAC;AACJ,CAAC","sourcesContent":["import { randomBytes } from 'node:crypto';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { createServer, type Server, type Socket } from 'node:net';\nimport { dirname, join } from 'node:path';\n\n/**\n * Magic preamble that must prefix all messages to authenticate them as workflow messages.\n * This prevents accidental processing of messages from port scanners or other local processes.\n */\nconst MESSAGE_PREAMBLE = 'WF:';\n\n/**\n * Generate a random authentication token for this server session.\n * Clients must include this token in all messages.\n */\nfunction generateAuthToken(): string {\n return randomBytes(16).toString('hex');\n}\n\n/**\n * Message types that can be sent between loader and builder\n */\nexport type SocketMessage =\n | {\n type: 'file-discovered';\n filePath: string;\n hasWorkflow: boolean;\n hasStep: boolean;\n hasSerde: boolean;\n }\n | { type: 'trigger-build' }\n | { type: 'build-complete' };\n\n/**\n * Configuration for the socket server\n */\nexport interface SocketServerConfig {\n isDevServer: boolean;\n onFileDiscovered: (\n filePath: string,\n hasWorkflow: boolean,\n hasStep: boolean,\n hasSerde: boolean\n ) => void;\n onTriggerBuild: () => void;\n socketInfoFilePath?: string;\n}\n\n/**\n * Interface for the socket IO instance returned by createSocketServer\n */\nexport interface SocketIO {\n emit(event: 'build-complete'): void;\n getAuthToken(): string;\n}\n\nfunction getDefaultSocketInfoFilePath(): string {\n return join(process.cwd(), '.next', 'cache', 'workflow-socket.json');\n}\n\n/**\n * Serialize a message with authentication preamble\n */\nexport function serializeMessage(\n message: SocketMessage,\n authToken: string\n): string {\n return `${MESSAGE_PREAMBLE}${authToken}:${JSON.stringify(message)}\\n`;\n}\n\n/**\n * Parse and authenticate a message from the socket\n * Returns the parsed message if valid, null otherwise\n */\nexport function parseMessage(\n line: string,\n authToken: string\n): SocketMessage | null {\n const trimmed = line.trim();\n if (!trimmed) {\n return null;\n }\n\n // Check for preamble\n if (!trimmed.startsWith(MESSAGE_PREAMBLE)) {\n console.warn('Received message without valid preamble, ignoring');\n return null;\n }\n\n // Extract auth token and payload\n const withoutPreamble = trimmed.slice(MESSAGE_PREAMBLE.length);\n const colonIndex = withoutPreamble.indexOf(':');\n if (colonIndex === -1) {\n console.warn('Received message without auth token separator, ignoring');\n return null;\n }\n\n const messageToken = withoutPreamble.slice(0, colonIndex);\n const payload = withoutPreamble.slice(colonIndex + 1);\n\n // Verify auth token\n if (messageToken !== authToken) {\n console.warn('Received message with invalid auth token, ignoring');\n return null;\n }\n\n // Parse JSON payload\n try {\n return JSON.parse(payload) as SocketMessage;\n } catch (error) {\n console.error('Failed to parse socket message JSON:', error);\n return null;\n }\n}\n\n/**\n * Create a TCP socket server for loader<->builder communication.\n * Returns a SocketIO interface for broadcasting messages and the auth token.\n *\n * SECURITY: Server listens on 127.0.0.1 (localhost only) and uses\n * message authentication to prevent processing of unauthorized messages.\n */\nexport async function createSocketServer(\n config: SocketServerConfig\n): Promise<SocketIO> {\n const authToken = generateAuthToken();\n const clients = new Set<Socket>();\n let buildTriggered = false;\n\n const server: Server = createServer((socket: Socket) => {\n socket.setNoDelay(true);\n clients.add(socket);\n\n // Send build-complete if build already finished (production mode)\n if (buildTriggered && !config.isDevServer) {\n socket.write(serializeMessage({ type: 'build-complete' }, authToken));\n }\n\n let buffer = '';\n\n socket.on('data', (data: Buffer) => {\n buffer += data.toString();\n\n // Process complete messages (newline-delimited)\n let newlineIndex = buffer.indexOf('\\n');\n while (newlineIndex !== -1) {\n const line = buffer.slice(0, newlineIndex);\n buffer = buffer.slice(newlineIndex + 1);\n newlineIndex = buffer.indexOf('\\n');\n\n const message = parseMessage(line, authToken);\n if (!message) {\n continue;\n }\n\n if (message.type === 'file-discovered') {\n config.onFileDiscovered(\n message.filePath,\n message.hasWorkflow,\n message.hasStep,\n message.hasSerde\n );\n } else if (message.type === 'trigger-build') {\n config.onTriggerBuild();\n }\n }\n });\n\n socket.on('end', () => {\n clients.delete(socket);\n });\n\n socket.on('error', (err: Error) => {\n console.error('Socket error:', err);\n clients.delete(socket);\n });\n });\n\n // Listen on random available port (localhost only)\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', () => {\n const address = server.address();\n if (address && typeof address === 'object') {\n const socketInfoFilePath =\n config.socketInfoFilePath || getDefaultSocketInfoFilePath();\n void (async () => {\n try {\n await mkdir(dirname(socketInfoFilePath), { recursive: true });\n await writeFile(\n socketInfoFilePath,\n JSON.stringify(\n {\n port: address.port,\n authToken,\n },\n null,\n 2\n )\n );\n process.env.WORKFLOW_SOCKET_INFO_PATH = socketInfoFilePath;\n process.env.WORKFLOW_SOCKET_PORT = String(address.port);\n process.env.WORKFLOW_SOCKET_AUTH = authToken;\n resolve();\n } catch (error) {\n reject(error);\n }\n })();\n return;\n }\n reject(new Error('Failed to obtain workflow socket server address'));\n });\n });\n\n return {\n emit: (_event: 'build-complete') => {\n buildTriggered = true;\n const message = serializeMessage({ type: 'build-complete' }, authToken);\n for (const client of clients) {\n client.write(message);\n }\n },\n getAuthToken: () => authToken,\n };\n}\n"]}
@@ -1,19 +0,0 @@
1
- export declare const DEFERRED_STEP_COPY_DIR_NAME = "__workflow_step_files__";
2
- export declare const DEFERRED_STEP_SOURCE_METADATA_PREFIX = "WORKFLOW_STEP_SOURCE_B64:";
3
- export interface DeferredStepSourceMetadata {
4
- relativeFilename: string;
5
- absolutePath: string;
6
- }
7
- export declare function isDeferredStepCopyFilePath(filePath: string): boolean;
8
- export declare function createDeferredStepSourceMetadataComment(metadata: DeferredStepSourceMetadata): string;
9
- export declare function createDeferredStepCopyInlineSourceMapComment({ sourcePath, sourceContent, generatedContent, }: {
10
- sourcePath: string;
11
- sourceContent: string;
12
- generatedContent?: string;
13
- }): string;
14
- export declare function parseInlineSourceMapComment(source: string): {
15
- sourceWithoutMapComment: string;
16
- sourceMap: string | null;
17
- };
18
- export declare function parseDeferredStepSourceMetadata(source: string): DeferredStepSourceMetadata | null;
19
- //# sourceMappingURL=step-copy-utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"step-copy-utils.d.ts","sourceRoot":"","sources":["../src/step-copy-utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,4BAA4B,CAAC;AACrE,eAAO,MAAM,oCAAoC,8BAA8B,CAAC;AAIhF,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAUD,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKpE;AAED,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,0BAA0B,GACnC,MAAM,CAKR;AAiBD,wBAAgB,4CAA4C,CAAC,EAC3D,UAAU,EACV,aAAa,EACb,gBAAgB,GACjB,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,GAAG,MAAM,CAiBT;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG;IAC3D,uBAAuB,EAAE,MAAM,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAuBA;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,MAAM,GACb,0BAA0B,GAAG,IAAI,CA8BnC"}
@@ -1,101 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFERRED_STEP_SOURCE_METADATA_PREFIX = exports.DEFERRED_STEP_COPY_DIR_NAME = void 0;
4
- exports.isDeferredStepCopyFilePath = isDeferredStepCopyFilePath;
5
- exports.createDeferredStepSourceMetadataComment = createDeferredStepSourceMetadataComment;
6
- exports.createDeferredStepCopyInlineSourceMapComment = createDeferredStepCopyInlineSourceMapComment;
7
- exports.parseInlineSourceMapComment = parseInlineSourceMapComment;
8
- exports.parseDeferredStepSourceMetadata = parseDeferredStepSourceMetadata;
9
- exports.DEFERRED_STEP_COPY_DIR_NAME = '__workflow_step_files__';
10
- exports.DEFERRED_STEP_SOURCE_METADATA_PREFIX = 'WORKFLOW_STEP_SOURCE_B64:';
11
- const INLINE_SOURCE_MAP_PATTERN = /(?:^|\r?\n)\s*\/\/[#@]\s*sourceMappingURL=data:application\/json(?:;charset=[^;,]+)?;base64,([A-Za-z0-9+/=]+)\s*$/;
12
- function escapeRegExp(input) {
13
- return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
14
- }
15
- function normalizePath(filePath) {
16
- return filePath.replace(/\\/g, '/');
17
- }
18
- function isDeferredStepCopyFilePath(filePath) {
19
- const normalizedPath = normalizePath(filePath);
20
- return normalizedPath.includes(`/.well-known/workflow/v1/step/${exports.DEFERRED_STEP_COPY_DIR_NAME}/`);
21
- }
22
- function createDeferredStepSourceMetadataComment(metadata) {
23
- const encoded = Buffer.from(JSON.stringify(metadata), 'utf-8').toString('base64');
24
- return `// ${exports.DEFERRED_STEP_SOURCE_METADATA_PREFIX}${encoded}`;
25
- }
26
- function getLineCount(source) {
27
- if (source.length === 0) {
28
- return 1;
29
- }
30
- const lineBreakMatches = source.match(/\r\n|\r|\n/g);
31
- return (lineBreakMatches?.length ?? 0) + 1;
32
- }
33
- function createIdentityLineMappings(lineCount) {
34
- if (lineCount <= 1) {
35
- return 'AAAA';
36
- }
37
- return `AAAA${';AACA'.repeat(lineCount - 1)}`;
38
- }
39
- function createDeferredStepCopyInlineSourceMapComment({ sourcePath, sourceContent, generatedContent, }) {
40
- const normalizedSourcePath = normalizePath(sourcePath);
41
- const sourceMap = {
42
- version: 3,
43
- file: normalizedSourcePath.split('/').pop() ?? normalizedSourcePath,
44
- sources: [normalizedSourcePath],
45
- sourcesContent: [sourceContent],
46
- names: [],
47
- mappings: createIdentityLineMappings(getLineCount(generatedContent ?? sourceContent)),
48
- };
49
- const encodedSourceMap = Buffer.from(JSON.stringify(sourceMap), 'utf-8').toString('base64');
50
- return `//# sourceMappingURL=data:application/json;base64,${encodedSourceMap}`;
51
- }
52
- function parseInlineSourceMapComment(source) {
53
- const mapMatch = source.match(INLINE_SOURCE_MAP_PATTERN);
54
- if (!mapMatch?.[1]) {
55
- return {
56
- sourceWithoutMapComment: source,
57
- sourceMap: null,
58
- };
59
- }
60
- const sourceWithoutMapComment = source.replace(INLINE_SOURCE_MAP_PATTERN, '');
61
- try {
62
- const decodedMap = Buffer.from(mapMatch[1], 'base64').toString('utf-8');
63
- JSON.parse(decodedMap);
64
- return {
65
- sourceWithoutMapComment,
66
- sourceMap: decodedMap,
67
- };
68
- }
69
- catch {
70
- return {
71
- sourceWithoutMapComment,
72
- sourceMap: null,
73
- };
74
- }
75
- }
76
- function parseDeferredStepSourceMetadata(source) {
77
- const pattern = new RegExp(`^\\s*//\\s*${escapeRegExp(exports.DEFERRED_STEP_SOURCE_METADATA_PREFIX)}([A-Za-z0-9+/=]+)\\s*$`, 'm');
78
- const match = source.match(pattern);
79
- const encoded = match?.[1];
80
- if (!encoded) {
81
- return null;
82
- }
83
- try {
84
- const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
85
- const parsed = JSON.parse(decoded);
86
- if (typeof parsed.relativeFilename !== 'string' ||
87
- parsed.relativeFilename.length === 0 ||
88
- typeof parsed.absolutePath !== 'string' ||
89
- parsed.absolutePath.length === 0) {
90
- return null;
91
- }
92
- return {
93
- relativeFilename: parsed.relativeFilename,
94
- absolutePath: normalizePath(parsed.absolutePath),
95
- };
96
- }
97
- catch {
98
- return null;
99
- }
100
- }
101
- //# sourceMappingURL=step-copy-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"step-copy-utils.js","sourceRoot":"","sources":["../src/step-copy-utils.ts"],"names":[],"mappings":"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","sourcesContent":["export const DEFERRED_STEP_COPY_DIR_NAME = '__workflow_step_files__';\nexport const DEFERRED_STEP_SOURCE_METADATA_PREFIX = 'WORKFLOW_STEP_SOURCE_B64:';\nconst INLINE_SOURCE_MAP_PATTERN =\n /(?:^|\\r?\\n)\\s*\\/\\/[#@]\\s*sourceMappingURL=data:application\\/json(?:;charset=[^;,]+)?;base64,([A-Za-z0-9+/=]+)\\s*$/;\n\nexport interface DeferredStepSourceMetadata {\n relativeFilename: string;\n absolutePath: string;\n}\n\nfunction escapeRegExp(input: string): string {\n return input.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction normalizePath(filePath: string): string {\n return filePath.replace(/\\\\/g, '/');\n}\n\nexport function isDeferredStepCopyFilePath(filePath: string): boolean {\n const normalizedPath = normalizePath(filePath);\n return normalizedPath.includes(\n `/.well-known/workflow/v1/step/${DEFERRED_STEP_COPY_DIR_NAME}/`\n );\n}\n\nexport function createDeferredStepSourceMetadataComment(\n metadata: DeferredStepSourceMetadata\n): string {\n const encoded = Buffer.from(JSON.stringify(metadata), 'utf-8').toString(\n 'base64'\n );\n return `// ${DEFERRED_STEP_SOURCE_METADATA_PREFIX}${encoded}`;\n}\n\nfunction getLineCount(source: string): number {\n if (source.length === 0) {\n return 1;\n }\n const lineBreakMatches = source.match(/\\r\\n|\\r|\\n/g);\n return (lineBreakMatches?.length ?? 0) + 1;\n}\n\nfunction createIdentityLineMappings(lineCount: number): string {\n if (lineCount <= 1) {\n return 'AAAA';\n }\n return `AAAA${';AACA'.repeat(lineCount - 1)}`;\n}\n\nexport function createDeferredStepCopyInlineSourceMapComment({\n sourcePath,\n sourceContent,\n generatedContent,\n}: {\n sourcePath: string;\n sourceContent: string;\n generatedContent?: string;\n}): string {\n const normalizedSourcePath = normalizePath(sourcePath);\n const sourceMap = {\n version: 3,\n file: normalizedSourcePath.split('/').pop() ?? normalizedSourcePath,\n sources: [normalizedSourcePath],\n sourcesContent: [sourceContent],\n names: [] as string[],\n mappings: createIdentityLineMappings(\n getLineCount(generatedContent ?? sourceContent)\n ),\n };\n const encodedSourceMap = Buffer.from(\n JSON.stringify(sourceMap),\n 'utf-8'\n ).toString('base64');\n return `//# sourceMappingURL=data:application/json;base64,${encodedSourceMap}`;\n}\n\nexport function parseInlineSourceMapComment(source: string): {\n sourceWithoutMapComment: string;\n sourceMap: string | null;\n} {\n const mapMatch = source.match(INLINE_SOURCE_MAP_PATTERN);\n if (!mapMatch?.[1]) {\n return {\n sourceWithoutMapComment: source,\n sourceMap: null,\n };\n }\n\n const sourceWithoutMapComment = source.replace(INLINE_SOURCE_MAP_PATTERN, '');\n try {\n const decodedMap = Buffer.from(mapMatch[1], 'base64').toString('utf-8');\n JSON.parse(decodedMap);\n return {\n sourceWithoutMapComment,\n sourceMap: decodedMap,\n };\n } catch {\n return {\n sourceWithoutMapComment,\n sourceMap: null,\n };\n }\n}\n\nexport function parseDeferredStepSourceMetadata(\n source: string\n): DeferredStepSourceMetadata | null {\n const pattern = new RegExp(\n `^\\\\s*//\\\\s*${escapeRegExp(DEFERRED_STEP_SOURCE_METADATA_PREFIX)}([A-Za-z0-9+/=]+)\\\\s*$`,\n 'm'\n );\n const match = source.match(pattern);\n const encoded = match?.[1];\n if (!encoded) {\n return null;\n }\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf-8');\n const parsed = JSON.parse(decoded) as Partial<DeferredStepSourceMetadata>;\n if (\n typeof parsed.relativeFilename !== 'string' ||\n parsed.relativeFilename.length === 0 ||\n typeof parsed.absolutePath !== 'string' ||\n parsed.absolutePath.length === 0\n ) {\n return null;\n }\n\n return {\n relativeFilename: parsed.relativeFilename,\n absolutePath: normalizePath(parsed.absolutePath),\n };\n } catch {\n return null;\n }\n}\n"]}