@jacobbd/relay-ai 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 +1 -1
- package/dist/{chunk-MVBA7ABV.js → chunk-EJONCU3B.js} +4 -4
- package/dist/chunk-EJONCU3B.js.map +1 -0
- package/dist/{chunk-SV2Y6OCD.js → chunk-P4S42QJK.js} +120 -301
- package/dist/chunk-P4S42QJK.js.map +1 -0
- package/dist/cli.js +341 -221
- package/dist/cli.js.map +1 -1
- package/dist/{provider-templates-6XYKAZB5.js → provider-templates-BPGB5V2L.js} +2 -2
- package/dist/ui/public/app.js +44 -3
- package/dist/ui/public/style.css +16 -0
- package/dist/{ui-command-DJZIIIWC.js → ui-command-EQJIZRZZ.js} +27 -13
- package/dist/{ui-command-DJZIIIWC.js.map → ui-command-EQJIZRZZ.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-MVBA7ABV.js.map +0 -1
- package/dist/chunk-SV2Y6OCD.js.map +0 -1
- /package/dist/{provider-templates-6XYKAZB5.js.map → provider-templates-BPGB5V2L.js.map} +0 -0
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
listAddableTemplates,
|
|
8
8
|
listSupportedTemplates,
|
|
9
9
|
listVisibleOAuthTemplates
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EJONCU3B.js";
|
|
11
11
|
init_provider_templates();
|
|
12
12
|
export {
|
|
13
13
|
PROVIDER_TEMPLATES,
|
|
@@ -17,4 +17,4 @@ export {
|
|
|
17
17
|
listSupportedTemplates,
|
|
18
18
|
listVisibleOAuthTemplates
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=provider-templates-
|
|
20
|
+
//# sourceMappingURL=provider-templates-BPGB5V2L.js.map
|
package/dist/ui/public/app.js
CHANGED
|
@@ -53,6 +53,7 @@ const state = {
|
|
|
53
53
|
listenMode: 'local', // 'local' | 'network'
|
|
54
54
|
passwordMode: 'new', // 'saved' | 'new'
|
|
55
55
|
password: '',
|
|
56
|
+
passwordVisible: false,
|
|
56
57
|
savePassword: false,
|
|
57
58
|
},
|
|
58
59
|
},
|
|
@@ -1059,6 +1060,8 @@ function buildProviderBodyContent(provider) {
|
|
|
1059
1060
|
const countEl = document.querySelector(`[data-id="${CSS.escape(provider.id)}"] .provider-models-count`);
|
|
1060
1061
|
if (countEl) countEl.textContent = `${result.count} models`;
|
|
1061
1062
|
provider.modelCount = result.count;
|
|
1063
|
+
state.modelsLoaded = false;
|
|
1064
|
+
await initModels();
|
|
1062
1065
|
} else {
|
|
1063
1066
|
feedback.textContent = result.error ?? 'Refresh failed';
|
|
1064
1067
|
feedback.className = 'key-feedback error';
|
|
@@ -1179,6 +1182,8 @@ function buildOAuthProviderBodyContent(provider) {
|
|
|
1179
1182
|
feedback.className = 'key-feedback success';
|
|
1180
1183
|
const countEl = document.querySelector(`[data-id="${CSS.escape(provider.id)}"] .provider-models-count`);
|
|
1181
1184
|
if (countEl) countEl.textContent = `${result.count} models`;
|
|
1185
|
+
state.modelsLoaded = false;
|
|
1186
|
+
await initModels();
|
|
1182
1187
|
} else {
|
|
1183
1188
|
feedback.textContent = result.error ?? 'Refresh failed';
|
|
1184
1189
|
feedback.className = 'key-feedback error';
|
|
@@ -1612,6 +1617,18 @@ async function initModels() {
|
|
|
1612
1617
|
state.modelsError = String(err);
|
|
1613
1618
|
state.modelsLoaded = true;
|
|
1614
1619
|
}
|
|
1620
|
+
// Keep the Providers header counts in sync after add / delete / OAuth / refresh.
|
|
1621
|
+
renderProviderStats();
|
|
1622
|
+
// Server tab caches its provider checklist — invalidate so new providers appear without a full reload.
|
|
1623
|
+
invalidateServerProviderCache();
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
function invalidateServerProviderCache() {
|
|
1627
|
+
state.server.form.providersLoaded = false;
|
|
1628
|
+
if (state.server.status?.running) return;
|
|
1629
|
+
if (state.server.form.expose !== 'specific') return;
|
|
1630
|
+
if (!document.getElementById('server-panel')) return;
|
|
1631
|
+
void loadServerProviders().then(() => renderServerPanel());
|
|
1615
1632
|
}
|
|
1616
1633
|
|
|
1617
1634
|
async function init() {
|
|
@@ -2264,7 +2281,14 @@ function seedServerFormFromSaved(saved) {
|
|
|
2264
2281
|
f.maskGatewayIds = saved.maskGatewayIds;
|
|
2265
2282
|
// Published Docker ports only reach 0.0.0.0 inside the container.
|
|
2266
2283
|
f.listenMode = isServerAdminUi() || saved.listenMode === 'network' ? 'network' : 'local';
|
|
2267
|
-
|
|
2284
|
+
// Env password (Docker): prefill the field so Start works and clients can copy it.
|
|
2285
|
+
// Keychain-saved password: keep "Use saved" (value never sent to the browser).
|
|
2286
|
+
if (saved.prefillPassword && !f.password) {
|
|
2287
|
+
f.password = saved.prefillPassword;
|
|
2288
|
+
f.passwordMode = 'new';
|
|
2289
|
+
} else {
|
|
2290
|
+
f.passwordMode = saved.hasSavedPassword ? 'saved' : 'new';
|
|
2291
|
+
}
|
|
2268
2292
|
if (f.expose === 'specific') loadServerProviders().then(renderServerPanel);
|
|
2269
2293
|
}
|
|
2270
2294
|
|
|
@@ -2305,6 +2329,10 @@ function renderServerPanel() {
|
|
|
2305
2329
|
panel.innerHTML = '<div class="skeleton skeleton-card"></div>';
|
|
2306
2330
|
return;
|
|
2307
2331
|
}
|
|
2332
|
+
// Lazy-load (or re-load after invalidate) when the specific-provider checklist is visible.
|
|
2333
|
+
if (!s.status.running && s.form.expose === 'specific' && !s.form.providersLoaded) {
|
|
2334
|
+
void loadServerProviders().then(() => renderServerPanel());
|
|
2335
|
+
}
|
|
2308
2336
|
panel.innerHTML = s.status.running ? renderServerRunning(s.status) : renderServerSetup(s);
|
|
2309
2337
|
}
|
|
2310
2338
|
|
|
@@ -2364,16 +2392,22 @@ function renderServerNetworkOptions() {
|
|
|
2364
2392
|
const s = state.server;
|
|
2365
2393
|
const f = s.form;
|
|
2366
2394
|
const hasSaved = Boolean(s.status?.saved?.hasSavedPassword);
|
|
2395
|
+
const hasEnv = Boolean(s.status?.saved?.hasEnvPassword);
|
|
2367
2396
|
const showPasswordInput = f.passwordMode === 'new' || !hasSaved;
|
|
2397
|
+
const inputType = f.passwordVisible ? 'text' : 'password';
|
|
2368
2398
|
|
|
2369
2399
|
return `
|
|
2370
2400
|
<div class="server-network-options">
|
|
2371
|
-
${hasSaved ? toggleGroupHtml([
|
|
2401
|
+
${hasSaved && !hasEnv ? toggleGroupHtml([
|
|
2372
2402
|
{ label: 'Use saved password', active: f.passwordMode === 'saved', onClick: "setServerPasswordMode('saved')" },
|
|
2373
2403
|
{ label: 'Enter new password', active: f.passwordMode === 'new', onClick: "setServerPasswordMode('new')" },
|
|
2374
2404
|
]) : ''}
|
|
2405
|
+
${hasEnv && f.passwordMode === 'new' ? '<div class="server-field-hint">Prefilled from RELAY_AI_SERVER_PASSWORD</div>' : ''}
|
|
2375
2406
|
${showPasswordInput ? `
|
|
2376
|
-
<
|
|
2407
|
+
<div class="server-password-row">
|
|
2408
|
+
<input type="${inputType}" class="key-input" id="server-password-input" placeholder="Server password" value="${escapeHtml(f.password)}" oninput="setServerPassword(this.value)" autocomplete="off">
|
|
2409
|
+
<button type="button" class="btn btn-ghost server-password-reveal" onclick="toggleServerPasswordVisible()" aria-pressed="${f.passwordVisible ? 'true' : 'false'}">${f.passwordVisible ? 'Hide' : 'Reveal'}</button>
|
|
2410
|
+
</div>
|
|
2377
2411
|
<label class="server-toggle-row">
|
|
2378
2412
|
<input type="checkbox" ${f.savePassword ? 'checked' : ''} onchange="setServerSavePassword(this.checked)">
|
|
2379
2413
|
<span>Save this password for next time</span>
|
|
@@ -2581,6 +2615,12 @@ function setServerPassword(value) {
|
|
|
2581
2615
|
state.server.form.password = value;
|
|
2582
2616
|
}
|
|
2583
2617
|
|
|
2618
|
+
function toggleServerPasswordVisible() {
|
|
2619
|
+
state.server.form.passwordVisible = !state.server.form.passwordVisible;
|
|
2620
|
+
renderServerPanel();
|
|
2621
|
+
document.getElementById('server-password-input')?.focus();
|
|
2622
|
+
}
|
|
2623
|
+
|
|
2584
2624
|
function setServerSavePassword(checked) {
|
|
2585
2625
|
state.server.form.savePassword = checked;
|
|
2586
2626
|
}
|
|
@@ -2676,6 +2716,7 @@ window.setServerFreeModelsOnly = setServerFreeModelsOnly;
|
|
|
2676
2716
|
window.setServerListenMode = setServerListenMode;
|
|
2677
2717
|
window.setServerPasswordMode = setServerPasswordMode;
|
|
2678
2718
|
window.setServerPassword = setServerPassword;
|
|
2719
|
+
window.toggleServerPasswordVisible = toggleServerPasswordVisible;
|
|
2679
2720
|
window.setServerSavePassword = setServerSavePassword;
|
|
2680
2721
|
window.submitServerStart = submitServerStart;
|
|
2681
2722
|
window.stopServerGateway = stopServerGateway;
|
package/dist/ui/public/style.css
CHANGED
|
@@ -1876,6 +1876,22 @@ input { font-family: inherit; }
|
|
|
1876
1876
|
gap: 10px;
|
|
1877
1877
|
}
|
|
1878
1878
|
|
|
1879
|
+
.server-password-row {
|
|
1880
|
+
display: flex;
|
|
1881
|
+
align-items: center;
|
|
1882
|
+
gap: 8px;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
.server-password-row .key-input {
|
|
1886
|
+
flex: 1;
|
|
1887
|
+
min-width: 0;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
.server-password-reveal {
|
|
1891
|
+
flex-shrink: 0;
|
|
1892
|
+
white-space: nowrap;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1879
1895
|
.server-provider-chips {
|
|
1880
1896
|
display: flex;
|
|
1881
1897
|
flex-wrap: wrap;
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
gatewayProviderLabel,
|
|
26
26
|
getAppHome,
|
|
27
27
|
getAppPathOverride,
|
|
28
|
+
getEnvServerPassword,
|
|
28
29
|
getSavedServerPassword,
|
|
29
30
|
getServerExposedProviders,
|
|
30
31
|
getServerFavoritesOnly,
|
|
@@ -71,14 +72,14 @@ import {
|
|
|
71
72
|
supportsClaudeTransparentMode,
|
|
72
73
|
validateCustomEndpointUrl,
|
|
73
74
|
writeSecureLogLine
|
|
74
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-P4S42QJK.js";
|
|
75
76
|
import {
|
|
76
77
|
__toCommonJS,
|
|
77
78
|
init_provider_templates,
|
|
78
79
|
listAddableTemplates,
|
|
79
80
|
listVisibleOAuthTemplates,
|
|
80
81
|
provider_templates_exports
|
|
81
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-EJONCU3B.js";
|
|
82
83
|
|
|
83
84
|
// src/ui-command.ts
|
|
84
85
|
import { createServer } from "http";
|
|
@@ -385,13 +386,16 @@ function buildModelRows(models, gateway) {
|
|
|
385
386
|
return rows.sort((a, b) => a.providerLabel.localeCompare(b.providerLabel) || a.name.localeCompare(b.name));
|
|
386
387
|
}
|
|
387
388
|
async function buildSavedConfig() {
|
|
389
|
+
const envPassword = getEnvServerPassword();
|
|
388
390
|
return {
|
|
389
391
|
favoritesOnly: getServerFavoritesOnly(),
|
|
390
392
|
freeModelsOnly: getServerFreeModelsOnly(),
|
|
391
393
|
exposedProviders: getServerExposedProviders(),
|
|
392
394
|
maskGatewayIds: getServerMaskGatewayIds(),
|
|
393
395
|
listenMode: getServerListenMode(),
|
|
394
|
-
hasSavedPassword: await hasSavedPasswordCached()
|
|
396
|
+
hasSavedPassword: await hasSavedPasswordCached(),
|
|
397
|
+
hasEnvPassword: Boolean(envPassword),
|
|
398
|
+
...envPassword ? { prefillPassword: envPassword } : {}
|
|
395
399
|
};
|
|
396
400
|
}
|
|
397
401
|
async function getServerStatus(opts) {
|
|
@@ -445,16 +449,26 @@ async function doStartGatewayServer(req, opts) {
|
|
|
445
449
|
let serverPassword = null;
|
|
446
450
|
if (req.listenMode === "network") {
|
|
447
451
|
if (req.passwordMode === "saved") {
|
|
448
|
-
const
|
|
449
|
-
if (!
|
|
450
|
-
|
|
452
|
+
const configured = await getSavedServerPassword() ?? getEnvServerPassword();
|
|
453
|
+
if (!configured) {
|
|
454
|
+
return {
|
|
455
|
+
ok: false,
|
|
456
|
+
error: "No configured password found \u2014 set RELAY_AI_SERVER_PASSWORD, or enter a new password."
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
serverPassword = configured;
|
|
451
460
|
} else {
|
|
452
461
|
const trimmed = (req.password ?? "").trim();
|
|
453
|
-
if (!trimmed)
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
462
|
+
if (!trimmed) {
|
|
463
|
+
const configured = getEnvServerPassword() ?? await getSavedServerPassword();
|
|
464
|
+
if (!configured) return { ok: false, error: "A server password is required for network mode." };
|
|
465
|
+
serverPassword = configured;
|
|
466
|
+
} else {
|
|
467
|
+
serverPassword = trimmed;
|
|
468
|
+
if (req.savePassword) {
|
|
469
|
+
await setSavedServerPassword(trimmed);
|
|
470
|
+
hasSavedPasswordCache = { value: true, expiresAt: Date.now() + SAVED_PASSWORD_CACHE_TTL_MS };
|
|
471
|
+
}
|
|
458
472
|
}
|
|
459
473
|
}
|
|
460
474
|
}
|
|
@@ -807,7 +821,7 @@ async function handleAddProvider(req, res) {
|
|
|
807
821
|
sendJson(res, 400, { error: "templateId required" });
|
|
808
822
|
return;
|
|
809
823
|
}
|
|
810
|
-
const { listSupportedTemplates } = await import("./provider-templates-
|
|
824
|
+
const { listSupportedTemplates } = await import("./provider-templates-BPGB5V2L.js");
|
|
811
825
|
const template = listSupportedTemplates().find((t) => t.id === templateId);
|
|
812
826
|
if (!template) {
|
|
813
827
|
sendJson(res, 404, { error: `Template '${templateId}' not found` });
|
|
@@ -1564,4 +1578,4 @@ export {
|
|
|
1564
1578
|
resolveUiShutdownDecision,
|
|
1565
1579
|
runUiCommand
|
|
1566
1580
|
};
|
|
1567
|
-
//# sourceMappingURL=ui-command-
|
|
1581
|
+
//# sourceMappingURL=ui-command-EQJIZRZZ.js.map
|