@dainprotocol/cli 1.2.31 → 1.2.34

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.
@@ -68,6 +68,7 @@ var isFirstStart = true;
68
68
  var proxyServer = null;
69
69
  var isCleaningUp = false;
70
70
  var debounceTimer = null;
71
+ var KILL_TIMEOUT_MS = 5000;
71
72
  function isPortAvailable(port) {
72
73
  return new Promise(function (resolve) {
73
74
  var server = (0, net_1.createServer)()
@@ -75,27 +76,72 @@ function isPortAvailable(port) {
75
76
  .on('error', function () { return resolve(false); });
76
77
  });
77
78
  }
79
+ /**
80
+ * Kill a child process and wait for it to exit.
81
+ * Sends SIGTERM first, escalates to SIGKILL after timeout.
82
+ */
83
+ function killProcess(proc) {
84
+ return new Promise(function (resolve) {
85
+ if (!proc.pid || proc.killed) {
86
+ resolve();
87
+ return;
88
+ }
89
+ var resolved = false;
90
+ var done = function () {
91
+ if (resolved)
92
+ return;
93
+ resolved = true;
94
+ clearTimeout(forceKillTimer);
95
+ resolve();
96
+ };
97
+ proc.once('close', done);
98
+ proc.once('exit', done);
99
+ proc.kill('SIGTERM');
100
+ // Escalate to SIGKILL if process doesn't exit within timeout
101
+ var forceKillTimer = setTimeout(function () {
102
+ if (!resolved) {
103
+ try {
104
+ proc.kill('SIGKILL');
105
+ }
106
+ catch (_a) { }
107
+ // Resolve after SIGKILL — don't wait forever
108
+ setTimeout(done, 500);
109
+ }
110
+ }, KILL_TIMEOUT_MS);
111
+ });
112
+ }
78
113
  function cleanup() {
79
- if (isCleaningUp)
80
- return;
81
- isCleaningUp = true;
82
- if (debounceTimer) {
83
- clearTimeout(debounceTimer);
84
- debounceTimer = null;
85
- }
86
- if (childProcess) {
87
- childProcess.kill('SIGTERM');
88
- childProcess = null;
89
- }
90
- if (watcher) {
91
- watcher.close();
92
- watcher = null;
93
- }
94
- if (mf) {
95
- mf.dispose();
96
- mf = null;
97
- }
98
- (0, utils_1.logInfo)('Development server and file watcher stopped.');
114
+ return __awaiter(this, void 0, void 0, function () {
115
+ return __generator(this, function (_a) {
116
+ switch (_a.label) {
117
+ case 0:
118
+ if (isCleaningUp)
119
+ return [2 /*return*/];
120
+ isCleaningUp = true;
121
+ if (debounceTimer) {
122
+ clearTimeout(debounceTimer);
123
+ debounceTimer = null;
124
+ }
125
+ if (!childProcess) return [3 /*break*/, 2];
126
+ return [4 /*yield*/, killProcess(childProcess)];
127
+ case 1:
128
+ _a.sent();
129
+ childProcess = null;
130
+ _a.label = 2;
131
+ case 2:
132
+ if (watcher) {
133
+ watcher.close();
134
+ watcher = null;
135
+ }
136
+ if (mf) {
137
+ mf.dispose();
138
+ mf = null;
139
+ }
140
+ (0, utils_1.logInfo)('Development server and file watcher stopped.');
141
+ return [2 /*return*/];
142
+ }
143
+ });
144
+ });
99
145
  }
100
146
  function gracefulShutdown() {
101
147
  return __awaiter(this, arguments, void 0, function (exitCode) {
@@ -103,81 +149,95 @@ function gracefulShutdown() {
103
149
  if (exitCode === void 0) { exitCode = 0; }
104
150
  return __generator(this, function (_b) {
105
151
  switch (_b.label) {
106
- case 0:
107
- cleanup();
108
- if (!proxyServer) return [3 /*break*/, 4];
109
- _b.label = 1;
152
+ case 0: return [4 /*yield*/, cleanup()];
110
153
  case 1:
111
- _b.trys.push([1, 3, , 4]);
112
- return [4 /*yield*/, proxyServer.stop()];
154
+ _b.sent();
155
+ if (!proxyServer) return [3 /*break*/, 5];
156
+ _b.label = 2;
113
157
  case 2:
158
+ _b.trys.push([2, 4, , 5]);
159
+ return [4 /*yield*/, proxyServer.stop()];
160
+ case 3:
114
161
  _b.sent();
115
162
  (0, utils_1.logInfo)('Proxy server closed.');
116
- return [3 /*break*/, 4];
117
- case 3:
118
- _a = _b.sent();
119
- return [3 /*break*/, 4];
163
+ return [3 /*break*/, 5];
120
164
  case 4:
165
+ _a = _b.sent();
166
+ return [3 /*break*/, 5];
167
+ case 5:
121
168
  process.exit(exitCode);
122
169
  return [2 /*return*/];
123
170
  }
124
171
  });
125
172
  });
126
173
  }
127
- function startProcess(mainFile, envVars, isRestart) {
128
- var _a, _b;
129
- if (isRestart === void 0) { isRestart = false; }
130
- if (childProcess) {
131
- childProcess.kill('SIGTERM');
132
- childProcess = null;
133
- }
134
- var spinner = (0, ora_1.default)(isRestart ? 'Restarting development server...' : 'Starting development server...').start();
135
- var hasStarted = false;
136
- var tsNodePath = path_1.default.join(process.cwd(), 'node_modules', '.bin', 'ts-node');
137
- if (!fs_extra_1.default.existsSync(tsNodePath)) {
138
- spinner.fail('ts-node not found. Run: npm install ts-node typescript');
139
- return;
140
- }
141
- if (!fs_extra_1.default.existsSync(mainFile)) {
142
- spinner.fail("Main file not found: ".concat(mainFile));
143
- return;
144
- }
145
- childProcess = (0, child_process_1.spawn)(tsNodePath, [mainFile], {
146
- env: __assign(__assign({}, process.env), envVars),
147
- stdio: ['inherit', 'pipe', 'pipe'],
148
- shell: false,
149
- });
150
- var markStarted = function (success) {
151
- if (hasStarted)
152
- return;
153
- hasStarted = true;
154
- if (success) {
155
- spinner.succeed(isRestart ? 'Development server restarted.' : 'Development server started.');
156
- if (tunnelUrl && isFirstStart) {
157
- (0, utils_1.displayTunnelUrl)(tunnelUrl);
158
- isFirstStart = false;
174
+ function startProcess(mainFile_1, envVars_1) {
175
+ return __awaiter(this, arguments, void 0, function (mainFile, envVars, isRestart) {
176
+ var spinner, hasStarted, tsNodePath, markStarted;
177
+ var _a, _b;
178
+ if (isRestart === void 0) { isRestart = false; }
179
+ return __generator(this, function (_c) {
180
+ switch (_c.label) {
181
+ case 0:
182
+ if (!childProcess) return [3 /*break*/, 2];
183
+ return [4 /*yield*/, killProcess(childProcess)];
184
+ case 1:
185
+ _c.sent();
186
+ childProcess = null;
187
+ _c.label = 2;
188
+ case 2:
189
+ spinner = (0, ora_1.default)(isRestart ? 'Restarting development server...' : 'Starting development server...').start();
190
+ hasStarted = false;
191
+ tsNodePath = path_1.default.join(process.cwd(), 'node_modules', '.bin', 'ts-node');
192
+ if (!fs_extra_1.default.existsSync(tsNodePath)) {
193
+ spinner.fail('ts-node not found. Run: npm install ts-node typescript');
194
+ return [2 /*return*/];
195
+ }
196
+ if (!fs_extra_1.default.existsSync(mainFile)) {
197
+ spinner.fail("Main file not found: ".concat(mainFile));
198
+ return [2 /*return*/];
199
+ }
200
+ childProcess = (0, child_process_1.spawn)(tsNodePath, [mainFile], {
201
+ env: __assign(__assign({}, process.env), envVars),
202
+ stdio: ['inherit', 'pipe', 'pipe'],
203
+ shell: false,
204
+ });
205
+ markStarted = function (success) {
206
+ if (hasStarted)
207
+ return;
208
+ hasStarted = true;
209
+ if (success) {
210
+ spinner.succeed(isRestart ? 'Development server restarted.' : 'Development server started.');
211
+ if (tunnelUrl && isFirstStart) {
212
+ (0, utils_1.displayTunnelUrl)(tunnelUrl);
213
+ isFirstStart = false;
214
+ }
215
+ }
216
+ else {
217
+ spinner.fail('Development server error.');
218
+ }
219
+ };
220
+ (_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', function (data) { markStarted(true); process.stdout.write(data.toString()); });
221
+ (_b = childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
222
+ var output = data.toString();
223
+ markStarted(output.includes('Error:') || output.includes('error:') ? false : true);
224
+ process.stderr.write(output);
225
+ });
226
+ childProcess.on('close', function (code) {
227
+ if (code !== 0 && code !== null && !hasStarted)
228
+ spinner.fail("Development server exited with code ".concat(code));
229
+ childProcess = null;
230
+ });
231
+ childProcess.on('error', function (error) { spinner.fail("Failed to start: ".concat(error.message)); childProcess = null; });
232
+ return [2 /*return*/];
159
233
  }
160
- }
161
- else {
162
- spinner.fail('Development server error.');
163
- }
164
- };
165
- (_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', function (data) { markStarted(true); process.stdout.write(data.toString()); });
166
- (_b = childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
167
- var output = data.toString();
168
- markStarted(output.includes('Error:') || output.includes('error:') ? false : true);
169
- process.stderr.write(output);
170
- });
171
- childProcess.on('close', function (code) {
172
- if (code !== 0 && code !== null && !hasStarted)
173
- spinner.fail("Development server exited with code ".concat(code));
174
- childProcess = null;
234
+ });
175
235
  });
176
- childProcess.on('error', function (error) { spinner.fail("Failed to start: ".concat(error.message)); childProcess = null; });
177
236
  }
178
237
  function dev(options) {
179
238
  return __awaiter(this, void 0, void 0, function () {
180
- var config, port, portNumber, runtime, mainFile, resolvedMain, envVars, proxySetup, watchPaths, dainDir, outFile, MFconfig_1, error_1;
239
+ var config, port, portNumber, runtime, mainFile, resolvedMain, envVars, proxySetup, watchPaths, isRestarting_1, dainDir, outFile, MFconfig_1, error_1;
240
+ var _this = this;
181
241
  return __generator(this, function (_a) {
182
242
  switch (_a.label) {
183
243
  case 0:
@@ -208,7 +268,7 @@ function dev(options) {
208
268
  process.once('unhandledRejection', function (reason) { (0, utils_1.logError)('Unhandled Rejection:', reason); gracefulShutdown(1); });
209
269
  _a.label = 1;
210
270
  case 1:
211
- _a.trys.push([1, 9, , 10]);
271
+ _a.trys.push([1, 10, , 11]);
212
272
  return [4 /*yield*/, isPortAvailable(portNumber)];
213
273
  case 2:
214
274
  if (!(_a.sent())) {
@@ -226,29 +286,44 @@ function dev(options) {
226
286
  tunnelUrl = proxySetup.tunnelUrl;
227
287
  _a.label = 4;
228
288
  case 4:
229
- if (!(runtime === 'node')) return [3 /*break*/, 5];
230
- startProcess(mainFile, envVars);
289
+ if (!(runtime === 'node')) return [3 /*break*/, 6];
290
+ return [4 /*yield*/, startProcess(mainFile, envVars)];
291
+ case 5:
292
+ _a.sent();
231
293
  watchPaths = [
232
294
  path_1.default.dirname(mainFile),
233
295
  config['static-dir'] ? path_1.default.join(process.cwd(), config['static-dir']) : (0, utils_1.getStaticFilesPath)(),
234
296
  ].filter(function (p) { return fs_extra_1.default.existsSync(p); });
297
+ isRestarting_1 = false;
235
298
  watcher = chokidar_1.default.watch(watchPaths, { ignored: /(^|[\/\\])\./, persistent: true, ignoreInitial: true });
236
299
  watcher.on('change', function (changedPath) {
237
300
  if (debounceTimer)
238
301
  clearTimeout(debounceTimer);
239
- debounceTimer = setTimeout(function () {
240
- (0, utils_1.logInfo)("File ".concat(changedPath, " changed. Restarting..."));
241
- startProcess(mainFile, envVars, true);
242
- }, 300);
302
+ debounceTimer = setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
303
+ return __generator(this, function (_a) {
304
+ switch (_a.label) {
305
+ case 0:
306
+ if (isRestarting_1)
307
+ return [2 /*return*/];
308
+ isRestarting_1 = true;
309
+ (0, utils_1.logInfo)("File ".concat(changedPath, " changed. Restarting..."));
310
+ return [4 /*yield*/, startProcess(mainFile, envVars, true)];
311
+ case 1:
312
+ _a.sent();
313
+ isRestarting_1 = false;
314
+ return [2 /*return*/];
315
+ }
316
+ });
317
+ }); }, 300);
243
318
  });
244
319
  (0, utils_1.logInfo)('Watching for file changes...');
245
- return [3 /*break*/, 8];
246
- case 5:
247
- if (!(runtime === 'workers')) return [3 /*break*/, 7];
320
+ return [3 /*break*/, 9];
321
+ case 6:
322
+ if (!(runtime === 'workers')) return [3 /*break*/, 8];
248
323
  dainDir = path_1.default.join(process.cwd(), '.dain');
249
324
  outFile = path_1.default.join(dainDir, path_1.default.basename(config['main-file'], '.ts') + '.mjs');
250
325
  return [4 /*yield*/, (0, build_1.default)({ config: options.config, runtime: 'workers', watch: true })];
251
- case 6:
326
+ case 7:
252
327
  _a.sent();
253
328
  MFconfig_1 = { scriptPath: outFile, modules: true, port: parseInt(port, 10), log: new miniflare_1.Log(miniflare_1.LogLevel.DEBUG), liveReload: true };
254
329
  mf = new miniflare_1.Miniflare(MFconfig_1);
@@ -262,15 +337,15 @@ function dev(options) {
262
337
  } }, 300);
263
338
  });
264
339
  (0, utils_1.logInfo)('Watching for file changes in source and build directories...');
265
- return [3 /*break*/, 8];
266
- case 7: throw new Error("Unsupported runtime: ".concat(runtime));
267
- case 8: return [3 /*break*/, 10];
268
- case 9:
340
+ return [3 /*break*/, 9];
341
+ case 8: throw new Error("Unsupported runtime: ".concat(runtime));
342
+ case 9: return [3 /*break*/, 11];
343
+ case 10:
269
344
  error_1 = _a.sent();
270
345
  (0, utils_1.logError)("Error in dev process for ".concat(runtime, " runtime:"), error_1);
271
346
  gracefulShutdown(1);
272
- return [3 /*break*/, 10];
273
- case 10: return [2 /*return*/];
347
+ return [3 /*break*/, 11];
348
+ case 11: return [2 /*return*/];
274
349
  }
275
350
  });
276
351
  });
package/dist/utils.js CHANGED
@@ -168,7 +168,7 @@ function displayTunnelUrl(tunnelUrl) {
168
168
  }
169
169
  function setupProxy(port, apiKey, config) {
170
170
  return __awaiter(this, void 0, void 0, function () {
171
- var spinner, client, tunnelUrl, error_1;
171
+ var spinner, client_2, tunnelUrl, error_1;
172
172
  return __generator(this, function (_a) {
173
173
  switch (_a.label) {
174
174
  case 0:
@@ -176,12 +176,41 @@ function setupProxy(port, apiKey, config) {
176
176
  _a.label = 1;
177
177
  case 1:
178
178
  _a.trys.push([1, 3, , 4]);
179
- client = new client_1.DainTunnel(config["tunnel-base-url"] || exports.DEFAULT_TUNNEL_BASE_URL, apiKey);
180
- return [4 /*yield*/, client.start(parseInt(port))];
179
+ client_2 = new client_1.DainTunnel(config["tunnel-base-url"] || exports.DEFAULT_TUNNEL_BASE_URL, apiKey);
180
+ // Handle tunnel lifecycle events
181
+ client_2.on("disconnected", function () {
182
+ console.log(chalk_1.default.yellow("\n⚠ Tunnel disconnected. Attempting to reconnect..."));
183
+ });
184
+ client_2.on("reconnecting", function (_a) {
185
+ var attempt = _a.attempt, delay = _a.delay;
186
+ console.log(chalk_1.default.yellow(" Reconnection attempt ".concat(attempt, "/10 in ").concat(Math.round(delay / 1000), "s...")));
187
+ });
188
+ client_2.on("reconnected", function () {
189
+ console.log(chalk_1.default.green("✓ Tunnel reconnected successfully"));
190
+ });
191
+ client_2.on("error", function (error) {
192
+ console.error(chalk_1.default.red("\n\u2717 Tunnel error: ".concat(error.message)));
193
+ });
194
+ client_2.on("max_reconnect_attempts", function () {
195
+ console.error(chalk_1.default.red("\n✗ Tunnel failed to reconnect after 10 attempts."));
196
+ console.log(chalk_1.default.yellow(" Resetting and trying again..."));
197
+ // Reset and try one more time (resetReconnection added in tunnel 1.1.31)
198
+ if (typeof client_2.resetReconnection === "function") {
199
+ client_2.resetReconnection();
200
+ client_2.start(parseInt(port)).catch(function (err) {
201
+ console.error(chalk_1.default.red("\n\u2717 Unable to restore tunnel connection: ".concat(err.message)));
202
+ console.log(chalk_1.default.yellow(" Please restart the dev server manually."));
203
+ });
204
+ }
205
+ else {
206
+ console.log(chalk_1.default.yellow(" Please restart the dev server manually."));
207
+ }
208
+ });
209
+ return [4 /*yield*/, client_2.start(parseInt(port))];
181
210
  case 2:
182
211
  tunnelUrl = _a.sent();
183
212
  spinner.succeed("Proxy setup complete");
184
- return [2 /*return*/, { client: client, tunnelUrl: tunnelUrl }];
213
+ return [2 /*return*/, { client: client_2, tunnelUrl: tunnelUrl }];
185
214
  case 3:
186
215
  error_1 = _a.sent();
187
216
  spinner.fail(chalk_1.default.red("Error setting up proxy"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dainprotocol/cli",
3
- "version": "1.2.31",
3
+ "version": "1.2.34",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -23,8 +23,8 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@ai-sdk/anthropic": "^0.0.50",
26
- "@dainprotocol/service-sdk": "^2.0.79",
27
- "@dainprotocol/tunnel": "^1.1.29",
26
+ "@dainprotocol/service-sdk": "2.0.80",
27
+ "@dainprotocol/tunnel": "1.1.33",
28
28
  "@types/fs-extra": "^11.0.4",
29
29
  "@types/localtunnel": "^2.0.4",
30
30
  "ai": "^3.3.41",