@ddtcorex/dsh-maestro-config 0.4.0 → 0.5.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/lib/client.js +85 -4
- package/lib/types/client/MaestroSettings.d.ts.map +1 -1
- package/lib/types/client/pin-ttl.d.ts +23 -0
- package/lib/types/client/pin-ttl.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/client/MaestroSettings.tsx +74 -2
- package/src/client/pin-ttl.ts +31 -0
- package/lib/types/client/Settings.d.ts +0 -11
- package/lib/types/client/Settings.d.ts.map +0 -1
package/cordis.patch.yml
CHANGED
|
@@ -3,4 +3,8 @@
|
|
|
3
3
|
- insert:
|
|
4
4
|
- id: maestro-config
|
|
5
5
|
name: '@ddtcorex/dsh-maestro-config'
|
|
6
|
+
# rpc.handle registers a webServer route inside an effect fiber which
|
|
7
|
+
# carries only the row's inject (not the module's); without webServer
|
|
8
|
+
# the row fails on harnesses that provide webServer after rows apply (DSH 0.1.5-rc.1+).
|
|
9
|
+
inject: ['connection', 'webServer']
|
|
6
10
|
config: {}
|
package/lib/client.js
CHANGED
|
@@ -2156,6 +2156,22 @@ function gitlabWebhookUrl(hostname) {
|
|
|
2156
2156
|
return `https://${authority}/hooks/gitlab-mr`;
|
|
2157
2157
|
}
|
|
2158
2158
|
|
|
2159
|
+
// src/client/pin-ttl.ts
|
|
2160
|
+
var PIN_TTL_PRESETS = [
|
|
2161
|
+
{ hours: 0, label: "Session only" },
|
|
2162
|
+
{ hours: 1, label: "1 hour" },
|
|
2163
|
+
{ hours: 8, label: "8 hours" },
|
|
2164
|
+
{ hours: 24, label: "1 day (default)" },
|
|
2165
|
+
{ hours: 168, label: "7 days" },
|
|
2166
|
+
{ hours: 720, label: "30 days" }
|
|
2167
|
+
];
|
|
2168
|
+
var DEFAULT_PIN_TTL_HOURS = 24;
|
|
2169
|
+
var MAX_PIN_TTL_HOURS = 8760;
|
|
2170
|
+
function presetForTtlHours(hours) {
|
|
2171
|
+
const value = hours === void 0 || !Number.isFinite(hours) ? DEFAULT_PIN_TTL_HOURS : hours;
|
|
2172
|
+
return PIN_TTL_PRESETS.some((preset) => preset.hours === value) ? value : null;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2159
2175
|
// src/client/MaestroSettings.tsx
|
|
2160
2176
|
var t = {
|
|
2161
2177
|
bgLayer1: "var(--dsw-alias-bg-layer-1)",
|
|
@@ -3003,6 +3019,14 @@ function LanAccess({ proxyStatus, lanPin }) {
|
|
|
3003
3019
|
if (!proxyStatus?.running) {
|
|
3004
3020
|
return (0, import_react.createElement)("p", { style: { color: t.stateError, fontSize: 12, margin: "8px 0 0" } }, proxyStatus?.errorMessage ?? "Proxy not running");
|
|
3005
3021
|
}
|
|
3022
|
+
if (urls.length === 0) {
|
|
3023
|
+
return (0, import_react.createElement)(
|
|
3024
|
+
"div",
|
|
3025
|
+
null,
|
|
3026
|
+
(0, import_react.createElement)("p", { style: captionStyle }, "No LAN listener is configured \u2014 set a LAN port under Tunnel to expose one."),
|
|
3027
|
+
lanPin !== null ? (0, import_react.createElement)(LanPinRow, { lanPin }) : null
|
|
3028
|
+
);
|
|
3029
|
+
}
|
|
3006
3030
|
return (0, import_react.createElement)(
|
|
3007
3031
|
"div",
|
|
3008
3032
|
null,
|
|
@@ -3043,7 +3067,56 @@ function LanPinRow({ lanPin }) {
|
|
|
3043
3067
|
) : null
|
|
3044
3068
|
);
|
|
3045
3069
|
}
|
|
3046
|
-
function
|
|
3070
|
+
function PinSessionTtl({ hours, onSave }) {
|
|
3071
|
+
const selected = presetForTtlHours(hours);
|
|
3072
|
+
const [custom, setCustom] = (0, import_react.useState)(false);
|
|
3073
|
+
const [draft, setDraft] = (0, import_react.useState)("");
|
|
3074
|
+
const customActive = custom || selected === null;
|
|
3075
|
+
const commit = () => {
|
|
3076
|
+
const parsed = Number(draft);
|
|
3077
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > MAX_PIN_TTL_HOURS) return;
|
|
3078
|
+
onSave(parsed);
|
|
3079
|
+
};
|
|
3080
|
+
return (0, import_react.createElement)(
|
|
3081
|
+
"div",
|
|
3082
|
+
{ "data-maestro-pin-ttl": "", style: { display: "flex", flexDirection: "column", gap: 6, alignItems: "flex-end" } },
|
|
3083
|
+
(0, import_react.createElement)(
|
|
3084
|
+
"select",
|
|
3085
|
+
{
|
|
3086
|
+
"data-maestro-pin-ttl-select": "",
|
|
3087
|
+
value: customActive ? "custom" : String(selected),
|
|
3088
|
+
onChange: (e) => {
|
|
3089
|
+
const next = e.target.value;
|
|
3090
|
+
if (next === "custom") {
|
|
3091
|
+
setCustom(true);
|
|
3092
|
+
setDraft(String(hours ?? 24));
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
setCustom(false);
|
|
3096
|
+
onSave(Number(next));
|
|
3097
|
+
},
|
|
3098
|
+
style: { height: 36, padding: "0 12px", border: `1px solid ${t.borderL2}`, borderRadius: 18, background: "var(--dsw-alias-bg-module-platform, #F5F6F7)", color: t.labelPrimary, font: "inherit", fontSize: 13 }
|
|
3099
|
+
},
|
|
3100
|
+
...PIN_TTL_PRESETS.map((preset) => (0, import_react.createElement)("option", { key: preset.hours, value: String(preset.hours) }, preset.label)),
|
|
3101
|
+
(0, import_react.createElement)("option", { key: "custom", value: "custom" }, "Custom\u2026")
|
|
3102
|
+
),
|
|
3103
|
+
customActive ? (0, import_react.createElement)(FieldInput, {
|
|
3104
|
+
"data-maestro-pin-ttl-custom": "",
|
|
3105
|
+
inputMode: "numeric",
|
|
3106
|
+
placeholder: "hours",
|
|
3107
|
+
value: draft,
|
|
3108
|
+
min: 1,
|
|
3109
|
+
max: MAX_PIN_TTL_HOURS,
|
|
3110
|
+
onChange: (e) => setDraft(e.target.value),
|
|
3111
|
+
onBlur: commit,
|
|
3112
|
+
onKeyDown: (e) => {
|
|
3113
|
+
if (e.key === "Enter") commit();
|
|
3114
|
+
},
|
|
3115
|
+
style: { width: 120 }
|
|
3116
|
+
}) : null
|
|
3117
|
+
);
|
|
3118
|
+
}
|
|
3119
|
+
function PublicAccess({ status, pin, showPin, onRevealPin, onHidePin, onRotatePin, pinTtlHours, onSavePinTtl }) {
|
|
3047
3120
|
return (0, import_react.createElement)(
|
|
3048
3121
|
"div",
|
|
3049
3122
|
null,
|
|
@@ -3065,7 +3138,15 @@ function PublicAccess({ status, pin, showPin, onRevealPin, onHidePin, onRotatePi
|
|
|
3065
3138
|
showPin ? (0, import_react.createElement)(Button, { variant: "outline", size: "sm", onClick: onHidePin }, "Hide") : (0, import_react.createElement)(Button, { variant: "outline", size: "sm", onClick: onRevealPin }, "Show"),
|
|
3066
3139
|
(0, import_react.createElement)(Button, { variant: "outline", size: "sm", onClick: onRotatePin }, "Rotate")
|
|
3067
3140
|
),
|
|
3068
|
-
(0, import_react.createElement)("p", { style: captionStyle }, "Stays the same across tunnel and DSH restarts; use Rotate when you need a new PIN.")
|
|
3141
|
+
(0, import_react.createElement)("p", { style: captionStyle }, "Stays the same across tunnel and DSH restarts; use Rotate when you need a new PIN."),
|
|
3142
|
+
(0, import_react.createElement)(SettingRow, {
|
|
3143
|
+
title: "PIN session duration",
|
|
3144
|
+
// The caption lives in the description column on purpose: a long caption
|
|
3145
|
+
// inside the control column claims its intrinsic width (min-width: auto)
|
|
3146
|
+
// and squeezes the title/description to a few characters per line.
|
|
3147
|
+
description: "How long a browser stays signed in after entering the PIN. Applies to the next login; covers the public tunnel and LAN access.",
|
|
3148
|
+
control: (0, import_react.createElement)(PinSessionTtl, { hours: pinTtlHours, onSave: onSavePinTtl })
|
|
3149
|
+
})
|
|
3069
3150
|
);
|
|
3070
3151
|
}
|
|
3071
3152
|
function NamedTunnelSetupNote() {
|
|
@@ -3542,8 +3623,8 @@ function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
|
3542
3623
|
(0, import_react.createElement)(SettingRow, { title: "Hostname", description: "Public hostname for the tunnel.", control: (0, import_react.createElement)(FieldInput, { placeholder: "dsh.example.com", value: config.tunnelHostname ?? "", onChange: (e) => saveField("tunnelHostname", e.target.value), style: { width: 260 } }) })
|
|
3543
3624
|
) : null,
|
|
3544
3625
|
(0, import_react.createElement)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap", padding: "12px 0", borderBottom: `1px solid ${t.borderL2}` } }, status?.running ? (0, import_react.createElement)(Button, { variant: "outline", size: "md", disabled: busy, onClick: stopTunnel }, "Stop tunnel") : (0, import_react.createElement)(Button, { variant: "primary", size: "md", disabled: busy, onClick: startTunnel }, "Start tunnel")),
|
|
3545
|
-
(0, import_react.createElement)("div", { style: { ...cardInsetStyle, marginTop: "12px" } }, (0, import_react.createElement)("div", { style: { fontSize: 13, fontWeight: 600, color: t.labelPrimary } }, "
|
|
3546
|
-
(0, import_react.createElement)("div", { style: { ...cardInsetStyle, marginTop: "12px" } }, (0, import_react.createElement)("div", { style: { fontSize: 13, fontWeight: 600, color: t.labelPrimary } }, "
|
|
3626
|
+
(0, import_react.createElement)("div", { style: { ...cardInsetStyle, marginTop: "12px" } }, (0, import_react.createElement)("div", { style: { fontSize: 13, fontWeight: 600, color: t.labelPrimary } }, "Public access"), (0, import_react.createElement)(PublicAccess, { status, pin, showPin, onRevealPin: revealPin, onHidePin: () => setShowPin(false), onRotatePin: rotatePin, pinTtlHours: config.pinSessionTtlHours, onSavePinTtl: (value) => saveField("pinSessionTtlHours", value) })),
|
|
3627
|
+
(0, import_react.createElement)("div", { style: { ...cardInsetStyle, marginTop: "12px" } }, (0, import_react.createElement)("div", { style: { fontSize: 13, fontWeight: 600, color: t.labelPrimary } }, "Remote access \u2014 LAN"), (0, import_react.createElement)(LanAccess, { proxyStatus, lanPin: lanPinEnabled === null ? null : { enabled: lanPinEnabled, pin: lanPin, show: showLanPin, onShow: revealLanPin, onHide: () => setShowLanPin(false), onRotate: rotateLanPin, onToggle: toggleLanPin } }))
|
|
3547
3628
|
),
|
|
3548
3629
|
gitlab: (0, import_react.createElement)(
|
|
3549
3630
|
"div",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MaestroSettings.d.ts","sourceRoot":"","sources":["../../../src/client/MaestroSettings.tsx"],"names":[],"mappings":"AACA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"MaestroSettings.d.ts","sourceRoot":"","sources":["../../../src/client/MaestroSettings.tsx"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAw0CH,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE;IAAE,OAAO,EAAE,GAAG,CAAC;IAAC,aAAa,CAAC,EAAE,GAAG,CAAA;CAAE;;;;;;;;;mBA4ZmE,GAAG;;gBAoBzK"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIN login-cookie lifetimes offered by the Settings card.
|
|
3
|
+
* `0` = session cookie (expires when the browser closes); an absent setting
|
|
4
|
+
* means the dsh-maestro-remote default of 24 hours.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PIN_TTL_PRESETS: ReadonlyArray<{
|
|
7
|
+
hours: number;
|
|
8
|
+
label: string;
|
|
9
|
+
}>;
|
|
10
|
+
/** Mirrors DEFAULT_PIN_SESSION_TTL_HOURS in dsh-maestro-remote. */
|
|
11
|
+
export declare const DEFAULT_PIN_TTL_HOURS = 24;
|
|
12
|
+
/**
|
|
13
|
+
* Mirrors MAX_PIN_SESSION_TTL_HOURS in dsh-maestro-remote. This bound only
|
|
14
|
+
* hints the custom input — the host resolver and the settings RPC enforce it.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_PIN_TTL_HOURS = 8760;
|
|
17
|
+
/**
|
|
18
|
+
* The preset hours to show as selected, or `null` when the stored value is not
|
|
19
|
+
* a preset (the caller then shows the "Custom…" option). An unset or unusable
|
|
20
|
+
* value falls back to the product default.
|
|
21
|
+
*/
|
|
22
|
+
export declare function presetForTtlHours(hours: number | undefined): number | null;
|
|
23
|
+
//# sourceMappingURL=pin-ttl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin-ttl.d.ts","sourceRoot":"","sources":["../../../src/client/pin-ttl.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAO3E,CAAA;AAED,mEAAmE;AACnE,eAAO,MAAM,qBAAqB,KAAK,CAAA;AACvC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAG1E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ddtcorex/dsh-maestro-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Maestro Config — shared settings service for the dsh-maestro-* suite over the single namespaced store (~/.dsh/maestro/settings.json)",
|
|
6
6
|
"type": "module",
|
|
@@ -13,6 +13,7 @@ import { createElement as h, useEffect, useRef, useState } from 'react'
|
|
|
13
13
|
import QRCode from 'qrcode'
|
|
14
14
|
import { MAESTRO_ENDPOINTS } from './api.js'
|
|
15
15
|
import { generateWebhookSecret, gitlabWebhookUrl } from './webhook-secret.js'
|
|
16
|
+
import { PIN_TTL_PRESETS, MAX_PIN_TTL_HOURS, presetForTtlHours } from './pin-ttl.js'
|
|
16
17
|
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
18
19
|
// DSH tokens — single source, no custom hex (except QR quiet zone #fff)
|
|
@@ -1055,6 +1056,17 @@ function LanAccess({ proxyStatus, lanPin }: { proxyStatus: any; lanPin: any }) {
|
|
|
1055
1056
|
if (!proxyStatus?.running) {
|
|
1056
1057
|
return h('p', { style: { color: t.stateError as string, fontSize: 12, margin: '8px 0 0' } }, proxyStatus?.errorMessage ?? 'Proxy not running')
|
|
1057
1058
|
}
|
|
1059
|
+
if (urls.length === 0) {
|
|
1060
|
+
// Without a LAN listener there is no LAN entry to advertise. Saying "no PIN
|
|
1061
|
+
// needed" next to the reader's own reachable-but-public URL would promise
|
|
1062
|
+
// access this card cannot deliver, so point at the setting instead.
|
|
1063
|
+
return h(
|
|
1064
|
+
'div',
|
|
1065
|
+
null,
|
|
1066
|
+
h('p', { style: captionStyle }, 'No LAN listener is configured — set a LAN port under Tunnel to expose one.'),
|
|
1067
|
+
lanPin !== null ? h(LanPinRow as any, { lanPin }) : null,
|
|
1068
|
+
)
|
|
1069
|
+
}
|
|
1058
1070
|
return h(
|
|
1059
1071
|
'div',
|
|
1060
1072
|
null,
|
|
@@ -1103,7 +1115,59 @@ function LanPinRow({ lanPin }: { lanPin: any }) {
|
|
|
1103
1115
|
)
|
|
1104
1116
|
}
|
|
1105
1117
|
|
|
1106
|
-
|
|
1118
|
+
/**
|
|
1119
|
+
* Login-cookie lifetime. Presets cover the common choices; "Custom…" reveals a
|
|
1120
|
+
* free hours input saved on blur/Enter — never per keystroke, so a half-typed
|
|
1121
|
+
* number is not persisted. The host resolver and the settings RPC own the
|
|
1122
|
+
* authoritative bounds; the input's min/max are an affordance only.
|
|
1123
|
+
*/
|
|
1124
|
+
function PinSessionTtl({ hours, onSave }: { hours: number | undefined; onSave: (hours: number) => void }) {
|
|
1125
|
+
const selected = presetForTtlHours(hours)
|
|
1126
|
+
const [custom, setCustom] = useState(false)
|
|
1127
|
+
const [draft, setDraft] = useState('')
|
|
1128
|
+
const customActive = custom || selected === null
|
|
1129
|
+
const commit = () => {
|
|
1130
|
+
const parsed = Number(draft)
|
|
1131
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > MAX_PIN_TTL_HOURS) return
|
|
1132
|
+
onSave(parsed)
|
|
1133
|
+
}
|
|
1134
|
+
return h(
|
|
1135
|
+
'div',
|
|
1136
|
+
{ 'data-maestro-pin-ttl': '', style: { display: 'flex', flexDirection: 'column' as const, gap: 6, alignItems: 'flex-end' } },
|
|
1137
|
+
h(
|
|
1138
|
+
'select',
|
|
1139
|
+
{
|
|
1140
|
+
'data-maestro-pin-ttl-select': '',
|
|
1141
|
+
value: customActive ? 'custom' : String(selected),
|
|
1142
|
+
onChange: (e: any) => {
|
|
1143
|
+
const next = e.target.value
|
|
1144
|
+
if (next === 'custom') { setCustom(true); setDraft(String(hours ?? 24)); return }
|
|
1145
|
+
setCustom(false)
|
|
1146
|
+
onSave(Number(next))
|
|
1147
|
+
},
|
|
1148
|
+
style: { height: 36, padding: '0 12px', border: `1px solid ${t.borderL2}`, borderRadius: 18, background: 'var(--dsw-alias-bg-module-platform, #F5F6F7)' as string, color: t.labelPrimary as string, font: 'inherit', fontSize: 13 },
|
|
1149
|
+
},
|
|
1150
|
+
...PIN_TTL_PRESETS.map((preset) => h('option', { key: preset.hours, value: String(preset.hours) }, preset.label)),
|
|
1151
|
+
h('option', { key: 'custom', value: 'custom' }, 'Custom…'),
|
|
1152
|
+
),
|
|
1153
|
+
customActive
|
|
1154
|
+
? h(FieldInput as any, {
|
|
1155
|
+
'data-maestro-pin-ttl-custom': '',
|
|
1156
|
+
inputMode: 'numeric',
|
|
1157
|
+
placeholder: 'hours',
|
|
1158
|
+
value: draft,
|
|
1159
|
+
min: 1,
|
|
1160
|
+
max: MAX_PIN_TTL_HOURS,
|
|
1161
|
+
onChange: (e: any) => setDraft(e.target.value),
|
|
1162
|
+
onBlur: commit,
|
|
1163
|
+
onKeyDown: (e: any) => { if (e.key === 'Enter') commit() },
|
|
1164
|
+
style: { width: 120 } as any,
|
|
1165
|
+
})
|
|
1166
|
+
: null,
|
|
1167
|
+
)
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
function PublicAccess({ status, pin, showPin, onRevealPin, onHidePin, onRotatePin, pinTtlHours, onSavePinTtl }: { status: any; pin: string | null; showPin: boolean; onRevealPin: () => void; onHidePin: () => void; onRotatePin: () => void; pinTtlHours: number | undefined; onSavePinTtl: (hours: number) => void }) {
|
|
1107
1171
|
return h(
|
|
1108
1172
|
'div',
|
|
1109
1173
|
null,
|
|
@@ -1128,6 +1192,14 @@ function PublicAccess({ status, pin, showPin, onRevealPin, onHidePin, onRotatePi
|
|
|
1128
1192
|
h(Button as any, { variant: 'outline', size: 'sm', onClick: onRotatePin }, 'Rotate'),
|
|
1129
1193
|
),
|
|
1130
1194
|
h('p', { style: captionStyle }, 'Stays the same across tunnel and DSH restarts; use Rotate when you need a new PIN.'),
|
|
1195
|
+
h(SettingRow as any, {
|
|
1196
|
+
title: 'PIN session duration',
|
|
1197
|
+
// The caption lives in the description column on purpose: a long caption
|
|
1198
|
+
// inside the control column claims its intrinsic width (min-width: auto)
|
|
1199
|
+
// and squeezes the title/description to a few characters per line.
|
|
1200
|
+
description: 'How long a browser stays signed in after entering the PIN. Applies to the next login; covers the public tunnel and LAN access.',
|
|
1201
|
+
control: h(PinSessionTtl as any, { hours: pinTtlHours, onSave: onSavePinTtl }),
|
|
1202
|
+
}),
|
|
1131
1203
|
)
|
|
1132
1204
|
}
|
|
1133
1205
|
|
|
@@ -1627,8 +1699,8 @@ export function MaestroSettingsTab({ rpcCall, configRpcCall }: { rpcCall: any; c
|
|
|
1627
1699
|
)
|
|
1628
1700
|
: null,
|
|
1629
1701
|
h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' as const, padding: '12px 0', borderBottom: `1px solid ${t.borderL2}` } }, status?.running ? h(Button as any, { variant: 'outline', size: 'md', disabled: busy, onClick: stopTunnel }, 'Stop tunnel') : h(Button as any, { variant: 'primary', size: 'md', disabled: busy, onClick: startTunnel }, 'Start tunnel')),
|
|
1702
|
+
h('div', { style: { ...cardInsetStyle, marginTop: '12px' } }, h('div', { style: { fontSize: 13, fontWeight: 600, color: t.labelPrimary as string } }, 'Public access'), h(PublicAccess as any, { status, pin, showPin, onRevealPin: revealPin, onHidePin: () => setShowPin(false), onRotatePin: rotatePin, pinTtlHours: config.pinSessionTtlHours, onSavePinTtl: (value: number) => saveField('pinSessionTtlHours', value) })),
|
|
1630
1703
|
h('div', { style: { ...cardInsetStyle, marginTop: '12px' } }, h('div', { style: { fontSize: 13, fontWeight: 600, color: t.labelPrimary as string } }, 'Remote access — LAN'), h(LanAccess as any, { proxyStatus, lanPin: lanPinEnabled === null ? null : { enabled: lanPinEnabled, pin: lanPin, show: showLanPin, onShow: revealLanPin, onHide: () => setShowLanPin(false), onRotate: rotateLanPin, onToggle: toggleLanPin } })),
|
|
1631
|
-
h('div', { style: { ...cardInsetStyle, marginTop: '12px' } }, h('div', { style: { fontSize: 13, fontWeight: 600, color: t.labelPrimary as string } }, 'Public access'), h(PublicAccess as any, { status, pin, showPin, onRevealPin: revealPin, onHidePin: () => setShowPin(false), onRotatePin: rotatePin })),
|
|
1632
1704
|
),
|
|
1633
1705
|
gitlab: h(
|
|
1634
1706
|
'div',
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIN login-cookie lifetimes offered by the Settings card.
|
|
3
|
+
* `0` = session cookie (expires when the browser closes); an absent setting
|
|
4
|
+
* means the dsh-maestro-remote default of 24 hours.
|
|
5
|
+
*/
|
|
6
|
+
export const PIN_TTL_PRESETS: ReadonlyArray<{ hours: number; label: string }> = [
|
|
7
|
+
{ hours: 0, label: 'Session only' },
|
|
8
|
+
{ hours: 1, label: '1 hour' },
|
|
9
|
+
{ hours: 8, label: '8 hours' },
|
|
10
|
+
{ hours: 24, label: '1 day (default)' },
|
|
11
|
+
{ hours: 168, label: '7 days' },
|
|
12
|
+
{ hours: 720, label: '30 days' },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
/** Mirrors DEFAULT_PIN_SESSION_TTL_HOURS in dsh-maestro-remote. */
|
|
16
|
+
export const DEFAULT_PIN_TTL_HOURS = 24
|
|
17
|
+
/**
|
|
18
|
+
* Mirrors MAX_PIN_SESSION_TTL_HOURS in dsh-maestro-remote. This bound only
|
|
19
|
+
* hints the custom input — the host resolver and the settings RPC enforce it.
|
|
20
|
+
*/
|
|
21
|
+
export const MAX_PIN_TTL_HOURS = 8760
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The preset hours to show as selected, or `null` when the stored value is not
|
|
25
|
+
* a preset (the caller then shows the "Custom…" option). An unset or unusable
|
|
26
|
+
* value falls back to the product default.
|
|
27
|
+
*/
|
|
28
|
+
export function presetForTtlHours(hours: number | undefined): number | null {
|
|
29
|
+
const value = hours === undefined || !Number.isFinite(hours) ? DEFAULT_PIN_TTL_HOURS : hours
|
|
30
|
+
return PIN_TTL_PRESETS.some((preset) => preset.hours === value) ? value : null
|
|
31
|
+
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
type RpcCall = (endpoint: string, payload?: unknown, signal?: AbortSignal) => Promise<unknown>;
|
|
2
|
-
export declare function Settings({ configRpcCall }: {
|
|
3
|
-
configRpcCall: RpcCall;
|
|
4
|
-
}): import("react").DetailedReactHTMLElement<{
|
|
5
|
-
'data-maestro-guard-settings': string;
|
|
6
|
-
style: {
|
|
7
|
-
maxWidth: number;
|
|
8
|
-
};
|
|
9
|
-
}, HTMLElement>;
|
|
10
|
-
export default Settings;
|
|
11
|
-
//# sourceMappingURL=Settings.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../../src/client/Settings.tsx"],"names":[],"mappings":"AAIA,KAAK,OAAO,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAiF9F,wBAAgB,QAAQ,CAAC,EAAE,aAAa,EAAE,EAAE;IAAE,aAAa,EAAE,OAAO,CAAA;CAAE;;;;;gBAiRrE;AAGD,eAAe,QAAQ,CAAA"}
|