@intranefr/superbackend 1.4.4 → 1.5.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/.env.example +5 -0
- package/README.md +11 -0
- package/index.js +39 -1
- package/package.json +11 -3
- package/public/sdk/ui-components.iife.js +191 -0
- package/sdk/ui-components/browser/src/index.js +228 -0
- package/src/admin/endpointRegistry.js +120 -0
- package/src/controllers/admin.controller.js +111 -5
- package/src/controllers/adminBlockDefinitions.controller.js +127 -0
- package/src/controllers/adminBlockDefinitionsAi.controller.js +54 -0
- package/src/controllers/adminCache.controller.js +342 -0
- package/src/controllers/adminContextBlockDefinitions.controller.js +141 -0
- package/src/controllers/adminCrons.controller.js +388 -0
- package/src/controllers/adminDbBrowser.controller.js +124 -0
- package/src/controllers/adminEjsVirtual.controller.js +13 -3
- package/src/controllers/adminHeadless.controller.js +91 -2
- package/src/controllers/adminHealthChecks.controller.js +570 -0
- package/src/controllers/adminI18n.controller.js +51 -29
- package/src/controllers/adminLlm.controller.js +126 -2
- package/src/controllers/adminPages.controller.js +720 -0
- package/src/controllers/adminPagesContextBlocksAi.controller.js +54 -0
- package/src/controllers/adminProxy.controller.js +113 -0
- package/src/controllers/adminRateLimits.controller.js +138 -0
- package/src/controllers/adminRbac.controller.js +803 -0
- package/src/controllers/adminScripts.controller.js +320 -0
- package/src/controllers/adminSeoConfig.controller.js +71 -48
- package/src/controllers/adminTerminals.controller.js +39 -0
- package/src/controllers/adminUiComponents.controller.js +315 -0
- package/src/controllers/adminUiComponentsAi.controller.js +34 -0
- package/src/controllers/blogAdmin.controller.js +279 -0
- package/src/controllers/blogAiAdmin.controller.js +224 -0
- package/src/controllers/blogAutomationAdmin.controller.js +141 -0
- package/src/controllers/blogInternal.controller.js +26 -0
- package/src/controllers/blogPublic.controller.js +89 -0
- package/src/controllers/fileManager.controller.js +190 -0
- package/src/controllers/fileManagerStoragePolicy.controller.js +23 -0
- package/src/controllers/healthChecksPublic.controller.js +196 -0
- package/src/controllers/metrics.controller.js +64 -4
- package/src/controllers/orgAdmin.controller.js +366 -0
- package/src/controllers/uiComponentsPublic.controller.js +118 -0
- package/src/middleware/auth.js +7 -0
- package/src/middleware/internalCronAuth.js +29 -0
- package/src/middleware/rbac.js +62 -0
- package/src/middleware.js +879 -56
- package/src/models/BlockDefinition.js +27 -0
- package/src/models/BlogAutomationLock.js +14 -0
- package/src/models/BlogAutomationRun.js +39 -0
- package/src/models/BlogPost.js +42 -0
- package/src/models/CacheEntry.js +26 -0
- package/src/models/ConsoleEntry.js +32 -0
- package/src/models/ConsoleLog.js +23 -0
- package/src/models/ContextBlockDefinition.js +33 -0
- package/src/models/CronExecution.js +47 -0
- package/src/models/CronJob.js +70 -0
- package/src/models/ExternalDbConnection.js +49 -0
- package/src/models/FileEntry.js +22 -0
- package/src/models/HeadlessModelDefinition.js +10 -0
- package/src/models/HealthAutoHealAttempt.js +57 -0
- package/src/models/HealthCheck.js +132 -0
- package/src/models/HealthCheckRun.js +51 -0
- package/src/models/HealthIncident.js +49 -0
- package/src/models/Page.js +95 -0
- package/src/models/PageCollection.js +42 -0
- package/src/models/ProxyEntry.js +66 -0
- package/src/models/RateLimitCounter.js +19 -0
- package/src/models/RateLimitMetricBucket.js +20 -0
- package/src/models/RbacGrant.js +25 -0
- package/src/models/RbacGroup.js +16 -0
- package/src/models/RbacGroupMember.js +13 -0
- package/src/models/RbacGroupRole.js +13 -0
- package/src/models/RbacRole.js +25 -0
- package/src/models/RbacUserRole.js +13 -0
- package/src/models/ScriptDefinition.js +42 -0
- package/src/models/ScriptRun.js +22 -0
- package/src/models/UiComponent.js +29 -0
- package/src/models/UiComponentProject.js +26 -0
- package/src/models/UiComponentProjectComponent.js +18 -0
- package/src/routes/admin.routes.js +1 -0
- package/src/routes/adminBlog.routes.js +21 -0
- package/src/routes/adminBlogAi.routes.js +16 -0
- package/src/routes/adminBlogAutomation.routes.js +27 -0
- package/src/routes/adminCache.routes.js +20 -0
- package/src/routes/adminConsoleManager.routes.js +302 -0
- package/src/routes/adminCrons.routes.js +25 -0
- package/src/routes/adminDbBrowser.routes.js +65 -0
- package/src/routes/adminEjsVirtual.routes.js +2 -1
- package/src/routes/adminHeadless.routes.js +8 -1
- package/src/routes/adminHealthChecks.routes.js +28 -0
- package/src/routes/adminI18n.routes.js +4 -3
- package/src/routes/adminLlm.routes.js +4 -2
- package/src/routes/adminPages.routes.js +55 -0
- package/src/routes/adminProxy.routes.js +15 -0
- package/src/routes/adminRateLimits.routes.js +17 -0
- package/src/routes/adminRbac.routes.js +38 -0
- package/src/routes/adminScripts.routes.js +21 -0
- package/src/routes/adminSeoConfig.routes.js +5 -4
- package/src/routes/adminTerminals.routes.js +13 -0
- package/src/routes/adminUiComponents.routes.js +30 -0
- package/src/routes/blogInternal.routes.js +14 -0
- package/src/routes/blogPublic.routes.js +9 -0
- package/src/routes/fileManager.routes.js +62 -0
- package/src/routes/fileManagerStoragePolicy.routes.js +9 -0
- package/src/routes/healthChecksPublic.routes.js +9 -0
- package/src/routes/log.routes.js +43 -60
- package/src/routes/metrics.routes.js +4 -2
- package/src/routes/orgAdmin.routes.js +6 -0
- package/src/routes/pages.routes.js +123 -0
- package/src/routes/proxy.routes.js +46 -0
- package/src/routes/rbac.routes.js +47 -0
- package/src/routes/uiComponentsPublic.routes.js +9 -0
- package/src/routes/webhook.routes.js +2 -1
- package/src/routes/workflows.routes.js +4 -0
- package/src/services/blockDefinitionsAi.service.js +247 -0
- package/src/services/blog.service.js +99 -0
- package/src/services/blogAutomation.service.js +978 -0
- package/src/services/blogCronsBootstrap.service.js +184 -0
- package/src/services/blogPublishing.service.js +58 -0
- package/src/services/cacheLayer.service.js +696 -0
- package/src/services/consoleManager.service.js +700 -0
- package/src/services/consoleOverride.service.js +6 -1
- package/src/services/cronScheduler.service.js +350 -0
- package/src/services/dbBrowser.service.js +536 -0
- package/src/services/ejsVirtual.service.js +102 -32
- package/src/services/fileManager.service.js +475 -0
- package/src/services/fileManagerStoragePolicy.service.js +285 -0
- package/src/services/headlessExternalModels.service.js +292 -0
- package/src/services/headlessModels.service.js +26 -6
- package/src/services/healthChecks.service.js +650 -0
- package/src/services/healthChecksBootstrap.service.js +109 -0
- package/src/services/healthChecksScheduler.service.js +106 -0
- package/src/services/llmDefaults.service.js +190 -0
- package/src/services/migrationAssets/s3.js +2 -2
- package/src/services/pages.service.js +602 -0
- package/src/services/pagesContext.service.js +331 -0
- package/src/services/pagesContextBlocksAi.service.js +349 -0
- package/src/services/proxy.service.js +535 -0
- package/src/services/rateLimiter.service.js +623 -0
- package/src/services/rbac.service.js +212 -0
- package/src/services/scriptsRunner.service.js +259 -0
- package/src/services/terminals.service.js +152 -0
- package/src/services/terminalsWs.service.js +100 -0
- package/src/services/uiComponentsAi.service.js +299 -0
- package/src/services/uiComponentsCrypto.service.js +39 -0
- package/src/services/workflow.service.js +23 -8
- package/src/utils/orgRoles.js +14 -0
- package/src/utils/rbac/engine.js +60 -0
- package/src/utils/rbac/rightsRegistry.js +29 -0
- package/views/admin-blog-automation.ejs +877 -0
- package/views/admin-blog-edit.ejs +542 -0
- package/views/admin-blog.ejs +399 -0
- package/views/admin-cache.ejs +681 -0
- package/views/admin-console-manager.ejs +680 -0
- package/views/admin-crons.ejs +645 -0
- package/views/admin-db-browser.ejs +445 -0
- package/views/admin-ejs-virtual.ejs +16 -10
- package/views/admin-file-manager.ejs +942 -0
- package/views/admin-headless.ejs +294 -24
- package/views/admin-health-checks.ejs +725 -0
- package/views/admin-i18n.ejs +59 -5
- package/views/admin-llm.ejs +99 -1
- package/views/admin-organizations.ejs +528 -10
- package/views/admin-pages.ejs +2424 -0
- package/views/admin-proxy.ejs +491 -0
- package/views/admin-rate-limiter.ejs +625 -0
- package/views/admin-rbac.ejs +1331 -0
- package/views/admin-scripts.ejs +497 -0
- package/views/admin-seo-config.ejs +61 -7
- package/views/admin-terminals.ejs +328 -0
- package/views/admin-ui-components.ejs +741 -0
- package/views/admin-users.ejs +261 -4
- package/views/admin-workflows.ejs +7 -7
- package/views/file-manager.ejs +866 -0
- package/views/pages/blocks/contact.ejs +27 -0
- package/views/pages/blocks/cta.ejs +18 -0
- package/views/pages/blocks/faq.ejs +20 -0
- package/views/pages/blocks/features.ejs +19 -0
- package/views/pages/blocks/hero.ejs +13 -0
- package/views/pages/blocks/html.ejs +5 -0
- package/views/pages/blocks/image.ejs +14 -0
- package/views/pages/blocks/testimonials.ejs +26 -0
- package/views/pages/blocks/text.ejs +10 -0
- package/views/pages/layouts/default.ejs +51 -0
- package/views/pages/layouts/minimal.ejs +42 -0
- package/views/pages/layouts/sidebar.ejs +54 -0
- package/views/pages/partials/footer.ejs +13 -0
- package/views/pages/partials/header.ejs +12 -0
- package/views/pages/partials/sidebar.ejs +8 -0
- package/views/pages/runtime/page.ejs +10 -0
- package/views/pages/templates/article.ejs +20 -0
- package/views/pages/templates/default.ejs +12 -0
- package/views/pages/templates/landing.ejs +14 -0
- package/views/pages/templates/listing.ejs +15 -0
- package/views/partials/admin-image-upload-modal.ejs +221 -0
- package/views/partials/dashboard/nav-items.ejs +14 -0
- package/views/partials/llm-provider-model-picker.ejs +183 -0
package/views/admin-i18n.ejs
CHANGED
|
@@ -113,6 +113,17 @@
|
|
|
113
113
|
<div class="text-xs text-gray-600 mb-1">To</div>
|
|
114
114
|
<input id="entryAiTo" class="border rounded px-3 py-2" readonly />
|
|
115
115
|
</div>
|
|
116
|
+
<div class="flex-1">
|
|
117
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
|
118
|
+
<%- include('partials/llm-provider-model-picker', {
|
|
119
|
+
providerInputId: 'entryAiProviderKey',
|
|
120
|
+
modelInputId: 'entryAiModel',
|
|
121
|
+
providerLabel: 'Provider',
|
|
122
|
+
modelLabel: 'Model',
|
|
123
|
+
showOpenRouterFetch: true,
|
|
124
|
+
}) %>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
116
127
|
<div class="flex gap-2">
|
|
117
128
|
<button type="button" onclick="aiTranslateEntry()" class="px-4 py-2 bg-purple-600 text-white rounded hover:bg-purple-700">AI translate</button>
|
|
118
129
|
</div>
|
|
@@ -147,8 +158,15 @@
|
|
|
147
158
|
<input id="aiFilter" class="w-full border rounded px-3 py-2" placeholder="Filter keys..." oninput="renderAiCandidates()" />
|
|
148
159
|
</div>
|
|
149
160
|
<div>
|
|
150
|
-
<
|
|
151
|
-
|
|
161
|
+
<div class="grid grid-cols-1 gap-2">
|
|
162
|
+
<%- include('partials/llm-provider-model-picker', {
|
|
163
|
+
providerInputId: 'aiProviderKey',
|
|
164
|
+
modelInputId: 'aiModel',
|
|
165
|
+
providerLabel: 'Provider',
|
|
166
|
+
modelLabel: 'Model',
|
|
167
|
+
showOpenRouterFetch: true,
|
|
168
|
+
}) %>
|
|
169
|
+
</div>
|
|
152
170
|
</div>
|
|
153
171
|
<div class="flex items-center gap-2 pt-8">
|
|
154
172
|
<input id="aiMissing" type="checkbox" onchange="renderAiCandidates()" />
|
|
@@ -204,7 +222,7 @@
|
|
|
204
222
|
</div>
|
|
205
223
|
|
|
206
224
|
<script>
|
|
207
|
-
const API_BASE = window.location.origin + "<%= baseUrl %>"
|
|
225
|
+
const API_BASE = window.location.origin + "<%= baseUrl || '' %>";
|
|
208
226
|
let allLocales = [];
|
|
209
227
|
let aiResults = [];
|
|
210
228
|
let aiCandidates = [];
|
|
@@ -213,6 +231,22 @@
|
|
|
213
231
|
let aiToLocaleKeySet = null;
|
|
214
232
|
let aiToLocaleKeySetFor = null;
|
|
215
233
|
|
|
234
|
+
function initLlmPickers() {
|
|
235
|
+
if (!window.__llmProviderModelPicker || !window.__llmProviderModelPicker.init) return;
|
|
236
|
+
|
|
237
|
+
window.__llmProviderModelPicker.init({
|
|
238
|
+
apiBase: API_BASE,
|
|
239
|
+
providerInputId: 'aiProviderKey',
|
|
240
|
+
modelInputId: 'aiModel',
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
window.__llmProviderModelPicker.init({
|
|
244
|
+
apiBase: API_BASE,
|
|
245
|
+
providerInputId: 'entryAiProviderKey',
|
|
246
|
+
modelInputId: 'entryAiModel',
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
216
250
|
function showToast(message, type = 'success') {
|
|
217
251
|
const container = document.getElementById('toast-container');
|
|
218
252
|
const toast = document.createElement('div');
|
|
@@ -323,6 +357,7 @@
|
|
|
323
357
|
document.getElementById('entryLocale').disabled = false;
|
|
324
358
|
|
|
325
359
|
document.getElementById('modal').classList.remove('hidden');
|
|
360
|
+
initLlmPickers();
|
|
326
361
|
}
|
|
327
362
|
|
|
328
363
|
function createMissing(key) {
|
|
@@ -341,6 +376,7 @@
|
|
|
341
376
|
document.getElementById('entryLocale').disabled = true;
|
|
342
377
|
|
|
343
378
|
document.getElementById('modal').classList.remove('hidden');
|
|
379
|
+
initLlmPickers();
|
|
344
380
|
}
|
|
345
381
|
|
|
346
382
|
async function aiTranslateEntry() {
|
|
@@ -348,11 +384,19 @@
|
|
|
348
384
|
const fromLocale = document.getElementById('entryAiFrom').value;
|
|
349
385
|
const toLocale = document.getElementById('entryAiTo').value || document.getElementById('entryLocale').value;
|
|
350
386
|
const text = document.getElementById('entryValue').value;
|
|
387
|
+
const providerKey = document.getElementById('entryAiProviderKey')?.value;
|
|
388
|
+
const model = document.getElementById('entryAiModel')?.value;
|
|
351
389
|
|
|
352
390
|
const res = await fetch(`${API_BASE}/api/admin/i18n/ai/translate-text`, {
|
|
353
391
|
method: 'POST',
|
|
354
392
|
headers: { 'Content-Type': 'application/json' },
|
|
355
|
-
body: JSON.stringify({
|
|
393
|
+
body: JSON.stringify({
|
|
394
|
+
fromLocale,
|
|
395
|
+
toLocale,
|
|
396
|
+
text,
|
|
397
|
+
providerKey: providerKey ? String(providerKey).trim() : undefined,
|
|
398
|
+
model: model ? String(model).trim() : undefined,
|
|
399
|
+
})
|
|
356
400
|
});
|
|
357
401
|
|
|
358
402
|
if (!res.ok) {
|
|
@@ -390,6 +434,7 @@
|
|
|
390
434
|
document.getElementById('entryLocale').disabled = true;
|
|
391
435
|
|
|
392
436
|
document.getElementById('modal').classList.remove('hidden');
|
|
437
|
+
initLlmPickers();
|
|
393
438
|
} catch (e) {
|
|
394
439
|
showToast(e.message, 'error');
|
|
395
440
|
}
|
|
@@ -489,6 +534,7 @@
|
|
|
489
534
|
document.getElementById('aiCandidateSummary').textContent = '0 selected';
|
|
490
535
|
|
|
491
536
|
document.getElementById('aiModal').classList.remove('hidden');
|
|
537
|
+
initLlmPickers();
|
|
492
538
|
loadAiCandidates();
|
|
493
539
|
}
|
|
494
540
|
|
|
@@ -634,6 +680,7 @@
|
|
|
634
680
|
try {
|
|
635
681
|
const fromLocale = document.getElementById('aiFrom').value;
|
|
636
682
|
const toLocale = document.getElementById('aiTo').value;
|
|
683
|
+
const providerKey = document.getElementById('aiProviderKey')?.value;
|
|
637
684
|
const model = document.getElementById('aiModel').value;
|
|
638
685
|
const keys = Array.from(aiSelectedKeys);
|
|
639
686
|
|
|
@@ -645,7 +692,14 @@
|
|
|
645
692
|
const res = await fetch(`${API_BASE}/api/admin/i18n/ai/preview`, {
|
|
646
693
|
method: 'POST',
|
|
647
694
|
headers: { 'Content-Type': 'application/json' },
|
|
648
|
-
body: JSON.stringify({
|
|
695
|
+
body: JSON.stringify({
|
|
696
|
+
fromLocale,
|
|
697
|
+
toLocale,
|
|
698
|
+
keys,
|
|
699
|
+
missingOnly: false,
|
|
700
|
+
providerKey: providerKey ? String(providerKey).trim() : undefined,
|
|
701
|
+
model: model ? String(model).trim() : undefined,
|
|
702
|
+
})
|
|
649
703
|
});
|
|
650
704
|
|
|
651
705
|
if (!res.ok) {
|
package/views/admin-llm.ejs
CHANGED
|
@@ -34,6 +34,47 @@
|
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
36
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-8">
|
|
37
|
+
<!-- Defaults + Model Suggestions -->
|
|
38
|
+
<div class="bg-white rounded-lg shadow">
|
|
39
|
+
<div class="px-4 py-3 border-b">
|
|
40
|
+
<h2 class="text-lg font-semibold text-gray-900">Centralized Defaults</h2>
|
|
41
|
+
<p class="text-sm text-gray-600">Global and per-system defaults used by AI features (provider/model). Models are suggestions only.</p>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="p-4 space-y-4">
|
|
44
|
+
<div class="flex items-center justify-end">
|
|
45
|
+
<button id="btnSaveCentralDefaults" class="px-3 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 text-sm">Save centralized defaults</button>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
48
|
+
<div>
|
|
49
|
+
<label class="block text-xs font-medium mb-1">Global default providerKey</label>
|
|
50
|
+
<input id="defaultsProviderKey" type="text" class="w-full border rounded px-2 py-1 text-sm" placeholder="e.g. openrouter" />
|
|
51
|
+
</div>
|
|
52
|
+
<div>
|
|
53
|
+
<label class="block text-xs font-medium mb-1">Global default model</label>
|
|
54
|
+
<input id="defaultsModel" type="text" class="w-full border rounded px-2 py-1 text-sm" placeholder="e.g. google/gemini-2.5-flash-lite" />
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
59
|
+
<div>
|
|
60
|
+
<div class="flex items-center justify-between mb-1">
|
|
61
|
+
<label class="block text-xs font-medium">System defaults (JSON map)</label>
|
|
62
|
+
</div>
|
|
63
|
+
<textarea id="systemDefaultsJson" rows="8" class="w-full border rounded px-2 py-1 text-sm font-mono" placeholder="{\n "pageBuilder.blocks.generate": { "providerKey": "openrouter", "model": "..." }\n}"></textarea>
|
|
64
|
+
<p class="text-[11px] text-gray-500 mt-1">Stored as <code>llm.systemDefaults</code>.</p>
|
|
65
|
+
</div>
|
|
66
|
+
<div>
|
|
67
|
+
<div class="flex items-center justify-between mb-1">
|
|
68
|
+
<label class="block text-xs font-medium">Provider model suggestions (JSON map)</label>
|
|
69
|
+
<button id="btnFetchOpenRouterModels" class="px-2 py-1 bg-gray-200 text-gray-800 rounded text-xs">Fetch OpenRouter models</button>
|
|
70
|
+
</div>
|
|
71
|
+
<textarea id="providerModelsJson" rows="8" class="w-full border rounded px-2 py-1 text-sm font-mono" placeholder="{\n "openrouter": [\"google/gemini-2.5-flash-lite\"]\n}"></textarea>
|
|
72
|
+
<p class="text-[11px] text-gray-500 mt-1">Stored as <code>llm.providerModels</code>. Suggestions only.</p>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
37
78
|
<!-- Providers + Prompts -->
|
|
38
79
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
39
80
|
<!-- Providers -->
|
|
@@ -388,6 +429,9 @@ console.log(result.content);</pre>
|
|
|
388
429
|
const API_BASE = window.location.origin + "<%= baseUrl %>" || window.location.origin;
|
|
389
430
|
let providers = {};
|
|
390
431
|
let prompts = {};
|
|
432
|
+
let defaults = { providerKey: '', model: '' };
|
|
433
|
+
let systemDefaults = {};
|
|
434
|
+
let providerModels = {};
|
|
391
435
|
let auditPage = 1;
|
|
392
436
|
let costPage = 1;
|
|
393
437
|
|
|
@@ -479,6 +523,14 @@ console.log(result.content);</pre>
|
|
|
479
523
|
if (!res.ok) throw new Error(data?.error || 'Failed to load config');
|
|
480
524
|
providers = data.providers || {};
|
|
481
525
|
prompts = data.prompts || {};
|
|
526
|
+
defaults = data.defaults || { providerKey: '', model: '' };
|
|
527
|
+
systemDefaults = data.systemDefaults || {};
|
|
528
|
+
providerModels = data.providerModels || {};
|
|
529
|
+
|
|
530
|
+
document.getElementById('defaultsProviderKey').value = defaults.providerKey || '';
|
|
531
|
+
document.getElementById('defaultsModel').value = defaults.model || '';
|
|
532
|
+
document.getElementById('systemDefaultsJson').value = JSON.stringify(systemDefaults || {}, null, 2);
|
|
533
|
+
document.getElementById('providerModelsJson').value = JSON.stringify(providerModels || {}, null, 2);
|
|
482
534
|
renderProviders();
|
|
483
535
|
renderPrompts();
|
|
484
536
|
} catch (e) {
|
|
@@ -488,10 +540,31 @@ console.log(result.content);</pre>
|
|
|
488
540
|
|
|
489
541
|
async function saveConfig() {
|
|
490
542
|
try {
|
|
543
|
+
defaults = {
|
|
544
|
+
providerKey: document.getElementById('defaultsProviderKey').value.trim(),
|
|
545
|
+
model: document.getElementById('defaultsModel').value.trim(),
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
try {
|
|
549
|
+
const rawSystemDefaults = document.getElementById('systemDefaultsJson').value;
|
|
550
|
+
systemDefaults = rawSystemDefaults && rawSystemDefaults.trim() ? JSON.parse(rawSystemDefaults) : {};
|
|
551
|
+
} catch (e) {
|
|
552
|
+
showToast('Invalid systemDefaults JSON: ' + e.message, 'error');
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
const rawProviderModels = document.getElementById('providerModelsJson').value;
|
|
558
|
+
providerModels = rawProviderModels && rawProviderModels.trim() ? JSON.parse(rawProviderModels) : {};
|
|
559
|
+
} catch (e) {
|
|
560
|
+
showToast('Invalid providerModels JSON: ' + e.message, 'error');
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
|
|
491
564
|
const res = await fetch(`${API_BASE}/api/admin/llm/config`, {
|
|
492
565
|
method: 'POST',
|
|
493
566
|
headers: { 'Content-Type': 'application/json' },
|
|
494
|
-
body: JSON.stringify({ providers, prompts }),
|
|
567
|
+
body: JSON.stringify({ providers, prompts, defaults, systemDefaults, providerModels }),
|
|
495
568
|
});
|
|
496
569
|
const data = await res.json();
|
|
497
570
|
if (!res.ok) throw new Error(data?.error || 'Failed to save config');
|
|
@@ -501,6 +574,28 @@ console.log(result.content);</pre>
|
|
|
501
574
|
}
|
|
502
575
|
}
|
|
503
576
|
|
|
577
|
+
async function fetchOpenRouterModels() {
|
|
578
|
+
try {
|
|
579
|
+
const res = await fetch(`${API_BASE}/api/admin/llm/openrouter/models`);
|
|
580
|
+
const data = await res.json();
|
|
581
|
+
if (!res.ok) throw new Error(data?.error || 'Failed to fetch OpenRouter models');
|
|
582
|
+
const models = Array.isArray(data?.models) ? data.models : [];
|
|
583
|
+
|
|
584
|
+
const rawProviderModels = document.getElementById('providerModelsJson').value;
|
|
585
|
+
let map = {};
|
|
586
|
+
try {
|
|
587
|
+
map = rawProviderModels && rawProviderModels.trim() ? JSON.parse(rawProviderModels) : {};
|
|
588
|
+
} catch (_) {
|
|
589
|
+
map = {};
|
|
590
|
+
}
|
|
591
|
+
map.openrouter = models;
|
|
592
|
+
document.getElementById('providerModelsJson').value = JSON.stringify(map, null, 2);
|
|
593
|
+
showToast('OpenRouter models loaded');
|
|
594
|
+
} catch (e) {
|
|
595
|
+
showToast(e.message, 'error');
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
504
599
|
function applyProviderPresetDefaults() {
|
|
505
600
|
const preset = document.getElementById('providerPreset').value;
|
|
506
601
|
const baseUrlInput = document.getElementById('providerBaseUrl');
|
|
@@ -848,6 +943,9 @@ console.log(result.content);</pre>
|
|
|
848
943
|
document.getElementById('btnSaveProvider').addEventListener('click', createOrUpdateProviderFromForm);
|
|
849
944
|
document.getElementById('providerPreset').addEventListener('change', applyProviderPresetDefaults);
|
|
850
945
|
|
|
946
|
+
document.getElementById('btnFetchOpenRouterModels').addEventListener('click', fetchOpenRouterModels);
|
|
947
|
+
document.getElementById('btnSaveCentralDefaults').addEventListener('click', saveConfig);
|
|
948
|
+
|
|
851
949
|
document.getElementById('btnAddPrompt').addEventListener('click', () => openPromptEditor(null));
|
|
852
950
|
document.getElementById('btnCancelPrompt').addEventListener('click', closePromptEditor);
|
|
853
951
|
document.getElementById('btnSavePrompt').addEventListener('click', createOrUpdatePromptFromForm);
|