@linxin666/dsh-remote-web-ui 0.1.17 → 0.1.19
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.i18n.yaml +2 -2
- package/README.md +5 -2
- package/README.zh.md +2 -2
- package/lib/client.js +82 -66
- package/lib/client.js.map +1 -1
- package/lib/index.js +18 -18
- package/lib/mobile.js +649 -45
- package/lib/mobile.js.map +1 -1
- package/lib/types/client/PluginSettingsCard.d.ts +11 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +11 -5
- package/lib/types/client/RemoteSettingsCard.d.ts +5 -0
- package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
- package/lib/types/client/RemoteSettingsCard.js +7 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +13 -7
- package/lib/types/client/settings-form.d.ts +8 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +15 -1
- package/lib/types/gate.d.ts +4 -9
- package/lib/types/gate.d.ts.map +1 -1
- package/lib/types/gate.js +5 -32
- package/lib/types/loopback.d.ts +25 -0
- package/lib/types/loopback.d.ts.map +1 -0
- package/lib/types/loopback.js +68 -0
- package/lib/types/mobile/markdown.d.ts +26 -0
- package/lib/types/mobile/markdown.d.ts.map +1 -0
- package/lib/types/mobile/markdown.js +272 -0
- package/lib/types/mobile/markdown.test.d.ts +2 -0
- package/lib/types/mobile/markdown.test.d.ts.map +1 -0
- package/lib/types/mobile/markdown.test.js +67 -0
- package/lib/types/mobile/messages.d.ts +14 -0
- package/lib/types/mobile/messages.d.ts.map +1 -1
- package/lib/types/mobile/messages.js +54 -2
- package/lib/types/mobile/messages.test.js +99 -0
- package/lib/types/mobile/mobile-styles.d.ts +1 -1
- package/lib/types/mobile/mobile-styles.d.ts.map +1 -1
- package/lib/types/mobile/mobile-styles.js +167 -0
- package/lib/types/mobile/views/ChatView.d.ts.map +1 -1
- package/lib/types/mobile/views/ChatView.js +81 -5
- package/lib/types/mobile/views/ChatView.test.js +105 -0
- package/package.json +1 -1
- package/src/client/PluginSettingsCard.tsx +50 -47
- package/src/client/RemoteSettingsCard.tsx +8 -0
- package/src/client/index.ts +13 -7
- package/src/client/settings-card.module.css +9 -0
- package/src/client/settings-form.ts +15 -1
- package/src/gate.ts +5 -30
- package/src/loopback.ts +63 -0
- package/src/mobile/markdown.test.ts +77 -0
- package/src/mobile/markdown.ts +278 -0
- package/src/mobile/messages.test.ts +106 -0
- package/src/mobile/messages.ts +66 -2
- package/src/mobile/mobile-styles.ts +167 -0
- package/src/mobile/views/ChatView.test.tsx +121 -0
- package/src/mobile/views/ChatView.tsx +164 -6
|
@@ -28,6 +28,17 @@ export interface PluginSettingsCardProps<TKey extends string = string> {
|
|
|
28
28
|
onSave: () => void;
|
|
29
29
|
/** Drop every staged edit. */
|
|
30
30
|
onDiscard: () => void;
|
|
31
|
+
/**
|
|
32
|
+
* Render the controls expanded on arrival (still collapsible). Defaults to
|
|
33
|
+
* true: promoted first-level sections show their settings immediately.
|
|
34
|
+
*/
|
|
35
|
+
defaultOpen?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Render without the collapse affordance: a static header and an always
|
|
38
|
+
* visible body. Used by first-level settings sections whose nav entry
|
|
39
|
+
* already provides the selection.
|
|
40
|
+
*/
|
|
41
|
+
alwaysOpen?: boolean;
|
|
31
42
|
/** The plugin's controls. */
|
|
32
43
|
children: ReactNode;
|
|
33
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,oGAAoG;AACpG,eAAO,MAAM,cAAc,kMAUjB,CAAA;AAEV,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzD,oEAAoE;AACpE,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,GAAG,WAAW,CAAA;AAE9E,wDAAwD;AACxD,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,0CAA0C;IAC1C,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAA;IACnF,uCAAuC;IACvC,QAAQ,EAAE,IAAI,CAAA;IACd,4EAA4E;IAC5E,cAAc,EAAE,IAAI,CAAA;IACpB,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAA;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,6BAA6B;IAC7B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,uBAAuB,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -28,24 +28,30 @@ export const CARD_COPY_KEYS = [
|
|
|
28
28
|
* @returns the card, or nothing while the namespace is still loading.
|
|
29
29
|
*/
|
|
30
30
|
export function PluginSettingsCard(props) {
|
|
31
|
-
const [open, setOpen] = useState(
|
|
32
|
-
const { state } = props;
|
|
31
|
+
const [open, setOpen] = useState(props.defaultOpen ?? true);
|
|
32
|
+
const { state, alwaysOpen } = props;
|
|
33
33
|
if (!state.available)
|
|
34
34
|
return null;
|
|
35
35
|
const title = props.t(props.titleKey);
|
|
36
36
|
const description = props.t(props.descriptionKey);
|
|
37
37
|
const blocked = !state.dirty || state.invalid || state.saving;
|
|
38
|
-
const
|
|
38
|
+
const expanded = alwaysOpen === true || open;
|
|
39
|
+
const cardClass = expanded ? `${css.cardOpen} ${css.card}` : css.card;
|
|
40
|
+
// With alwaysOpen the nav entry already provides the selection, so the
|
|
41
|
+
// header is a static title row instead of a disclosure button.
|
|
42
|
+
const header = alwaysOpen === true
|
|
43
|
+
? (_jsxs("div", { className: css.headerStatic, children: [_jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, title: title, children: title }), _jsx("span", { className: css.description, title: description, children: description })] }), state.dirty ? _jsx("span", { className: css.pending, title: props.t('settings.unsaved'), children: props.t('settings.unsaved') }) : null] }))
|
|
44
|
+
: (_jsxs("button", { type: "button", className: css.header, "aria-expanded": open, "aria-label": `${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`, onClick: () => { setOpen(!open); }, children: [_jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, title: title, children: title }), _jsx("span", { className: css.description, title: description, children: description })] }), state.dirty ? _jsx("span", { className: css.pending, title: props.t('settings.unsaved'), children: props.t('settings.unsaved') }) : null, _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: open ? `${css.chevron} ${css.chevronOpen}` : css.chevron, children: _jsx("path", { d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z", fill: "currentColor" }) })] }));
|
|
39
45
|
// The namespace exists but the Host does not serve it to this client (the
|
|
40
46
|
// official settings allowlist omits third-party namespaces): show a card
|
|
41
47
|
// that explains the gap instead of vanishing, so a missing card never
|
|
42
48
|
// reads as a missing plugin.
|
|
43
49
|
if (!state.exposed) {
|
|
44
|
-
return (_jsxs("li", { className: cardClass, children: [
|
|
50
|
+
return (_jsxs("li", { className: cardClass, children: [header, expanded
|
|
45
51
|
? (_jsx("div", { className: css.body, children: _jsx("p", { className: css.notExposed, role: "status", children: props.t('settings.notExposed') }) }))
|
|
46
52
|
: null] }));
|
|
47
53
|
}
|
|
48
|
-
return (_jsxs("li", { className: cardClass, children: [
|
|
54
|
+
return (_jsxs("li", { className: cardClass, children: [header, expanded
|
|
49
55
|
? (_jsxs("div", { className: css.body, children: [!state.writable ? _jsx("p", { className: css.readOnly, role: "status", children: props.t('settings.readOnly') }) : null, props.children, _jsxs("div", { className: css.footer, children: [state.failed
|
|
50
56
|
? (_jsxs("p", { className: css.failed, role: "status", children: [props.t('settings.saveFailed'), state.failedReason ? ' - ' + state.failedReason : ''] }))
|
|
51
57
|
: null, _jsx("button", { type: "button", className: css.discard, disabled: !state.dirty || state.saving, onClick: props.onDiscard, children: props.t('settings.discard') }), _jsx("button", { type: "button", className: css.save, disabled: blocked, onClick: props.onSave, children: props.t(!state.saving ? 'settings.save' : 'settings.saving') })] })] }))
|
|
@@ -67,6 +67,11 @@ export declare class RemoteSettingsCardController {
|
|
|
67
67
|
* @returns the card's snapshot and its form actions.
|
|
68
68
|
*/
|
|
69
69
|
inject(): RemoteSettingsCardFace;
|
|
70
|
+
/**
|
|
71
|
+
* Release the card's scope subscription and bound stores; the slot
|
|
72
|
+
* disposer calls this on teardown.
|
|
73
|
+
*/
|
|
74
|
+
dispose(): void;
|
|
70
75
|
}
|
|
71
76
|
/** Props the renderer binds for the remote-control card. */
|
|
72
77
|
export type RemoteSettingsCardProps = PropsRuntime<'web-ui.plugin.item'> & PropsLocale<'remote'> & InjectFace<RemoteSettingsCardFace>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE1F,OAAO,EAAkD,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExJ,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAwB,SAAQ,SAAS;IACxD,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,sBAAsB;IACtB,UAAU,EAAE,cAAc,CAAA;IAC1B,gCAAgC;IAChC,cAAc,EAAE,cAAc,CAAA;IAC9B,yBAAyB;IACzB,UAAU,EAAE,cAAc,CAAA;IAC1B,0BAA0B;IAC1B,UAAU,EAAE,cAAc,CAAA;IAC1B,sBAAsB;IACtB,oBAAoB,EAAE,cAAc,CAAA;IACpC,kCAAkC;IAClC,aAAa,EAAE,cAAc,CAAA;IAC7B,iCAAiC;IACjC,UAAU,EAAE,cAAc,CAAA;IAC1B,4CAA4C;IAC5C,iBAAiB,EAAE,cAAc,CAAA;CAClC;AAED,gEAAgE;AAChE,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,KAAK,EAAE;QACL,oEAAoE;QACpE,kBAAkB,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAA;KAC3D,CAAA;CACF;AAED,qEAAqE;AACrE,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAE9D,iFAAiF;gBACrE,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC;IAehD,OAAO,CAAC,UAAU;IAelB;;;OAGG;IACH,MAAM,IAAI,sBAAsB;
|
|
1
|
+
{"version":3,"file":"RemoteSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE1F,OAAO,EAAkD,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExJ,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAwB,SAAQ,SAAS;IACxD,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,sBAAsB;IACtB,UAAU,EAAE,cAAc,CAAA;IAC1B,gCAAgC;IAChC,cAAc,EAAE,cAAc,CAAA;IAC9B,yBAAyB;IACzB,UAAU,EAAE,cAAc,CAAA;IAC1B,0BAA0B;IAC1B,UAAU,EAAE,cAAc,CAAA;IAC1B,sBAAsB;IACtB,oBAAoB,EAAE,cAAc,CAAA;IACpC,kCAAkC;IAClC,aAAa,EAAE,cAAc,CAAA;IAC7B,iCAAiC;IACjC,UAAU,EAAE,cAAc,CAAA;IAC1B,4CAA4C;IAC5C,iBAAiB,EAAE,cAAc,CAAA;CAClC;AAED,gEAAgE;AAChE,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,KAAK,EAAE;QACL,oEAAoE;QACpE,kBAAkB,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAA;KAC3D,CAAA;CACF;AAED,qEAAqE;AACrE,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAE9D,iFAAiF;gBACrE,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC;IAehD,OAAO,CAAC,UAAU;IAelB;;;OAGG;IACH,MAAM,IAAI,sBAAsB;IAIhC;;;OAGG;IACH,OAAO,IAAI,IAAI;CAGhB;AAED,4DAA4D;AAC5D,MAAM,MAAM,uBAAuB,GACjC,YAAY,CAAC,oBAAoB,CAAC,GAChC,WAAW,CAAC,QAAQ,CAAC,GACrB,UAAU,CAAC,sBAAsB,CAAC,CAAA;AAEtC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,+BAsHhE"}
|
|
@@ -41,6 +41,13 @@ export class RemoteSettingsCardController {
|
|
|
41
41
|
inject() {
|
|
42
42
|
return { hooks: { remoteSettingsCard: this.store }, ...this.form.actions() };
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Release the card's scope subscription and bound stores; the slot
|
|
46
|
+
* disposer calls this on teardown.
|
|
47
|
+
*/
|
|
48
|
+
dispose() {
|
|
49
|
+
this.form.dispose();
|
|
50
|
+
}
|
|
44
51
|
}
|
|
45
52
|
/**
|
|
46
53
|
* Render the remote-control card.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAa7G,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAIrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACrE,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACnE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAC/F,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAErE,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,0CAA0C;QAC1C,MAAM,EAAE,SAAS,CAAA;KAClB;IAED,UAAU,OAAO;QACf;;;;WAIG;QACH,gBAAgB,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,uBAAuB,CAAA;SAAE,CAAA;QACnF;;;;;WAKG;QACH,oBAAoB,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,4BAA4B,CAAA;SAAE,CAAA;KAC3F;CACF;AAED,4GAA4G;AAC5G,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;CACd;AAED,mEAAmE;AACnE,MAAM,WAAW,4BAA4B;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,KAAK,CAAA;CACjB;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf;;;;WAIG;QACH,aAAa,CAAC,EAAE;YAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;SAAE,CAAA;KAC1E;CACF;AAYD,wCAAwC;AACxC,eAAO,MAAM,MAAM,UAA+D,CAAA;AAElF;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAa7G,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAIrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACrE,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACnE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAC/F,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAErE,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,0CAA0C;QAC1C,MAAM,EAAE,SAAS,CAAA;KAClB;IAED,UAAU,OAAO;QACf;;;;WAIG;QACH,gBAAgB,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,uBAAuB,CAAA;SAAE,CAAA;QACnF;;;;;WAKG;QACH,oBAAoB,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,4BAA4B,CAAA;SAAE,CAAA;KAC3F;CACF;AAED,4GAA4G;AAC5G,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;CACd;AAED,mEAAmE;AACnE,MAAM,WAAW,4BAA4B;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,KAAK,CAAA;CACjB;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf;;;;WAIG;QACH,aAAa,CAAC,EAAE;YAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;SAAE,CAAA;KAC1E;CACF;AAYD,wCAAwC;AACxC,eAAO,MAAM,MAAM,UAA+D,CAAA;AAElF;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAgH9C"}
|
|
@@ -86,13 +86,19 @@ export function apply(ctx) {
|
|
|
86
86
|
// Plugin configuration card: one staged form over the `remote-web-ui`
|
|
87
87
|
// settings namespace, contributed to the Web UI plugin group.
|
|
88
88
|
const remoteSettings = new RemoteSettingsCardController(settingsScope);
|
|
89
|
-
ctx.slots.inject('web-ui.plugin.item', () =>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
ctx.slots.inject('web-ui.plugin.item', () => {
|
|
90
|
+
const unregister = ctx.slots.register({
|
|
91
|
+
name: 'web-ui.plugin.item',
|
|
92
|
+
id: 'remote-web-ui',
|
|
93
|
+
order: 90,
|
|
94
|
+
locale: NS,
|
|
95
|
+
inject: () => remoteSettings.inject(),
|
|
96
|
+
}, RemoteSettingsCard);
|
|
97
|
+
return () => {
|
|
98
|
+
remoteSettings.dispose();
|
|
99
|
+
unregister();
|
|
100
|
+
};
|
|
101
|
+
});
|
|
96
102
|
// Phone-side boot flow + heartbeats. Loopback pages (the desktop) never
|
|
97
103
|
// heartbeat; the server ignores unpaired heartbeats anyway. Both run only
|
|
98
104
|
// while the plugin is enabled.
|
|
@@ -149,11 +149,19 @@ export declare class CardForm<T> {
|
|
|
149
149
|
private readonly specs;
|
|
150
150
|
private readonly staged;
|
|
151
151
|
private readonly listeners;
|
|
152
|
+
/** The scope subscription installed in the constructor; released by dispose(). */
|
|
153
|
+
private readonly disposeScope;
|
|
154
|
+
private disposed;
|
|
152
155
|
private saving;
|
|
153
156
|
private failed;
|
|
154
157
|
private failedReason;
|
|
155
158
|
/** @param scope - the bound settings scope for this card's namespace. */
|
|
156
159
|
constructor(scope: SettingsScope<T>, specs: FieldSpec[]);
|
|
160
|
+
/**
|
|
161
|
+
* Release the scope subscription and every bound store listener. The card
|
|
162
|
+
* must call this on teardown; later calls are no-ops.
|
|
163
|
+
*/
|
|
164
|
+
dispose(): void;
|
|
157
165
|
/** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
|
|
158
166
|
bind<S>(project: () => S): SnapshotStore<S>;
|
|
159
167
|
/** Read the card-level state: what the Host serves, and what a save would do. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"settings-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-form.ts"],"names":[],"mappings":"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"}
|
|
@@ -91,6 +91,9 @@ export class CardForm {
|
|
|
91
91
|
specs;
|
|
92
92
|
staged = new Map();
|
|
93
93
|
listeners = new Set();
|
|
94
|
+
/** The scope subscription installed in the constructor; released by dispose(). */
|
|
95
|
+
disposeScope;
|
|
96
|
+
disposed = false;
|
|
94
97
|
saving = false;
|
|
95
98
|
failed = false;
|
|
96
99
|
failedReason;
|
|
@@ -98,7 +101,18 @@ export class CardForm {
|
|
|
98
101
|
constructor(scope, specs) {
|
|
99
102
|
this.scope = scope;
|
|
100
103
|
this.specs = new Map(specs.map(spec => [spec.field, spec]));
|
|
101
|
-
scope.subscribe(() => { this.publish(); });
|
|
104
|
+
this.disposeScope = scope.subscribe(() => { this.publish(); });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Release the scope subscription and every bound store listener. The card
|
|
108
|
+
* must call this on teardown; later calls are no-ops.
|
|
109
|
+
*/
|
|
110
|
+
dispose() {
|
|
111
|
+
if (this.disposed)
|
|
112
|
+
return;
|
|
113
|
+
this.disposed = true;
|
|
114
|
+
this.disposeScope();
|
|
115
|
+
this.listeners.clear();
|
|
102
116
|
}
|
|
103
117
|
/** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
|
|
104
118
|
bind(project) {
|
package/lib/types/gate.d.ts
CHANGED
|
@@ -13,18 +13,13 @@
|
|
|
13
13
|
import type { IncomingMessage } from 'node:http';
|
|
14
14
|
import type { PairingService } from './pairing.ts';
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* IPv6 loopback, any IPv4 address
|
|
19
|
-
*
|
|
20
|
-
* the connection plugin, and external host plugins only need the
|
|
21
|
-
* classification, not the whole trust decision.
|
|
16
|
+
* Loopback classification for the desktop client. The predicates now live in
|
|
17
|
+
* the shared synced copy (shared/host/loopback.ts, mirrored to ./loopback.ts
|
|
18
|
+
* by scripts/sync-shared.mjs): localhost, IPv6 loopback, and any IPv4 address
|
|
19
|
+
* in 127/8.
|
|
22
20
|
* @param hostname - WHATWG URL hostname (IPv6 literals retain brackets).
|
|
23
21
|
* @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8.
|
|
24
22
|
*/
|
|
25
|
-
export declare function isLoopbackHostname(hostname: string): boolean;
|
|
26
|
-
/** Whether a socket remote address names the loopback range (127/8, ::1, IPv4-mapped). */
|
|
27
|
-
export declare function isLoopbackAddress(address: string | undefined): boolean;
|
|
28
23
|
/**
|
|
29
24
|
* Read one cookie value from a Cookie header.
|
|
30
25
|
* @param header - the raw Cookie header value (or undefined).
|
package/lib/types/gate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASvF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAQvE;AAED,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAKlE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,cAAc,EACvB,oBAAoB,GAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAQ,EACtD,OAAO,GAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAQ,GACxC,CAAC,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAW9H"}
|
package/lib/types/gate.js
CHANGED
|
@@ -10,42 +10,15 @@
|
|
|
10
10
|
* gives "停止" real teeth: revoked devices 403 on their next request,
|
|
11
11
|
* including the mux/SSE stream (which then dies on reconnect).
|
|
12
12
|
*/
|
|
13
|
+
import { isLoopbackAddress, isLoopbackHostname } from "./loopback.js";
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* IPv6 loopback, any IPv4 address
|
|
17
|
-
*
|
|
18
|
-
* the connection plugin, and external host plugins only need the
|
|
19
|
-
* classification, not the whole trust decision.
|
|
15
|
+
* Loopback classification for the desktop client. The predicates now live in
|
|
16
|
+
* the shared synced copy (shared/host/loopback.ts, mirrored to ./loopback.ts
|
|
17
|
+
* by scripts/sync-shared.mjs): localhost, IPv6 loopback, and any IPv4 address
|
|
18
|
+
* in 127/8.
|
|
20
19
|
* @param hostname - WHATWG URL hostname (IPv6 literals retain brackets).
|
|
21
20
|
* @returns true for localhost, IPv6 loopback, or any IPv4 address in 127/8.
|
|
22
21
|
*/
|
|
23
|
-
export function isLoopbackHostname(hostname) {
|
|
24
|
-
if (hostname === 'localhost' || hostname === '[::1]')
|
|
25
|
-
return true;
|
|
26
|
-
const parts = hostname.split('.');
|
|
27
|
-
return parts.length === 4
|
|
28
|
-
&& parts[0] === '127'
|
|
29
|
-
&& parts.every(part => /^\d{1,3}$/.test(part) && Number(part) <= 255);
|
|
30
|
-
}
|
|
31
|
-
/** Whether a socket remote address names the loopback range (127/8, ::1, IPv4-mapped). */
|
|
32
|
-
export function isLoopbackAddress(address) {
|
|
33
|
-
if (address === undefined)
|
|
34
|
-
return false;
|
|
35
|
-
const normalized = address.toLowerCase();
|
|
36
|
-
if (normalized === '::1')
|
|
37
|
-
return true;
|
|
38
|
-
if (normalized.startsWith('::ffff:'))
|
|
39
|
-
return isIPv4Loopback(normalized.slice('::ffff:'.length));
|
|
40
|
-
return isIPv4Loopback(normalized);
|
|
41
|
-
}
|
|
42
|
-
/** IPv4 127/8 predicate (four decimal octets, first == 127). */
|
|
43
|
-
function isIPv4Loopback(v4) {
|
|
44
|
-
const parts = v4.split('.');
|
|
45
|
-
return parts.length === 4
|
|
46
|
-
&& parts[0] === '127'
|
|
47
|
-
&& parts.every(part => /^\d{1,3}$/.test(part) && Number(part) <= 255);
|
|
48
|
-
}
|
|
49
22
|
/**
|
|
50
23
|
* Read one cookie value from a Cookie header.
|
|
51
24
|
* @param header - the raw Cookie header value (or undefined).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loopback trust fence shared by the host route families: socket address,
|
|
3
|
+
* Host header, and browser same-origin markers. Packages receive this file as
|
|
4
|
+
* a generated copy via scripts/sync-shared.mjs; edit the shared source and
|
|
5
|
+
* re-run the sync instead of editing a copy.
|
|
6
|
+
*
|
|
7
|
+
* Semantics: RFC 5735 IPv4 127/8, ::1, IPv4-mapped ::ffff:127/8 (matching the
|
|
8
|
+
* remote-web-ui gate), localhost hostnames, plus the browser same-origin
|
|
9
|
+
* markers (sec-fetch-site and Origin) for the request-level fence.
|
|
10
|
+
* @module dsh-web-ui-shared/host/loopback
|
|
11
|
+
*/
|
|
12
|
+
import type { IncomingMessage } from 'node:http';
|
|
13
|
+
/** IPv4 127/8 predicate (four decimal octets, first == 127). */
|
|
14
|
+
export declare function isIPv4Loopback(v4: string): boolean;
|
|
15
|
+
/** Whether a socket remote address names the loopback range (127/8, ::1, IPv4-mapped). */
|
|
16
|
+
export declare function isLoopbackAddress(address: string | undefined): boolean;
|
|
17
|
+
/** Whether a normalized URL hostname names the loopback authority (localhost, [::1], 127/8). */
|
|
18
|
+
export declare function isLoopbackHostname(hostname: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Request-level trust fence: a loopback socket address AND a loopback Host
|
|
21
|
+
* header, plus browser same-origin markers. The socket address is
|
|
22
|
+
* authoritative; X-Forwarded-For is never trusted.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isLoopbackRequest(request: IncomingMessage): boolean;
|
|
25
|
+
//# sourceMappingURL=loopback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback.d.ts","sourceRoot":"","sources":["../../src/loopback.ts"],"names":[],"mappings":"AACA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAEhD,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAKlD;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAMtE;AAED,gGAAgG;AAChG,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAmBnE"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Generated by scripts/sync-shared.mjs from shared/host/loopback.ts. Do not edit this copy; edit the shared source and run "node scripts/sync-shared.mjs".
|
|
2
|
+
/**
|
|
3
|
+
* Loopback trust fence shared by the host route families: socket address,
|
|
4
|
+
* Host header, and browser same-origin markers. Packages receive this file as
|
|
5
|
+
* a generated copy via scripts/sync-shared.mjs; edit the shared source and
|
|
6
|
+
* re-run the sync instead of editing a copy.
|
|
7
|
+
*
|
|
8
|
+
* Semantics: RFC 5735 IPv4 127/8, ::1, IPv4-mapped ::ffff:127/8 (matching the
|
|
9
|
+
* remote-web-ui gate), localhost hostnames, plus the browser same-origin
|
|
10
|
+
* markers (sec-fetch-site and Origin) for the request-level fence.
|
|
11
|
+
* @module dsh-web-ui-shared/host/loopback
|
|
12
|
+
*/
|
|
13
|
+
/** IPv4 127/8 predicate (four decimal octets, first == 127). */
|
|
14
|
+
export function isIPv4Loopback(v4) {
|
|
15
|
+
const parts = v4.split('.');
|
|
16
|
+
return parts.length === 4
|
|
17
|
+
&& parts[0] === '127'
|
|
18
|
+
&& parts.every(part => /^\d{1,3}$/.test(part) && Number(part) <= 255);
|
|
19
|
+
}
|
|
20
|
+
/** Whether a socket remote address names the loopback range (127/8, ::1, IPv4-mapped). */
|
|
21
|
+
export function isLoopbackAddress(address) {
|
|
22
|
+
if (address === undefined)
|
|
23
|
+
return false;
|
|
24
|
+
const normalized = address.toLowerCase();
|
|
25
|
+
if (normalized === '::1')
|
|
26
|
+
return true;
|
|
27
|
+
if (normalized.startsWith('::ffff:'))
|
|
28
|
+
return isIPv4Loopback(normalized.slice('::ffff:'.length));
|
|
29
|
+
return isIPv4Loopback(normalized);
|
|
30
|
+
}
|
|
31
|
+
/** Whether a normalized URL hostname names the loopback authority (localhost, [::1], 127/8). */
|
|
32
|
+
export function isLoopbackHostname(hostname) {
|
|
33
|
+
if (hostname === 'localhost' || hostname === '[::1]')
|
|
34
|
+
return true;
|
|
35
|
+
return isIPv4Loopback(hostname);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Request-level trust fence: a loopback socket address AND a loopback Host
|
|
39
|
+
* header, plus browser same-origin markers. The socket address is
|
|
40
|
+
* authoritative; X-Forwarded-For is never trusted.
|
|
41
|
+
*/
|
|
42
|
+
export function isLoopbackRequest(request) {
|
|
43
|
+
if (!isLoopbackAddress(request.socket.remoteAddress))
|
|
44
|
+
return false;
|
|
45
|
+
const host = request.headers.host;
|
|
46
|
+
if (typeof host !== 'string')
|
|
47
|
+
return false;
|
|
48
|
+
let hostUrl;
|
|
49
|
+
try {
|
|
50
|
+
hostUrl = new URL('http://' + host);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (!isLoopbackHostname(hostUrl.hostname))
|
|
56
|
+
return false;
|
|
57
|
+
if (request.headers['sec-fetch-site'] === 'cross-site')
|
|
58
|
+
return false;
|
|
59
|
+
const origin = request.headers.origin;
|
|
60
|
+
if (origin === undefined)
|
|
61
|
+
return true;
|
|
62
|
+
try {
|
|
63
|
+
return new URL(origin).host === hostUrl.host;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A compact GFM-subset markdown renderer for the mobile chat: headings,
|
|
3
|
+
* paragraphs, fenced + inline code, bold/italic/strikethrough, links,
|
|
4
|
+
* images, lists, blockquotes, hr, and tables. All HTML is escaped before
|
|
5
|
+
* transformation — the output only ever contains the renderer's own tags.
|
|
6
|
+
* Dependency-free on purpose (the mobile bundle stays at ~456 KB); the
|
|
7
|
+
* escape-first + protocol allow-list design mirrors the desktop panel's
|
|
8
|
+
* preview renderer (dsh-aionui-panel/src/client/preview/markdown.ts).
|
|
9
|
+
* Pure and exported for tests.
|
|
10
|
+
* @module dsh-remote-web-ui/mobile/markdown
|
|
11
|
+
*/
|
|
12
|
+
/** Escape HTML special characters. */
|
|
13
|
+
export declare function escapeHtml(text: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Guard a raw link/image target against dangerous protocols. Returns the
|
|
16
|
+
* (trimmed) raw string when safe, else null. Only http:, https:, mailto:
|
|
17
|
+
* and fragment anchors (#...) are allowed; anything with another scheme
|
|
18
|
+
* — javascript:, data:, vbscript:, etc. — is rejected so the value never
|
|
19
|
+
* reaches dangerouslySetInnerHTML.
|
|
20
|
+
*/
|
|
21
|
+
export declare function safeUrl(raw: string): string | null;
|
|
22
|
+
/** Inline pass: code spans, bold, italic, strikethrough, images, links. */
|
|
23
|
+
export declare function renderInline(text: string): string;
|
|
24
|
+
/** Render a markdown document to HTML (block pass). */
|
|
25
|
+
export declare function renderMarkdown(source: string): string;
|
|
26
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/mobile/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,sCAAsC;AACtC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQlD;AAgBD,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqFjD;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA+HrD"}
|