rovloom 0.6.0 → 0.6.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.md +2 -2
- package/dist/src/admin/index.js +1 -1
- package/dist/src/{chunk-g27b2gmx.js → chunk-0e9gg4sg.js} +2 -2
- package/dist/src/chunk-1xer1ent.js +102 -0
- package/dist/src/{chunk-863tk45b.js → chunk-41fny9qm.js} +5 -5
- package/dist/src/{chunk-zjzrcc59.js → chunk-59h200cr.js} +139 -7
- package/dist/src/chunk-5w5srj3b.js +93 -0
- package/dist/src/{chunk-d4ejrtjq.js → chunk-6n6b1xpy.js} +1 -1
- package/dist/src/{chunk-ez7d5dac.js → chunk-6w4g9fw8.js} +4 -1
- package/dist/src/{chunk-0dqx2mmz.js → chunk-73aq2qkz.js} +1 -1
- package/dist/src/{chunk-n6wtjyfb.js → chunk-8c9yc0ge.js} +5 -5
- package/dist/src/{chunk-57ayxqnb.js → chunk-8fy8w7ds.js} +2 -23
- package/dist/src/{chunk-2tn0r64b.js → chunk-9h9x79bx.js} +5 -5
- package/dist/src/{chunk-qjh9x872.js → chunk-av31bx1e.js} +1 -1
- package/dist/src/{chunk-0xgpxdgc.js → chunk-bbdtsg4b.js} +7 -5
- package/dist/src/{chunk-q5pgbwb3.js → chunk-e7jgpxkf.js} +2 -2
- package/dist/src/{chunk-zj48jvfe.js → chunk-efty77sb.js} +3 -40
- package/dist/src/{chunk-gyvqqnjb.js → chunk-enj7s8cv.js} +49 -29
- package/dist/src/{chunk-jka7v3wb.js → chunk-ftpy8xx3.js} +311 -23
- package/dist/src/{chunk-zdxww7ms.js → chunk-h3xyq7zk.js} +1 -1
- package/dist/src/{chunk-ttsrctxg.js → chunk-hxmq28pg.js} +9 -7
- package/dist/src/{chunk-s3ydr65k.js → chunk-j59ac0xs.js} +2 -2
- package/dist/src/{chunk-5s2emvww.js → chunk-j6svdqr8.js} +10 -302
- package/dist/src/{chunk-9zkq0kc8.js → chunk-jkzfck98.js} +3 -3
- package/dist/src/{chunk-ssp57p43.js → chunk-m76cmkfy.js} +7 -5
- package/dist/src/{chunk-d2kz25f2.js → chunk-m96mbzcw.js} +674 -308
- package/dist/src/{chunk-yv9px0f5.js → chunk-n3z3jaxy.js} +20 -14
- package/dist/src/{chunk-jf4r0r44.js → chunk-ndj0ay2p.js} +19 -18
- package/dist/src/{chunk-5b8g62kw.js → chunk-pgs9jp6t.js} +61 -179
- package/dist/src/chunk-pksaqt9a.js +25 -0
- package/dist/src/{chunk-wxqhscsw.js → chunk-pnep7yhj.js} +7 -99
- package/dist/src/chunk-qn5xae7g.js +66 -0
- package/dist/src/{chunk-0pewfj89.js → chunk-qp8tgms2.js} +1 -1
- package/dist/src/{chunk-mg0fd6ph.js → chunk-rmgw8h27.js} +10 -8
- package/dist/src/{chunk-gbsbwssz.js → chunk-sf4ztxba.js} +3 -3
- package/dist/src/{chunk-x0td5wn4.js → chunk-shez7hkc.js} +1 -1
- package/dist/src/chunk-sqz614bh.js +30 -0
- package/dist/src/{chunk-09f9q26d.js → chunk-vdwzb63d.js} +2 -2
- package/dist/src/chunk-xtvgm6kf.js +48 -0
- package/dist/src/chunk-y8zm75jt.js +157 -0
- package/dist/src/chunk-yasqw2vj.js +756 -0
- package/dist/src/{chunk-srfbjwtk.js → chunk-z0qmfqvd.js} +3 -3
- package/dist/src/chunk-zm705snh.js +53 -0
- package/dist/src/cli/index.js +29 -28
- package/dist/src/cli/main.js +5 -5
- package/dist/src/connector/herdr/installation.js +4 -4
- package/dist/src/connector/herdr/provider.js +9 -9
- package/dist/src/connector/herdr/runtime.js +7 -7
- package/dist/src/connector/luvus/index.js +7 -6
- package/dist/src/mcp/index.js +16 -15
- package/dist/src/runtime/index.js +16 -15
- package/dist/src/service/index.js +2 -2
- package/dist/src/store.js +4 -4
- package/dist/src/transport/index.js +9 -9
- package/dist/src/webui/index.js +141 -939
- package/package.json +1 -1
- package/dist/src/chunk-0qgk7mhz.js +0 -52
- package/dist/src/chunk-3dvn33c4.js +0 -1299
- package/dist/src/chunk-5j0gj6w2.js +0 -7
- package/dist/src/chunk-vwcntax3.js +0 -228
- package/dist/src/chunk-ytpfmcp1.js +0 -25
- package/dist/src/chunk-zjkjjm81.js +0 -1114
package/dist/src/webui/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
DEFAULT_PAIRING_POLICY_REF
|
|
4
|
-
} from "../chunk-5j0gj6w2.js";
|
|
5
2
|
import {
|
|
6
3
|
ReadError2,
|
|
7
4
|
createSnapshotReader2,
|
|
@@ -13,10 +10,17 @@ import {
|
|
|
13
10
|
|
|
14
11
|
// src/webui/i18n.ts
|
|
15
12
|
var chinese = Object.freeze({
|
|
16
|
-
"resources.previous": "\u4E0A\u4E00\u9875",
|
|
17
|
-
"resources.next": "\u4E0B\u4E00\u9875",
|
|
18
13
|
"resources.tokens": "MCP Token",
|
|
19
|
-
"resources.
|
|
14
|
+
"resources.pairingCodes": "\u914D\u5BF9\u7801",
|
|
15
|
+
"resources.createCode": "\u751F\u6210\u914D\u5BF9\u7801",
|
|
16
|
+
"resources.codesNote": "\u4E00\u673A\u4E00\u7801\uFF1A\u751F\u6210\u540E\u628A\u52A0\u5165\u547D\u4EE4\u590D\u5236\u5230\u76EE\u6807\u673A\u5668\u6267\u884C\uFF0C\u5373\u5B8C\u6210\u914D\u5BF9\u3002\u672A\u4F7F\u7528\u7684\u7801\u53EF\u968F\u65F6\u4F5C\u5E9F\u3002",
|
|
17
|
+
"resources.codeCreatedNote": "\u5DF2\u751F\u6210\u3002\u590D\u5236\u4E0B\u9762\u7684\u547D\u4EE4\u5230 Connector \u673A\u5668\u8FD0\u884C\u5373\u53EF\uFF08\u7801\u53EA\u663E\u793A\u4E00\u6B21\u547D\u4EE4\u5F62\u6001\uFF0C\u5217\u8868\u4E2D\u53EF\u518D\u6B21\u590D\u5236\uFF09\u3002",
|
|
18
|
+
"resources.code_unused": "\u672A\u4F7F\u7528",
|
|
19
|
+
"resources.code_used": "\u5DF2\u4F7F\u7528",
|
|
20
|
+
"resources.code_revoked": "\u5DF2\u4F5C\u5E9F",
|
|
21
|
+
"resources.code_failed": "\u5931\u8D25",
|
|
22
|
+
"resources.revokeCode": "\u4F5C\u5E9F",
|
|
23
|
+
"resources.confirmRevokeCode": "\u4F5C\u5E9F\u8FD9\u5F20\u914D\u5BF9\u7801\uFF1F\u76EE\u6807\u8BBE\u5907\u9700\u751F\u6210\u65B0\u7801\u3002",
|
|
20
24
|
"resources.name": "\u540D\u79F0",
|
|
21
25
|
"resources.expiry": "\u6709\u6548\u671F",
|
|
22
26
|
"resources.days": "{count} \u5929",
|
|
@@ -37,17 +41,12 @@ var chinese = Object.freeze({
|
|
|
37
41
|
"resources.deleteDeviceNote": "\u5220\u9664\u8BBE\u5907\u53CA\u5176\u8FD0\u884C\u914D\u7F6E\u3001\u914D\u5BF9\u8BB0\u5F55\u548C\u8C03\u7528\u5185\u5BB9\uFF0C\u5F53\u524D\u8FDE\u63A5\u4F1A\u65AD\u5F00\u3002",
|
|
38
42
|
"resources.confirmDevice": "\u5220\u9664\u8BE5\u8BBE\u5907\u53CA\u5176\u914D\u5BF9\u3001\u8C03\u7528\u8BB0\u5F55\uFF1F\u5982\u9700\u518D\u6B21\u8FDE\u63A5\uFF0C\u8BF7\u91CD\u65B0\u914D\u5BF9\u3002",
|
|
39
43
|
"resources.confirmToken": "\u5220\u9664 Token\u300C{name}\u300D\uFF1F\u4F7F\u7528\u5B83\u7684\u5BA2\u6237\u7AEF\u5C06\u65E0\u6CD5\u7EE7\u7EED\u8BBF\u95EE\u3002",
|
|
40
|
-
"resources.confirmPairing": "\u5220\u9664\u8FD9\u6761\u914D\u5BF9\u8BB0\u5F55\uFF1F\u672A\u5B8C\u6210\u7684\u914D\u5BF9\u4F1A\u7EC8\u6B62\uFF0C\u5DF2\u914D\u5BF9\u8BBE\u5907\u4ECD\u4FDD\u7559\u3002",
|
|
41
44
|
"resources.emptyTokens": "\u8FD8\u6CA1\u6709 MCP Token\u3002\u5728\u4E0A\u65B9\u521B\u5EFA\u4E00\u4E2A\uFF0C\u5373\u53EF\u8FDE\u63A5\u4F60\u7684 AI \u5BA2\u6237\u7AEF\u3002",
|
|
42
|
-
"resources.emptyPairings": "\u6682\u65E0\u914D\u5BF9\u8BB0\u5F55\u3002",
|
|
43
45
|
"resources.loading": "\u6B63\u5728\u52A0\u8F7D\u2026",
|
|
44
46
|
"resources.saving": "\u6B63\u5728\u4FDD\u5B58\u2026",
|
|
45
47
|
"resources.saved": "\u5DF2\u4FDD\u5B58",
|
|
46
48
|
"resources.failed": "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002",
|
|
47
49
|
"resources.invalid": "\u8BF7\u4F7F\u7528\u4E0D\u91CD\u590D\u7684\u540D\u79F0\uFF08\u5B57\u6BCD\u3001\u6570\u5B57\u3001- \u6216 _\uFF09\uFF0C\u5E76\u9009\u62E9\u6709\u6548\u671F\u3002",
|
|
48
|
-
"resources.pending": "\u7B49\u5F85\u914D\u5BF9",
|
|
49
|
-
"resources.paired": "\u5DF2\u914D\u5BF9",
|
|
50
|
-
"resources.cancelled": "\u5DF2\u53D6\u6D88",
|
|
51
50
|
"nav.workspace": "\u5DE5\u4F5C\u7A7A\u95F4",
|
|
52
51
|
"nav.overview": "\u6982\u89C8",
|
|
53
52
|
"nav.devices": "\u8BBE\u5907\u7BA1\u7406",
|
|
@@ -66,11 +65,6 @@ var chinese = Object.freeze({
|
|
|
66
65
|
"overview.attention": "\u9700\u8981\u5173\u6CE8",
|
|
67
66
|
"overview.attentionNote": "\u672C\u9875\u5C1A\u672A\u9A8C\u8BC1\u8FDE\u63A5\u7684\u8BBE\u5907",
|
|
68
67
|
"overview.scope": "\u8BBE\u5907\u7EDF\u8BA1\u4EC5\u8986\u76D6\u5F53\u524D\u9875\uFF1B\u8FC7\u671F\u89C2\u6D4B\u4E0D\u4EE3\u8868\u5F53\u524D\u72B6\u6001\u3002",
|
|
69
|
-
"overview.gateway": "\u7F51\u5173\u8FD0\u884C\u72B6\u6001",
|
|
70
|
-
"overview.available": "\u53EF\u7528",
|
|
71
|
-
"overview.degraded": "\u53D7\u9650",
|
|
72
|
-
"overview.unavailable": "\u4E0D\u53EF\u7528",
|
|
73
|
-
"overview.unverified": "\u672A\u6838\u5B9E",
|
|
74
68
|
"overview.store": "\u6570\u636E\u5B58\u50A8",
|
|
75
69
|
"overview.transport": "\u8BBE\u5907\u901A\u9053",
|
|
76
70
|
"overview.native": "\u539F\u751F\u8FD0\u884C\u73AF\u5883",
|
|
@@ -85,23 +79,16 @@ var chinese = Object.freeze({
|
|
|
85
79
|
"devices.results": "\u5F53\u524D\u9875\u663E\u793A {shown} / {count} \u53F0\u8BBE\u5907",
|
|
86
80
|
"devices.noMatches": "\u6CA1\u6709\u5339\u914D\u7684\u8BBE\u5907",
|
|
87
81
|
"devices.noMatchesHint": "\u8BD5\u8BD5\u5176\u4ED6\u540D\u79F0\u3001ID \u6216\u6807\u7B7E\uFF0C\u6216\u5207\u6362\u72B6\u6001\u7B5B\u9009\u3002",
|
|
88
|
-
"devices.inspect": "\u67E5\u770B\u8BE6\u60C5",
|
|
89
82
|
"devices.record": "\u89C2\u6D4B\u8BE6\u60C5",
|
|
90
83
|
"devices.open": "\u67E5\u770B {name} \u7684\u8BE6\u60C5",
|
|
84
|
+
"overview.available": "\u53EF\u7528",
|
|
85
|
+
"overview.degraded": "\u964D\u7EA7",
|
|
86
|
+
"overview.unavailable": "\u4E0D\u53EF\u7528",
|
|
87
|
+
"overview.unverified": "\u672A\u6838\u9A8C",
|
|
91
88
|
"pairing.pageTitle": "\u8FDE\u63A5\u4E00\u53F0\u65B0\u8BBE\u5907",
|
|
92
|
-
"pairing.pageDescription": "\
|
|
93
|
-
"pairing.stepCreate": "\u521B\u5EFA\u914D\u5BF9\u7533\u8BF7",
|
|
94
|
-
"pairing.stepRun": "\u8FD0\u884C Connector",
|
|
95
|
-
"pairing.stepApprove": "\u6838\u5BF9\u5E76\u6279\u51C6",
|
|
96
|
-
"pairing.formTitle": "\u6DFB\u52A0\u4F60\u7684\u5DE5\u4F5C\u7AD9",
|
|
97
|
-
"pairing.namePlaceholder": "\u4F8B\u5982 office-workstation",
|
|
98
|
-
"pairing.nameHint": "\u4F7F\u7528 1\u201363 \u4F4D\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u6216\u8FDE\u5B57\u7B26\u3002",
|
|
99
|
-
"pairing.advanced": "\u9AD8\u7EA7\uFF1A\u914D\u5BF9\u7B56\u7565",
|
|
100
|
-
"pairing.guideTitle": "\u7136\u540E\uFF0C\u5728\u5DE5\u4F5C\u7AD9\u4E0A\u8FD0\u884C",
|
|
101
|
-
"pairing.guideDescription": "\u5728\u5B89\u88C5\u4E86 Luvus \u6216 Herdr \u7684\u8BBE\u5907\u7EC8\u7AEF\u4E2D\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\uFF0C\u6309\u63D0\u793A\u8F93\u5165 Gateway \u5730\u5740\u548C\u7533\u8BF7\u7F16\u53F7\u3002",
|
|
102
|
-
"pairing.guideNote": "\u8BA4\u9886\u540E\uFF0C\u6838\u5BF9\u7F51\u9875\u548C\u7EC8\u7AEF\u4E0A\u7684\u4EE3\u7801\uFF0C\u518D\u6279\u51C6\u672C\u673A\u539F\u751F\u5B89\u88C5\u8BBF\u95EE\u3002",
|
|
89
|
+
"pairing.pageDescription": "\u751F\u6210\u4E00\u673A\u4E00\u7801\uFF0C\u628A\u52A0\u5165\u547D\u4EE4\u590D\u5236\u5230\u76EE\u6807\u673A\u5668\u8FD0\u884C\u5373\u53EF\uFF1B\u6CA1\u6709\u7533\u8BF7\u3001\u6279\u51C6\u6216\u6838\u5BF9\u7801\u3002",
|
|
103
90
|
"pairing.loginRequired": "\u914D\u5BF9\u9700\u8981\u7BA1\u7406\u4F1A\u8BDD",
|
|
104
|
-
"pairing.loginHint": "\u4ECE Gateway \u7684\u7BA1\u7406\u5165\u53E3\u767B\u5F55\u540E\uFF0C\u5373\u53EF\
|
|
91
|
+
"pairing.loginHint": "\u4ECE Gateway \u7684\u7BA1\u7406\u5165\u53E3\u767B\u5F55\u540E\uFF0C\u5373\u53EF\u751F\u6210\u914D\u5BF9\u7801\u3002",
|
|
105
92
|
"connect.title": "\u628A\u5DE5\u4F5C\u7A7A\u95F4\u8FDE\u63A5\u5230 AI",
|
|
106
93
|
"connect.description": "\u8BBE\u5907\u5B8C\u6210\u914D\u5BF9\u540E\uFF0C\u4E3A AI \u5BA2\u6237\u7AEF\u7B7E\u53D1\u4E13\u7528 MCP Bearer\u3002",
|
|
107
94
|
"connect.stepOne": "\u627E\u5230\u5DF2\u6709\u8C03\u7528\u65B9",
|
|
@@ -113,7 +100,6 @@ var chinese = Object.freeze({
|
|
|
113
100
|
"connect.docker": "Docker \u90E8\u7F72\u547D\u4EE4",
|
|
114
101
|
"connect.docs": "\u67E5\u770B\u5B8C\u6574\u8FDE\u63A5\u6307\u5357",
|
|
115
102
|
"copy.action": "\u590D\u5236\u547D\u4EE4",
|
|
116
|
-
"copy.id": "\u590D\u5236\u7533\u8BF7\u7F16\u53F7",
|
|
117
103
|
"copy.done": "\u5DF2\u590D\u5236",
|
|
118
104
|
"copy.failed": "\u672A\u80FD\u590D\u5236\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u6587\u672C",
|
|
119
105
|
"empty.title": "\u4F60\u7684\u7B2C\u4E00\u53F0\u8BBE\u5907\uFF0C\u4ECE\u8FD9\u91CC\u5F00\u59CB",
|
|
@@ -130,11 +116,9 @@ var chinese = Object.freeze({
|
|
|
130
116
|
"app.footer": "Rovloom \xB7 Gateway \u63A7\u5236\u53F0",
|
|
131
117
|
"preference.switch": "\u5207\u6362\u4E3A {value}",
|
|
132
118
|
"language.label": "\u8BED\u8A00",
|
|
133
|
-
"language.system": "\u8DDF\u968F\u6D4F\u89C8\u5668",
|
|
134
119
|
"language.chinese": "\u7B80\u4F53\u4E2D\u6587",
|
|
135
120
|
"language.english": "English",
|
|
136
121
|
"theme.label": "\u4E3B\u9898",
|
|
137
|
-
"theme.system": "\u8DDF\u968F\u7CFB\u7EDF",
|
|
138
122
|
"theme.light": "\u6D45\u8272",
|
|
139
123
|
"theme.dark": "\u6DF1\u8272",
|
|
140
124
|
"manage.heading": "\u8BBE\u5907\u7BA1\u7406\u64CD\u4F5C",
|
|
@@ -165,28 +149,6 @@ var chinese = Object.freeze({
|
|
|
165
149
|
"manage.revokeEffect": "\u6301\u4E45\u64A4\u9500\u6210\u529F\u540E\uFF0C\u65E7\u8EAB\u4EFD\u5C06\u4E0D\u80FD\u91CD\u65B0\u63A5\u5165\uFF1B\u7ED3\u679C\u4EE5\u5F53\u524D\u6301\u4E45\u56DE\u6267\u4E3A\u51C6\uFF0C\u539F\u751F\u5DE5\u4F5C\u53EF\u80FD\u7EE7\u7EED\u3002",
|
|
166
150
|
"manage.nativeEffect": "\u6B64\u64CD\u4F5C\u4E0D\u4FDD\u8BC1\u505C\u6B62\u6216\u56DE\u6EDA\u539F\u751F\u5DE5\u4F5C\u3002",
|
|
167
151
|
"manage.action": "\u64CD\u4F5C",
|
|
168
|
-
"pairing.title": "\u5728\u7EBF\u6DFB\u52A0\u8BBE\u5907",
|
|
169
|
-
"pairing.intro": "\u4E3A\u5DE5\u4F5C\u7AD9\u8D77\u4E00\u4E2A\u540D\u79F0\u3002\u521B\u5EFA\u914D\u5BF9\u7533\u8BF7\u540E\uFF0C\u6309\u53F3\u4FA7\u6307\u5F15\u5B8C\u6210\u8FDE\u63A5\u3002",
|
|
170
|
-
"pairing.name": "\u65B0\u8BBE\u5907\u540D\u79F0",
|
|
171
|
-
"pairing.policy": "\u6388\u6743\u653F\u7B56\u5F15\u7528",
|
|
172
|
-
"pairing.create": "\u65B0\u5EFA\u914D\u5BF9\u7533\u8BF7",
|
|
173
|
-
"pairing.preparing": "\u6B63\u5728\u51C6\u5907\u540E\u53F0\u786E\u8BA4\u2026",
|
|
174
|
-
"pairing.review": "\u8BF7\u6838\u5BF9\u4EE5\u4E0B\u540E\u53F0\u6458\u8981\uFF0C\u786E\u8BA4\u540E\u624D\u4F1A\u63D0\u4EA4\u3002",
|
|
175
|
-
"pairing.confirm": "\u786E\u8BA4\u6267\u884C",
|
|
176
|
-
"pairing.cancel": "\u53D6\u6D88",
|
|
177
|
-
"pairing.created": "\u7533\u8BF7\u5DF2\u521B\u5EFA\u3002\u628A\u7533\u8BF7\u7F16\u53F7\u4EA4\u7ED9\u65B0\u8BBE\u5907\uFF1A",
|
|
178
|
-
"pairing.waitingClaim": "\u7B49\u5F85\u8BBE\u5907\u63D0\u4EA4\u8BA4\u9886\u2026",
|
|
179
|
-
"pairing.claimArrived": "\u8BBE\u5907\u5DF2\u53D1\u8D77\u8FDE\u63A5\u3002\u786E\u8BA4\u4E0B\u65B9\u4EE3\u7801\u4E0E\u5DE5\u4F5C\u7AD9\u7EC8\u7AEF\u4E00\u81F4\u540E\uFF0C\u518D\u6279\u51C6\u914D\u5BF9\uFF1A",
|
|
180
|
-
"pairing.userCode": "\u6838\u5BF9\u7801",
|
|
181
|
-
"pairing.approve": "\u6279\u51C6\u7B7E\u53D1\u51ED\u636E",
|
|
182
|
-
"pairing.approved": "\u5DF2\u6279\u51C6\uFF0C\u51ED\u636E\u5DF2\u6258\u7BA1\u4EA4\u4ED8\uFF0C\u7B49\u5F85\u8BBE\u5907\u53D6\u56DE\u2026",
|
|
183
|
-
"pairing.paired": "\u8BBE\u5907\u5DF2\u53D6\u56DE\u51ED\u636E\uFF0C\u914D\u5BF9\u5B8C\u6210\u3002",
|
|
184
|
-
"pairing.activated": "\u8BBE\u5907\u5DF2\u53D6\u56DE\u51ED\u636E\u5E76\u5B8C\u6210\u539F\u751F\u6FC0\u6D3B\uFF0C\u53EF\u6B63\u5F0F\u4F7F\u7528\u3002",
|
|
185
|
-
"pairing.statusPending": "\u7533\u8BF7\u5F85\u8BA4\u9886",
|
|
186
|
-
"pairing.expired": "\u7533\u8BF7\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u65B0\u5EFA\u3002",
|
|
187
|
-
"pairing.failed": "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u3002",
|
|
188
|
-
"pairing.application": "\u7533\u8BF7\u7F16\u53F7",
|
|
189
|
-
"pairing.machine": "\u8BBE\u5907",
|
|
190
152
|
"manage.machine": "\u76EE\u6807\u8BBE\u5907",
|
|
191
153
|
"manage.epoch": "\u8FDE\u63A5\u4EE3\u6B21",
|
|
192
154
|
"manage.revision": "\u8D44\u6E90\u7248\u672C",
|
|
@@ -219,6 +181,15 @@ var chinese = Object.freeze({
|
|
|
219
181
|
"error.timeout": "\u8BFB\u53D6\u8D85\u8FC7 5 \u79D2\u3002\u5F53\u524D\u663E\u793A\u4E0D\u662F\u5B9E\u65F6\u72B6\u6001\u3002",
|
|
220
182
|
"error.cancelled": "\u5DF2\u53D6\u6D88\u672C\u6B21\u8BFB\u53D6\u3002",
|
|
221
183
|
"time.noObservation": "\u5C1A\u65E0\u53EF\u4FE1\u89C2\u6D4B",
|
|
184
|
+
"reason.auth_failed": "\u8BA4\u8BC1\u5931\u8D25",
|
|
185
|
+
"reason.backend_unavailable": "\u540E\u7AEF\u4E0D\u53EF\u7528",
|
|
186
|
+
"reason.binding_mismatch": "\u7ED1\u5B9A\u4E0D\u4E00\u81F4",
|
|
187
|
+
"reason.connection_closed": "\u8FDE\u63A5\u5DF2\u5173\u95ED",
|
|
188
|
+
"reason.credential_expired": "\u51ED\u636E\u5DF2\u8FC7\u671F",
|
|
189
|
+
"reason.heartbeat_timeout": "\u5FC3\u8DF3\u8D85\u65F6",
|
|
190
|
+
"reason.not_recorded": "\u672A\u8BB0\u5F55",
|
|
191
|
+
"reason.protocol_error": "\u534F\u8BAE\u9519\u8BEF",
|
|
192
|
+
"reason.stale": "\u72B6\u6001\u8FC7\u671F",
|
|
222
193
|
"time.noHeartbeat": "\u5C1A\u65E0\u53EF\u4FE1\u5FC3\u8DF3",
|
|
223
194
|
"time.observed": "{time} \xB7 {age}{expired}",
|
|
224
195
|
"time.expiredSuffix": " \xB7 \u5DF2\u8FC7\u671F",
|
|
@@ -250,15 +221,6 @@ var chinese = Object.freeze({
|
|
|
250
221
|
"persisted.offline": "\u79BB\u7EBF\u767B\u8BB0 (offline)",
|
|
251
222
|
"persisted.online": "\u5728\u7EBF\u767B\u8BB0 (online)",
|
|
252
223
|
"persisted.revoked": "\u8EAB\u4EFD\u5DF2\u64A4\u9500 (revoked)",
|
|
253
|
-
"reason.backend_unavailable": "\u540E\u7AEF\u4E0D\u53EF\u7528",
|
|
254
|
-
"reason.not_recorded": "\u672A\u8BB0\u5F55",
|
|
255
|
-
"reason.stale": "\u89C2\u6D4B\u5DF2\u8FC7\u671F",
|
|
256
|
-
"reason.auth_failed": "\u8BA4\u8BC1\u5931\u8D25",
|
|
257
|
-
"reason.credential_expired": "\u51ED\u636E\u8FC7\u671F",
|
|
258
|
-
"reason.heartbeat_timeout": "\u5FC3\u8DF3\u8D85\u65F6",
|
|
259
|
-
"reason.protocol_error": "\u534F\u8BAE\u9519\u8BEF",
|
|
260
|
-
"reason.connection_closed": "\u8FDE\u63A5\u5DF2\u5173\u95ED",
|
|
261
|
-
"reason.binding_mismatch": "\u914D\u7F6E\u4E0D\u4E00\u81F4",
|
|
262
224
|
"device.expired": "\u8BBE\u5907\u89C2\u6D4B\u5DF2\u8FC7\u671F",
|
|
263
225
|
"device.revokedHistory": "\u4E0A\u6B21\u6301\u4E45\u767B\u8BB0\uFF1A\u8EAB\u4EFD\u5DF2\u64A4\u9500\uFF08\u5DF2\u8FC7\u671F\uFF09",
|
|
264
226
|
"device.oldRecords": "\u65E7\u8FDE\u63A5\u4E0E\u8BA4\u8BC1\u8BB0\u5F55\u4E0D\u80FD\u6062\u590D\u6388\u6743",
|
|
@@ -287,10 +249,6 @@ var chinese = Object.freeze({
|
|
|
287
249
|
"devices.health": "\u8FDE\u63A5\u4E0E\u8BA4\u8BC1",
|
|
288
250
|
"devices.activity": "\u6700\u8FD1\u5FC3\u8DF3",
|
|
289
251
|
"devices.received": "Gateway \u63A5\u6536 {time}",
|
|
290
|
-
"devices.observations": "\u89C2\u6D4B\u65F6\u95F4",
|
|
291
|
-
"devices.emptyHeading": "\u5C1A\u65E0\u53EF\u5C55\u793A\u7684\u8BBE\u5907",
|
|
292
|
-
"devices.empty": "\u6B64\u8303\u56F4\u5C1A\u65E0\u8BBE\u5907\u3002\u7531\u53D7\u4FDD\u62A4\u7684\u672C\u673A\u7BA1\u7406\u6E20\u9053\u5EFA\u7ACB\u914D\u5BF9\u7533\u8BF7\u540E\u518D\u5237\u65B0\u3002",
|
|
293
|
-
"devices.heartbeat": "\u6700\u8FD1\u5FC3\u8DF3\uFF1A{age} \xB7 Gateway \u63A5\u6536 {time}",
|
|
294
252
|
"devices.observed": "\u8BBE\u5907\u72B6\u6001\u89C2\u6D4B\uFF1A{time}",
|
|
295
253
|
"devices.connectionObserved": "\u8FDE\u63A5\u89C2\u6D4B\uFF1A{time}",
|
|
296
254
|
"devices.authObserved": "\u8BA4\u8BC1\u89C2\u6D4B\uFF1A{time}",
|
|
@@ -351,10 +309,17 @@ var chinese = Object.freeze({
|
|
|
351
309
|
"gateway.degradedNote": "\u5F53\u524D\u7981\u6B62\u7BA1\u7406\u5199\u5165\uFF1B\u6301\u4E45\u64A4\u9500\u7B49\u64CD\u4F5C\u53EF\u80FD\u5C1A\u672A\u751F\u6548\uFF0C\u8BF7\u4F7F\u7528\u53D7\u4FDD\u62A4\u672C\u673A\u8BCA\u65AD\u3002"
|
|
352
310
|
});
|
|
353
311
|
var english = Object.freeze({
|
|
354
|
-
"resources.previous": "Previous",
|
|
355
|
-
"resources.next": "Next",
|
|
356
312
|
"resources.tokens": "MCP tokens",
|
|
357
|
-
"resources.
|
|
313
|
+
"resources.pairingCodes": "Pairing codes",
|
|
314
|
+
"resources.createCode": "Generate code",
|
|
315
|
+
"resources.codesNote": "One code per device: run the displayed join command on the target machine to pair. Unused codes can be revoked anytime.",
|
|
316
|
+
"resources.codeCreatedNote": "Code created. Copy the command below and run it on the Connector machine.",
|
|
317
|
+
"resources.code_unused": "Unused",
|
|
318
|
+
"resources.code_used": "Used",
|
|
319
|
+
"resources.code_revoked": "Revoked",
|
|
320
|
+
"resources.code_failed": "Failed",
|
|
321
|
+
"resources.revokeCode": "Revoke",
|
|
322
|
+
"resources.confirmRevokeCode": "Revoke this pairing code? Generate a new one for the device.",
|
|
358
323
|
"resources.name": "Name",
|
|
359
324
|
"resources.expiry": "Valid for",
|
|
360
325
|
"resources.days": "{count} days",
|
|
@@ -375,17 +340,12 @@ var english = Object.freeze({
|
|
|
375
340
|
"resources.deleteDeviceNote": "Remove this device, runtime configuration, pairing records and call content, and disconnect it.",
|
|
376
341
|
"resources.confirmDevice": "Delete this device and its pairing and call records? Pair it again to reconnect.",
|
|
377
342
|
"resources.confirmToken": "Delete token \u201C{name}\u201D? Clients using it will lose access.",
|
|
378
|
-
"resources.confirmPairing": "Delete this pairing record? Unfinished pairing will stop. Paired devices are kept.",
|
|
379
343
|
"resources.emptyTokens": "No MCP tokens yet. Create one above to connect your AI client.",
|
|
380
|
-
"resources.emptyPairings": "No pairing records.",
|
|
381
344
|
"resources.loading": "Loading\u2026",
|
|
382
345
|
"resources.saving": "Saving\u2026",
|
|
383
346
|
"resources.saved": "Saved",
|
|
384
347
|
"resources.failed": "The operation did not complete. Refresh and try again.",
|
|
385
348
|
"resources.invalid": "Use a unique name (letters, numbers, - or _) and a valid expiry.",
|
|
386
|
-
"resources.pending": "Pending",
|
|
387
|
-
"resources.paired": "Paired",
|
|
388
|
-
"resources.cancelled": "Cancelled",
|
|
389
349
|
"nav.workspace": "WORKSPACE",
|
|
390
350
|
"nav.overview": "Overview",
|
|
391
351
|
"nav.devices": "Devices",
|
|
@@ -404,11 +364,6 @@ var english = Object.freeze({
|
|
|
404
364
|
"overview.attention": "Needs attention",
|
|
405
365
|
"overview.attentionNote": "Devices without a verified connection",
|
|
406
366
|
"overview.scope": "Device counts cover this page only. Expired observations do not establish current state.",
|
|
407
|
-
"overview.gateway": "Gateway health",
|
|
408
|
-
"overview.available": "Available",
|
|
409
|
-
"overview.degraded": "Degraded",
|
|
410
|
-
"overview.unavailable": "Unavailable",
|
|
411
|
-
"overview.unverified": "Unverified",
|
|
412
367
|
"overview.store": "Storage",
|
|
413
368
|
"overview.transport": "Device transport",
|
|
414
369
|
"overview.native": "Native runtime",
|
|
@@ -423,23 +378,16 @@ var english = Object.freeze({
|
|
|
423
378
|
"devices.results": "Showing {shown} of {count} devices on this page",
|
|
424
379
|
"devices.noMatches": "No matching devices",
|
|
425
380
|
"devices.noMatchesHint": "Try another name, ID or label, or change the status filter.",
|
|
426
|
-
"devices.inspect": "View details",
|
|
427
381
|
"devices.record": "Observation details",
|
|
428
382
|
"devices.open": "View details for {name}",
|
|
383
|
+
"overview.available": "Available",
|
|
384
|
+
"overview.degraded": "Degraded",
|
|
385
|
+
"overview.unavailable": "Unavailable",
|
|
386
|
+
"overview.unverified": "Unverified",
|
|
429
387
|
"pairing.pageTitle": "Bring a new device on board",
|
|
430
|
-
"pairing.pageDescription": "
|
|
431
|
-
"pairing.stepCreate": "Create an application",
|
|
432
|
-
"pairing.stepRun": "Run Connector",
|
|
433
|
-
"pairing.stepApprove": "Verify and approve",
|
|
434
|
-
"pairing.formTitle": "Add your workstation",
|
|
435
|
-
"pairing.namePlaceholder": "e.g. office-workstation",
|
|
436
|
-
"pairing.nameHint": "Use 1\u201363 lowercase letters, digits, dots, underscores or hyphens.",
|
|
437
|
-
"pairing.advanced": "Advanced: pairing policy",
|
|
438
|
-
"pairing.guideTitle": "Then, on your workstation",
|
|
439
|
-
"pairing.guideDescription": "Run this command on the device with Luvus or Herdr installed. Enter the Gateway address and application ID when prompted.",
|
|
440
|
-
"pairing.guideNote": "Match the code on this page with the terminal, then approve local native installation access.",
|
|
388
|
+
"pairing.pageDescription": "Generate a per-device code and run the join command on the target machine. No applications, approvals or verification codes.",
|
|
441
389
|
"pairing.loginRequired": "A management session is required",
|
|
442
|
-
"pairing.loginHint": "Sign in through the Gateway management entry to
|
|
390
|
+
"pairing.loginHint": "Sign in through the Gateway management entry to generate pairing codes.",
|
|
443
391
|
"connect.title": "Connect your workspace to AI",
|
|
444
392
|
"connect.description": "Once a device is paired, issue a dedicated MCP Bearer for your AI client.",
|
|
445
393
|
"connect.stepOne": "Find an existing caller",
|
|
@@ -451,7 +399,6 @@ var english = Object.freeze({
|
|
|
451
399
|
"connect.docker": "Docker deployment commands",
|
|
452
400
|
"connect.docs": "Read the connection guide",
|
|
453
401
|
"copy.action": "Copy command",
|
|
454
|
-
"copy.id": "Copy application ID",
|
|
455
402
|
"copy.done": "Copied",
|
|
456
403
|
"copy.failed": "Copy unavailable; select the text manually",
|
|
457
404
|
"empty.title": "Start with your first device",
|
|
@@ -468,11 +415,9 @@ var english = Object.freeze({
|
|
|
468
415
|
"app.footer": "Rovloom \xB7 Gateway console",
|
|
469
416
|
"preference.switch": "Switch to {value}",
|
|
470
417
|
"language.label": "Language",
|
|
471
|
-
"language.system": "Browser language",
|
|
472
418
|
"language.chinese": "\u7B80\u4F53\u4E2D\u6587",
|
|
473
419
|
"language.english": "English",
|
|
474
420
|
"theme.label": "Theme",
|
|
475
|
-
"theme.system": "System theme",
|
|
476
421
|
"theme.light": "Light",
|
|
477
422
|
"theme.dark": "Dark",
|
|
478
423
|
"manage.heading": "Device management",
|
|
@@ -503,28 +448,6 @@ var english = Object.freeze({
|
|
|
503
448
|
"manage.revokeEffect": "After durable revocation, that identity cannot reconnect. The current durable receipt determines the outcome; native work may continue.",
|
|
504
449
|
"manage.nativeEffect": "This operation does not guarantee stopping or rolling back native work.",
|
|
505
450
|
"manage.action": "Action",
|
|
506
|
-
"pairing.title": "Add a device online",
|
|
507
|
-
"pairing.intro": "Give your workstation a name. Create an application, then follow the steps on the right.",
|
|
508
|
-
"pairing.name": "New device name",
|
|
509
|
-
"pairing.policy": "Authorization policy reference",
|
|
510
|
-
"pairing.create": "Create pairing application",
|
|
511
|
-
"pairing.preparing": "Preparing the background confirmation\u2026",
|
|
512
|
-
"pairing.review": "Review the background summary below; nothing is submitted until you confirm.",
|
|
513
|
-
"pairing.confirm": "Confirm",
|
|
514
|
-
"pairing.cancel": "Cancel",
|
|
515
|
-
"pairing.created": "Application created. Give this pairing ID to the new device:",
|
|
516
|
-
"pairing.waitingClaim": "Waiting for the device to submit its claim\u2026",
|
|
517
|
-
"pairing.claimArrived": "The device submitted a claim. Approve issuance only if the check code matches the device screen:",
|
|
518
|
-
"pairing.userCode": "Check code",
|
|
519
|
-
"pairing.approve": "Approve credential issuance",
|
|
520
|
-
"pairing.approved": "Approved. The credential is held for delivery; waiting for the device to collect it\u2026",
|
|
521
|
-
"pairing.paired": "The device collected its credential. Pairing complete.",
|
|
522
|
-
"pairing.activated": "Credential collected and native activation complete. Ready to use.",
|
|
523
|
-
"pairing.statusPending": "Awaiting claim",
|
|
524
|
-
"pairing.expired": "This application expired; create a new one.",
|
|
525
|
-
"pairing.failed": "The operation did not complete; prepare it again.",
|
|
526
|
-
"pairing.application": "Pairing ID",
|
|
527
|
-
"pairing.machine": "Device",
|
|
528
451
|
"manage.machine": "Target device",
|
|
529
452
|
"manage.epoch": "Connection epoch",
|
|
530
453
|
"manage.revision": "Resource revision",
|
|
@@ -557,6 +480,15 @@ var english = Object.freeze({
|
|
|
557
480
|
"error.timeout": "The read exceeded 5 seconds. The displayed state is not live.",
|
|
558
481
|
"error.cancelled": "This read was cancelled.",
|
|
559
482
|
"time.noObservation": "No trusted observation",
|
|
483
|
+
"reason.auth_failed": "Authentication failed",
|
|
484
|
+
"reason.backend_unavailable": "Backend unavailable",
|
|
485
|
+
"reason.binding_mismatch": "Binding mismatch",
|
|
486
|
+
"reason.connection_closed": "Connection closed",
|
|
487
|
+
"reason.credential_expired": "Credential expired",
|
|
488
|
+
"reason.heartbeat_timeout": "Heartbeat timed out",
|
|
489
|
+
"reason.not_recorded": "Not recorded",
|
|
490
|
+
"reason.protocol_error": "Protocol error",
|
|
491
|
+
"reason.stale": "Stale",
|
|
560
492
|
"time.noHeartbeat": "No trusted heartbeat",
|
|
561
493
|
"time.observed": "{time} \xB7 {age}{expired}",
|
|
562
494
|
"time.expiredSuffix": " \xB7 expired",
|
|
@@ -588,15 +520,6 @@ var english = Object.freeze({
|
|
|
588
520
|
"persisted.offline": "Registered offline (offline)",
|
|
589
521
|
"persisted.online": "Registered online (online)",
|
|
590
522
|
"persisted.revoked": "Identity revoked (revoked)",
|
|
591
|
-
"reason.backend_unavailable": "Backend unavailable",
|
|
592
|
-
"reason.not_recorded": "Not recorded",
|
|
593
|
-
"reason.stale": "Observation expired",
|
|
594
|
-
"reason.auth_failed": "Authentication failed",
|
|
595
|
-
"reason.credential_expired": "Credential expired",
|
|
596
|
-
"reason.heartbeat_timeout": "Heartbeat timed out",
|
|
597
|
-
"reason.protocol_error": "Protocol error",
|
|
598
|
-
"reason.connection_closed": "Connection closed",
|
|
599
|
-
"reason.binding_mismatch": "Binding mismatch",
|
|
600
523
|
"device.expired": "Device observation expired",
|
|
601
524
|
"device.revokedHistory": "Last stored registration: identity revoked (expired)",
|
|
602
525
|
"device.oldRecords": "Old connection and authentication records cannot restore authorization",
|
|
@@ -625,10 +548,6 @@ var english = Object.freeze({
|
|
|
625
548
|
"devices.health": "Connection & authentication",
|
|
626
549
|
"devices.activity": "Last heartbeat",
|
|
627
550
|
"devices.received": "Gateway received {time}",
|
|
628
|
-
"devices.observations": "Observations",
|
|
629
|
-
"devices.emptyHeading": "No devices to display",
|
|
630
|
-
"devices.empty": "There are no devices in this scope. Create a pairing request through the protected local management channel, then refresh.",
|
|
631
|
-
"devices.heartbeat": "Last heartbeat: {age} \xB7 Gateway received {time}",
|
|
632
551
|
"devices.observed": "Device state observed: {time}",
|
|
633
552
|
"devices.connectionObserved": "Connection observed: {time}",
|
|
634
553
|
"devices.authObserved": "Authentication observed: {time}",
|
|
@@ -1728,49 +1647,6 @@ function checkDeviceIntent(value) {
|
|
|
1728
1647
|
summary({ ...operation, recovery_generation: "validation", expected_revision: 0, reason: "administrator_request" }, "invalid_request");
|
|
1729
1648
|
return JSON.parse(JSON.stringify(value));
|
|
1730
1649
|
}
|
|
1731
|
-
function checkPairingIntent(value) {
|
|
1732
|
-
record(value, ["action"], ["machine_id", "name", "policy_ref", "labels", "pairing_id", "claim_id", "user_code"], "invalid_request");
|
|
1733
|
-
const action = value.action;
|
|
1734
|
-
if (action === "pairing_create") {
|
|
1735
|
-
const hasName = Object.hasOwn(value, "name");
|
|
1736
|
-
const keys = hasName ? ["action", "name", "policy_ref", "labels"] : ["action", "machine_id", "policy_ref"];
|
|
1737
|
-
record(value, keys, [], "invalid_request");
|
|
1738
|
-
const intent = value;
|
|
1739
|
-
const operation = intent.action === "pairing_create" && "name" in intent ? {
|
|
1740
|
-
action: "pairing_create",
|
|
1741
|
-
target: { name: intent.name, policy_ref: intent.policy_ref, labels: intent.labels }
|
|
1742
|
-
} : {
|
|
1743
|
-
action: "pairing_create",
|
|
1744
|
-
target: {
|
|
1745
|
-
machine_id: intent.machine_id,
|
|
1746
|
-
policy_ref: intent.policy_ref
|
|
1747
|
-
}
|
|
1748
|
-
};
|
|
1749
|
-
summary({ ...operation, recovery_generation: "validation", expected_revision: 0, reason: "administrator_request" }, "invalid_request");
|
|
1750
|
-
return JSON.parse(JSON.stringify(value));
|
|
1751
|
-
}
|
|
1752
|
-
if (action === "pairing_claim_approve") {
|
|
1753
|
-
record(value, ["action", "machine_id", "pairing_id", "claim_id", "user_code"], [], "invalid_request");
|
|
1754
|
-
const intent = value;
|
|
1755
|
-
if (intent.action !== "pairing_claim_approve") {
|
|
1756
|
-
invalid("invalid_request");
|
|
1757
|
-
}
|
|
1758
|
-
summary({
|
|
1759
|
-
action: "pairing_claim_approve",
|
|
1760
|
-
target: {
|
|
1761
|
-
machine_id: intent.machine_id,
|
|
1762
|
-
pairing_id: intent.pairing_id,
|
|
1763
|
-
claim_id: intent.claim_id,
|
|
1764
|
-
user_code: intent.user_code
|
|
1765
|
-
},
|
|
1766
|
-
recovery_generation: "validation",
|
|
1767
|
-
expected_revision: 0,
|
|
1768
|
-
reason: "administrator_request"
|
|
1769
|
-
}, "invalid_request");
|
|
1770
|
-
return JSON.parse(JSON.stringify(value));
|
|
1771
|
-
}
|
|
1772
|
-
invalid("invalid_request");
|
|
1773
|
-
}
|
|
1774
1650
|
function pairingSummary(v, problem) {
|
|
1775
1651
|
const target = v.target;
|
|
1776
1652
|
if (v.action === "pairing_create") {
|
|
@@ -2720,683 +2596,6 @@ function createDeviceActions(options) {
|
|
|
2720
2596
|
};
|
|
2721
2597
|
}
|
|
2722
2598
|
|
|
2723
|
-
// src/webui/pairing-flow.ts
|
|
2724
|
-
function snapshot2(value) {
|
|
2725
|
-
const copy = JSON.parse(JSON.stringify(value));
|
|
2726
|
-
function freeze(item) {
|
|
2727
|
-
if (item && typeof item === "object") {
|
|
2728
|
-
for (const child of Object.values(item)) {
|
|
2729
|
-
freeze(child);
|
|
2730
|
-
}
|
|
2731
|
-
Object.freeze(item);
|
|
2732
|
-
}
|
|
2733
|
-
}
|
|
2734
|
-
freeze(copy);
|
|
2735
|
-
return copy;
|
|
2736
|
-
}
|
|
2737
|
-
function failure2(error) {
|
|
2738
|
-
return error instanceof ManagementClientError ? error.problem : "unavailable";
|
|
2739
|
-
}
|
|
2740
|
-
function operationOf(intent) {
|
|
2741
|
-
if (intent.action === "pairing_claim_approve") {
|
|
2742
|
-
return {
|
|
2743
|
-
action: "pairing_claim_approve",
|
|
2744
|
-
target: {
|
|
2745
|
-
machine_id: intent.machine_id,
|
|
2746
|
-
pairing_id: intent.pairing_id,
|
|
2747
|
-
claim_id: intent.claim_id,
|
|
2748
|
-
user_code: intent.user_code
|
|
2749
|
-
}
|
|
2750
|
-
};
|
|
2751
|
-
}
|
|
2752
|
-
return "name" in intent ? { action: "pairing_create", target: { name: intent.name, policy_ref: intent.policy_ref, labels: intent.labels } } : { action: "pairing_create", target: { machine_id: intent.machine_id, policy_ref: intent.policy_ref } };
|
|
2753
|
-
}
|
|
2754
|
-
var operationName = {
|
|
2755
|
-
pairing_create: "pairings_create",
|
|
2756
|
-
pairing_claim_approve: "pairings_claim_approve"
|
|
2757
|
-
};
|
|
2758
|
-
function createPairingManagementFlow(options) {
|
|
2759
|
-
let state = { phase: "idle" };
|
|
2760
|
-
let intent;
|
|
2761
|
-
let write;
|
|
2762
|
-
let review;
|
|
2763
|
-
let original;
|
|
2764
|
-
let active;
|
|
2765
|
-
let generation = 0;
|
|
2766
|
-
let disposed = false;
|
|
2767
|
-
const requestId = options.requestId ?? managementRequestId;
|
|
2768
|
-
async function execute(operation, args, signal) {
|
|
2769
|
-
if (signal.aborted) {
|
|
2770
|
-
throw new ManagementClientError("aborted");
|
|
2771
|
-
}
|
|
2772
|
-
managementWriteBody(operation, args);
|
|
2773
|
-
const reply = await options.transport.execute(operation, args, signal);
|
|
2774
|
-
return checkManagementWriteReply(operation, reply, args);
|
|
2775
|
-
}
|
|
2776
|
-
function begin(phase, signal) {
|
|
2777
|
-
if (disposed || active || state.phase !== phase || signal?.aborted) {
|
|
2778
|
-
throw new ManagementClientError("invalid_request");
|
|
2779
|
-
}
|
|
2780
|
-
const controller = new AbortController;
|
|
2781
|
-
active = controller;
|
|
2782
|
-
const current = ++generation;
|
|
2783
|
-
const abort = () => cancel();
|
|
2784
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
2785
|
-
return {
|
|
2786
|
-
controller,
|
|
2787
|
-
current: () => !disposed && generation === current && !controller.signal.aborted,
|
|
2788
|
-
done() {
|
|
2789
|
-
signal?.removeEventListener("abort", abort);
|
|
2790
|
-
if (active === controller) {
|
|
2791
|
-
active = undefined;
|
|
2792
|
-
}
|
|
2793
|
-
}
|
|
2794
|
-
};
|
|
2795
|
-
}
|
|
2796
|
-
function unconfirmed(problem) {
|
|
2797
|
-
if (!original) {
|
|
2798
|
-
state = { phase: "failed", problem: problem ?? "unavailable" };
|
|
2799
|
-
return;
|
|
2800
|
-
}
|
|
2801
|
-
state = { phase: "unconfirmed", operation: original, ...problem ? { problem } : {} };
|
|
2802
|
-
}
|
|
2803
|
-
function accept(receipt) {
|
|
2804
|
-
if (!original || !intent || !review || receipt.request_id !== original.request_id || receipt.history_epoch !== original.history_epoch || receipt.recovery_generation !== original.recovery_generation || receipt.action !== intent.action || receipt.operation_digest !== review.operation_digest) {
|
|
2805
|
-
throw new ManagementClientError("invalid_response", true);
|
|
2806
|
-
}
|
|
2807
|
-
if (intent.action === "pairing_claim_approve" && receipt.target.machine_id !== intent.machine_id) {
|
|
2808
|
-
throw new ManagementClientError("invalid_response", true);
|
|
2809
|
-
}
|
|
2810
|
-
if (receipt.evidence !== "current_durable" || receipt.operation_state === "outcome_unknown") {
|
|
2811
|
-
unconfirmed("outcome_unconfirmed");
|
|
2812
|
-
} else {
|
|
2813
|
-
state = receipt.operation_state === "committed" ? { phase: "committed", receipt } : { phase: "not_committed", receipt };
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
function cancel() {
|
|
2817
|
-
if (!active) {
|
|
2818
|
-
if (state.phase === "idle" || state.phase === "awaiting_confirmation") {
|
|
2819
|
-
generation++;
|
|
2820
|
-
state = { phase: "cancelled" };
|
|
2821
|
-
}
|
|
2822
|
-
return;
|
|
2823
|
-
}
|
|
2824
|
-
generation++;
|
|
2825
|
-
const controller = active;
|
|
2826
|
-
active = undefined;
|
|
2827
|
-
const uncertain = state.phase === "submitting" || state.phase === "checking";
|
|
2828
|
-
controller.abort();
|
|
2829
|
-
if (uncertain) {
|
|
2830
|
-
unconfirmed("aborted");
|
|
2831
|
-
} else {
|
|
2832
|
-
state = { phase: "cancelled" };
|
|
2833
|
-
}
|
|
2834
|
-
}
|
|
2835
|
-
return {
|
|
2836
|
-
state() {
|
|
2837
|
-
return snapshot2(state);
|
|
2838
|
-
},
|
|
2839
|
-
async prepare(value, signal) {
|
|
2840
|
-
const pending = begin("idle", signal);
|
|
2841
|
-
try {
|
|
2842
|
-
intent = checkPairingIntent(value);
|
|
2843
|
-
state = { phase: "preparing", intent };
|
|
2844
|
-
const id = requestId();
|
|
2845
|
-
const history = await execute("history_open", {}, pending.controller.signal);
|
|
2846
|
-
if (!pending.current()) {
|
|
2847
|
-
return snapshot2(state);
|
|
2848
|
-
}
|
|
2849
|
-
const resource = "machine_id" in intent ? await execute("write_state_get", { machine_id: intent.machine_id }, pending.controller.signal) : {
|
|
2850
|
-
resource_revision: 0,
|
|
2851
|
-
recovery_generation: history.recovery_generation,
|
|
2852
|
-
connection_epoch: null,
|
|
2853
|
-
binding_revision: null
|
|
2854
|
-
};
|
|
2855
|
-
if (!pending.current()) {
|
|
2856
|
-
return snapshot2(state);
|
|
2857
|
-
}
|
|
2858
|
-
if (history.recovery_generation !== resource.recovery_generation) {
|
|
2859
|
-
throw new ManagementClientError("conflict");
|
|
2860
|
-
}
|
|
2861
|
-
const draft = {
|
|
2862
|
-
...operationOf(intent),
|
|
2863
|
-
request_id: id,
|
|
2864
|
-
history_epoch: history.history_epoch,
|
|
2865
|
-
recovery_generation: history.recovery_generation,
|
|
2866
|
-
expected_revision: resource.resource_revision,
|
|
2867
|
-
reason: "administrator_request"
|
|
2868
|
-
};
|
|
2869
|
-
const confirmation = await execute("confirmations_create", draft, pending.controller.signal);
|
|
2870
|
-
if (!pending.current()) {
|
|
2871
|
-
return snapshot2(state);
|
|
2872
|
-
}
|
|
2873
|
-
review = snapshot2(confirmation);
|
|
2874
|
-
write = {
|
|
2875
|
-
request_id: id,
|
|
2876
|
-
history_epoch: history.history_epoch,
|
|
2877
|
-
recovery_generation: history.recovery_generation,
|
|
2878
|
-
expected_revision: resource.resource_revision,
|
|
2879
|
-
reason: draft.reason,
|
|
2880
|
-
confirmation_id: confirmation.confirmation_id
|
|
2881
|
-
};
|
|
2882
|
-
original = {
|
|
2883
|
-
request_id: id,
|
|
2884
|
-
history_epoch: history.history_epoch,
|
|
2885
|
-
recovery_generation: history.recovery_generation
|
|
2886
|
-
};
|
|
2887
|
-
if (confirmation.state === "expired") {
|
|
2888
|
-
throw new ManagementClientError("conflict");
|
|
2889
|
-
}
|
|
2890
|
-
if (confirmation.state === "consumed") {
|
|
2891
|
-
unconfirmed("outcome_unconfirmed");
|
|
2892
|
-
} else {
|
|
2893
|
-
state = { phase: "awaiting_confirmation", review };
|
|
2894
|
-
}
|
|
2895
|
-
} catch (error) {
|
|
2896
|
-
if (pending.current()) {
|
|
2897
|
-
state = { phase: "failed", problem: failure2(error) };
|
|
2898
|
-
}
|
|
2899
|
-
} finally {
|
|
2900
|
-
pending.done();
|
|
2901
|
-
}
|
|
2902
|
-
return snapshot2(state);
|
|
2903
|
-
},
|
|
2904
|
-
async confirm(signal) {
|
|
2905
|
-
const pending = begin("awaiting_confirmation", signal);
|
|
2906
|
-
try {
|
|
2907
|
-
if (!write || !review || !intent) {
|
|
2908
|
-
throw new ManagementClientError("invalid_request");
|
|
2909
|
-
}
|
|
2910
|
-
state = { phase: "confirming", review };
|
|
2911
|
-
const confirmed = await execute("confirmations_confirm", { ...write, operation_digest: review.operation_digest }, pending.controller.signal);
|
|
2912
|
-
if (!pending.current()) {
|
|
2913
|
-
return snapshot2(state);
|
|
2914
|
-
}
|
|
2915
|
-
if (managementConfirmationKey(confirmed) !== managementConfirmationKey(review)) {
|
|
2916
|
-
throw new ManagementClientError("invalid_response");
|
|
2917
|
-
}
|
|
2918
|
-
if (confirmed.state === "consumed") {
|
|
2919
|
-
unconfirmed("outcome_unconfirmed");
|
|
2920
|
-
return snapshot2(state);
|
|
2921
|
-
}
|
|
2922
|
-
if (confirmed.state !== "confirmed") {
|
|
2923
|
-
throw new ManagementClientError("conflict");
|
|
2924
|
-
}
|
|
2925
|
-
const operation = operationName[intent.action];
|
|
2926
|
-
const target = intent.action === "pairing_claim_approve" ? {
|
|
2927
|
-
machine_id: intent.machine_id,
|
|
2928
|
-
pairing_id: intent.pairing_id,
|
|
2929
|
-
claim_id: intent.claim_id,
|
|
2930
|
-
user_code: intent.user_code
|
|
2931
|
-
} : ("name" in intent) ? { name: intent.name, policy_ref: intent.policy_ref, labels: intent.labels } : { machine_id: intent.machine_id, policy_ref: intent.policy_ref };
|
|
2932
|
-
state = { phase: "submitting", review };
|
|
2933
|
-
const receipt = await execute(operation, { ...write, ...target }, pending.controller.signal);
|
|
2934
|
-
if (pending.current()) {
|
|
2935
|
-
accept(receipt);
|
|
2936
|
-
}
|
|
2937
|
-
} catch (error) {
|
|
2938
|
-
if (pending.current()) {
|
|
2939
|
-
if (state.phase === "submitting") {
|
|
2940
|
-
unconfirmed(failure2(error));
|
|
2941
|
-
} else {
|
|
2942
|
-
state = { phase: "failed", problem: failure2(error) };
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
} finally {
|
|
2946
|
-
pending.done();
|
|
2947
|
-
}
|
|
2948
|
-
return snapshot2(state);
|
|
2949
|
-
},
|
|
2950
|
-
async checkReceipt(signal) {
|
|
2951
|
-
const pending = begin("unconfirmed", signal);
|
|
2952
|
-
try {
|
|
2953
|
-
if (!original) {
|
|
2954
|
-
throw new ManagementClientError("invalid_request");
|
|
2955
|
-
}
|
|
2956
|
-
state = { phase: "checking", operation: original };
|
|
2957
|
-
const receipt = await execute("operations_get", original, pending.controller.signal);
|
|
2958
|
-
if (pending.current()) {
|
|
2959
|
-
accept(receipt);
|
|
2960
|
-
}
|
|
2961
|
-
} catch (error) {
|
|
2962
|
-
if (pending.current()) {
|
|
2963
|
-
unconfirmed(failure2(error));
|
|
2964
|
-
}
|
|
2965
|
-
} finally {
|
|
2966
|
-
pending.done();
|
|
2967
|
-
}
|
|
2968
|
-
return snapshot2(state);
|
|
2969
|
-
},
|
|
2970
|
-
cancel,
|
|
2971
|
-
dispose() {
|
|
2972
|
-
cancel();
|
|
2973
|
-
disposed = true;
|
|
2974
|
-
}
|
|
2975
|
-
};
|
|
2976
|
-
}
|
|
2977
|
-
|
|
2978
|
-
// src/webui/pairing-actions.ts
|
|
2979
|
-
var errors2 = {
|
|
2980
|
-
invalid_request: "manage.invalid",
|
|
2981
|
-
invalid_response: "manage.invalid",
|
|
2982
|
-
unauthenticated: "manage.unauthenticated",
|
|
2983
|
-
forbidden: "manage.forbidden",
|
|
2984
|
-
conflict: "manage.conflict",
|
|
2985
|
-
busy: "manage.busy",
|
|
2986
|
-
unavailable: "manage.unavailable",
|
|
2987
|
-
outcome_unconfirmed: "manage.unknown",
|
|
2988
|
-
aborted: "manage.cancelled"
|
|
2989
|
-
};
|
|
2990
|
-
function entryRenderSignature(language, entry) {
|
|
2991
|
-
return [
|
|
2992
|
-
language,
|
|
2993
|
-
entry.name,
|
|
2994
|
-
entry.machine_id,
|
|
2995
|
-
entry.pairing_id,
|
|
2996
|
-
entry.status,
|
|
2997
|
-
entry.claim?.status ?? "",
|
|
2998
|
-
entry.claim?.user_code ?? "",
|
|
2999
|
-
entry.claim?.activation ?? ""
|
|
3000
|
-
].join("|");
|
|
3001
|
-
}
|
|
3002
|
-
function node3(tag, className = "") {
|
|
3003
|
-
const element = document.createElement(tag);
|
|
3004
|
-
element.className = className;
|
|
3005
|
-
return element;
|
|
3006
|
-
}
|
|
3007
|
-
function createPairingActions(options) {
|
|
3008
|
-
const region = node3("section", "pairing-section");
|
|
3009
|
-
const steps = node3("ol", "pairing-steps");
|
|
3010
|
-
const stepItems = ["pairing.stepCreate", "pairing.stepRun", "pairing.stepApprove"].map((key, index) => {
|
|
3011
|
-
const item = node3("li");
|
|
3012
|
-
const number = node3("span", "pairing-step-number");
|
|
3013
|
-
number.textContent = String(index + 1).padStart(2, "0");
|
|
3014
|
-
const label = node3("span");
|
|
3015
|
-
item.append(number, label);
|
|
3016
|
-
steps.append(item);
|
|
3017
|
-
return { item, label, key };
|
|
3018
|
-
});
|
|
3019
|
-
const layout = node3("div", "pairing-layout");
|
|
3020
|
-
const setup = node3("div", "pairing-setup");
|
|
3021
|
-
const heading = node3("h2");
|
|
3022
|
-
const intro = node3("p", "muted");
|
|
3023
|
-
const form = node3("form", "pairing-form");
|
|
3024
|
-
const nameLabel = node3("label");
|
|
3025
|
-
const nameCaption = node3("span");
|
|
3026
|
-
const nameInput = node3("input");
|
|
3027
|
-
nameInput.name = "pairing-name";
|
|
3028
|
-
nameInput.required = true;
|
|
3029
|
-
nameInput.maxLength = 63;
|
|
3030
|
-
nameInput.pattern = "[a-z0-9][a-z0-9._-]{0,62}";
|
|
3031
|
-
nameInput.autocomplete = "off";
|
|
3032
|
-
const nameHint = node3("small", "field-hint");
|
|
3033
|
-
nameHint.id = "pairing-name-hint";
|
|
3034
|
-
nameInput.setAttribute("aria-describedby", nameHint.id);
|
|
3035
|
-
nameLabel.append(nameCaption, nameInput, nameHint);
|
|
3036
|
-
const policyLabel = node3("label");
|
|
3037
|
-
const policyCaption = node3("span");
|
|
3038
|
-
const policyInput = node3("input");
|
|
3039
|
-
policyInput.name = "pairing-policy";
|
|
3040
|
-
policyInput.required = true;
|
|
3041
|
-
policyInput.maxLength = 128;
|
|
3042
|
-
policyInput.autocomplete = "off";
|
|
3043
|
-
policyInput.value = DEFAULT_PAIRING_POLICY_REF;
|
|
3044
|
-
policyLabel.append(policyCaption, policyInput);
|
|
3045
|
-
const create = node3("button", "pairing-confirm");
|
|
3046
|
-
create.type = "submit";
|
|
3047
|
-
const advanced = node3("details", "pairing-advanced");
|
|
3048
|
-
const advancedSummary = node3("summary");
|
|
3049
|
-
advanced.append(advancedSummary, policyLabel);
|
|
3050
|
-
form.append(nameLabel, advanced, create);
|
|
3051
|
-
const reviewBox = node3("div", "pairing-review");
|
|
3052
|
-
reviewBox.hidden = true;
|
|
3053
|
-
const reviewText = node3("p", "pairing-status");
|
|
3054
|
-
const reviewFacts = node3("dl", "facts pairing-facts");
|
|
3055
|
-
const controls = node3("div", "pairing-controls");
|
|
3056
|
-
const confirm = node3("button", "pairing-confirm");
|
|
3057
|
-
const check = node3("button");
|
|
3058
|
-
const cancel = node3("button");
|
|
3059
|
-
for (const button of [confirm, check, cancel]) {
|
|
3060
|
-
button.type = "button";
|
|
3061
|
-
}
|
|
3062
|
-
controls.append(confirm, check, cancel);
|
|
3063
|
-
reviewBox.append(reviewText, reviewFacts, controls);
|
|
3064
|
-
const message = node3("p", "pairing-status");
|
|
3065
|
-
message.setAttribute("role", "status");
|
|
3066
|
-
message.setAttribute("aria-live", "polite");
|
|
3067
|
-
const list = node3("ul", "pairing-entries");
|
|
3068
|
-
setup.append(heading, intro, form, reviewBox, message);
|
|
3069
|
-
const guide = node3("aside", "pairing-guide");
|
|
3070
|
-
const guideIcon = node3("span", "pairing-guide-icon");
|
|
3071
|
-
guideIcon.append(uiIcon("connect"));
|
|
3072
|
-
const guideHeading = node3("h2");
|
|
3073
|
-
const guideDescription = node3("p", "muted");
|
|
3074
|
-
const command = node3("div", "command-snippet");
|
|
3075
|
-
const commandCode = node3("code");
|
|
3076
|
-
commandCode.textContent = "rovloom connector --claim";
|
|
3077
|
-
const commandCopy = copyControl("rovloom connector --claim", "");
|
|
3078
|
-
command.append(commandCode, commandCopy);
|
|
3079
|
-
const guideNote = node3("p", "pairing-guide-note");
|
|
3080
|
-
guide.append(guideIcon, guideHeading, guideDescription, command, guideNote);
|
|
3081
|
-
layout.append(setup, guide);
|
|
3082
|
-
region.append(steps, layout, list);
|
|
3083
|
-
let i18n;
|
|
3084
|
-
let available = false;
|
|
3085
|
-
let disposed = false;
|
|
3086
|
-
let flow;
|
|
3087
|
-
let flowIntent;
|
|
3088
|
-
let timer;
|
|
3089
|
-
const entries = new Map;
|
|
3090
|
-
const pollMs = options.pollMs ?? 4000;
|
|
3091
|
-
function fact(term, value) {
|
|
3092
|
-
const dt = node3("dt");
|
|
3093
|
-
dt.textContent = term;
|
|
3094
|
-
const dd = node3("dd");
|
|
3095
|
-
dd.textContent = value;
|
|
3096
|
-
reviewFacts.append(dt, dd);
|
|
3097
|
-
}
|
|
3098
|
-
function paintFlow(state) {
|
|
3099
|
-
if (!i18n) {
|
|
3100
|
-
return;
|
|
3101
|
-
}
|
|
3102
|
-
const t = i18n.t.bind(i18n);
|
|
3103
|
-
check.hidden = true;
|
|
3104
|
-
confirm.hidden = true;
|
|
3105
|
-
if (state.phase === "idle" || state.phase === "cancelled") {
|
|
3106
|
-
reviewBox.hidden = true;
|
|
3107
|
-
return;
|
|
3108
|
-
}
|
|
3109
|
-
reviewBox.hidden = false;
|
|
3110
|
-
if (state.phase === "preparing" || state.phase === "confirming" || state.phase === "submitting") {
|
|
3111
|
-
reviewText.textContent = t("pairing.preparing");
|
|
3112
|
-
return;
|
|
3113
|
-
}
|
|
3114
|
-
if (state.phase === "awaiting_confirmation") {
|
|
3115
|
-
reviewText.textContent = t("pairing.review");
|
|
3116
|
-
reviewFacts.replaceChildren();
|
|
3117
|
-
const summary = state.review.summary;
|
|
3118
|
-
fact(t("manage.action"), t(summary.action === "pairing_create" ? "pairing.create" : "pairing.approve"));
|
|
3119
|
-
if (summary.action === "pairing_create") {
|
|
3120
|
-
fact(t("pairing.name"), "name" in summary.target ? summary.target.name : summary.target.machine_id);
|
|
3121
|
-
fact(t("pairing.policy"), summary.target.policy_ref);
|
|
3122
|
-
} else if (summary.action === "pairing_claim_approve") {
|
|
3123
|
-
fact(t("pairing.machine"), summary.target.machine_id);
|
|
3124
|
-
fact(t("pairing.userCode"), summary.target.user_code);
|
|
3125
|
-
}
|
|
3126
|
-
fact(t("manage.expires"), new Date(state.review.expires_at).toISOString());
|
|
3127
|
-
confirm.hidden = false;
|
|
3128
|
-
confirm.textContent = t("pairing.confirm");
|
|
3129
|
-
return;
|
|
3130
|
-
}
|
|
3131
|
-
if (state.phase === "committed") {
|
|
3132
|
-
reviewBox.hidden = true;
|
|
3133
|
-
const receipt = state.receipt;
|
|
3134
|
-
if (state.receipt.action === "pairing_create" && receipt.pairing_id && receipt.machine_id) {
|
|
3135
|
-
const name = flowIntent?.action === "pairing_create" && "name" in flowIntent ? flowIntent.name : entries.get(receipt.pairing_id)?.name ?? receipt.machine_id;
|
|
3136
|
-
addEntry({
|
|
3137
|
-
name,
|
|
3138
|
-
machine_id: receipt.machine_id,
|
|
3139
|
-
pairing_id: receipt.pairing_id,
|
|
3140
|
-
status: "pending",
|
|
3141
|
-
item: node3("li", "pairing-entry")
|
|
3142
|
-
});
|
|
3143
|
-
message.textContent = t("pairing.created");
|
|
3144
|
-
} else if (state.receipt.action === "pairing_claim_approve") {
|
|
3145
|
-
message.textContent = t("pairing.approved");
|
|
3146
|
-
}
|
|
3147
|
-
flow = undefined;
|
|
3148
|
-
flowIntent = undefined;
|
|
3149
|
-
ensurePolling();
|
|
3150
|
-
return;
|
|
3151
|
-
}
|
|
3152
|
-
if (state.phase === "not_committed") {
|
|
3153
|
-
reviewText.textContent = t("manage.notCommitted");
|
|
3154
|
-
flow = undefined;
|
|
3155
|
-
flowIntent = undefined;
|
|
3156
|
-
return;
|
|
3157
|
-
}
|
|
3158
|
-
if (state.phase === "unconfirmed") {
|
|
3159
|
-
reviewText.textContent = t("manage.unknown");
|
|
3160
|
-
check.hidden = false;
|
|
3161
|
-
check.textContent = t("manage.check");
|
|
3162
|
-
return;
|
|
3163
|
-
}
|
|
3164
|
-
if (state.phase === "failed") {
|
|
3165
|
-
reviewText.textContent = t(errors2[state.problem]);
|
|
3166
|
-
if (state.problem === "unauthenticated" || state.problem === "forbidden") {
|
|
3167
|
-
options.authorizationLost(state.problem);
|
|
3168
|
-
}
|
|
3169
|
-
flow = undefined;
|
|
3170
|
-
flowIntent = undefined;
|
|
3171
|
-
return;
|
|
3172
|
-
}
|
|
3173
|
-
reviewBox.hidden = true;
|
|
3174
|
-
}
|
|
3175
|
-
async function start(intent) {
|
|
3176
|
-
if (disposed || !available || flow) {
|
|
3177
|
-
return;
|
|
3178
|
-
}
|
|
3179
|
-
flowIntent = intent;
|
|
3180
|
-
flow = createPairingManagementFlow({ transport: options.transport });
|
|
3181
|
-
paintFlow(await flow.prepare(intent));
|
|
3182
|
-
}
|
|
3183
|
-
function renderEntry(entry) {
|
|
3184
|
-
if (!i18n) {
|
|
3185
|
-
return;
|
|
3186
|
-
}
|
|
3187
|
-
const signature = entryRenderSignature(i18n.language, entry);
|
|
3188
|
-
if (entry.rendered === signature) {
|
|
3189
|
-
return;
|
|
3190
|
-
}
|
|
3191
|
-
entry.rendered = signature;
|
|
3192
|
-
const t = i18n.t.bind(i18n);
|
|
3193
|
-
entry.item.replaceChildren();
|
|
3194
|
-
const head = node3("div", "pairing-entry-head");
|
|
3195
|
-
const title = node3("strong");
|
|
3196
|
-
title.textContent = entry.name;
|
|
3197
|
-
const status = node3("span", "muted");
|
|
3198
|
-
status.textContent = entry.claim?.activation === "configured" ? t("pairing.activated") : entry.status === "paired" ? t("pairing.paired") : entry.status === "failed" ? t("pairing.failed") : entry.status === "expired" || entry.status === "cancelled" ? t("pairing.expired") : entry.claim?.status === "approved" ? t("pairing.approved") : entry.claim ? t("pairing.claimArrived") : t("pairing.waitingClaim");
|
|
3199
|
-
head.append(title, status);
|
|
3200
|
-
entry.item.append(head);
|
|
3201
|
-
status.classList.add("badge");
|
|
3202
|
-
const facts = node3("dl", "facts");
|
|
3203
|
-
const idTerm = node3("dt");
|
|
3204
|
-
idTerm.textContent = t("pairing.application");
|
|
3205
|
-
const idValue = node3("dd");
|
|
3206
|
-
const idCode = node3("code");
|
|
3207
|
-
idCode.textContent = entry.pairing_id;
|
|
3208
|
-
idValue.append(idCode, copyControl(entry.pairing_id, t("copy.id")));
|
|
3209
|
-
const machineTerm = node3("dt");
|
|
3210
|
-
machineTerm.textContent = t("pairing.machine");
|
|
3211
|
-
const machineValue = node3("dd");
|
|
3212
|
-
machineValue.textContent = entry.machine_id;
|
|
3213
|
-
facts.append(idTerm, idValue, machineTerm, machineValue);
|
|
3214
|
-
entry.item.append(facts);
|
|
3215
|
-
updateSteps();
|
|
3216
|
-
if (entry.status === "pending" && entry.claim?.status === "pending") {
|
|
3217
|
-
const codeLabel = node3("p", "muted");
|
|
3218
|
-
codeLabel.textContent = t("pairing.userCode");
|
|
3219
|
-
const code = node3("div", "pairing-code");
|
|
3220
|
-
code.textContent = entry.claim.user_code;
|
|
3221
|
-
const approve = node3("button", "pairing-confirm");
|
|
3222
|
-
approve.type = "button";
|
|
3223
|
-
approve.textContent = t("pairing.approve");
|
|
3224
|
-
const claim = entry.claim;
|
|
3225
|
-
approve.addEventListener("click", () => {
|
|
3226
|
-
start({
|
|
3227
|
-
action: "pairing_claim_approve",
|
|
3228
|
-
machine_id: entry.machine_id,
|
|
3229
|
-
pairing_id: entry.pairing_id,
|
|
3230
|
-
claim_id: claim.claim_id,
|
|
3231
|
-
user_code: claim.user_code
|
|
3232
|
-
});
|
|
3233
|
-
});
|
|
3234
|
-
entry.item.append(codeLabel, code, approve);
|
|
3235
|
-
}
|
|
3236
|
-
}
|
|
3237
|
-
function updateSteps() {
|
|
3238
|
-
const entry = [...entries.values()].at(-1);
|
|
3239
|
-
const finished = entry?.claim?.activation === "configured" || entry?.status === "paired" && !entry.claim;
|
|
3240
|
-
const stage = !entry || ["expired", "failed", "cancelled"].includes(entry.status) ? 0 : finished ? 3 : entry.claim ? 2 : 1;
|
|
3241
|
-
for (const [index, step] of stepItems.entries()) {
|
|
3242
|
-
step.item.dataset.state = index < stage ? "complete" : index === stage ? "current" : "upcoming";
|
|
3243
|
-
if (index === stage) {
|
|
3244
|
-
step.item.setAttribute("aria-current", "step");
|
|
3245
|
-
} else {
|
|
3246
|
-
step.item.removeAttribute("aria-current");
|
|
3247
|
-
}
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
function addEntry(entry) {
|
|
3251
|
-
const existing = entries.get(entry.pairing_id);
|
|
3252
|
-
if (existing) {
|
|
3253
|
-
existing.status = entry.status;
|
|
3254
|
-
renderEntry(existing);
|
|
3255
|
-
return;
|
|
3256
|
-
}
|
|
3257
|
-
entries.set(entry.pairing_id, entry);
|
|
3258
|
-
options.committed?.();
|
|
3259
|
-
list.append(entry.item);
|
|
3260
|
-
renderEntry(entry);
|
|
3261
|
-
}
|
|
3262
|
-
function unfinished(entry) {
|
|
3263
|
-
return entry.status === "pending" || entry.status === "paired" && entry.claim?.status === "delivered";
|
|
3264
|
-
}
|
|
3265
|
-
async function poll() {
|
|
3266
|
-
for (const entry of entries.values()) {
|
|
3267
|
-
if (disposed || !unfinished(entry)) {
|
|
3268
|
-
continue;
|
|
3269
|
-
}
|
|
3270
|
-
try {
|
|
3271
|
-
const args = { machine_id: entry.machine_id, pairing_id: entry.pairing_id };
|
|
3272
|
-
managementWriteBody("pairings_get", args);
|
|
3273
|
-
const reply = await options.transport.execute("pairings_get", args, new AbortController().signal);
|
|
3274
|
-
const status = checkManagementWriteReply("pairings_get", reply, args);
|
|
3275
|
-
entry.status = status.status;
|
|
3276
|
-
entry.claim = status.claim;
|
|
3277
|
-
renderEntry(entry);
|
|
3278
|
-
} catch (error) {
|
|
3279
|
-
if (error instanceof ManagementClientError && (error.problem === "unauthenticated" || error.problem === "forbidden")) {
|
|
3280
|
-
stopPolling();
|
|
3281
|
-
options.authorizationLost(error.problem);
|
|
3282
|
-
return;
|
|
3283
|
-
}
|
|
3284
|
-
}
|
|
3285
|
-
}
|
|
3286
|
-
if (![...entries.values()].some(unfinished)) {
|
|
3287
|
-
stopPolling();
|
|
3288
|
-
}
|
|
3289
|
-
}
|
|
3290
|
-
function ensurePolling() {
|
|
3291
|
-
if (disposed || timer || ![...entries.values()].some(unfinished)) {
|
|
3292
|
-
return;
|
|
3293
|
-
}
|
|
3294
|
-
timer = setInterval(() => {
|
|
3295
|
-
poll();
|
|
3296
|
-
}, pollMs);
|
|
3297
|
-
}
|
|
3298
|
-
function stopPolling() {
|
|
3299
|
-
if (timer) {
|
|
3300
|
-
clearInterval(timer);
|
|
3301
|
-
timer = undefined;
|
|
3302
|
-
}
|
|
3303
|
-
}
|
|
3304
|
-
form.addEventListener("submit", (event) => {
|
|
3305
|
-
event.preventDefault();
|
|
3306
|
-
const name = nameInput.value.trim();
|
|
3307
|
-
const policy = policyInput.value.trim();
|
|
3308
|
-
if (!name || !policy) {
|
|
3309
|
-
return;
|
|
3310
|
-
}
|
|
3311
|
-
start({ action: "pairing_create", name, policy_ref: policy, labels: [] });
|
|
3312
|
-
});
|
|
3313
|
-
confirm.addEventListener("click", () => {
|
|
3314
|
-
if (flow) {
|
|
3315
|
-
flow.confirm().then(paintFlow);
|
|
3316
|
-
}
|
|
3317
|
-
});
|
|
3318
|
-
check.addEventListener("click", () => {
|
|
3319
|
-
if (flow) {
|
|
3320
|
-
flow.checkReceipt().then(paintFlow);
|
|
3321
|
-
}
|
|
3322
|
-
});
|
|
3323
|
-
cancel.addEventListener("click", () => {
|
|
3324
|
-
flow?.cancel();
|
|
3325
|
-
if (flow) {
|
|
3326
|
-
paintFlow(flow.state());
|
|
3327
|
-
}
|
|
3328
|
-
if (flow?.state().phase === "cancelled") {
|
|
3329
|
-
flow = undefined;
|
|
3330
|
-
flowIntent = undefined;
|
|
3331
|
-
}
|
|
3332
|
-
});
|
|
3333
|
-
return {
|
|
3334
|
-
region,
|
|
3335
|
-
update(localizer, isAvailable) {
|
|
3336
|
-
i18n = localizer;
|
|
3337
|
-
available = isAvailable;
|
|
3338
|
-
region.hidden = !isAvailable;
|
|
3339
|
-
const t = localizer.t.bind(localizer);
|
|
3340
|
-
heading.textContent = t("pairing.formTitle");
|
|
3341
|
-
for (const step of stepItems) {
|
|
3342
|
-
step.label.textContent = t(step.key);
|
|
3343
|
-
}
|
|
3344
|
-
updateSteps();
|
|
3345
|
-
nameInput.placeholder = t("pairing.namePlaceholder");
|
|
3346
|
-
nameHint.textContent = t("pairing.nameHint");
|
|
3347
|
-
advancedSummary.textContent = t("pairing.advanced");
|
|
3348
|
-
guideHeading.textContent = t("pairing.guideTitle");
|
|
3349
|
-
guideDescription.textContent = t("pairing.guideDescription");
|
|
3350
|
-
guideNote.textContent = t("pairing.guideNote");
|
|
3351
|
-
commandCopy.setAttribute("aria-label", t("copy.action"));
|
|
3352
|
-
commandCopy.title = t("copy.action");
|
|
3353
|
-
intro.textContent = t("pairing.intro");
|
|
3354
|
-
nameCaption.textContent = t("pairing.name");
|
|
3355
|
-
policyCaption.textContent = t("pairing.policy");
|
|
3356
|
-
create.textContent = t("pairing.create");
|
|
3357
|
-
cancel.textContent = t("pairing.cancel");
|
|
3358
|
-
for (const entry of entries.values()) {
|
|
3359
|
-
renderEntry(entry);
|
|
3360
|
-
}
|
|
3361
|
-
if (flow) {
|
|
3362
|
-
paintFlow(flow.state());
|
|
3363
|
-
}
|
|
3364
|
-
if (isAvailable) {
|
|
3365
|
-
ensurePolling();
|
|
3366
|
-
}
|
|
3367
|
-
},
|
|
3368
|
-
suspend() {
|
|
3369
|
-
stopPolling();
|
|
3370
|
-
},
|
|
3371
|
-
remove(pairingId) {
|
|
3372
|
-
entries.get(pairingId)?.item.remove();
|
|
3373
|
-
entries.delete(pairingId);
|
|
3374
|
-
if (flowIntent && "pairing_id" in flowIntent && flowIntent.pairing_id === pairingId) {
|
|
3375
|
-
flow?.dispose();
|
|
3376
|
-
flow = undefined;
|
|
3377
|
-
flowIntent = undefined;
|
|
3378
|
-
reviewBox.hidden = true;
|
|
3379
|
-
}
|
|
3380
|
-
updateSteps();
|
|
3381
|
-
},
|
|
3382
|
-
clear() {
|
|
3383
|
-
stopPolling();
|
|
3384
|
-
flow?.dispose();
|
|
3385
|
-
flow = undefined;
|
|
3386
|
-
flowIntent = undefined;
|
|
3387
|
-
entries.clear();
|
|
3388
|
-
list.replaceChildren();
|
|
3389
|
-
reviewBox.hidden = true;
|
|
3390
|
-
message.textContent = "";
|
|
3391
|
-
},
|
|
3392
|
-
dispose() {
|
|
3393
|
-
disposed = true;
|
|
3394
|
-
stopPolling();
|
|
3395
|
-
flow?.dispose();
|
|
3396
|
-
}
|
|
3397
|
-
};
|
|
3398
|
-
}
|
|
3399
|
-
|
|
3400
2599
|
// src/webui/resource-client.ts
|
|
3401
2600
|
class ResourceError extends Error {
|
|
3402
2601
|
code;
|
|
@@ -3407,15 +2606,15 @@ class ResourceError extends Error {
|
|
|
3407
2606
|
}
|
|
3408
2607
|
|
|
3409
2608
|
// src/webui/resource-panel.ts
|
|
3410
|
-
function
|
|
2609
|
+
function node3(tag, text = "", className = "") {
|
|
3411
2610
|
const element = document.createElement(tag);
|
|
3412
2611
|
element.textContent = text;
|
|
3413
2612
|
element.className = className;
|
|
3414
2613
|
return element;
|
|
3415
2614
|
}
|
|
3416
2615
|
function createResourcePanel(options) {
|
|
3417
|
-
const region =
|
|
3418
|
-
const feedback =
|
|
2616
|
+
const region = node3("section", "", "resource-panel");
|
|
2617
|
+
const feedback = node3("p", "", "resource-feedback");
|
|
3419
2618
|
feedback.setAttribute("role", "status");
|
|
3420
2619
|
let i18n;
|
|
3421
2620
|
let key = "";
|
|
@@ -3423,14 +2622,15 @@ function createResourcePanel(options) {
|
|
|
3423
2622
|
let pending = false;
|
|
3424
2623
|
let controller = new AbortController;
|
|
3425
2624
|
let data;
|
|
3426
|
-
let cursor = 0;
|
|
3427
2625
|
let tokenName = "";
|
|
3428
2626
|
let tokenDays = "365";
|
|
2627
|
+
let codeName = "";
|
|
2628
|
+
let created;
|
|
3429
2629
|
let version = 0;
|
|
3430
2630
|
let route;
|
|
3431
2631
|
let language = "";
|
|
3432
2632
|
function button(label, action, danger = false) {
|
|
3433
|
-
const result =
|
|
2633
|
+
const result = node3("button", label, danger ? "danger-button" : "");
|
|
3434
2634
|
result.type = "button";
|
|
3435
2635
|
result.disabled = pending;
|
|
3436
2636
|
result.addEventListener("click", action);
|
|
@@ -3454,7 +2654,7 @@ function createResourcePanel(options) {
|
|
|
3454
2654
|
pending = true;
|
|
3455
2655
|
feedback.textContent = i18n.t("resources.loading");
|
|
3456
2656
|
try {
|
|
3457
|
-
const value = await request(key === "connect" ? "tokens_list" : "
|
|
2657
|
+
const value = await request(key === "connect" ? "tokens_list" : "pairing_codes_list", key === "connect" ? {} : {});
|
|
3458
2658
|
if (generation !== version || !active) {
|
|
3459
2659
|
return;
|
|
3460
2660
|
}
|
|
@@ -3483,7 +2683,10 @@ function createResourcePanel(options) {
|
|
|
3483
2683
|
feedback.textContent = i18n.t("resources.saving");
|
|
3484
2684
|
render();
|
|
3485
2685
|
try {
|
|
3486
|
-
await request(operation, args);
|
|
2686
|
+
const reply = operation === "pairing_codes_create" ? await request(operation, args) : await request(operation, args);
|
|
2687
|
+
if (operation === "pairing_codes_create" && reply && typeof reply.code === "string") {
|
|
2688
|
+
created = reply;
|
|
2689
|
+
}
|
|
3487
2690
|
if (generation !== version || !active) {
|
|
3488
2691
|
return;
|
|
3489
2692
|
}
|
|
@@ -3492,6 +2695,9 @@ function createResourcePanel(options) {
|
|
|
3492
2695
|
tokenName = "";
|
|
3493
2696
|
tokenDays = "365";
|
|
3494
2697
|
}
|
|
2698
|
+
if (operation === "pairing_codes_create") {
|
|
2699
|
+
codeName = "";
|
|
2700
|
+
}
|
|
3495
2701
|
if (operation === "devices_delete") {
|
|
3496
2702
|
options.committed(route.machineId ?? undefined);
|
|
3497
2703
|
} else {
|
|
@@ -3521,21 +2727,21 @@ function createResourcePanel(options) {
|
|
|
3521
2727
|
return;
|
|
3522
2728
|
}
|
|
3523
2729
|
const { t } = i18n;
|
|
3524
|
-
const body =
|
|
2730
|
+
const body = node3("div", "", "resource-body");
|
|
3525
2731
|
if (key === "device") {
|
|
3526
|
-
const card =
|
|
3527
|
-
card.append(
|
|
2732
|
+
const card = node3("article", "", "resource-delete-card");
|
|
2733
|
+
card.append(node3("div", t("resources.deleteDeviceNote"), "muted"), button(t("resources.deleteDevice"), () => remove("devices_delete", { machine_id: route.machineId }, t("resources.confirmDevice")), true));
|
|
3528
2734
|
body.append(card);
|
|
3529
2735
|
} else {
|
|
3530
|
-
const heading =
|
|
3531
|
-
heading.append(
|
|
2736
|
+
const heading = node3("div", "", "section-heading");
|
|
2737
|
+
heading.append(node3("h2", t(key === "connect" ? "resources.tokens" : "resources.pairingCodes")), button(t("action.refresh"), () => {
|
|
3532
2738
|
refresh();
|
|
3533
2739
|
}));
|
|
3534
2740
|
body.append(heading);
|
|
3535
2741
|
if (key === "connect") {
|
|
3536
|
-
const form =
|
|
3537
|
-
const nameLabel =
|
|
3538
|
-
const name =
|
|
2742
|
+
const form = node3("form", "", "token-create-form");
|
|
2743
|
+
const nameLabel = node3("label", t("resources.name"));
|
|
2744
|
+
const name = node3("input");
|
|
3539
2745
|
name.name = "token-name";
|
|
3540
2746
|
name.required = true;
|
|
3541
2747
|
name.pattern = "[A-Za-z0-9_-]{1,128}";
|
|
@@ -3547,12 +2753,12 @@ function createResourcePanel(options) {
|
|
|
3547
2753
|
tokenName = name.value;
|
|
3548
2754
|
});
|
|
3549
2755
|
nameLabel.append(name);
|
|
3550
|
-
const daysLabel =
|
|
3551
|
-
const days =
|
|
2756
|
+
const daysLabel = node3("label", t("resources.expiry"));
|
|
2757
|
+
const days = node3("select");
|
|
3552
2758
|
days.name = "token-days";
|
|
3553
2759
|
days.disabled = pending;
|
|
3554
2760
|
for (const value of [365, 90, 30, 7]) {
|
|
3555
|
-
const option =
|
|
2761
|
+
const option = node3("option", t("resources.days", { count: value }));
|
|
3556
2762
|
option.value = String(value);
|
|
3557
2763
|
days.append(option);
|
|
3558
2764
|
}
|
|
@@ -3561,7 +2767,7 @@ function createResourcePanel(options) {
|
|
|
3561
2767
|
tokenDays = days.value;
|
|
3562
2768
|
});
|
|
3563
2769
|
daysLabel.append(days);
|
|
3564
|
-
const submit =
|
|
2770
|
+
const submit = node3("button", t("resources.create"), "primary-button");
|
|
3565
2771
|
submit.type = "submit";
|
|
3566
2772
|
submit.disabled = pending;
|
|
3567
2773
|
form.append(nameLabel, daysLabel, submit);
|
|
@@ -3569,21 +2775,21 @@ function createResourcePanel(options) {
|
|
|
3569
2775
|
event.preventDefault();
|
|
3570
2776
|
mutate("tokens_create", { principal: name.value.trim(), days: Number(days.value) });
|
|
3571
2777
|
});
|
|
3572
|
-
body.append(
|
|
2778
|
+
body.append(node3("p", t("resources.tokenNote"), "muted"), form);
|
|
3573
2779
|
if (data?.resource) {
|
|
3574
|
-
const endpoint =
|
|
3575
|
-
endpoint.append(
|
|
3576
|
-
body.append(endpoint,
|
|
2780
|
+
const endpoint = node3("div", "", "mcp-endpoint");
|
|
2781
|
+
endpoint.append(node3("span", t("resources.endpoint")), node3("code", data.resource), copyControl(data.resource, t("copy.action")));
|
|
2782
|
+
body.append(endpoint, node3("p", t("resources.endpointNote"), "muted"));
|
|
3577
2783
|
}
|
|
3578
2784
|
for (const item of data?.items ?? []) {
|
|
3579
2785
|
const token = item;
|
|
3580
|
-
const card =
|
|
2786
|
+
const card = node3("article", "", "token-card");
|
|
3581
2787
|
card.dataset.tokenPrincipal = token.principal;
|
|
3582
|
-
const summary =
|
|
3583
|
-
summary.append(
|
|
3584
|
-
const controls =
|
|
2788
|
+
const summary = node3("div", "", "token-summary");
|
|
2789
|
+
summary.append(node3("h3", token.principal), node3("span", t(token.expires_at > Date.now() ? "resources.active" : "resources.expired"), "badge"), node3("span", t("resources.expiresAt", { time: i18n.timestamp(token.expires_at) }), "muted"));
|
|
2790
|
+
const controls = node3("div", "", "token-controls");
|
|
3585
2791
|
if (token.token) {
|
|
3586
|
-
const value =
|
|
2792
|
+
const value = node3("input");
|
|
3587
2793
|
value.type = "password";
|
|
3588
2794
|
value.value = token.token;
|
|
3589
2795
|
value.readOnly = true;
|
|
@@ -3597,7 +2803,7 @@ function createResourcePanel(options) {
|
|
|
3597
2803
|
});
|
|
3598
2804
|
controls.append(value, toggle, copyControl(token.token, t("copy.action")));
|
|
3599
2805
|
} else {
|
|
3600
|
-
controls.append(
|
|
2806
|
+
controls.append(node3("span", t("resources.legacy"), "muted"), button(t("resources.reissue"), () => {
|
|
3601
2807
|
if (window.confirm(t("resources.confirmReissue"))) {
|
|
3602
2808
|
mutate("tokens_rotate", { principal: token.principal });
|
|
3603
2809
|
}
|
|
@@ -3608,34 +2814,60 @@ function createResourcePanel(options) {
|
|
|
3608
2814
|
body.append(card);
|
|
3609
2815
|
}
|
|
3610
2816
|
} else {
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
2817
|
+
const host = typeof location === "undefined" ? "127.0.0.1" : location.hostname;
|
|
2818
|
+
const form = node3("form", "", "token-create-form");
|
|
2819
|
+
const nameLabel = node3("label", t("resources.name"));
|
|
2820
|
+
const name = node3("input");
|
|
2821
|
+
name.name = "code-name";
|
|
2822
|
+
name.pattern = "[A-Za-z0-9._-]{0,63}";
|
|
2823
|
+
name.maxLength = 63;
|
|
2824
|
+
name.placeholder = "workstation";
|
|
2825
|
+
name.disabled = pending;
|
|
2826
|
+
name.value = codeName;
|
|
2827
|
+
name.addEventListener("input", () => {
|
|
2828
|
+
codeName = name.value;
|
|
2829
|
+
});
|
|
2830
|
+
nameLabel.append(name);
|
|
2831
|
+
const submit = node3("button", t("resources.createCode"), "primary-button");
|
|
2832
|
+
submit.type = "submit";
|
|
2833
|
+
submit.disabled = pending;
|
|
2834
|
+
form.append(nameLabel, submit);
|
|
2835
|
+
form.addEventListener("submit", (event) => {
|
|
2836
|
+
event.preventDefault();
|
|
2837
|
+
mutate("pairing_codes_create", name.value.trim() ? { name: name.value.trim() } : {});
|
|
2838
|
+
});
|
|
2839
|
+
body.append(node3("p", t("resources.codesNote"), "muted"), form);
|
|
2840
|
+
if (created) {
|
|
2841
|
+
const command = "rovloom connector --join ws://" + host + ":" + created.device_port + "#" + created.code;
|
|
2842
|
+
const card = node3("article", "", "pairing-record code-created");
|
|
2843
|
+
const details = node3("div");
|
|
2844
|
+
details.append(node3("h3", created.name), node3("p", t("resources.codeCreatedNote"), "muted"));
|
|
2845
|
+
const block = node3("div", "", "command-snippet");
|
|
2846
|
+
block.append(node3("code", command), copyControl(command, t("copy.action")));
|
|
2847
|
+
card.append(details, block);
|
|
3618
2848
|
body.append(card);
|
|
2849
|
+
created = undefined;
|
|
3619
2850
|
}
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
2851
|
+
const port = data?.device_port ?? 9443;
|
|
2852
|
+
for (const item of data?.items ?? []) {
|
|
2853
|
+
const entry = item;
|
|
2854
|
+
const card = node3("article", "", "pairing-record");
|
|
2855
|
+
const details = node3("div");
|
|
2856
|
+
const label = t("resources.code_" + entry.status);
|
|
2857
|
+
details.append(node3("h3", entry.name), node3("code", entry.machine_id), node3("p", label + " \xB7 " + i18n.timestamp(entry.created_at) + (entry.used_at ? " \xB7 " + i18n.timestamp(entry.used_at) : ""), "muted"));
|
|
2858
|
+
card.append(details);
|
|
2859
|
+
if (entry.status === "unused" && entry.code) {
|
|
2860
|
+
const command = "rovloom connector --join ws://" + host + ":" + port + "#" + entry.code;
|
|
2861
|
+
const block = node3("div", "", "command-snippet");
|
|
2862
|
+
block.append(node3("code", command), copyControl(command, t("copy.action")));
|
|
2863
|
+
card.append(block);
|
|
2864
|
+
card.append(button(t("resources.revokeCode"), () => remove("pairing_codes_revoke", { code_id: entry.code_id }, t("resources.confirmRevokeCode")), true));
|
|
2865
|
+
}
|
|
2866
|
+
body.append(card);
|
|
3634
2867
|
}
|
|
3635
|
-
body.append(pages);
|
|
3636
2868
|
}
|
|
3637
|
-
if (data?.items.length === 0) {
|
|
3638
|
-
body.append(
|
|
2869
|
+
if (data?.items.length === 0 && key === "connect") {
|
|
2870
|
+
body.append(node3("p", t("resources.emptyTokens"), "empty"));
|
|
3639
2871
|
}
|
|
3640
2872
|
}
|
|
3641
2873
|
region.replaceChildren(body, feedback);
|
|
@@ -3644,9 +2876,10 @@ function createResourcePanel(options) {
|
|
|
3644
2876
|
active = false;
|
|
3645
2877
|
key = "";
|
|
3646
2878
|
data = undefined;
|
|
3647
|
-
cursor = 0;
|
|
3648
2879
|
tokenName = "";
|
|
3649
2880
|
tokenDays = "365";
|
|
2881
|
+
codeName = "";
|
|
2882
|
+
created = undefined;
|
|
3650
2883
|
version++;
|
|
3651
2884
|
controller.abort();
|
|
3652
2885
|
pending = false;
|
|
@@ -3677,8 +2910,8 @@ function createResourcePanel(options) {
|
|
|
3677
2910
|
region.hidden = false;
|
|
3678
2911
|
if (changed) {
|
|
3679
2912
|
key = nextKey;
|
|
3680
|
-
cursor = 0;
|
|
3681
2913
|
data = undefined;
|
|
2914
|
+
created = undefined;
|
|
3682
2915
|
version++;
|
|
3683
2916
|
controller.abort();
|
|
3684
2917
|
controller = new AbortController;
|
|
@@ -3803,37 +3036,16 @@ function mountWebUi(root, read = unavailableRead, clock, management, resources)
|
|
|
3803
3036
|
if (actions) {
|
|
3804
3037
|
footer.before(actions.region);
|
|
3805
3038
|
}
|
|
3806
|
-
const pairing = management ? createPairingActions({
|
|
3807
|
-
transport: management,
|
|
3808
|
-
committed() {
|
|
3809
|
-
resourcePanel?.refresh();
|
|
3810
|
-
},
|
|
3811
|
-
authorizationLost(problem) {
|
|
3812
|
-
if (disposed) {
|
|
3813
|
-
return;
|
|
3814
|
-
}
|
|
3815
|
-
reader.dispose();
|
|
3816
|
-
actions?.clear();
|
|
3817
|
-
pairing?.clear();
|
|
3818
|
-
paint({ snapshot: null, pending: false, stale: true, ageMs: 0, problem }, route);
|
|
3819
|
-
}
|
|
3820
|
-
}) : undefined;
|
|
3821
|
-
if (pairing) {
|
|
3822
|
-
footer.before(pairing.region);
|
|
3823
|
-
}
|
|
3824
3039
|
const resourcePanel = resources ? createResourcePanel({
|
|
3825
3040
|
transport: resources,
|
|
3826
|
-
committed(machine
|
|
3041
|
+
committed(machine) {
|
|
3827
3042
|
if (machine) {
|
|
3828
3043
|
location.hash = "#view=devices";
|
|
3829
|
-
} else if (pairingId) {
|
|
3830
|
-
pairing?.remove(pairingId);
|
|
3831
3044
|
}
|
|
3832
3045
|
},
|
|
3833
3046
|
authorizationLost(problem) {
|
|
3834
3047
|
reader.dispose();
|
|
3835
3048
|
actions?.clear();
|
|
3836
|
-
pairing?.clear();
|
|
3837
3049
|
paint({ snapshot: null, pending: false, stale: true, ageMs: 0, problem }, route);
|
|
3838
3050
|
}
|
|
3839
3051
|
}) : undefined;
|
|
@@ -3848,9 +3060,7 @@ function mountWebUi(root, read = unavailableRead, clock, management, resources)
|
|
|
3848
3060
|
indicator.dataset.state = state.pending ? "pending" : state.stale ? "stale" : state.snapshot ? "current" : "empty";
|
|
3849
3061
|
if (["unauthenticated", "forbidden", "not_found"].includes(state.problem ?? "")) {
|
|
3850
3062
|
actions?.clear();
|
|
3851
|
-
pairing?.clear();
|
|
3852
3063
|
}
|
|
3853
|
-
pairing?.update(i18n, !!state.snapshot && !state.stale && state.snapshot.value.status.mode === "active");
|
|
3854
3064
|
actions?.update(i18n, !!state.snapshot && !state.stale && state.snapshot.value.status.mode === "active", state.snapshot ? state.snapshot.observedAt + state.ageMs : undefined);
|
|
3855
3065
|
const section = current.machineId ? "devices" : current.section ?? "overview";
|
|
3856
3066
|
content.dataset.section = section;
|
|
@@ -3865,9 +3075,6 @@ function mountWebUi(root, read = unavailableRead, clock, management, resources)
|
|
|
3865
3075
|
const active = !!state.snapshot && !state.stale && state.snapshot.value.status.mode === "active";
|
|
3866
3076
|
sidebarStatus.dataset.state = active ? "current" : "unknown";
|
|
3867
3077
|
statusValue.textContent = i18n.t(active ? "gateway.active" : state.snapshot ? state.stale ? "reader.stale" : "gateway.degraded" : "reader.empty");
|
|
3868
|
-
if (pairing) {
|
|
3869
|
-
pairing.region.hidden = section !== "pairing" || !active;
|
|
3870
|
-
}
|
|
3871
3078
|
renderPage(content, state, current, i18n, !!actions, filter);
|
|
3872
3079
|
const authorized = active && !["unauthenticated", "forbidden", "not_found"].includes(state.problem ?? "");
|
|
3873
3080
|
resourcePanel?.update(current, i18n, authorized);
|
|
@@ -4001,7 +3208,6 @@ function mountWebUi(root, read = unavailableRead, clock, management, resources)
|
|
|
4001
3208
|
function navigate() {
|
|
4002
3209
|
filter = { query: "", status: "all" };
|
|
4003
3210
|
actions?.suspend();
|
|
4004
|
-
pairing?.suspend();
|
|
4005
3211
|
if (location.hash === "#management-content") {
|
|
4006
3212
|
content.focus();
|
|
4007
3213
|
return;
|
|
@@ -4014,7 +3220,6 @@ function mountWebUi(root, read = unavailableRead, clock, management, resources)
|
|
|
4014
3220
|
function visibility() {
|
|
4015
3221
|
if (document.visibilityState === "hidden") {
|
|
4016
3222
|
actions?.suspend();
|
|
4017
|
-
pairing?.suspend();
|
|
4018
3223
|
}
|
|
4019
3224
|
reader.visible(document.visibilityState !== "hidden");
|
|
4020
3225
|
}
|
|
@@ -4028,7 +3233,6 @@ function mountWebUi(root, read = unavailableRead, clock, management, resources)
|
|
|
4028
3233
|
}
|
|
4029
3234
|
function hide() {
|
|
4030
3235
|
actions?.suspend();
|
|
4031
|
-
pairing?.suspend();
|
|
4032
3236
|
reader.dispose();
|
|
4033
3237
|
resourcePanel?.clear();
|
|
4034
3238
|
content.replaceChildren();
|
|
@@ -4041,7 +3245,6 @@ function mountWebUi(root, read = unavailableRead, clock, management, resources)
|
|
|
4041
3245
|
reader.dispose();
|
|
4042
3246
|
resourcePanel?.dispose();
|
|
4043
3247
|
actions?.dispose();
|
|
4044
|
-
pairing?.dispose();
|
|
4045
3248
|
content.removeEventListener("click", deviceAction);
|
|
4046
3249
|
content.removeEventListener("click", filterDevices);
|
|
4047
3250
|
content.removeEventListener("input", searchDevices);
|
|
@@ -4448,7 +3651,6 @@ export {
|
|
|
4448
3651
|
createManagementPageCsrf,
|
|
4449
3652
|
createManagementPageRead,
|
|
4450
3653
|
createManagementWriteClient,
|
|
4451
|
-
createPairingManagementFlow,
|
|
4452
3654
|
createSnapshotReader2 as createSnapshotReader,
|
|
4453
3655
|
mountWebUi,
|
|
4454
3656
|
parseRoute,
|
|
@@ -4456,4 +3658,4 @@ export {
|
|
|
4456
3658
|
unavailableRead
|
|
4457
3659
|
};
|
|
4458
3660
|
|
|
4459
|
-
//# debugId=
|
|
3661
|
+
//# debugId=57232E8032FB7D7964756E2164756E21
|