@kevisual/cnb 0.0.55 → 0.0.56
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/agent/routes/workspace/index.ts +1 -0
- package/agent/routes/workspace/rerun.ts +55 -0
- package/dist/cli.js +262 -8
- package/dist/npc.js +316 -16
- package/dist/opencode.js +238 -6
- package/dist/routes.js +238 -6
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { app, cnbManager } from '../../app.ts';
|
|
3
|
+
|
|
4
|
+
app.route({
|
|
5
|
+
path: 'cnb',
|
|
6
|
+
key: 'rerun',
|
|
7
|
+
description: '重新启动工作区,定时任务',
|
|
8
|
+
middleware: ['auth'],
|
|
9
|
+
metadata: {
|
|
10
|
+
args: {
|
|
11
|
+
repo: z.string().optional().describe('仓库名称,例如:owner/repo'),
|
|
12
|
+
config: z.string().optional().describe('工作区配置'),
|
|
13
|
+
event: z.string().optional().describe('触发事件来源,api_trigger_event'),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}).define(async (ctx) => {
|
|
17
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
18
|
+
const repo = ctx.args.repo;
|
|
19
|
+
const config = ctx.args.config;
|
|
20
|
+
const event = ctx.args.event || 'api_trigger_event';
|
|
21
|
+
const res = await cnb.workspace.list({ status: "running" })
|
|
22
|
+
if (res.code !== 200) {
|
|
23
|
+
ctx.throw(500, res.message || 'Failed to list workspaces');
|
|
24
|
+
}
|
|
25
|
+
const list = res.data?.list || []
|
|
26
|
+
const _list = list.filter(item => {
|
|
27
|
+
// 如果指定了 repo 参数,则只重启该仓库相关的工作区;如果未指定 repo 参数,则重启所有包含 '/dev' 的工作区
|
|
28
|
+
if (repo) {
|
|
29
|
+
if (item.slug === repo) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
if (item.slug.includes('/dev')) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
})
|
|
39
|
+
for (const item of _list) {
|
|
40
|
+
const branch = item.branch || 'main';
|
|
41
|
+
const repo = item.slug;
|
|
42
|
+
const sn = item.sn;
|
|
43
|
+
// 先停止工作区
|
|
44
|
+
await cnb.workspace.stopWorkspace({ sn });
|
|
45
|
+
if (config) {
|
|
46
|
+
await cnb.build.startBuild(repo, { branch, config, event });
|
|
47
|
+
} else {
|
|
48
|
+
await cnb.workspace.startWorkspace(repo, { branch });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
ctx.body = {
|
|
53
|
+
content: '工作区重新启动中',
|
|
54
|
+
}
|
|
55
|
+
}).addTo(app)
|
package/dist/cli.js
CHANGED
|
@@ -46804,7 +46804,8 @@ app.route({
|
|
|
46804
46804
|
summary: "列出cnb代码仓库, 可选flags参数,如 KnowledgeBase",
|
|
46805
46805
|
args: {
|
|
46806
46806
|
search: tool.schema.string().optional().describe("搜索关键词"),
|
|
46807
|
-
|
|
46807
|
+
page: tool.schema.number().optional().describe("分页页码,默认 1"),
|
|
46808
|
+
pageSize: tool.schema.number().optional().describe("每页数量,默认99"),
|
|
46808
46809
|
flags: tool.schema.string().optional().describe("仓库标记,如果是知识库则填写 KnowledgeBase")
|
|
46809
46810
|
}
|
|
46810
46811
|
})
|
|
@@ -46812,13 +46813,17 @@ app.route({
|
|
|
46812
46813
|
}).define(async (ctx) => {
|
|
46813
46814
|
const cnb = await cnbManager.getContext(ctx);
|
|
46814
46815
|
const search = ctx.query?.search;
|
|
46815
|
-
const
|
|
46816
|
+
const page = ctx.query?.page || 1;
|
|
46817
|
+
let pageSize = ctx.query?.pageSize || 99;
|
|
46816
46818
|
const flags = ctx.query?.flags;
|
|
46817
46819
|
const params = {};
|
|
46818
46820
|
if (flags) {
|
|
46819
46821
|
params.flags = flags;
|
|
46820
46822
|
}
|
|
46821
|
-
|
|
46823
|
+
if (pageSize > 99) {
|
|
46824
|
+
pageSize = 99;
|
|
46825
|
+
}
|
|
46826
|
+
const res = await cnb.repo.getRepoList({ search, page, page_size: pageSize + 1, role: "developer", ...params });
|
|
46822
46827
|
if (res.code === 200) {
|
|
46823
46828
|
const repos = res.data.map((item) => ({
|
|
46824
46829
|
name: item.name,
|
|
@@ -46826,7 +46831,9 @@ app.route({
|
|
|
46826
46831
|
description: item.description,
|
|
46827
46832
|
web_url: item.web_url
|
|
46828
46833
|
}));
|
|
46829
|
-
|
|
46834
|
+
const list = repos.slice(0, pageSize);
|
|
46835
|
+
const hasMore = repos.length > pageSize;
|
|
46836
|
+
ctx.body = { content: JSON.stringify(repos), list, hasMore, page, pageSize };
|
|
46830
46837
|
} else {
|
|
46831
46838
|
ctx.throw(500, "获取仓库列表失败");
|
|
46832
46839
|
}
|
|
@@ -47419,6 +47426,57 @@ app.route({
|
|
|
47419
47426
|
ctx.forward(res);
|
|
47420
47427
|
}).addTo(app);
|
|
47421
47428
|
|
|
47429
|
+
// agent/routes/workspace/rerun.ts
|
|
47430
|
+
app.route({
|
|
47431
|
+
path: "cnb",
|
|
47432
|
+
key: "rerun",
|
|
47433
|
+
description: "重新启动工作区,定时任务",
|
|
47434
|
+
middleware: ["auth"],
|
|
47435
|
+
metadata: {
|
|
47436
|
+
args: {
|
|
47437
|
+
repo: zod_default.string().optional().describe("仓库名称,例如:owner/repo"),
|
|
47438
|
+
config: zod_default.string().optional().describe("工作区配置"),
|
|
47439
|
+
event: zod_default.string().optional().describe("触发事件来源,api_trigger_event")
|
|
47440
|
+
}
|
|
47441
|
+
}
|
|
47442
|
+
}).define(async (ctx) => {
|
|
47443
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
47444
|
+
const repo2 = ctx.args.repo;
|
|
47445
|
+
const config3 = ctx.args.config;
|
|
47446
|
+
const event = ctx.args.event || "api_trigger_event";
|
|
47447
|
+
const res = await cnb.workspace.list({ status: "running" });
|
|
47448
|
+
if (res.code !== 200) {
|
|
47449
|
+
ctx.throw(500, res.message || "Failed to list workspaces");
|
|
47450
|
+
}
|
|
47451
|
+
const list = res.data?.list || [];
|
|
47452
|
+
const _list = list.filter((item) => {
|
|
47453
|
+
if (repo2) {
|
|
47454
|
+
if (item.slug === repo2) {
|
|
47455
|
+
return true;
|
|
47456
|
+
}
|
|
47457
|
+
} else {
|
|
47458
|
+
if (item.slug.includes("/dev")) {
|
|
47459
|
+
return true;
|
|
47460
|
+
}
|
|
47461
|
+
}
|
|
47462
|
+
return false;
|
|
47463
|
+
});
|
|
47464
|
+
for (const item of _list) {
|
|
47465
|
+
const branch = item.branch || "main";
|
|
47466
|
+
const repo3 = item.slug;
|
|
47467
|
+
const sn = item.sn;
|
|
47468
|
+
await cnb.workspace.stopWorkspace({ sn });
|
|
47469
|
+
if (config3) {
|
|
47470
|
+
await cnb.build.startBuild(repo3, { branch, config: config3, event });
|
|
47471
|
+
} else {
|
|
47472
|
+
await cnb.workspace.startWorkspace(repo3, { branch });
|
|
47473
|
+
}
|
|
47474
|
+
}
|
|
47475
|
+
ctx.body = {
|
|
47476
|
+
content: "工作区重新启动中"
|
|
47477
|
+
};
|
|
47478
|
+
}).addTo(app);
|
|
47479
|
+
|
|
47422
47480
|
// agent/routes/workspace/index.ts
|
|
47423
47481
|
app.route({
|
|
47424
47482
|
path: "cnb",
|
|
@@ -48403,8 +48461,8 @@ app.route({
|
|
|
48403
48461
|
const cnb = await cnbManager.getContext(ctx);
|
|
48404
48462
|
let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
|
|
48405
48463
|
const issueNumber = ctx.query?.issueNumber;
|
|
48406
|
-
const page = ctx.query?.page
|
|
48407
|
-
const page_size = ctx.query?.page_size
|
|
48464
|
+
const page = ctx.query?.page ?? 1;
|
|
48465
|
+
const page_size = ctx.query?.page_size ?? 100;
|
|
48408
48466
|
if (!repo2) {
|
|
48409
48467
|
ctx.throw(400, "缺少参数 repo");
|
|
48410
48468
|
}
|
|
@@ -55413,6 +55471,180 @@ app.route({
|
|
|
55413
55471
|
ctx.forward(res);
|
|
55414
55472
|
}).addTo(app);
|
|
55415
55473
|
|
|
55474
|
+
// agent/routes/labels/issue-label.ts
|
|
55475
|
+
app.route({
|
|
55476
|
+
path: "cnb",
|
|
55477
|
+
key: "list-issue-labels",
|
|
55478
|
+
description: "查询 Issue 的标签列表",
|
|
55479
|
+
middleware: ["auth"],
|
|
55480
|
+
metadata: {
|
|
55481
|
+
tags: ["opencode"],
|
|
55482
|
+
...createSkill({
|
|
55483
|
+
skill: "list-issue-labels",
|
|
55484
|
+
title: "查询 Issue 标签列表",
|
|
55485
|
+
summary: "查询 Issue 的标签列表",
|
|
55486
|
+
args: {
|
|
55487
|
+
repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
|
|
55488
|
+
issueNumber: tool.schema.number().describe("Issue 编号"),
|
|
55489
|
+
page: tool.schema.number().optional().describe("分页页码,默认 1"),
|
|
55490
|
+
pageSize: tool.schema.number().optional().describe("分页每页大小,默认 30")
|
|
55491
|
+
}
|
|
55492
|
+
})
|
|
55493
|
+
}
|
|
55494
|
+
}).define(async (ctx) => {
|
|
55495
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
55496
|
+
let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
|
|
55497
|
+
const issueNumber = ctx.query?.issueNumber;
|
|
55498
|
+
const page = ctx.query?.page;
|
|
55499
|
+
const pageSize = ctx.query?.pageSize;
|
|
55500
|
+
if (!repo2) {
|
|
55501
|
+
ctx.throw(400, "缺少参数 repo");
|
|
55502
|
+
}
|
|
55503
|
+
if (!issueNumber) {
|
|
55504
|
+
ctx.throw(400, "缺少参数 issueNumber");
|
|
55505
|
+
}
|
|
55506
|
+
const res = await cnb.labels.issueLabel.list(repo2, issueNumber, {
|
|
55507
|
+
page,
|
|
55508
|
+
page_size: pageSize
|
|
55509
|
+
});
|
|
55510
|
+
ctx.forward(res);
|
|
55511
|
+
}).addTo(app);
|
|
55512
|
+
app.route({
|
|
55513
|
+
path: "cnb",
|
|
55514
|
+
key: "set-issue-labels",
|
|
55515
|
+
description: "设置 Issue 标签(完全替换现有标签)",
|
|
55516
|
+
middleware: ["auth"],
|
|
55517
|
+
metadata: {
|
|
55518
|
+
tags: ["opencode"],
|
|
55519
|
+
...createSkill({
|
|
55520
|
+
skill: "set-issue-labels",
|
|
55521
|
+
title: "设置 Issue 标签",
|
|
55522
|
+
summary: "设置 Issue 标签(完全替换现有标签)",
|
|
55523
|
+
args: {
|
|
55524
|
+
repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
|
|
55525
|
+
issueNumber: tool.schema.number().describe("Issue 编号"),
|
|
55526
|
+
labels: tool.schema.array(tool.schema.string()).describe("标签名称数组")
|
|
55527
|
+
}
|
|
55528
|
+
})
|
|
55529
|
+
}
|
|
55530
|
+
}).define(async (ctx) => {
|
|
55531
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
55532
|
+
let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
|
|
55533
|
+
const issueNumber = ctx.query?.issueNumber;
|
|
55534
|
+
const labels2 = ctx.query?.labels;
|
|
55535
|
+
if (!repo2) {
|
|
55536
|
+
ctx.throw(400, "缺少参数 repo");
|
|
55537
|
+
}
|
|
55538
|
+
if (!issueNumber) {
|
|
55539
|
+
ctx.throw(400, "缺少参数 issueNumber");
|
|
55540
|
+
}
|
|
55541
|
+
if (!labels2 || !Array.isArray(labels2)) {
|
|
55542
|
+
ctx.throw(400, "缺少参数 labels");
|
|
55543
|
+
}
|
|
55544
|
+
const res = await cnb.labels.issueLabel.set(repo2, issueNumber, { labels: labels2 });
|
|
55545
|
+
ctx.forward(res);
|
|
55546
|
+
}).addTo(app);
|
|
55547
|
+
app.route({
|
|
55548
|
+
path: "cnb",
|
|
55549
|
+
key: "add-issue-labels",
|
|
55550
|
+
description: "新增 Issue 标签(追加到现有标签)",
|
|
55551
|
+
middleware: ["auth"],
|
|
55552
|
+
metadata: {
|
|
55553
|
+
tags: ["opencode"],
|
|
55554
|
+
...createSkill({
|
|
55555
|
+
skill: "add-issue-labels",
|
|
55556
|
+
title: "新增 Issue 标签",
|
|
55557
|
+
summary: "新增 Issue 标签(追加到现有标签)",
|
|
55558
|
+
args: {
|
|
55559
|
+
repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
|
|
55560
|
+
issueNumber: tool.schema.number().describe("Issue 编号"),
|
|
55561
|
+
labels: tool.schema.array(tool.schema.string()).describe("标签名称数组")
|
|
55562
|
+
}
|
|
55563
|
+
})
|
|
55564
|
+
}
|
|
55565
|
+
}).define(async (ctx) => {
|
|
55566
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
55567
|
+
let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
|
|
55568
|
+
const issueNumber = ctx.query?.issueNumber;
|
|
55569
|
+
const labels2 = ctx.query?.labels;
|
|
55570
|
+
if (!repo2) {
|
|
55571
|
+
ctx.throw(400, "缺少参数 repo");
|
|
55572
|
+
}
|
|
55573
|
+
if (!issueNumber) {
|
|
55574
|
+
ctx.throw(400, "缺少参数 issueNumber");
|
|
55575
|
+
}
|
|
55576
|
+
if (!labels2 || !Array.isArray(labels2)) {
|
|
55577
|
+
ctx.throw(400, "缺少参数 labels");
|
|
55578
|
+
}
|
|
55579
|
+
const res = await cnb.labels.issueLabel.add(repo2, issueNumber, { labels: labels2 });
|
|
55580
|
+
ctx.forward(res);
|
|
55581
|
+
}).addTo(app);
|
|
55582
|
+
app.route({
|
|
55583
|
+
path: "cnb",
|
|
55584
|
+
key: "clear-issue-labels",
|
|
55585
|
+
description: "清空 Issue 标签(移除所有标签)",
|
|
55586
|
+
middleware: ["auth"],
|
|
55587
|
+
metadata: {
|
|
55588
|
+
tags: ["opencode"],
|
|
55589
|
+
...createSkill({
|
|
55590
|
+
skill: "clear-issue-labels",
|
|
55591
|
+
title: "清空 Issue 标签",
|
|
55592
|
+
summary: "清空 Issue 标签(移除所有标签)",
|
|
55593
|
+
args: {
|
|
55594
|
+
repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
|
|
55595
|
+
issueNumber: tool.schema.number().describe("Issue 编号")
|
|
55596
|
+
}
|
|
55597
|
+
})
|
|
55598
|
+
}
|
|
55599
|
+
}).define(async (ctx) => {
|
|
55600
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
55601
|
+
let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
|
|
55602
|
+
const issueNumber = ctx.query?.issueNumber;
|
|
55603
|
+
if (!repo2) {
|
|
55604
|
+
ctx.throw(400, "缺少参数 repo");
|
|
55605
|
+
}
|
|
55606
|
+
if (!issueNumber) {
|
|
55607
|
+
ctx.throw(400, "缺少参数 issueNumber");
|
|
55608
|
+
}
|
|
55609
|
+
const res = await cnb.labels.issueLabel.clear(repo2, issueNumber);
|
|
55610
|
+
ctx.forward(res);
|
|
55611
|
+
}).addTo(app);
|
|
55612
|
+
app.route({
|
|
55613
|
+
path: "cnb",
|
|
55614
|
+
key: "remove-issue-label",
|
|
55615
|
+
description: "删除 Issue 指定标签",
|
|
55616
|
+
middleware: ["auth"],
|
|
55617
|
+
metadata: {
|
|
55618
|
+
tags: ["opencode"],
|
|
55619
|
+
...createSkill({
|
|
55620
|
+
skill: "remove-issue-label",
|
|
55621
|
+
title: "删除 Issue 标签",
|
|
55622
|
+
summary: "删除 Issue 指定标签",
|
|
55623
|
+
args: {
|
|
55624
|
+
repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
|
|
55625
|
+
issueNumber: tool.schema.number().describe("Issue 编号"),
|
|
55626
|
+
name: tool.schema.string().describe("标签名称")
|
|
55627
|
+
}
|
|
55628
|
+
})
|
|
55629
|
+
}
|
|
55630
|
+
}).define(async (ctx) => {
|
|
55631
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
55632
|
+
let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
|
|
55633
|
+
const issueNumber = ctx.query?.issueNumber;
|
|
55634
|
+
const name21 = ctx.query?.name;
|
|
55635
|
+
if (!repo2) {
|
|
55636
|
+
ctx.throw(400, "缺少参数 repo");
|
|
55637
|
+
}
|
|
55638
|
+
if (!issueNumber) {
|
|
55639
|
+
ctx.throw(400, "缺少参数 issueNumber");
|
|
55640
|
+
}
|
|
55641
|
+
if (!name21) {
|
|
55642
|
+
ctx.throw(400, "缺少参数 name");
|
|
55643
|
+
}
|
|
55644
|
+
const res = await cnb.labels.issueLabel.remove(repo2, issueNumber, name21);
|
|
55645
|
+
ctx.forward(res);
|
|
55646
|
+
}).addTo(app);
|
|
55647
|
+
|
|
55416
55648
|
// agent/routes/index.ts
|
|
55417
55649
|
var checkAppId = (ctx, appId) => {
|
|
55418
55650
|
const _appId = ctx?.app?.appId;
|
|
@@ -55464,7 +55696,7 @@ var {
|
|
|
55464
55696
|
Help
|
|
55465
55697
|
} = import__3.default;
|
|
55466
55698
|
|
|
55467
|
-
// ../../node_modules/.pnpm/@kevisual+remote-app@0.0.
|
|
55699
|
+
// ../../node_modules/.pnpm/@kevisual+remote-app@0.0.7/node_modules/@kevisual/remote-app/dist/app.js
|
|
55468
55700
|
var __create4 = Object.create;
|
|
55469
55701
|
var __getProtoOf4 = Object.getPrototypeOf;
|
|
55470
55702
|
var __defProp5 = Object.defineProperty;
|
|
@@ -55679,10 +55911,12 @@ class RemoteApp {
|
|
|
55679
55911
|
reconnectAttempts = 0;
|
|
55680
55912
|
reconnectTimer = null;
|
|
55681
55913
|
isManuallyClosed = false;
|
|
55914
|
+
isInitializing = false;
|
|
55915
|
+
initId = 0;
|
|
55682
55916
|
constructor(opts) {
|
|
55683
55917
|
this.mainApp = opts?.app;
|
|
55684
55918
|
const token2 = opts.token;
|
|
55685
|
-
const url4 = opts.url;
|
|
55919
|
+
const url4 = opts.url || "https://kevisual.cn/ws/proxy";
|
|
55686
55920
|
const id = opts.id;
|
|
55687
55921
|
const username = opts.username;
|
|
55688
55922
|
this.username = username;
|
|
@@ -55748,10 +55982,17 @@ class RemoteApp {
|
|
|
55748
55982
|
return wsURL;
|
|
55749
55983
|
}
|
|
55750
55984
|
async init() {
|
|
55985
|
+
if (this.isInitializing) {
|
|
55986
|
+
return;
|
|
55987
|
+
}
|
|
55988
|
+
this.isInitializing = true;
|
|
55989
|
+
const currentInitId = ++this.initId;
|
|
55751
55990
|
if (!this.url) {
|
|
55991
|
+
this.isInitializing = false;
|
|
55752
55992
|
throw new Error("No url provided for remote app");
|
|
55753
55993
|
}
|
|
55754
55994
|
if (!this.id) {
|
|
55995
|
+
this.isInitializing = false;
|
|
55755
55996
|
throw new Error("No id provided for remote app");
|
|
55756
55997
|
}
|
|
55757
55998
|
this.isError = false;
|
|
@@ -55761,11 +56002,20 @@ class RemoteApp {
|
|
|
55761
56002
|
const ws = new WebSocket(this.getWsURL(this.url));
|
|
55762
56003
|
const that = this;
|
|
55763
56004
|
ws.onopen = function() {
|
|
56005
|
+
if (currentInitId !== that.initId) {
|
|
56006
|
+
ws.close();
|
|
56007
|
+
return;
|
|
56008
|
+
}
|
|
55764
56009
|
that.isConnected = true;
|
|
56010
|
+
that.isInitializing = false;
|
|
55765
56011
|
that.onOpen();
|
|
55766
56012
|
console.log("[remote-app] WebSocket connection opened");
|
|
55767
56013
|
};
|
|
55768
56014
|
ws.onclose = function() {
|
|
56015
|
+
if (currentInitId !== that.initId) {
|
|
56016
|
+
return;
|
|
56017
|
+
}
|
|
56018
|
+
that.isInitializing = false;
|
|
55769
56019
|
that.isConnected = false;
|
|
55770
56020
|
that.onClose();
|
|
55771
56021
|
};
|
|
@@ -55773,6 +56023,10 @@ class RemoteApp {
|
|
|
55773
56023
|
that.onMessage(event.data);
|
|
55774
56024
|
};
|
|
55775
56025
|
ws.onerror = function(error49) {
|
|
56026
|
+
if (currentInitId !== that.initId) {
|
|
56027
|
+
return;
|
|
56028
|
+
}
|
|
56029
|
+
that.isInitializing = false;
|
|
55776
56030
|
that.onError(error49);
|
|
55777
56031
|
};
|
|
55778
56032
|
this.ws = ws;
|