dsh-remote-control 1.0.0 → 1.2.0
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/cordis.patch.yml +4 -0
- package/dist/bundle/client.cjs +484 -0
- package/dist/bundle/index.js +577 -433
- package/package.json +14 -6
- package/dist/src/core/clock.d.ts +0 -45
- package/dist/src/core/clock.js +0 -83
- package/dist/src/core/clock.js.map +0 -1
- package/dist/src/core/keys.d.ts +0 -98
- package/dist/src/core/keys.js +0 -176
- package/dist/src/core/keys.js.map +0 -1
- package/dist/src/core/pairing-window.d.ts +0 -95
- package/dist/src/core/pairing-window.js +0 -92
- package/dist/src/core/pairing-window.js.map +0 -1
- package/dist/src/core/runtime.d.ts +0 -104
- package/dist/src/core/runtime.js +0 -491
- package/dist/src/core/runtime.js.map +0 -1
- package/dist/src/core/sleep-policy.d.ts +0 -81
- package/dist/src/core/sleep-policy.js +0 -134
- package/dist/src/core/sleep-policy.js.map +0 -1
- package/dist/src/core/window.d.ts +0 -88
- package/dist/src/core/window.js +0 -185
- package/dist/src/core/window.js.map +0 -1
- package/dist/src/index.d.ts +0 -70
- package/dist/src/index.js +0 -882
- package/dist/src/index.js.map +0 -1
- package/dist/src/platform/carrier-services.d.ts +0 -96
- package/dist/src/platform/carrier-services.js +0 -982
- package/dist/src/platform/carrier-services.js.map +0 -1
- package/dist/src/platform/guard.d.ts +0 -60
- package/dist/src/platform/guard.js +0 -124
- package/dist/src/platform/guard.js.map +0 -1
- package/dist/src/platform/mock-kernel.d.ts +0 -95
- package/dist/src/platform/mock-kernel.js +0 -180
- package/dist/src/platform/mock-kernel.js.map +0 -1
- package/dist/src/platform/qr.d.ts +0 -28
- package/dist/src/platform/qr.js +0 -80
- package/dist/src/platform/qr.js.map +0 -1
- package/dist/src/platform/sleep-posix.d.ts +0 -17
- package/dist/src/platform/sleep-posix.js +0 -91
- package/dist/src/platform/sleep-posix.js.map +0 -1
- package/dist/src/ports/index.d.ts +0 -246
- package/dist/src/ports/index.js +0 -2
- package/dist/src/ports/index.js.map +0 -1
- package/dist/src/shell/config.d.ts +0 -56
- package/dist/src/shell/config.js +0 -212
- package/dist/src/shell/config.js.map +0 -1
- package/dist/src/shell/pairing-text.d.ts +0 -38
- package/dist/src/shell/pairing-text.js +0 -22
- package/dist/src/shell/pairing-text.js.map +0 -1
- package/dist/src/shell/status.d.ts +0 -39
- package/dist/src/shell/status.js +0 -119
- package/dist/src/shell/status.js.map +0 -1
- package/dist/src/transport/relay.d.ts +0 -107
- package/dist/src/transport/relay.js +0 -359
- package/dist/src/transport/relay.js.map +0 -1
- package/dist/tests/carrier-events.test.d.ts +0 -1
- package/dist/tests/carrier-events.test.js +0 -88
- package/dist/tests/carrier-events.test.js.map +0 -1
- package/dist/tests/carrier-services.test.d.ts +0 -1
- package/dist/tests/carrier-services.test.js +0 -562
- package/dist/tests/carrier-services.test.js.map +0 -1
- package/dist/tests/carrier-vocabulary.test.d.ts +0 -1
- package/dist/tests/carrier-vocabulary.test.js +0 -149
- package/dist/tests/carrier-vocabulary.test.js.map +0 -1
- package/dist/tests/clock-probe-timers.test.d.ts +0 -1
- package/dist/tests/clock-probe-timers.test.js +0 -73
- package/dist/tests/clock-probe-timers.test.js.map +0 -1
- package/dist/tests/command-result.test.d.ts +0 -1
- package/dist/tests/command-result.test.js +0 -185
- package/dist/tests/command-result.test.js.map +0 -1
- package/dist/tests/config.test.d.ts +0 -1
- package/dist/tests/config.test.js +0 -223
- package/dist/tests/config.test.js.map +0 -1
- package/dist/tests/guard.test.d.ts +0 -1
- package/dist/tests/guard.test.js +0 -175
- package/dist/tests/guard.test.js.map +0 -1
- package/dist/tests/ids-and-keys.test.d.ts +0 -1
- package/dist/tests/ids-and-keys.test.js +0 -211
- package/dist/tests/ids-and-keys.test.js.map +0 -1
- package/dist/tests/pairing-text.test.d.ts +0 -1
- package/dist/tests/pairing-text.test.js +0 -62
- package/dist/tests/pairing-text.test.js.map +0 -1
- package/dist/tests/pairing-window.test.d.ts +0 -1
- package/dist/tests/pairing-window.test.js +0 -165
- package/dist/tests/pairing-window.test.js.map +0 -1
- package/dist/tests/relay-client.test.d.ts +0 -1
- package/dist/tests/relay-client.test.js +0 -557
- package/dist/tests/relay-client.test.js.map +0 -1
- package/dist/tests/runtime.test.d.ts +0 -1
- package/dist/tests/runtime.test.js +0 -963
- package/dist/tests/runtime.test.js.map +0 -1
- package/dist/tests/sleep.test.d.ts +0 -1
- package/dist/tests/sleep.test.js +0 -264
- package/dist/tests/sleep.test.js.map +0 -1
- package/dist/tests/status.test.d.ts +0 -1
- package/dist/tests/status.test.js +0 -238
- package/dist/tests/status.test.js.map +0 -1
- package/dist/tests/window.test.d.ts +0 -1
- package/dist/tests/window.test.js +0 -210
- package/dist/tests/window.test.js.map +0 -1
package/cordis.patch.yml
CHANGED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-remote-control",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name2 in all)
|
|
14
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
|
|
26
|
+
// client/src/main.ts
|
|
27
|
+
var main_exports = {};
|
|
28
|
+
__export(main_exports, {
|
|
29
|
+
apply: () => apply,
|
|
30
|
+
inject: () => inject,
|
|
31
|
+
name: () => name
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(main_exports);
|
|
34
|
+
|
|
35
|
+
// client/src/pill.ts
|
|
36
|
+
var STATUS_ROUTE = "/plugins/dsh-remote-control/status";
|
|
37
|
+
var NEW_ROUTE = "/plugins/dsh-remote-control/pairing/new";
|
|
38
|
+
var IMAGE_ROUTE = "/plugins/dsh-remote-control/pairing.png";
|
|
39
|
+
var SLOT_NAME = "conversation.composer.dock";
|
|
40
|
+
var PILL_ID = "dsh-remote-control";
|
|
41
|
+
var PILL_ORDER = 20;
|
|
42
|
+
var STYLE_ID = "dsh-remote-control/pill.css";
|
|
43
|
+
var POLL_MS = 2e3;
|
|
44
|
+
function panelViewFor(answer, httpStatus) {
|
|
45
|
+
if (!answer || typeof answer !== "object") return { kind: "failed", detail: `HTTP ${httpStatus}` };
|
|
46
|
+
if (answer.state === "ready") {
|
|
47
|
+
const token = typeof answer.token === "string" ? answer.token : "";
|
|
48
|
+
const epoch = typeof answer.epoch === "string" ? answer.epoch : "";
|
|
49
|
+
const expiresInMs = typeof answer.expiresInMs === "number" ? answer.expiresInMs : 0;
|
|
50
|
+
if (token === "" || expiresInMs <= 0) return { kind: "failed", detail: "\u53D1\u7801\u56DE\u7B54\u91CC\u7684\u7801\u4E0D\u5B8C\u6574" };
|
|
51
|
+
return { kind: "qr", token, expiresInMs, imageSrc: `${IMAGE_ROUTE}?e=${encodeURIComponent(epoch)}` };
|
|
52
|
+
}
|
|
53
|
+
if (answer.state === "unavailable") {
|
|
54
|
+
return {
|
|
55
|
+
kind: "unavailable",
|
|
56
|
+
reason: answer.reason === "relay-offline" ? "\u4E2D\u7EE7\u8FD8\u6CA1\u8FDE\u4E0A\uFF0C\u6682\u65F6\u65E0\u6CD5\u914D\u5BF9\u3002" : "\u73B0\u5728\u53D1\u4E0D\u51FA\u914D\u5BF9\u7801\u3002"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
kind: "failed",
|
|
61
|
+
// 把宿主说的那道守卫一起印出来:这条路由在浏览器里点,屏幕上的这句话就是唯一的现场。
|
|
62
|
+
detail: typeof answer.error === "string" ? typeof answer.guard === "string" ? `${answer.error}\uFF08${answer.guard}\uFF09` : answer.error : `HTTP ${httpStatus}`
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function pillLabel(status) {
|
|
66
|
+
const relay = status?.relay;
|
|
67
|
+
if (relay === "idle") return { text: "\u8FDC\u7A0B\u672A\u542F\u52A8", tone: "off" };
|
|
68
|
+
if (relay === "offline") return { text: "\u8FDC\u7A0B\u672A\u8FDE\u63A5", tone: "off" };
|
|
69
|
+
if (relay === "connecting") return { text: "\u8FDE\u63A5\u4E2D", tone: "wait" };
|
|
70
|
+
if (relay !== "online") return { text: "\u8FDC\u7A0B\u63A7\u5236", tone: "off" };
|
|
71
|
+
const paired = typeof status?.paired === "number" ? status.paired : 0;
|
|
72
|
+
return paired > 0 ? { text: "\u5DF2\u914D\u5BF9", tone: "on" } : { text: "\u672A\u914D\u5BF9", tone: "off" };
|
|
73
|
+
}
|
|
74
|
+
var RELAY_TEXT = {
|
|
75
|
+
online: "\u5DF2\u8FDE\u63A5",
|
|
76
|
+
connecting: "\u8FDE\u63A5\u4E2D",
|
|
77
|
+
offline: "\u672A\u8FDE\u63A5",
|
|
78
|
+
idle: "\u672A\u542F\u52A8"
|
|
79
|
+
};
|
|
80
|
+
function relayAddress(url) {
|
|
81
|
+
if (typeof url !== "string" || url.trim() === "") return "";
|
|
82
|
+
const withoutScheme = url.trim().replace(/^[a-z][a-z0-9+.-]*:\/\//i, "");
|
|
83
|
+
const authority = /^[^/?]*/.exec(withoutScheme)?.[0] ?? "";
|
|
84
|
+
return authority.slice(0, 40);
|
|
85
|
+
}
|
|
86
|
+
function infoRows(status) {
|
|
87
|
+
const rows = [];
|
|
88
|
+
const label = typeof status?.hostLabel === "string" ? status.hostLabel.trim() : "";
|
|
89
|
+
if (label !== "") rows.push(["\u672C\u673A", label]);
|
|
90
|
+
const server = relayAddress(status?.serverUrl);
|
|
91
|
+
if (server !== "") rows.push(["\u4E2D\u7EE7", server]);
|
|
92
|
+
const relay = typeof status?.relay === "string" ? status.relay : "";
|
|
93
|
+
rows.push(["\u72B6\u6001", RELAY_TEXT[relay] ?? "\u672A\u77E5"]);
|
|
94
|
+
rows.push(["\u5DF2\u914D\u5BF9", `${typeof status?.paired === "number" ? status.paired : 0} \u53F0`]);
|
|
95
|
+
return rows;
|
|
96
|
+
}
|
|
97
|
+
function secondsText(ms) {
|
|
98
|
+
const whole = Math.max(0, Math.round(ms / 1e3));
|
|
99
|
+
if (whole < 60) return `${whole} \u79D2`;
|
|
100
|
+
return `${Math.floor(whole / 60)} \u5206 ${whole % 60} \u79D2`;
|
|
101
|
+
}
|
|
102
|
+
var CSS = `
|
|
103
|
+
.drc-pill { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 2px 8px;
|
|
104
|
+
border: 0; border-radius: 999px; background: transparent; color: inherit; font: inherit;
|
|
105
|
+
font-size: 12px; line-height: 18px; cursor: pointer;
|
|
106
|
+
/* \u5BBF\u4E3B\u90A3\u4E00\u6392\u6324\u4E0D\u4E0B\u65F6\u4F1A\u81EA\u5DF1\u622A\u65AD\uFF08\u300C6 \u8F6E \u2026\u300D\u90A3\u79CD\uFF09\uFF0C\u6211\u4EEC\u4E5F\u8DDF\u8FD9\u4E2A\u5F62\u72B6\u8D70\uFF1A
|
|
107
|
+
\u4E00\u884C\u5199\u5B8C\uFF0C\u5199\u4E0D\u4E0B\u5C31\u7701\u7565\u53F7\u3002**\u6CA1\u6709\u8FD9\u4E24\u6761**\u7684\u8BDD\uFF0Cflex \u9879\u4F1A\u88AB\u538B\u5230\u300C\u4E2D\u6587\u6700\u5C0F\u5185\u5BB9\u5BBD\u5EA6
|
|
108
|
+
= \u4E00\u4E2A\u5B57\u300D\uFF0C\u4E8E\u662F\u300C\u5DF2\u8FDE 1 \u53F0\u300D\u7AD6\u7740\u6392\u6210\u56DB\u884C\uFF082026-10-03 \u771F\u5C4F\u5E55\u622A\u56FE\uFF09\u3002 */
|
|
109
|
+
flex: 0 1 auto; white-space: nowrap; }
|
|
110
|
+
.drc-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
111
|
+
.drc-pill:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04)); }
|
|
112
|
+
.drc-dot { width: 6px; height: 6px; flex: 0 0 auto; border-radius: 50%; background: var(--dsw-alias-label-dimmed, #9aa0a6); }
|
|
113
|
+
.drc-dot[data-tone="wait"] { background: var(--dsw-alias-state-warn-primary, #faad14); }
|
|
114
|
+
.drc-dot[data-tone="on"] { background: var(--dsw-alias-state-success-primary, #52c41a); }
|
|
115
|
+
.drc-panel { position: absolute; bottom: calc(100% + 8px); right: 0; z-index: 30; width: 240px;
|
|
116
|
+
padding: 12px 14px; border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, 0.1)); border-radius: 12px;
|
|
117
|
+
background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-1, #ffffff));
|
|
118
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14), 0 2px 6px rgba(0, 0, 0, 0.06);
|
|
119
|
+
color: var(--dsw-alias-label-primary); font-size: 12px; line-height: 18px; }
|
|
120
|
+
/* \u8FDE\u63A5\u4FE1\u606F\u90A3\u4E00\u680F\uFF1A\u952E\u5DE6\u503C\u53F3\uFF0C\u503C\u88AB\u622A\u65AD\u65F6\u7701\u7565\u53F7\u2014\u2014\u548C\u90A3\u9897 pill \u540C\u4E00\u5957"\u6324\u4E0D\u4E0B\u5C31\u622A\u6587\u5B57\u4E0D\u6491\u5BB9\u5668"\u3002 */
|
|
121
|
+
.drc-info { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px;
|
|
122
|
+
padding-bottom: 6px; border-bottom: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, 0.08)); }
|
|
123
|
+
.drc-row { display: flex; align-items: baseline; gap: 8px; white-space: nowrap; }
|
|
124
|
+
.drc-key { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary); }
|
|
125
|
+
.drc-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; text-align: right; }
|
|
126
|
+
.drc-qr { display: block; width: 200px; height: 200px; margin: 0 auto; image-rendering: pixelated; }
|
|
127
|
+
.drc-code { margin: 8px 0 0; text-align: center; font-weight: 600; font-size: 14px; letter-spacing: 2px; }
|
|
128
|
+
.drc-note { margin: 4px 0 0; text-align: center; color: var(--dsw-alias-label-tertiary); }
|
|
129
|
+
.drc-note[data-kind="failed"] { color: var(--dsw-alias-state-error-primary, #ff4d4f); }
|
|
130
|
+
.drc-actions { display: flex; gap: 6px; justify-content: center; margin-top: 8px; }
|
|
131
|
+
.drc-btn { padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, 0.1));
|
|
132
|
+
border-radius: 8px; background: transparent; color: inherit; font: inherit; font-size: 12px; cursor: pointer; }
|
|
133
|
+
`;
|
|
134
|
+
function isSlots(value) {
|
|
135
|
+
if (!value || typeof value !== "object") return false;
|
|
136
|
+
const record = value;
|
|
137
|
+
return typeof record.inject === "function" && typeof record.register === "function";
|
|
138
|
+
}
|
|
139
|
+
function pickSlots(source) {
|
|
140
|
+
if (isSlots(source)) return source;
|
|
141
|
+
const asGettable = source;
|
|
142
|
+
if (asGettable && typeof asGettable.get === "function") {
|
|
143
|
+
try {
|
|
144
|
+
const got = asGettable.get("slots", true);
|
|
145
|
+
if (isSlots(got)) return got;
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return void 0;
|
|
150
|
+
}
|
|
151
|
+
function findCreateElement() {
|
|
152
|
+
try {
|
|
153
|
+
if (typeof require !== "function") return void 0;
|
|
154
|
+
const moduleId = "react";
|
|
155
|
+
const react = require(moduleId);
|
|
156
|
+
const create = react?.createElement ?? react?.default?.createElement;
|
|
157
|
+
return typeof create === "function" ? create : void 0;
|
|
158
|
+
} catch {
|
|
159
|
+
return void 0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function warn(message, error) {
|
|
163
|
+
try {
|
|
164
|
+
const detail = error instanceof Error ? error.message : error === void 0 ? "" : String(error);
|
|
165
|
+
console.warn(`[dsh-remote-control pill] ${message} ${detail}`);
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function ensureStyle(doc) {
|
|
170
|
+
try {
|
|
171
|
+
if (doc.querySelector(`style[data-plugin-css="${STYLE_ID}"]`)) return;
|
|
172
|
+
const element = doc.createElement("style");
|
|
173
|
+
element.setAttribute("data-plugin-css", STYLE_ID);
|
|
174
|
+
element.textContent = CSS;
|
|
175
|
+
doc.head.appendChild(element);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
warn("\u6837\u5F0F\u6CE8\u5165\u5931\u8D25\uFF08pill \u4ECD\u53EF\u7528\uFF0C\u53EA\u662F\u6CA1\u914D\u8272\uFF09", error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function buildPill(root, deps) {
|
|
181
|
+
const doc = root.ownerDocument;
|
|
182
|
+
ensureStyle(doc);
|
|
183
|
+
const button = doc.createElement("button");
|
|
184
|
+
button.type = "button";
|
|
185
|
+
button.className = "drc-pill";
|
|
186
|
+
button.setAttribute("aria-haspopup", "dialog");
|
|
187
|
+
button.setAttribute("aria-expanded", "false");
|
|
188
|
+
const dot = doc.createElement("span");
|
|
189
|
+
dot.className = "drc-dot";
|
|
190
|
+
dot.setAttribute("aria-hidden", "true");
|
|
191
|
+
const label = doc.createElement("span");
|
|
192
|
+
label.className = "drc-label";
|
|
193
|
+
button.appendChild(dot);
|
|
194
|
+
button.appendChild(label);
|
|
195
|
+
root.appendChild(button);
|
|
196
|
+
let panel;
|
|
197
|
+
let statusTimer;
|
|
198
|
+
let countTimer;
|
|
199
|
+
let view = { kind: "info" };
|
|
200
|
+
let expiresInMs = 0;
|
|
201
|
+
let lastStatus;
|
|
202
|
+
let disposed = false;
|
|
203
|
+
const pairedNow = () => typeof lastStatus?.paired === "number" ? lastStatus.paired : 0;
|
|
204
|
+
const write = () => {
|
|
205
|
+
const next = pillLabel(lastStatus);
|
|
206
|
+
label.textContent = next.text;
|
|
207
|
+
dot.setAttribute("data-tone", next.tone);
|
|
208
|
+
button.setAttribute("title", `dsh-remote-control\uFF1A${next.text}`);
|
|
209
|
+
button.setAttribute("aria-label", next.text);
|
|
210
|
+
};
|
|
211
|
+
const text = (tag, className, content) => {
|
|
212
|
+
const node = doc.createElement(tag);
|
|
213
|
+
node.className = className;
|
|
214
|
+
node.textContent = content;
|
|
215
|
+
return node;
|
|
216
|
+
};
|
|
217
|
+
const buttonOf = (content, onClick) => {
|
|
218
|
+
const node = doc.createElement("button");
|
|
219
|
+
node.type = "button";
|
|
220
|
+
node.className = "drc-btn";
|
|
221
|
+
node.textContent = content;
|
|
222
|
+
node.addEventListener("click", onClick);
|
|
223
|
+
return node;
|
|
224
|
+
};
|
|
225
|
+
const infoBlock = () => {
|
|
226
|
+
if (!lastStatus) return void 0;
|
|
227
|
+
const box = doc.createElement("div");
|
|
228
|
+
box.className = "drc-info";
|
|
229
|
+
for (const [key, value] of infoRows(lastStatus)) {
|
|
230
|
+
const row = doc.createElement("div");
|
|
231
|
+
row.className = "drc-row";
|
|
232
|
+
row.appendChild(text("span", "drc-key", key));
|
|
233
|
+
row.appendChild(text("span", "drc-value", value));
|
|
234
|
+
box.appendChild(row);
|
|
235
|
+
}
|
|
236
|
+
return box;
|
|
237
|
+
};
|
|
238
|
+
const paint = () => {
|
|
239
|
+
if (!panel) return;
|
|
240
|
+
panel.replaceChildren();
|
|
241
|
+
const info = infoBlock();
|
|
242
|
+
if (info) panel.appendChild(info);
|
|
243
|
+
if (view.kind === "info") {
|
|
244
|
+
const actions2 = doc.createElement("div");
|
|
245
|
+
actions2.className = "drc-actions";
|
|
246
|
+
actions2.appendChild(buttonOf(pairedNow() > 0 ? "\u518D\u914D\u4E00\u53F0" : "\u751F\u6210\u914D\u5BF9\u7801", () => void requestPairing()));
|
|
247
|
+
panel.appendChild(actions2);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (view.kind === "loading") {
|
|
251
|
+
panel.appendChild(text("p", "drc-note", "\u6B63\u5728\u751F\u6210\u914D\u5BF9\u7801\u2026"));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (view.kind === "qr") {
|
|
255
|
+
const image = doc.createElement("img");
|
|
256
|
+
image.className = "drc-qr";
|
|
257
|
+
image.setAttribute("alt", "\u914D\u5BF9\u4E8C\u7EF4\u7801");
|
|
258
|
+
image.src = view.imageSrc;
|
|
259
|
+
panel.appendChild(image);
|
|
260
|
+
panel.appendChild(text("p", "drc-code", view.token));
|
|
261
|
+
panel.appendChild(text("p", "drc-note", `\u626B\u7801\u914D\u5BF9 \xB7 ${secondsText(expiresInMs)}\u540E\u8FC7\u671F`));
|
|
262
|
+
const actions2 = doc.createElement("div");
|
|
263
|
+
actions2.className = "drc-actions";
|
|
264
|
+
actions2.appendChild(buttonOf("\u6362\u4E00\u5F20", () => void requestPairing()));
|
|
265
|
+
panel.appendChild(actions2);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const note = view.kind === "unavailable" ? text("p", "drc-note", view.reason) : (() => {
|
|
269
|
+
const node = text("p", "drc-note", `\u914D\u5BF9\u8BF7\u6C42\u6CA1\u6210\u529F\uFF1A${view.detail}`);
|
|
270
|
+
node.setAttribute("data-kind", "failed");
|
|
271
|
+
return node;
|
|
272
|
+
})();
|
|
273
|
+
panel.appendChild(note);
|
|
274
|
+
const actions = doc.createElement("div");
|
|
275
|
+
actions.className = "drc-actions";
|
|
276
|
+
actions.appendChild(buttonOf("\u518D\u8BD5\u4E00\u6B21", () => void requestPairing()));
|
|
277
|
+
panel.appendChild(actions);
|
|
278
|
+
};
|
|
279
|
+
const closePanel = () => {
|
|
280
|
+
if (countTimer !== void 0) {
|
|
281
|
+
clearInterval(countTimer);
|
|
282
|
+
countTimer = void 0;
|
|
283
|
+
}
|
|
284
|
+
if (panel) {
|
|
285
|
+
panel.remove();
|
|
286
|
+
panel = void 0;
|
|
287
|
+
}
|
|
288
|
+
button.setAttribute("aria-expanded", "false");
|
|
289
|
+
};
|
|
290
|
+
async function requestPairing() {
|
|
291
|
+
if (disposed || !panel) return;
|
|
292
|
+
view = { kind: "loading" };
|
|
293
|
+
paint();
|
|
294
|
+
let answer;
|
|
295
|
+
let httpStatus = 0;
|
|
296
|
+
try {
|
|
297
|
+
const response = await deps.fetchImpl(NEW_ROUTE, {
|
|
298
|
+
method: "POST",
|
|
299
|
+
headers: { "x-drc-pair": "1" },
|
|
300
|
+
credentials: "same-origin"
|
|
301
|
+
});
|
|
302
|
+
httpStatus = typeof response?.status === "number" ? response.status : 0;
|
|
303
|
+
answer = await response?.json?.();
|
|
304
|
+
} catch (error) {
|
|
305
|
+
view = { kind: "failed", detail: error instanceof Error ? error.message : String(error) };
|
|
306
|
+
paint();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (disposed || !panel) return;
|
|
310
|
+
view = panelViewFor(answer, httpStatus);
|
|
311
|
+
if (view.kind === "qr") {
|
|
312
|
+
expiresInMs = view.expiresInMs;
|
|
313
|
+
if (countTimer === void 0) {
|
|
314
|
+
countTimer = setInterval(() => {
|
|
315
|
+
expiresInMs -= 1e3;
|
|
316
|
+
if (expiresInMs <= 0) void requestPairing();
|
|
317
|
+
else paint();
|
|
318
|
+
}, 1e3);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
paint();
|
|
322
|
+
}
|
|
323
|
+
const openPanel = () => {
|
|
324
|
+
if (panel || disposed) return;
|
|
325
|
+
panel = doc.createElement("div");
|
|
326
|
+
panel.className = "drc-panel";
|
|
327
|
+
panel.setAttribute("role", "dialog");
|
|
328
|
+
panel.setAttribute("aria-label", "dsh-remote-control \u8FDE\u63A5\u4FE1\u606F");
|
|
329
|
+
panel.tabIndex = -1;
|
|
330
|
+
root.appendChild(panel);
|
|
331
|
+
button.setAttribute("aria-expanded", "true");
|
|
332
|
+
view = { kind: "info" };
|
|
333
|
+
paint();
|
|
334
|
+
try {
|
|
335
|
+
panel.focus();
|
|
336
|
+
} catch {
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
const inside = (candidate) => {
|
|
340
|
+
if (!candidate || typeof candidate !== "object") return false;
|
|
341
|
+
try {
|
|
342
|
+
return root.contains(candidate) || (panel?.contains(candidate) ?? false);
|
|
343
|
+
} catch {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
const onPointerDown = (event) => {
|
|
348
|
+
if (!panel) return;
|
|
349
|
+
if (inside(event?.target)) return;
|
|
350
|
+
closePanel();
|
|
351
|
+
};
|
|
352
|
+
const onKeyDown = (event) => {
|
|
353
|
+
if (event.key === "Escape") closePanel();
|
|
354
|
+
};
|
|
355
|
+
async function pollStatus() {
|
|
356
|
+
if (disposed) return;
|
|
357
|
+
try {
|
|
358
|
+
if (doc.visibilityState === "hidden") return;
|
|
359
|
+
} catch {
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
const response = await deps.fetchImpl(`${STATUS_ROUTE}?t=${Date.now()}`, {
|
|
363
|
+
headers: { accept: "application/json" },
|
|
364
|
+
credentials: "same-origin"
|
|
365
|
+
});
|
|
366
|
+
if (!response || response.status !== 200) return;
|
|
367
|
+
const body = await response.json?.();
|
|
368
|
+
if (!body || typeof body !== "object") return;
|
|
369
|
+
lastStatus = body;
|
|
370
|
+
write();
|
|
371
|
+
} catch (error) {
|
|
372
|
+
deps.warn?.("status poll failed");
|
|
373
|
+
warn("status poll failed\uFF08pill \u4F1A\u505C\u5728\u9ED8\u8BA4\u6587\u6848\u4E0A\uFF09", error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
button.addEventListener("click", () => {
|
|
377
|
+
if (panel) closePanel();
|
|
378
|
+
else openPanel();
|
|
379
|
+
});
|
|
380
|
+
doc.addEventListener("pointerdown", onPointerDown, true);
|
|
381
|
+
doc.addEventListener("keydown", onKeyDown);
|
|
382
|
+
write();
|
|
383
|
+
void pollStatus();
|
|
384
|
+
statusTimer = setInterval(() => void pollStatus(), POLL_MS);
|
|
385
|
+
return () => {
|
|
386
|
+
if (disposed) return;
|
|
387
|
+
disposed = true;
|
|
388
|
+
if (statusTimer !== void 0) clearInterval(statusTimer);
|
|
389
|
+
closePanel();
|
|
390
|
+
doc.removeEventListener("pointerdown", onPointerDown, true);
|
|
391
|
+
doc.removeEventListener("keydown", onKeyDown);
|
|
392
|
+
button.remove();
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
function mountPill(ctx, createElement) {
|
|
396
|
+
if (!createElement) {
|
|
397
|
+
warn("\u88C5\u8F7D\u5668\u7ED9\u4E0D\u51FA react\uFF1A\u914D\u5BF9\u90A3\u9897 pill \u4E0D\u4F1A\u51FA\u73B0");
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
let mounted = false;
|
|
401
|
+
const mount = (slots) => {
|
|
402
|
+
if (mounted) return;
|
|
403
|
+
let cleanup;
|
|
404
|
+
const attach = (node) => {
|
|
405
|
+
const element = node;
|
|
406
|
+
if (element && typeof element.appendChild === "function" && element.ownerDocument) {
|
|
407
|
+
if (cleanup) return;
|
|
408
|
+
element.style.position = "relative";
|
|
409
|
+
cleanup = buildPill(element, {
|
|
410
|
+
fetchImpl: (input, init) => globalThis.fetch(input, init)
|
|
411
|
+
});
|
|
412
|
+
} else if (cleanup) {
|
|
413
|
+
cleanup();
|
|
414
|
+
cleanup = void 0;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
const component = () => createElement("span", { ref: attach });
|
|
418
|
+
mounted = true;
|
|
419
|
+
try {
|
|
420
|
+
slots.inject(SLOT_NAME, () => {
|
|
421
|
+
try {
|
|
422
|
+
slots.register({ name: SLOT_NAME, id: PILL_ID, order: PILL_ORDER, inject: () => ({}) }, component);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
warn("\u69FD\u4F4D\u6CE8\u518C\u5931\u8D25\uFF08\u90A3\u9897 pill \u4E0D\u51FA\u73B0\uFF09", error);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
} catch (error) {
|
|
428
|
+
mounted = false;
|
|
429
|
+
warn("\u69FD\u4F4D\u6CE8\u5165\u5931\u8D25\uFF08\u90A3\u9897 pill \u4E0D\u51FA\u73B0\uFF09", error);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
ctx.effect?.(() => () => {
|
|
434
|
+
if (cleanup) {
|
|
435
|
+
cleanup();
|
|
436
|
+
cleanup = void 0;
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
} catch {
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
let early;
|
|
443
|
+
try {
|
|
444
|
+
early = pickSlots(ctx.slots) ?? pickSlots(ctx.get?.("slots", true));
|
|
445
|
+
} catch {
|
|
446
|
+
}
|
|
447
|
+
if (early) mount(early);
|
|
448
|
+
try {
|
|
449
|
+
ctx.inject?.(["slots"], ((...args) => {
|
|
450
|
+
for (const candidate of [...args, ctx]) {
|
|
451
|
+
const found = pickSlots(candidate);
|
|
452
|
+
if (found) {
|
|
453
|
+
mount(found);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}));
|
|
458
|
+
} catch (error) {
|
|
459
|
+
warn("ctx.inject \u53E3\u4E0D\u53EF\u7528\uFF1Aslots \u518D\u665A\u5230\u4E5F\u6CA1\u4EBA\u8865\u6302", error);
|
|
460
|
+
}
|
|
461
|
+
if (!mounted) {
|
|
462
|
+
warn("apply \u65F6\u6CA1\u63A2\u5230 slots\uFF08\u5DF2\u6302\u6CE8\u5165\u56DE\u8C03\u7B49\u5B83\u665A\u5230\uFF09\uFF1Bpill \u4E00\u76F4\u4E0D\u51FA\u73B0\u5C31\u662F\u8FD9\u4EE3\u5BBF\u4E3B\u6CA1\u8FD9\u4E2A\u670D\u52A1");
|
|
463
|
+
}
|
|
464
|
+
return mounted;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// client/src/main.ts
|
|
468
|
+
var name = "dsh-remote-control";
|
|
469
|
+
var inject = ["slots"];
|
|
470
|
+
function apply(ctx) {
|
|
471
|
+
try {
|
|
472
|
+
mountPill(ctx, findCreateElement());
|
|
473
|
+
} catch (error) {
|
|
474
|
+
try {
|
|
475
|
+
console.error("[dsh-remote-control] pill \u6302\u8F7D\u629B\u9519\uFF08\u5DF2\u541E\u6389\uFF09\uFF1A", error);
|
|
476
|
+
} catch {
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return module.exports;
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
|