@hyzyn/dsh-docker 0.12.0 → 0.13.1
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.en.md +40 -7
- package/README.md +33 -6
- package/client-src/index.js +87 -4
- package/client-src/log-stream.js +27 -4
- package/client.js +23 -23
- package/lib/index.js +27 -0
- package/lib/index.js.map +1 -1
- package/lib/ssh-exec.d.ts +13 -0
- package/lib/ssh-exec.js +21 -0
- package/lib/ssh-exec.js.map +1 -1
- package/package.json +6 -3
- package/scripts/client-smoke.mjs +61 -0
- package/scripts/route-smoke.mjs +11 -0
package/lib/index.js
CHANGED
|
@@ -1290,6 +1290,18 @@ const plugin = definePlugin({
|
|
|
1290
1290
|
ttyBookHosts: [...books.entries()].map(([name, spec]) => ({ name, host: spec.host, port: spec.port })),
|
|
1291
1291
|
ttyAvailable: books.size > 0,
|
|
1292
1292
|
toolsRegistered: registeredNames,
|
|
1293
|
+
/*
|
|
1294
|
+
* SSE 帧协议版本(客户端据此决定「怎样才算已就绪」)。
|
|
1295
|
+
*
|
|
1296
|
+
* 2 = 四条流在**执行管道真的起来**时先发一帧 `ready`(见 readyOnStart)。客户端半体
|
|
1297
|
+
* 与宿主半体同包同版本,正常不会错位;但开发档里「宿主进程还是旧代码(模块已在内存
|
|
1298
|
+
* 里)、浏览器却从磁盘读到新的 client.js」这种组合会让新客户端死等一帧永远不来的
|
|
1299
|
+
* `ready`,把界面钉在「正在连接事件流…」上(2026-10-11 用户在 test profile 上实测到)。
|
|
1300
|
+
* 所以把版本放在这里:客户端读到 <2 就退回旧判据(响应头就算连上),读到 2 才只认
|
|
1301
|
+
* `ready`。字段缺失(更老的宿主)由客户端按「发 ready」以外的规则兜底,见
|
|
1302
|
+
* client-src/index.js 的 hostSendsReadyFrame。
|
|
1303
|
+
*/
|
|
1304
|
+
streamProtocol: 2,
|
|
1293
1305
|
};
|
|
1294
1306
|
};
|
|
1295
1307
|
/* ---------- 活跃 SSE 长流清点 ---------- */
|
|
@@ -1312,6 +1324,16 @@ const plugin = definePlugin({
|
|
|
1312
1324
|
activeStreams.clear();
|
|
1313
1325
|
};
|
|
1314
1326
|
/* ---------- 通用 SSE 长连接(三条流共用一份基建) ---------- */
|
|
1327
|
+
/**
|
|
1328
|
+
* 「执行管道真的起来了」→ 一帧 `ready`(配合 {@link StreamHandlers.onStart})。
|
|
1329
|
+
*
|
|
1330
|
+
* 为什么必须有这一帧:SSE 的 `onopen` **只证明响应头到了**——`openSseStream` 是先把
|
|
1331
|
+
* 200 + `text/event-stream` flush 出去、再去起 `docker ...`。目标不可达 / SSH 正在
|
|
1332
|
+
* 重连时 `acquire()` 可能卡十几秒,浏览器却已经「连上」了;客户端据此把活动条点亮成
|
|
1333
|
+
* 绿色的「实时接收中(docker events)」,而那条流一个字都还没收到(2026-10-11 用户现场)。
|
|
1334
|
+
* 现在客户端的 `open` 只认这帧,响应头不再算数。
|
|
1335
|
+
*/
|
|
1336
|
+
const readyOnStart = (sendEvent) => () => sendEvent('ready', {});
|
|
1315
1337
|
/**
|
|
1316
1338
|
* 通用 SSE 长连接。日志流(`docker logs -f`)、统计流(`docker stats`)、
|
|
1317
1339
|
* 拉取流(`docker pull`)三者只差「执行器 + 结束原因 + end 附加字段」,
|
|
@@ -1326,6 +1348,7 @@ const plugin = definePlugin({
|
|
|
1326
1348
|
* - 执行器抛错 → `error` 帧后关闭响应。
|
|
1327
1349
|
*
|
|
1328
1350
|
* 调用方负责「参数校验」——校验失败时写常规 JSON(4xx)并直接返回,不建流。
|
|
1351
|
+
* 管道起来后要发的那帧 `ready` 见 {@link readyOnStart}(由调用方挂在 `onStart` 上)。
|
|
1329
1352
|
*/
|
|
1330
1353
|
const openSseStream = async (res, options) => {
|
|
1331
1354
|
const write = res.write?.bind(res);
|
|
@@ -3141,6 +3164,7 @@ const plugin = definePlugin({
|
|
|
3141
3164
|
}, {
|
|
3142
3165
|
onStdout: (chunk) => coalescer.push('d', chunk),
|
|
3143
3166
|
onStderr: (chunk) => coalescer.push('e', chunk),
|
|
3167
|
+
onStart: readyOnStart(sendEvent),
|
|
3144
3168
|
}, signal);
|
|
3145
3169
|
return result.code;
|
|
3146
3170
|
}
|
|
@@ -3242,6 +3266,7 @@ const plugin = definePlugin({
|
|
|
3242
3266
|
}
|
|
3243
3267
|
},
|
|
3244
3268
|
onStderr: (chunk) => sendEvent('line', { e: chunk }),
|
|
3269
|
+
onStart: readyOnStart(sendEvent),
|
|
3245
3270
|
};
|
|
3246
3271
|
const result = await api.statsStream(safeIds, handlers, signal);
|
|
3247
3272
|
// 收尾:最后一个对象可能还没闭合(进程退出前只写了半行),能解析就发
|
|
@@ -3308,6 +3333,7 @@ const plugin = definePlugin({
|
|
|
3308
3333
|
pending = pending.slice(-4096);
|
|
3309
3334
|
},
|
|
3310
3335
|
onStderr: (chunk) => sendEvent('line', { e: chunk }),
|
|
3336
|
+
onStart: readyOnStart(sendEvent),
|
|
3311
3337
|
};
|
|
3312
3338
|
const result = await api.eventsStream(handlers, signal);
|
|
3313
3339
|
// 收尾:最后一行可能没换行符(进程退出前只写半行),能解析就发
|
|
@@ -3381,6 +3407,7 @@ const plugin = definePlugin({
|
|
|
3381
3407
|
const result = await api.pullStream(safeRef, {
|
|
3382
3408
|
onStdout: (chunk) => coalescer.push('d', chunk),
|
|
3383
3409
|
onStderr: (chunk) => coalescer.push('e', chunk),
|
|
3410
|
+
onStart: readyOnStart(sendEvent),
|
|
3384
3411
|
}, signal);
|
|
3385
3412
|
auditCapabilityUse({ ...useFields, event: 'end', ok: true, durationMs: Date.now() - startedAt, reason: 'pull-exit', ...(result.code === null ? {} : { code: result.code }) });
|
|
3386
3413
|
return result.code;
|