@fgv/ts-res-browser-cli 5.0.0-2 → 5.0.0-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/README.md +35 -11
- package/lib/cli.d.ts +0 -4
- package/lib/cli.js +8 -17
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/options.d.ts +5 -0
- package/lib/simpleBrowserLauncher.d.ts +32 -0
- package/lib/{browserLauncher.js → simpleBrowserLauncher.js} +53 -125
- package/lib/zipArchiver.d.ts +2 -14
- package/lib/zipArchiver.js +11 -72
- package/package.json +11 -12
- package/src/cli.ts +17 -20
- package/src/index.ts +1 -1
- package/src/options.ts +6 -0
- package/src/{browserLauncher.ts → simpleBrowserLauncher.ts} +56 -144
- package/src/zipArchiver.ts +12 -97
- package/.rush/temp/45629f175c0b2c015132e9451c317583db1c0e2d.tar.log +0 -32
- package/.rush/temp/chunked-rush-logs/ts-res-browser-cli.build.chunks.jsonl +0 -5
- package/.rush/temp/operation/build/all.log +0 -5
- package/.rush/temp/operation/build/log-chunks.jsonl +0 -5
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/shrinkwrap-deps.json +0 -651
- package/lib/browserLauncher.d.ts +0 -53
- package/lib/browserLauncher.d.ts.map +0 -1
- package/lib/browserLauncher.js.map +0 -1
- package/lib/cli.d.ts.map +0 -1
- package/lib/cli.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/options.d.ts.map +0 -1
- package/lib/options.js.map +0 -1
- package/lib/zipArchiver.d.ts.map +0 -1
- package/lib/zipArchiver.js.map +0 -1
- package/rush-logs/ts-res-browser-cli.build.cache.log +0 -3
- package/rush-logs/ts-res-browser-cli.build.log +0 -5
- package/tsconfig.json +0 -7
package/README.md
CHANGED
|
@@ -17,19 +17,28 @@ Command-line interface to launch ts-res-browser with specified resources and con
|
|
|
17
17
|
npm install -g @fgv/ts-res-browser-cli
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
Or use directly with npx (no installation required):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @fgv/ts-res-browser-cli --help
|
|
24
|
+
```
|
|
25
|
+
|
|
20
26
|
## Usage
|
|
21
27
|
|
|
22
28
|
### Basic Usage
|
|
23
29
|
|
|
24
30
|
```bash
|
|
25
31
|
# Launch browser with resources from a directory
|
|
26
|
-
ts-res-browser-cli browse --input ./resources --config default
|
|
32
|
+
ts-res-browser-cli browse --input ./resources --config default --serve
|
|
33
|
+
|
|
34
|
+
# With npx (no installation required)
|
|
35
|
+
npx @fgv/ts-res-browser-cli --input ./resources --config default --serve
|
|
27
36
|
|
|
28
37
|
# Launch with a specific configuration file
|
|
29
|
-
ts-res-browser-cli browse --input ./my-resources --config ./config.json
|
|
38
|
+
ts-res-browser-cli browse --input ./my-resources --config ./config.json --serve
|
|
30
39
|
|
|
31
40
|
# Create ZIP and launch without opening browser automatically
|
|
32
|
-
ts-res-browser-cli browse --input ./resources --config extended-example --no-open
|
|
41
|
+
ts-res-browser-cli browse --input ./resources --config extended-example --serve --no-open
|
|
33
42
|
```
|
|
34
43
|
|
|
35
44
|
### ZIP Workflow
|
|
@@ -42,19 +51,33 @@ The CLI automatically creates ZIP archives containing your resources and configu
|
|
|
42
51
|
|
|
43
52
|
```bash
|
|
44
53
|
# Creates: ~/Downloads/ts-res-bundle-[timestamp].zip
|
|
45
|
-
ts-res-browser-cli browse --input ./resources --config my-config
|
|
54
|
+
ts-res-browser-cli browse --input ./resources --config my-config --serve
|
|
46
55
|
```
|
|
47
56
|
|
|
48
|
-
###
|
|
57
|
+
### Server Options
|
|
58
|
+
|
|
59
|
+
The CLI provides several ways to launch the browser with a server:
|
|
49
60
|
|
|
50
61
|
```bash
|
|
51
|
-
#
|
|
62
|
+
# Recommended: Universal server start (works everywhere)
|
|
63
|
+
ts-res-browser-cli browse --input ./resources --serve
|
|
64
|
+
|
|
65
|
+
# Development server (monorepo environment only)
|
|
52
66
|
ts-res-browser-cli browse --input ./resources --dev
|
|
53
67
|
|
|
54
|
-
#
|
|
68
|
+
# Connect to existing server
|
|
55
69
|
ts-res-browser-cli browse --input ./resources --url http://localhost:3001
|
|
56
70
|
```
|
|
57
71
|
|
|
72
|
+
**Server Flag Behavior:**
|
|
73
|
+
- `--serve`: Works in both monorepo and published packages
|
|
74
|
+
- **Monorepo**: Starts webpack dev server with hot reloading (port 3000)
|
|
75
|
+
- **Published packages**: Starts static file server (port 8080)
|
|
76
|
+
- `--dev`: Development server with hot reloading (monorepo only)
|
|
77
|
+
- **Monorepo**: Same as `--serve`
|
|
78
|
+
- **Published packages**: Shows error with instructions to use `--serve`
|
|
79
|
+
- `--url`: Connect to existing server at specified URL
|
|
80
|
+
|
|
58
81
|
### Advanced Options
|
|
59
82
|
|
|
60
83
|
```bash
|
|
@@ -64,8 +87,8 @@ ts-res-browser-cli browse \
|
|
|
64
87
|
--context-filter "language=en-US|territory=US" \
|
|
65
88
|
--reduce-qualifiers
|
|
66
89
|
|
|
67
|
-
# Interactive mode with sample data
|
|
68
|
-
ts-res-browser-cli browse --interactive
|
|
90
|
+
# Interactive mode with sample data (requires server)
|
|
91
|
+
ts-res-browser-cli browse --interactive --serve
|
|
69
92
|
|
|
70
93
|
# Verbose output
|
|
71
94
|
ts-res-browser-cli browse --input ./resources --verbose
|
|
@@ -89,8 +112,9 @@ Launch ts-res-browser with specified resources and configuration.
|
|
|
89
112
|
- `-p, --port <number>`: Port for local browser instance
|
|
90
113
|
- `--url <url>`: URL of remote browser instance
|
|
91
114
|
- `--no-open`: Do not open browser automatically
|
|
92
|
-
- `--interactive`: Launch in interactive mode with sample data
|
|
93
|
-
- `--
|
|
115
|
+
- `--interactive`: Launch in interactive mode with sample data (requires --serve, --dev, or --url)
|
|
116
|
+
- `--serve`: Start server (dev in monorepo, serve in published packages) and connect automatically
|
|
117
|
+
- `--dev`: Start development server locally (monorepo only)
|
|
94
118
|
- `-v, --verbose`: Verbose output
|
|
95
119
|
- `-q, --quiet`: Quiet output
|
|
96
120
|
|
package/lib/cli.d.ts
CHANGED
package/lib/cli.js
CHANGED
|
@@ -60,16 +60,15 @@ const ts_utils_1 = require("@fgv/ts-utils");
|
|
|
60
60
|
const TsRes = __importStar(require("@fgv/ts-res"));
|
|
61
61
|
const fs_1 = require("fs");
|
|
62
62
|
const path = __importStar(require("path"));
|
|
63
|
-
const
|
|
63
|
+
const simpleBrowserLauncher_1 = require("./simpleBrowserLauncher");
|
|
64
64
|
/**
|
|
65
65
|
* Main CLI class for ts-res-browser-cli
|
|
66
66
|
*/
|
|
67
67
|
class TsResBrowserCliApp {
|
|
68
68
|
constructor() {
|
|
69
69
|
this._program = new commander_1.Command();
|
|
70
|
-
this._launcher = new
|
|
70
|
+
this._launcher = new simpleBrowserLauncher_1.SimpleBrowserLauncher();
|
|
71
71
|
this._setupCommands();
|
|
72
|
-
this._setupGracefulShutdown();
|
|
73
72
|
}
|
|
74
73
|
/**
|
|
75
74
|
* Runs the CLI with the provided arguments
|
|
@@ -102,6 +101,7 @@ class TsResBrowserCliApp {
|
|
|
102
101
|
.option('--no-open', 'Do not open browser automatically')
|
|
103
102
|
.option('--interactive', 'Launch in interactive mode with sample data', false)
|
|
104
103
|
.option('--dev', 'Automatically start development server locally', false)
|
|
104
|
+
.option('--serve', 'Start server (dev in monorepo, serve in published packages) and connect automatically', false)
|
|
105
105
|
.action(async (options) => {
|
|
106
106
|
// If no options provided, show help
|
|
107
107
|
if (!this._hasOptions(options)) {
|
|
@@ -130,6 +130,7 @@ class TsResBrowserCliApp {
|
|
|
130
130
|
.option('--no-open', 'Do not open browser automatically')
|
|
131
131
|
.option('--interactive', 'Launch in interactive mode with sample data', false)
|
|
132
132
|
.option('--dev', 'Automatically start development server locally', false)
|
|
133
|
+
.option('--serve', 'Start server (dev in monorepo, serve in published packages) and connect automatically', false)
|
|
133
134
|
.action(async (options) => {
|
|
134
135
|
await this._handleBrowseCommand(options);
|
|
135
136
|
});
|
|
@@ -161,7 +162,8 @@ class TsResBrowserCliApp {
|
|
|
161
162
|
options.reduceQualifiers ||
|
|
162
163
|
options.interactive ||
|
|
163
164
|
options.url ||
|
|
164
|
-
options.dev
|
|
165
|
+
options.dev ||
|
|
166
|
+
options.serve);
|
|
165
167
|
}
|
|
166
168
|
/**
|
|
167
169
|
* Handles the browse command
|
|
@@ -348,7 +350,8 @@ class TsResBrowserCliApp {
|
|
|
348
350
|
url: options.url,
|
|
349
351
|
open: options.open,
|
|
350
352
|
interactive: options.interactive || false,
|
|
351
|
-
dev: options.dev || false
|
|
353
|
+
dev: options.dev || false,
|
|
354
|
+
serve: options.serve || false
|
|
352
355
|
};
|
|
353
356
|
return (0, ts_utils_1.succeed)(browseOptions);
|
|
354
357
|
}
|
|
@@ -356,18 +359,6 @@ class TsResBrowserCliApp {
|
|
|
356
359
|
return (0, ts_utils_1.fail)(`Failed to parse options: ${error}`);
|
|
357
360
|
}
|
|
358
361
|
}
|
|
359
|
-
/**
|
|
360
|
-
* Sets up graceful shutdown handling
|
|
361
|
-
*/
|
|
362
|
-
_setupGracefulShutdown() {
|
|
363
|
-
const shutdown = (signal) => {
|
|
364
|
-
console.log(`\nReceived ${signal}, shutting down gracefully...`);
|
|
365
|
-
this._launcher.shutdown();
|
|
366
|
-
process.exit(0);
|
|
367
|
-
};
|
|
368
|
-
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
369
|
-
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
370
|
-
}
|
|
371
362
|
}
|
|
372
363
|
exports.TsResBrowserCliApp = TsResBrowserCliApp;
|
|
373
364
|
//# sourceMappingURL=cli.js.map
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -38,5 +38,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
38
38
|
// Export main components
|
|
39
39
|
__exportStar(require("./cli"), exports);
|
|
40
40
|
__exportStar(require("./options"), exports);
|
|
41
|
-
__exportStar(require("./
|
|
41
|
+
__exportStar(require("./simpleBrowserLauncher"), exports);
|
|
42
42
|
//# sourceMappingURL=index.js.map
|
package/lib/options.d.ts
CHANGED
|
@@ -59,6 +59,10 @@ export interface IBrowseOptions {
|
|
|
59
59
|
* Whether to automatically start the development server
|
|
60
60
|
*/
|
|
61
61
|
dev?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Whether to start server (dev in monorepo, serve in published packages) and connect automatically
|
|
64
|
+
*/
|
|
65
|
+
serve?: boolean;
|
|
62
66
|
/**
|
|
63
67
|
* Whether to use ZIP loading mode (internal flag)
|
|
64
68
|
*/
|
|
@@ -91,5 +95,6 @@ export interface IBrowseCommandOptions {
|
|
|
91
95
|
interactive?: boolean;
|
|
92
96
|
url?: string;
|
|
93
97
|
dev?: boolean;
|
|
98
|
+
serve?: boolean;
|
|
94
99
|
}
|
|
95
100
|
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { IBrowseOptions } from './options';
|
|
3
|
+
/**
|
|
4
|
+
* Simplified browser launcher using direct dependency on ts-res-browser
|
|
5
|
+
*/
|
|
6
|
+
export declare class SimpleBrowserLauncher {
|
|
7
|
+
/**
|
|
8
|
+
* Launches the browser with the specified options
|
|
9
|
+
*/
|
|
10
|
+
launch(options: IBrowseOptions): Promise<Result<void>>;
|
|
11
|
+
/**
|
|
12
|
+
* Starts the server using ts-res-browser CLI directly
|
|
13
|
+
*/
|
|
14
|
+
private _startServer;
|
|
15
|
+
/**
|
|
16
|
+
* Opens the browser to the specified URL
|
|
17
|
+
*/
|
|
18
|
+
private _openBrowser;
|
|
19
|
+
/**
|
|
20
|
+
* Builds the URL with query parameters based on options
|
|
21
|
+
*/
|
|
22
|
+
private _buildUrl;
|
|
23
|
+
/**
|
|
24
|
+
* Determines if a ZIP archive should be created based on the options
|
|
25
|
+
*/
|
|
26
|
+
private _shouldCreateZip;
|
|
27
|
+
/**
|
|
28
|
+
* Creates a ZIP archive containing the input and config files
|
|
29
|
+
*/
|
|
30
|
+
private _createZipArchive;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=simpleBrowserLauncher.d.ts.map
|
|
@@ -54,21 +54,28 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
54
54
|
};
|
|
55
55
|
})();
|
|
56
56
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
-
exports.
|
|
57
|
+
exports.SimpleBrowserLauncher = void 0;
|
|
58
58
|
const child_process_1 = require("child_process");
|
|
59
59
|
const path = __importStar(require("path"));
|
|
60
|
-
const http = __importStar(require("http"));
|
|
61
60
|
const ts_utils_1 = require("@fgv/ts-utils");
|
|
62
61
|
const zipArchiver_1 = require("./zipArchiver");
|
|
63
62
|
/**
|
|
64
|
-
*
|
|
63
|
+
* Simplified browser launcher using direct dependency on ts-res-browser
|
|
65
64
|
*/
|
|
66
|
-
class
|
|
65
|
+
class SimpleBrowserLauncher {
|
|
67
66
|
/**
|
|
68
67
|
* Launches the browser with the specified options
|
|
69
68
|
*/
|
|
70
69
|
async launch(options) {
|
|
71
70
|
try {
|
|
71
|
+
// Validate options before proceeding
|
|
72
|
+
if (options.interactive && !options.dev && !options.serve && !options.url) {
|
|
73
|
+
return (0, ts_utils_1.fail)('Interactive mode requires either --dev/--serve to start a local server or --url to specify a remote server.\n\n' +
|
|
74
|
+
'Examples:\n' +
|
|
75
|
+
' ts-res-browser-cli --interactive --dev\n' +
|
|
76
|
+
' ts-res-browser-cli --interactive --serve\n' +
|
|
77
|
+
' ts-res-browser-cli --interactive --url https://example.com/ts-res-browser');
|
|
78
|
+
}
|
|
72
79
|
// Check if we need to create a ZIP archive for file-based inputs
|
|
73
80
|
let zipCreated = false;
|
|
74
81
|
let finalOptions = Object.assign({}, options);
|
|
@@ -90,25 +97,15 @@ class BrowserLauncher {
|
|
|
90
97
|
loadZip: true, zipFile: zipFileName, zipPath: zipResult.value.zipPath });
|
|
91
98
|
zipCreated = true;
|
|
92
99
|
}
|
|
93
|
-
// Start
|
|
94
|
-
if (finalOptions.dev && !finalOptions.url) {
|
|
100
|
+
// Start server if requested
|
|
101
|
+
if ((finalOptions.dev || finalOptions.serve) && !finalOptions.url) {
|
|
95
102
|
if (!finalOptions.quiet) {
|
|
96
|
-
console.log('Starting TS-RES Browser
|
|
103
|
+
console.log('Starting TS-RES Browser server...');
|
|
97
104
|
}
|
|
98
|
-
const serverResult = await this.
|
|
105
|
+
const serverResult = await this._startServer(finalOptions);
|
|
99
106
|
if (serverResult.isFailure()) {
|
|
100
107
|
return serverResult;
|
|
101
108
|
}
|
|
102
|
-
// Wait for server to be ready
|
|
103
|
-
const port = options.port || 3000;
|
|
104
|
-
const readyResult = await this._waitForServerReady(port, options.verbose || false);
|
|
105
|
-
if (readyResult.isFailure()) {
|
|
106
|
-
this._stopDevServer();
|
|
107
|
-
return readyResult;
|
|
108
|
-
}
|
|
109
|
-
if (!options.quiet) {
|
|
110
|
-
console.log(`Development server started on port ${port}`);
|
|
111
|
-
}
|
|
112
109
|
}
|
|
113
110
|
// Build URL with parameters
|
|
114
111
|
const url = this._buildUrl(finalOptions);
|
|
@@ -150,6 +147,39 @@ class BrowserLauncher {
|
|
|
150
147
|
return (0, ts_utils_1.fail)(`Failed to launch browser: ${error}`);
|
|
151
148
|
}
|
|
152
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Starts the server using ts-res-browser CLI directly
|
|
152
|
+
*/
|
|
153
|
+
async _startServer(options) {
|
|
154
|
+
try {
|
|
155
|
+
// Use ts-res-browser directly from node_modules
|
|
156
|
+
const browserPath = require.resolve('@fgv/ts-res-browser/cli.js');
|
|
157
|
+
const command = `node "${browserPath}" ${options.dev ? 'dev' : 'serve'}`;
|
|
158
|
+
if (options.verbose) {
|
|
159
|
+
console.log(`Running: ${command}`);
|
|
160
|
+
}
|
|
161
|
+
return new Promise((resolve) => {
|
|
162
|
+
const child = (0, child_process_1.exec)(command, (error) => {
|
|
163
|
+
if (error) {
|
|
164
|
+
resolve((0, ts_utils_1.fail)(`Failed to start server: ${error.message}`));
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
resolve((0, ts_utils_1.succeed)(undefined));
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
// Give server time to start, then assume success
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
if (options.verbose) {
|
|
173
|
+
console.log('Server startup initiated');
|
|
174
|
+
}
|
|
175
|
+
resolve((0, ts_utils_1.succeed)(undefined));
|
|
176
|
+
}, 2000);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return (0, ts_utils_1.fail)(`Failed to start server: ${error}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
153
183
|
/**
|
|
154
184
|
* Opens the browser to the specified URL
|
|
155
185
|
*/
|
|
@@ -173,8 +203,9 @@ class BrowserLauncher {
|
|
|
173
203
|
* Builds the URL with query parameters based on options
|
|
174
204
|
*/
|
|
175
205
|
_buildUrl(options) {
|
|
176
|
-
// Use provided URL or default
|
|
177
|
-
const
|
|
206
|
+
// Use provided URL or default based on server type
|
|
207
|
+
const defaultPort = options.dev ? 3000 : 8080;
|
|
208
|
+
const baseUrl = options.url || `http://localhost:${options.port || defaultPort}`;
|
|
178
209
|
const params = new URLSearchParams();
|
|
179
210
|
if (options.input) {
|
|
180
211
|
params.set('input', options.input);
|
|
@@ -212,103 +243,6 @@ class BrowserLauncher {
|
|
|
212
243
|
const queryString = params.toString();
|
|
213
244
|
return queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
|
214
245
|
}
|
|
215
|
-
/**
|
|
216
|
-
* Starts the development server for ts-res-browser
|
|
217
|
-
*/
|
|
218
|
-
async _startDevServer(options) {
|
|
219
|
-
try {
|
|
220
|
-
// Find the ts-res-browser project directory
|
|
221
|
-
// Assume we're running from tools/ts-res-browser-cli, so go up and over to tools/ts-res-browser
|
|
222
|
-
const browserProjectPath = path.resolve(__dirname, '../../ts-res-browser');
|
|
223
|
-
if (options.verbose) {
|
|
224
|
-
console.log(`Looking for ts-res-browser at: ${browserProjectPath}`);
|
|
225
|
-
}
|
|
226
|
-
const port = options.port || 3000;
|
|
227
|
-
const env = Object.assign(Object.assign({}, process.env), { PORT: port.toString() });
|
|
228
|
-
this._devServer = (0, child_process_1.spawn)('rushx', ['dev'], {
|
|
229
|
-
cwd: browserProjectPath,
|
|
230
|
-
env,
|
|
231
|
-
stdio: options.verbose ? 'inherit' : ['ignore', 'pipe', 'pipe']
|
|
232
|
-
});
|
|
233
|
-
this._devServer.on('error', (error) => {
|
|
234
|
-
return (0, ts_utils_1.fail)(`Failed to start development server: ${error}`);
|
|
235
|
-
});
|
|
236
|
-
// Give the server a moment to start
|
|
237
|
-
await this._sleep(3000);
|
|
238
|
-
if (this._devServer && !this._devServer.killed) {
|
|
239
|
-
if (options.verbose) {
|
|
240
|
-
console.log('Development server process started successfully');
|
|
241
|
-
}
|
|
242
|
-
return (0, ts_utils_1.succeed)(undefined);
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
return (0, ts_utils_1.fail)('Development server process failed to start');
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
catch (error) {
|
|
249
|
-
return (0, ts_utils_1.fail)(`Failed to start development server: ${error}`);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Waits for the development server to be ready by checking HTTP availability
|
|
254
|
-
*/
|
|
255
|
-
async _waitForServerReady(port, verbose, maxAttempts = 60) {
|
|
256
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
257
|
-
try {
|
|
258
|
-
const isReady = await this._checkServerHealth(port);
|
|
259
|
-
if (isReady) {
|
|
260
|
-
if (verbose) {
|
|
261
|
-
console.log(`Server is ready at http://localhost:${port}`);
|
|
262
|
-
}
|
|
263
|
-
return (0, ts_utils_1.succeed)(undefined);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
catch (error) {
|
|
267
|
-
// Server not ready yet, continue waiting
|
|
268
|
-
}
|
|
269
|
-
if (verbose && attempt % 10 === 0) {
|
|
270
|
-
console.log(`Waiting for server to be ready... (attempt ${attempt}/${maxAttempts})`);
|
|
271
|
-
}
|
|
272
|
-
await this._sleep(1000);
|
|
273
|
-
}
|
|
274
|
-
return (0, ts_utils_1.fail)(`Server did not become ready after ${maxAttempts} attempts`);
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Checks if the server is responding
|
|
278
|
-
*/
|
|
279
|
-
async _checkServerHealth(port) {
|
|
280
|
-
return new Promise((resolve) => {
|
|
281
|
-
const request = http.get(`http://localhost:${port}`, (res) => {
|
|
282
|
-
resolve(res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 400);
|
|
283
|
-
});
|
|
284
|
-
request.on('error', () => {
|
|
285
|
-
resolve(false);
|
|
286
|
-
});
|
|
287
|
-
request.setTimeout(3000, () => {
|
|
288
|
-
request.destroy();
|
|
289
|
-
resolve(false);
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Stops the development server
|
|
295
|
-
*/
|
|
296
|
-
_stopDevServer() {
|
|
297
|
-
if (this._devServer && !this._devServer.killed) {
|
|
298
|
-
this._devServer.kill('SIGTERM');
|
|
299
|
-
setTimeout(() => {
|
|
300
|
-
if (this._devServer && !this._devServer.killed) {
|
|
301
|
-
this._devServer.kill('SIGKILL');
|
|
302
|
-
}
|
|
303
|
-
}, 5000);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Sleep for the specified number of milliseconds
|
|
308
|
-
*/
|
|
309
|
-
_sleep(ms) {
|
|
310
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
311
|
-
}
|
|
312
246
|
/**
|
|
313
247
|
* Determines if a ZIP archive should be created based on the options
|
|
314
248
|
*/
|
|
@@ -336,12 +270,6 @@ class BrowserLauncher {
|
|
|
336
270
|
return (0, ts_utils_1.fail)(`Failed to create ZIP archive: ${error instanceof Error ? error.message : String(error)}`);
|
|
337
271
|
}
|
|
338
272
|
}
|
|
339
|
-
/**
|
|
340
|
-
* Graceful shutdown - stops development server if running
|
|
341
|
-
*/
|
|
342
|
-
shutdown() {
|
|
343
|
-
this._stopDevServer();
|
|
344
|
-
}
|
|
345
273
|
}
|
|
346
|
-
exports.
|
|
347
|
-
//# sourceMappingURL=
|
|
274
|
+
exports.SimpleBrowserLauncher = SimpleBrowserLauncher;
|
|
275
|
+
//# sourceMappingURL=simpleBrowserLauncher.js.map
|
package/lib/zipArchiver.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { ZipArchive } from '@fgv/ts-res';
|
|
2
3
|
export interface ZipArchiveOptions {
|
|
3
4
|
input?: string;
|
|
4
5
|
config?: string;
|
|
@@ -6,20 +7,7 @@ export interface ZipArchiveOptions {
|
|
|
6
7
|
}
|
|
7
8
|
export interface ZipArchiveResult {
|
|
8
9
|
zipPath: string;
|
|
9
|
-
manifest:
|
|
10
|
-
}
|
|
11
|
-
export interface ZipManifest {
|
|
12
|
-
timestamp: string;
|
|
13
|
-
input?: {
|
|
14
|
-
type: 'file' | 'directory';
|
|
15
|
-
originalPath: string;
|
|
16
|
-
archivePath: string;
|
|
17
|
-
};
|
|
18
|
-
config?: {
|
|
19
|
-
type: 'file';
|
|
20
|
-
originalPath: string;
|
|
21
|
-
archivePath: string;
|
|
22
|
-
};
|
|
10
|
+
manifest: ZipArchive.IZipArchiveManifest;
|
|
23
11
|
}
|
|
24
12
|
export declare class ZipArchiver {
|
|
25
13
|
/**
|
package/lib/zipArchiver.js
CHANGED
|
@@ -34,11 +34,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.zipArchiver = exports.ZipArchiver = void 0;
|
|
37
|
-
const archiver = __importStar(require("archiver"));
|
|
38
37
|
const fs = __importStar(require("fs"));
|
|
39
38
|
const path = __importStar(require("path"));
|
|
40
39
|
const os = __importStar(require("os"));
|
|
41
40
|
const ts_utils_1 = require("@fgv/ts-utils");
|
|
41
|
+
const ts_res_1 = require("@fgv/ts-res");
|
|
42
42
|
class ZipArchiver {
|
|
43
43
|
/**
|
|
44
44
|
* Create a ZIP archive containing the specified input and config files/directories
|
|
@@ -53,79 +53,18 @@ class ZipArchiver {
|
|
|
53
53
|
if (!fs.existsSync(outputDir)) {
|
|
54
54
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
56
|
+
// Create ZIP archive using the new zip-archive packlet
|
|
57
|
+
const creator = new ts_res_1.ZipArchive.ZipArchiveCreator();
|
|
58
|
+
const createResult = await creator.createFromBuffer({
|
|
59
|
+
inputPath: options.input,
|
|
60
|
+
configPath: options.config
|
|
59
61
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
timestamp: new Date().toISOString()
|
|
63
|
-
};
|
|
64
|
-
// Promise to handle async archiving
|
|
65
|
-
const archivePromise = new Promise((resolve, reject) => {
|
|
66
|
-
output.on('close', () => {
|
|
67
|
-
resolve();
|
|
68
|
-
});
|
|
69
|
-
output.on('error', (err) => {
|
|
70
|
-
reject(err);
|
|
71
|
-
});
|
|
72
|
-
archive.on('error', (err) => {
|
|
73
|
-
reject(err);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
// Pipe archive data to the file
|
|
77
|
-
archive.pipe(output);
|
|
78
|
-
// Add input files/directory
|
|
79
|
-
if (options.input) {
|
|
80
|
-
const inputPath = path.resolve(options.input);
|
|
81
|
-
if (!fs.existsSync(inputPath)) {
|
|
82
|
-
return (0, ts_utils_1.fail)(`Input path does not exist: ${inputPath}`);
|
|
83
|
-
}
|
|
84
|
-
const stats = fs.statSync(inputPath);
|
|
85
|
-
if (stats.isDirectory()) {
|
|
86
|
-
// Add entire directory recursively, preserving structure
|
|
87
|
-
const dirName = path.basename(inputPath);
|
|
88
|
-
archive.directory(inputPath, `input/${dirName}`);
|
|
89
|
-
manifest.input = {
|
|
90
|
-
type: 'directory',
|
|
91
|
-
originalPath: inputPath,
|
|
92
|
-
archivePath: `input/${dirName}`
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
else if (stats.isFile()) {
|
|
96
|
-
// Add single file
|
|
97
|
-
const fileName = path.basename(inputPath);
|
|
98
|
-
archive.file(inputPath, { name: `input/${fileName}` });
|
|
99
|
-
manifest.input = {
|
|
100
|
-
type: 'file',
|
|
101
|
-
originalPath: inputPath,
|
|
102
|
-
archivePath: `input/${fileName}`
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
// Add config file
|
|
107
|
-
if (options.config) {
|
|
108
|
-
const configPath = path.resolve(options.config);
|
|
109
|
-
if (!fs.existsSync(configPath)) {
|
|
110
|
-
return (0, ts_utils_1.fail)(`Config file does not exist: ${configPath}`);
|
|
111
|
-
}
|
|
112
|
-
const stats = fs.statSync(configPath);
|
|
113
|
-
if (!stats.isFile()) {
|
|
114
|
-
return (0, ts_utils_1.fail)(`Config path must be a file: ${configPath}`);
|
|
115
|
-
}
|
|
116
|
-
const fileName = path.basename(configPath);
|
|
117
|
-
archive.file(configPath, { name: `config/${fileName}` });
|
|
118
|
-
manifest.config = {
|
|
119
|
-
type: 'file',
|
|
120
|
-
originalPath: configPath,
|
|
121
|
-
archivePath: `config/${fileName}`
|
|
122
|
-
};
|
|
62
|
+
if (createResult.isFailure()) {
|
|
63
|
+
return (0, ts_utils_1.fail)(createResult.message);
|
|
123
64
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
await archive.finalize();
|
|
128
|
-
await archivePromise;
|
|
65
|
+
const { zipBuffer, manifest } = createResult.value;
|
|
66
|
+
// Write the ZIP buffer to disk
|
|
67
|
+
fs.writeFileSync(zipPath, zipBuffer);
|
|
129
68
|
return (0, ts_utils_1.succeed)({
|
|
130
69
|
zipPath,
|
|
131
70
|
manifest
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fgv/ts-res-browser-cli",
|
|
3
|
-
"version": "5.0.0-
|
|
3
|
+
"version": "5.0.0-21",
|
|
4
4
|
"description": "Command-line interface to launch ts-res-browser with specified options",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -22,26 +22,25 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"commander": "^11.0.0",
|
|
25
|
-
"
|
|
26
|
-
"@
|
|
27
|
-
"@fgv/ts-
|
|
28
|
-
"@fgv/ts-
|
|
29
|
-
"@fgv/ts-utils": "5.0.0-
|
|
30
|
-
"@fgv/ts-json-base": "5.0.0-2"
|
|
25
|
+
"@fgv/ts-res": "5.0.0-21",
|
|
26
|
+
"@fgv/ts-json-base": "5.0.0-21",
|
|
27
|
+
"@fgv/ts-json": "5.0.0-21",
|
|
28
|
+
"@fgv/ts-res-browser": "5.0.0-21",
|
|
29
|
+
"@fgv/ts-utils": "5.0.0-21"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"@rushstack/heft": "~0.74.
|
|
34
|
-
"@rushstack/heft-node-rig": "~2.9.
|
|
32
|
+
"@rushstack/heft": "~0.74.2",
|
|
33
|
+
"@rushstack/heft-node-rig": "~2.9.3",
|
|
35
34
|
"@types/jest": "^29.5.14",
|
|
36
35
|
"@types/node": "^20.14.9",
|
|
37
36
|
"eslint": "^8.57.0",
|
|
38
37
|
"jest": "^29.7.0",
|
|
39
|
-
"typescript": "^5.
|
|
40
|
-
"@fgv/ts-utils-jest": "5.0.0-
|
|
38
|
+
"typescript": "^5.8.3",
|
|
39
|
+
"@fgv/ts-utils-jest": "5.0.0-21"
|
|
41
40
|
},
|
|
42
41
|
"scripts": {
|
|
43
42
|
"build": "heft build --clean",
|
|
44
|
-
"test": "
|
|
43
|
+
"test": "echo 'No tests configured for ts-res-browser-cli - this is a CLI launcher tool' && exit 0",
|
|
45
44
|
"clean": "heft clean",
|
|
46
45
|
"lint": "eslint src --ext .ts",
|
|
47
46
|
"fixlint": "eslint src --ext .ts --fix"
|