@intranefr/superbackend 1.5.0 → 1.5.2
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 +15 -0
- package/README.md +11 -0
- package/analysis-only.skill +0 -0
- package/index.js +23 -0
- package/package.json +8 -2
- package/src/admin/endpointRegistry.js +120 -0
- package/src/controllers/admin.controller.js +90 -6
- 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/adminExperiments.controller.js +200 -0
- package/src/controllers/adminHeadless.controller.js +9 -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 +126 -4
- package/src/controllers/adminSeoConfig.controller.js +71 -48
- 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/experiments.controller.js +85 -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/internalExperiments.controller.js +17 -0
- package/src/controllers/metrics.controller.js +64 -4
- package/src/controllers/orgAdmin.controller.js +80 -0
- package/src/helpers/mongooseHelper.js +258 -0
- package/src/helpers/scriptBase.js +230 -0
- package/src/helpers/scriptRunner.js +335 -0
- package/src/middleware/rbac.js +62 -0
- package/src/middleware.js +810 -48
- 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/Experiment.js +75 -0
- package/src/models/ExperimentAssignment.js +23 -0
- package/src/models/ExperimentEvent.js +26 -0
- package/src/models/ExperimentMetricBucket.js +30 -0
- package/src/models/ExternalDbConnection.js +49 -0
- package/src/models/FileEntry.js +22 -0
- package/src/models/GlobalSetting.js +1 -2
- 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 +1 -0
- package/src/models/Webhook.js +2 -0
- package/src/routes/admin.routes.js +2 -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/adminExperiments.routes.js +29 -0
- package/src/routes/adminHeadless.routes.js +2 -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/adminSeoConfig.routes.js +5 -4
- package/src/routes/adminUiComponents.routes.js +2 -1
- package/src/routes/blogInternal.routes.js +14 -0
- package/src/routes/blogPublic.routes.js +9 -0
- package/src/routes/experiments.routes.js +30 -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/internalExperiments.routes.js +15 -0
- package/src/routes/log.routes.js +43 -60
- package/src/routes/metrics.routes.js +4 -2
- package/src/routes/orgAdmin.routes.js +1 -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/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 +185 -0
- package/src/services/blogPublishing.service.js +58 -0
- package/src/services/cacheLayer.service.js +696 -0
- package/src/services/consoleManager.service.js +738 -0
- package/src/services/consoleOverride.service.js +7 -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/experiments.service.js +273 -0
- package/src/services/experimentsAggregation.service.js +308 -0
- package/src/services/experimentsCronsBootstrap.service.js +118 -0
- package/src/services/experimentsRetention.service.js +43 -0
- package/src/services/experimentsWs.service.js +134 -0
- package/src/services/fileManager.service.js +475 -0
- package/src/services/fileManagerStoragePolicy.service.js +285 -0
- package/src/services/globalSettings.service.js +15 -0
- 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/jsonConfigs.service.js +2 -2
- 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 +215 -15
- package/src/services/uiComponentsAi.service.js +6 -19
- 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 +33 -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-dashboard.ejs +28 -8
- package/views/admin-db-browser.ejs +445 -0
- package/views/admin-ejs-virtual.ejs +16 -10
- package/views/admin-experiments.ejs +91 -0
- package/views/admin-file-manager.ejs +942 -0
- 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 +163 -1
- 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 +597 -3
- package/views/admin-seo-config.ejs +61 -7
- package/views/admin-ui-components.ejs +57 -25
- 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 +12 -0
- package/views/partials/dashboard/palette.ejs +5 -3
- package/views/partials/llm-provider-model-picker.ejs +183 -0
- package/src/routes/llmUi.routes.js +0 -26
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
items: [
|
|
14
14
|
{ id: 'users', label: 'Users', path: adminPath + '/users', icon: 'ti-users' },
|
|
15
15
|
{ id: 'orgs', label: 'Organizations', path: adminPath + '/organizations', icon: 'ti-building-community' },
|
|
16
|
+
{ id: 'rbac', label: 'RBAC', path: adminPath + '/rbac', icon: 'ti-lock' },
|
|
16
17
|
{ id: 'notifications', label: 'Notifications', path: adminPath + '/notifications', icon: 'ti-bell' },
|
|
17
18
|
{ id: 'invites', label: 'Waiting List', path: adminPath + '/waiting-list', icon: 'ti-mail-forward' },
|
|
18
19
|
]
|
|
@@ -25,8 +26,11 @@
|
|
|
25
26
|
{ id: 'json', label: 'JSON Configs', path: adminPath + '/json-configs', icon: 'ti-braces' },
|
|
26
27
|
{ id: 'seo', label: 'SEO Config', path: adminPath + '/seo-config', icon: 'ti-search' },
|
|
27
28
|
{ id: 'assets', label: 'Assets', path: adminPath + '/assets', icon: 'ti-photo' },
|
|
29
|
+
{ id: 'file-manager', label: 'File Manager', path: adminPath + '/file-manager', icon: 'ti-folder' },
|
|
28
30
|
{ id: 'ui-components', label: 'UI Components', path: adminPath + '/ui-components', icon: 'ti-components' },
|
|
29
31
|
{ id: 'headless', label: 'Headless CMS', path: adminPath + '/headless', icon: 'ti-table' },
|
|
32
|
+
{ id: 'pages', label: 'Pages', path: adminPath + '/pages', icon: 'ti-file-text' },
|
|
33
|
+
{ id: 'blog-system', label: 'Blog system', path: adminPath + '/blog', icon: 'ti-news' },
|
|
30
34
|
]
|
|
31
35
|
},
|
|
32
36
|
{
|
|
@@ -35,6 +39,10 @@
|
|
|
35
39
|
{ id: 'settings', label: 'Global Settings', path: adminPath + '/global-settings', icon: 'ti-settings' },
|
|
36
40
|
{ id: 'flags', label: 'Feature Flags', path: adminPath + '/feature-flags', icon: 'ti-flag' },
|
|
37
41
|
{ id: 'ejs', label: 'Virtual EJS', path: adminPath + '/ejs-virtual', icon: 'ti-code' },
|
|
42
|
+
{ id: 'rate-limiter', label: 'Rate Limiter', path: adminPath + '/rate-limiter', icon: 'ti-traffic-cone' },
|
|
43
|
+
{ id: 'proxy', label: 'Proxy system', path: adminPath + '/proxy', icon: 'ti-world' },
|
|
44
|
+
{ id: 'cache', label: 'Cache Layer', path: adminPath + '/cache', icon: 'ti-database' },
|
|
45
|
+
{ id: 'db-browser', label: 'DB Browser', path: adminPath + '/db-browser', icon: 'ti-database-search' },
|
|
38
46
|
{ id: 'migration', label: 'Migration', path: adminPath + '/migration', icon: 'ti-database-export' },
|
|
39
47
|
{ id: 'webhooks', label: 'Webhooks', path: adminPath + '/webhooks', icon: 'ti-webhook' },
|
|
40
48
|
{ id: 'coolify', label: 'Coolify Deploy', path: adminPath + '/coolify-deploy', icon: 'ti-rocket' },
|
|
@@ -45,6 +53,9 @@
|
|
|
45
53
|
items: [
|
|
46
54
|
{ id: 'audit', label: 'Audit Logs', path: adminPath + '/audit', icon: 'ti-history' },
|
|
47
55
|
{ id: 'errors', label: 'Error Tracking', path: adminPath + '/errors', icon: 'ti-bug' },
|
|
56
|
+
{ id: 'experiments', label: 'Experiments', path: adminPath + '/experiments', icon: 'ti-flask-2' },
|
|
57
|
+
{ id: 'console-manager', label: 'Console Manager', path: adminPath + '/console-manager', icon: 'ti-terminal-2' },
|
|
58
|
+
{ id: 'health-checks', label: 'Health Checks', path: adminPath + '/health-checks', icon: 'ti-heartbeat' },
|
|
48
59
|
{ id: 'metrics', label: 'Metrics', path: adminPath + '/metrics', icon: 'ti-chart-bar' },
|
|
49
60
|
{ id: 'llm', label: 'LLM/AI', path: adminPath + '/admin-llm', icon: 'ti-brain' },
|
|
50
61
|
]
|
|
@@ -61,6 +72,7 @@
|
|
|
61
72
|
items: [
|
|
62
73
|
{ id: 'workflows', label: 'Workflows', path: adminPath + '/workflows/all', icon: 'ti-robot' },
|
|
63
74
|
{ id: 'scripts', label: 'Scripts', path: adminPath + '/scripts', icon: 'ti-terminal-2' },
|
|
75
|
+
{ id: 'crons', label: 'Crons', path: adminPath + '/crons', icon: 'ti-clock' },
|
|
64
76
|
{ id: 'terminals', label: 'Terminals', path: adminPath + '/terminals', icon: 'ti-terminal' },
|
|
65
77
|
]
|
|
66
78
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<!-- Command Palette Component -->
|
|
2
2
|
<div v-if="showPalette" class="fixed inset-0 z-[100] flex items-start justify-center pt-[15vh] px-4">
|
|
3
3
|
<!-- Backdrop -->
|
|
4
|
-
<div class="fixed inset-0 bg-gray-900/50 backdrop-blur-sm" @click="closePalette"></div>
|
|
4
|
+
<div class="fixed inset-0 bg-gray-900/50 backdrop-blur-sm" @click.stop="closePalette('backdrop-click')" @mousedown.stop></div>
|
|
5
5
|
|
|
6
6
|
<!-- Palette Modal -->
|
|
7
|
-
<div class="relative w-full max-w-2xl bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden flex flex-col"
|
|
7
|
+
<div class="relative w-full max-w-2xl bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden flex flex-col"
|
|
8
|
+
@click.stop
|
|
9
|
+
@mousedown.stop>
|
|
8
10
|
<!-- Input -->
|
|
9
11
|
<div class="relative flex items-center px-4 py-4 border-b border-gray-200">
|
|
10
12
|
<i class="ti ti-search text-gray-400 text-xl mr-3"></i>
|
|
@@ -17,7 +19,7 @@
|
|
|
17
19
|
@keydown.down.prevent="navigatePalette(1)"
|
|
18
20
|
@keydown.up.prevent="navigatePalette(-1)"
|
|
19
21
|
@keydown.enter.prevent="selectPaletteItem"
|
|
20
|
-
@keydown.esc="closePalette"
|
|
22
|
+
@keydown.esc="closePalette('escape-key')"
|
|
21
23
|
>
|
|
22
24
|
<div class="flex items-center gap-1 ml-4">
|
|
23
25
|
<kbd class="px-2 py-1 bg-gray-100 border border-gray-300 rounded text-xs text-gray-500 font-sans">ESC</kbd>
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
<div class="min-w-[200px]">
|
|
2
|
+
<label class="block text-xs font-medium text-gray-600 mb-1"><%= (typeof providerLabel !== 'undefined' && providerLabel) ? providerLabel : 'LLM Provider Key' %></label>
|
|
3
|
+
<input id="<%= providerInputId %>" class="w-full border rounded px-2 py-2 text-sm" placeholder="e.g. openrouter" list="<%= providerInputId %>__datalist" />
|
|
4
|
+
<datalist id="<%= providerInputId %>__datalist"></datalist>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<div class="min-w-[260px]">
|
|
8
|
+
<div class="flex flex-wrap items-center justify-between gap-2 mb-1">
|
|
9
|
+
<label class="block text-xs font-medium text-gray-600"><%= (typeof modelLabel !== 'undefined' && modelLabel) ? modelLabel : 'Model' %></label>
|
|
10
|
+
<% if ((typeof showOpenRouterFetch === 'undefined') ? true : (showOpenRouterFetch !== false)) { %>
|
|
11
|
+
<button
|
|
12
|
+
type="button"
|
|
13
|
+
class="px-2 py-1 bg-gray-200 text-gray-800 rounded text-[11px] whitespace-nowrap"
|
|
14
|
+
onclick="window.__llmProviderModelPicker && window.__llmProviderModelPicker.fetchOpenRouterModels && window.__llmProviderModelPicker.fetchOpenRouterModels({ providerInputId: '<%= providerInputId %>', modelInputId: '<%= modelInputId %>' })"
|
|
15
|
+
>
|
|
16
|
+
Fetch OpenRouter models
|
|
17
|
+
</button>
|
|
18
|
+
<% } %>
|
|
19
|
+
</div>
|
|
20
|
+
<input id="<%= modelInputId %>" class="w-full border rounded px-2 py-2 text-sm" placeholder="e.g. google/gemini-2.5-flash-lite" list="<%= modelInputId %>__datalist" />
|
|
21
|
+
<datalist id="<%= modelInputId %>__datalist"></datalist>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
(function () {
|
|
26
|
+
if (!window.__llmProviderModelPicker) {
|
|
27
|
+
window.__llmProviderModelPicker = { instances: {} };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function safeJsonParse(raw, fallback) {
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(raw);
|
|
33
|
+
} catch (_) {
|
|
34
|
+
return fallback;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function fetchJson(url) {
|
|
39
|
+
const res = await fetch(url);
|
|
40
|
+
const data = await res.json();
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
throw new Error(data?.error || 'Request failed');
|
|
43
|
+
}
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function setDatalistOptions(datalistEl, items) {
|
|
48
|
+
datalistEl.innerHTML = '';
|
|
49
|
+
const uniq = Array.from(new Set((items || []).filter(Boolean)));
|
|
50
|
+
for (const item of uniq) {
|
|
51
|
+
const opt = document.createElement('option');
|
|
52
|
+
opt.value = String(item);
|
|
53
|
+
datalistEl.appendChild(opt);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function trim(v) {
|
|
58
|
+
return String(v || '').trim();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function isOpenRouterProvider({ providerKey, providerConfig }) {
|
|
62
|
+
const pk = String(providerKey || '').trim().toLowerCase();
|
|
63
|
+
if (pk === 'openrouter') return true;
|
|
64
|
+
|
|
65
|
+
const baseUrl = providerConfig && typeof providerConfig === 'object'
|
|
66
|
+
? String(providerConfig.baseUrl || providerConfig.baseURL || '').trim().toLowerCase()
|
|
67
|
+
: '';
|
|
68
|
+
|
|
69
|
+
return Boolean(baseUrl && baseUrl.includes('openrouter'));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getInstanceKey({ providerInputId, modelInputId }) {
|
|
73
|
+
return `${String(providerInputId || '').trim()}::${String(modelInputId || '').trim()}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getOrCreateInstance(opts) {
|
|
77
|
+
const key = getInstanceKey(opts);
|
|
78
|
+
const existing = window.__llmProviderModelPicker.instances[key];
|
|
79
|
+
if (existing) return existing;
|
|
80
|
+
|
|
81
|
+
const inst = {
|
|
82
|
+
apiBase: opts.apiBase,
|
|
83
|
+
providerInputId: opts.providerInputId,
|
|
84
|
+
modelInputId: opts.modelInputId,
|
|
85
|
+
providers: {},
|
|
86
|
+
providerModels: {},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
window.__llmProviderModelPicker.instances[key] = inst;
|
|
90
|
+
return inst;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function loadConfig(inst) {
|
|
94
|
+
const data = await fetchJson(`${inst.apiBase}/api/admin/llm/config`);
|
|
95
|
+
inst.providers = data.providers || {};
|
|
96
|
+
inst.providerModels = data.providerModels || {};
|
|
97
|
+
return data;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function renderProviderOptions(inst) {
|
|
101
|
+
const providerInput = document.getElementById(inst.providerInputId);
|
|
102
|
+
const providerList = document.getElementById(`${inst.providerInputId}__datalist`);
|
|
103
|
+
if (!providerInput || !providerList) return;
|
|
104
|
+
|
|
105
|
+
const providerKeys = Object.keys(inst.providers || {}).sort();
|
|
106
|
+
setDatalistOptions(providerList, providerKeys);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function renderModelOptions(inst) {
|
|
110
|
+
const providerInput = document.getElementById(inst.providerInputId);
|
|
111
|
+
const modelList = document.getElementById(`${inst.modelInputId}__datalist`);
|
|
112
|
+
if (!providerInput || !modelList) return;
|
|
113
|
+
|
|
114
|
+
const providerKey = trim(providerInput.value);
|
|
115
|
+
const models = providerKey && inst.providerModels && typeof inst.providerModels === 'object'
|
|
116
|
+
? inst.providerModels[providerKey]
|
|
117
|
+
: null;
|
|
118
|
+
|
|
119
|
+
setDatalistOptions(modelList, Array.isArray(models) ? models : []);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function maybeAutoFetchOpenRouterModels(inst) {
|
|
123
|
+
try {
|
|
124
|
+
const providerInput = document.getElementById(inst.providerInputId);
|
|
125
|
+
if (!providerInput) return;
|
|
126
|
+
|
|
127
|
+
const providerKey = trim(providerInput.value);
|
|
128
|
+
const providerConfig = inst.providers && typeof inst.providers === 'object' ? inst.providers[providerKey] : null;
|
|
129
|
+
if (!isOpenRouterProvider({ providerKey, providerConfig })) return;
|
|
130
|
+
|
|
131
|
+
const existing = inst.providerModels && typeof inst.providerModels === 'object' ? inst.providerModels.openrouter : null;
|
|
132
|
+
if (Array.isArray(existing) && existing.length > 0) return;
|
|
133
|
+
|
|
134
|
+
await fetchOpenRouterModels({
|
|
135
|
+
apiBase: inst.apiBase,
|
|
136
|
+
providerInputId: inst.providerInputId,
|
|
137
|
+
modelInputId: inst.modelInputId,
|
|
138
|
+
});
|
|
139
|
+
} catch {
|
|
140
|
+
// ignore
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function fetchOpenRouterModels(opts) {
|
|
145
|
+
const inst = getOrCreateInstance(opts || {});
|
|
146
|
+
inst.apiBase = (opts && opts.apiBase) || inst.apiBase || window.__llmProviderModelPicker.defaultApiBase || null;
|
|
147
|
+
if (!inst.apiBase) return;
|
|
148
|
+
|
|
149
|
+
const data = await fetchJson(`${inst.apiBase}/api/admin/llm/openrouter/models`);
|
|
150
|
+
const models = Array.isArray(data?.models) ? data.models : [];
|
|
151
|
+
|
|
152
|
+
inst.providerModels = inst.providerModels && typeof inst.providerModels === 'object' ? inst.providerModels : {};
|
|
153
|
+
inst.providerModels.openrouter = models;
|
|
154
|
+
renderModelOptions(inst);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function init(opts) {
|
|
158
|
+
const inst = getOrCreateInstance(opts || {});
|
|
159
|
+
|
|
160
|
+
if (opts && opts.apiBase) {
|
|
161
|
+
window.__llmProviderModelPicker.defaultApiBase = opts.apiBase;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
await loadConfig(inst);
|
|
165
|
+
renderProviderOptions(inst);
|
|
166
|
+
renderModelOptions(inst);
|
|
167
|
+
await maybeAutoFetchOpenRouterModels(inst);
|
|
168
|
+
|
|
169
|
+
const providerInput = document.getElementById(inst.providerInputId);
|
|
170
|
+
if (providerInput) {
|
|
171
|
+
providerInput.addEventListener('change', async () => {
|
|
172
|
+
renderModelOptions(inst);
|
|
173
|
+
await maybeAutoFetchOpenRouterModels(inst);
|
|
174
|
+
});
|
|
175
|
+
providerInput.addEventListener('input', () => renderModelOptions(inst));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
window.__llmProviderModelPicker.init = init;
|
|
180
|
+
window.__llmProviderModelPicker.fetchOpenRouterModels = fetchOpenRouterModels;
|
|
181
|
+
window.__llmProviderModelPicker._util = { safeJsonParse };
|
|
182
|
+
})();
|
|
183
|
+
</script>
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const express = require('express');
|
|
2
|
-
const router = express.Router();
|
|
3
|
-
|
|
4
|
-
const { basicAuth } = require('../middleware/auth');
|
|
5
|
-
const adminUiComponentsController = require('../controllers/adminUiComponents.controller');
|
|
6
|
-
|
|
7
|
-
router.use(basicAuth);
|
|
8
|
-
|
|
9
|
-
router.get('/projects', adminUiComponentsController.listProjects);
|
|
10
|
-
router.post('/projects', adminUiComponentsController.createProject);
|
|
11
|
-
router.get('/projects/:projectId', adminUiComponentsController.getProject);
|
|
12
|
-
router.put('/projects/:projectId', adminUiComponentsController.updateProject);
|
|
13
|
-
router.delete('/projects/:projectId', adminUiComponentsController.deleteProject);
|
|
14
|
-
router.post('/projects/:projectId/rotate-key', adminUiComponentsController.rotateProjectKey);
|
|
15
|
-
|
|
16
|
-
router.get('/components', adminUiComponentsController.listComponents);
|
|
17
|
-
router.post('/components', adminUiComponentsController.createComponent);
|
|
18
|
-
router.get('/components/:code', adminUiComponentsController.getComponent);
|
|
19
|
-
router.put('/components/:code', adminUiComponentsController.updateComponent);
|
|
20
|
-
router.delete('/components/:code', adminUiComponentsController.deleteComponent);
|
|
21
|
-
|
|
22
|
-
router.get('/projects/:projectId/components', adminUiComponentsController.listProjectAssignments);
|
|
23
|
-
router.post('/projects/:projectId/components/:code', adminUiComponentsController.setAssignment);
|
|
24
|
-
router.delete('/projects/:projectId/components/:code', adminUiComponentsController.deleteAssignment);
|
|
25
|
-
|
|
26
|
-
module.exports = router;
|