@betterportal/config-manager 10.0.31 → 10.1.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/lib/.bsb/clients/service-betterportal-config-manager.d.ts +1 -1
- package/lib/.bsb/clients/service-betterportal-config-manager.js +1 -1
- package/lib/plugins/service-betterportal-config-manager/adminApi.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/adminApi.js +117 -31
- package/lib/plugins/service-betterportal-config-manager/adminApi.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bootstrapEndpoint.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bootstrapEndpoint.js +15 -13
- package/lib/plugins/service-betterportal-config-manager/bootstrapEndpoint.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/_theme.bootstrap1/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/_theme.bootstrap1/GET.js +121 -6
- package/lib/plugins/service-betterportal-config-manager/bp-routes/auth/_theme.bootstrap1/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_theme.bootstrap1/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_theme.bootstrap1/GET.js +36 -2
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_theme.bootstrap1/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.d.ts +6 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.js +3 -0
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/_theme.bootstrap1/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/_theme.bootstrap1/GET.js +114 -31
- package/lib/plugins/service-betterportal-config-manager/bp-routes/services/_theme.bootstrap1/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/route.impl.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/route.impl.js +9 -4
- package/lib/plugins/service-betterportal-config-manager/bp-routes/tenants/route.impl.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/index.d.ts +4 -0
- package/lib/plugins/service-betterportal-config-manager/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/index.js +45 -9
- package/lib/plugins/service-betterportal-config-manager/index.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/menuEditor.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/menuEditor.js +7 -1
- package/lib/plugins/service-betterportal-config-manager/menuEditor.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/routeMounts.d.ts +8 -0
- package/lib/plugins/service-betterportal-config-manager/routeMounts.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-config-manager/routeMounts.js +22 -0
- package/lib/plugins/service-betterportal-config-manager/routeMounts.js.map +1 -0
- package/lib/plugins/service-betterportal-config-manager/setupTokens.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/setupTokens.js +50 -0
- package/lib/plugins/service-betterportal-config-manager/setupTokens.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/core.d.ts +2 -0
- package/lib/plugins/service-betterportal-config-manager/storage/core.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/storage/core.js +67 -2
- package/lib/plugins/service-betterportal-config-manager/storage/core.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/syncApi.d.ts +2 -1
- package/lib/plugins/service-betterportal-config-manager/syncApi.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/syncApi.js +56 -1
- package/lib/plugins/service-betterportal-config-manager/syncApi.js.map +1 -1
- package/lib/schemas/service-betterportal-config-manager.json +1 -1
- package/lib/schemas/service-betterportal-config-manager.plugin.json +1 -1
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated BSB virtual client for service-betterportal-config-manager
|
|
3
3
|
* DO NOT EDIT - Regenerated on every build
|
|
4
|
-
* @version 10.
|
|
4
|
+
* @version 10.1.1
|
|
5
5
|
*/
|
|
6
6
|
import { ServiceClient, BSBService } from "@bsb/base";
|
|
7
7
|
import type { Observable, BSBServiceClientDefinition, EventInputType } from "@bsb/base";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated BSB virtual client for service-betterportal-config-manager
|
|
3
3
|
* DO NOT EDIT - Regenerated on every build
|
|
4
|
-
* @version 10.
|
|
4
|
+
* @version 10.1.1
|
|
5
5
|
*/
|
|
6
6
|
import { ServiceClient, bsb, createBroadcastEvent, createEventSchemas } from "@bsb/base";
|
|
7
7
|
const _platformConfigChangedSchema = bsb.object({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminApi.d.ts","sourceRoot":"","sources":["../../../src/plugins/service-betterportal-config-manager/adminApi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAEjB,mBAAmB,EAEpB,MAAM,yBAAyB,CAAC;AAUjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"adminApi.d.ts","sourceRoot":"","sources":["../../../src/plugins/service-betterportal-config-manager/adminApi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAEjB,mBAAmB,EAEpB,MAAM,yBAAyB,CAAC;AAUjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AA8yBzD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAqnCN"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { eventHeaders, htmlResponse, jsonResponse, resolveEmbeddedRequestContext, signServiceConfigTicket, uuidv7 } from "@betterportal/framework";
|
|
2
2
|
import { generateApiKey, hashApiKey } from "./storage/index.js";
|
|
3
3
|
import { getManifestCache } from "./syncApi.js";
|
|
4
|
+
import { apiRoutePath, isApiRoute } from "./routeMounts.js";
|
|
4
5
|
const API_BASE = "/.well-known/bp/admin";
|
|
5
6
|
const CONFIG_TICKET_TTL_SECONDS = 5 * 60;
|
|
6
7
|
// Parse-only base for relative request URLs. Never emit this origin.
|
|
7
8
|
const RELATIVE_URL_PARSE_BASE = "http://betterportal.invalid";
|
|
9
|
+
const ROLE_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,63}$/;
|
|
10
|
+
const RESERVED_ROLE_IDS = new Set(["*", "root"]);
|
|
8
11
|
async function readFormBody(event) {
|
|
9
12
|
const fd = await event.req.formData().catch(() => null);
|
|
10
13
|
if (!fd)
|
|
@@ -14,6 +17,24 @@ async function readFormBody(event) {
|
|
|
14
17
|
out[k] = v; });
|
|
15
18
|
return out;
|
|
16
19
|
}
|
|
20
|
+
async function readFormBodyWithArrays(event) {
|
|
21
|
+
const fd = await event.req.formData().catch(() => null);
|
|
22
|
+
if (!fd)
|
|
23
|
+
return {};
|
|
24
|
+
const out = {};
|
|
25
|
+
fd.forEach((v, k) => {
|
|
26
|
+
if (typeof v !== "string")
|
|
27
|
+
return;
|
|
28
|
+
const existing = out[k];
|
|
29
|
+
if (Array.isArray(existing))
|
|
30
|
+
existing.push(v);
|
|
31
|
+
else if (typeof existing === "string")
|
|
32
|
+
out[k] = [existing, v];
|
|
33
|
+
else
|
|
34
|
+
out[k] = v;
|
|
35
|
+
});
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
17
38
|
function escapeHtml(s) {
|
|
18
39
|
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
|
|
19
40
|
}
|
|
@@ -26,7 +47,7 @@ async function readJsonBody(event) {
|
|
|
26
47
|
async function readFormOrJsonBody(event) {
|
|
27
48
|
const contentType = event.req.headers.get("content-type") ?? "";
|
|
28
49
|
if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
|
|
29
|
-
return
|
|
50
|
+
return readFormBodyWithArrays(event);
|
|
30
51
|
}
|
|
31
52
|
return readJsonBody(event);
|
|
32
53
|
}
|
|
@@ -45,6 +66,18 @@ function htmxError(message, status = 400) {
|
|
|
45
66
|
function validationError(event, message) {
|
|
46
67
|
return wantsHtmx(event) ? htmxError(message, 400) : jsonResponse({ error: message }, 400);
|
|
47
68
|
}
|
|
69
|
+
function validateRoleId(value) {
|
|
70
|
+
if (typeof value !== "string")
|
|
71
|
+
return undefined;
|
|
72
|
+
const roleId = value.trim();
|
|
73
|
+
if (!roleId)
|
|
74
|
+
return undefined;
|
|
75
|
+
if (!ROLE_ID_PATTERN.test(roleId))
|
|
76
|
+
return undefined;
|
|
77
|
+
if (RESERVED_ROLE_IDS.has(roleId.toLowerCase()))
|
|
78
|
+
return undefined;
|
|
79
|
+
return roleId;
|
|
80
|
+
}
|
|
48
81
|
function trimmedString(body, key) {
|
|
49
82
|
const value = body[key];
|
|
50
83
|
return typeof value === "string" ? value.trim() : undefined;
|
|
@@ -59,6 +92,12 @@ function routeMethodsFromManifest(methods) {
|
|
|
59
92
|
const normalized = (methods ?? []).filter((method) => method === "GET" || method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE" || method === "OPTIONS");
|
|
60
93
|
return normalized.length ? normalized : ["GET"];
|
|
61
94
|
}
|
|
95
|
+
function hasPageRenderer(view) {
|
|
96
|
+
const renderers = view.html?.themeRenderers;
|
|
97
|
+
if (!renderers)
|
|
98
|
+
return view.renderable !== false;
|
|
99
|
+
return Object.values(renderers).some((renderer) => Array.isArray(renderer.renderModes) && renderer.renderModes.includes("page"));
|
|
100
|
+
}
|
|
62
101
|
function appMatchesTenantUrl(app, tenantUrl) {
|
|
63
102
|
let host = "";
|
|
64
103
|
try {
|
|
@@ -187,7 +226,9 @@ function parseRouteCreateBody(body) {
|
|
|
187
226
|
return { error: viewId.error };
|
|
188
227
|
const manifestView = getManifestCache().get(serviceId.value)?.viewIndex[viewId.value];
|
|
189
228
|
const renderable = manifestView?.renderable !== false;
|
|
190
|
-
const
|
|
229
|
+
const manifest = getManifestCache().get(serviceId.value);
|
|
230
|
+
const serviceRoutePath = manifestView?.path ?? `/${viewId.value}`;
|
|
231
|
+
const path = renderable ? requiredRouteString(body, "path", "Mount path") : { value: apiRoutePath(manifest?.serviceId ?? serviceId.value, serviceRoutePath) };
|
|
191
232
|
if (path.error)
|
|
192
233
|
return { error: path.error };
|
|
193
234
|
if (!path.value.startsWith("/"))
|
|
@@ -196,6 +237,7 @@ function parseRouteCreateBody(body) {
|
|
|
196
237
|
if (title.error)
|
|
197
238
|
return { error: title.error };
|
|
198
239
|
const route = {
|
|
240
|
+
kind: renderable ? "page" : "api",
|
|
199
241
|
path: path.value,
|
|
200
242
|
serviceId: serviceId.value,
|
|
201
243
|
viewId: viewId.value,
|
|
@@ -281,7 +323,8 @@ function addRouteDependencies(appDef, route) {
|
|
|
281
323
|
continue;
|
|
282
324
|
appDef.routes.push({
|
|
283
325
|
id: uuidv7(),
|
|
284
|
-
|
|
326
|
+
kind: "api",
|
|
327
|
+
path: apiRoutePath(manifest.serviceId, dependency.path),
|
|
285
328
|
serviceId: route.serviceId,
|
|
286
329
|
viewId: dependencyViewId,
|
|
287
330
|
targetPath: dependency.path,
|
|
@@ -1269,6 +1312,11 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1269
1312
|
const title = body.title;
|
|
1270
1313
|
if (!title)
|
|
1271
1314
|
return wantsHtmx(event) ? htmxError("title required") : jsonResponse({ error: "title required" }, 400);
|
|
1315
|
+
const roleId = validateRoleId(body.id);
|
|
1316
|
+
if (!roleId) {
|
|
1317
|
+
const message = "role id must start with a letter or number, may contain letters, numbers, dot, underscore, colon, or dash, and cannot be reserved";
|
|
1318
|
+
return wantsHtmx(event) ? htmxError(message) : jsonResponse({ error: message }, 400);
|
|
1319
|
+
}
|
|
1272
1320
|
const { config, appDef } = await getAppOr404(appId);
|
|
1273
1321
|
if (!appDef)
|
|
1274
1322
|
return wantsHtmx(event) ? htmxError("App not found", 404) : jsonResponse({ error: "App not found" }, 404);
|
|
@@ -1277,7 +1325,7 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1277
1325
|
return authResult.response;
|
|
1278
1326
|
const auth = authResult.auth;
|
|
1279
1327
|
const role = {
|
|
1280
|
-
id:
|
|
1328
|
+
id: roleId,
|
|
1281
1329
|
title,
|
|
1282
1330
|
description: body.description,
|
|
1283
1331
|
permissions: Array.isArray(body.permissions) ? body.permissions : []
|
|
@@ -1424,15 +1472,20 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1424
1472
|
return validationError(event, "View is required.");
|
|
1425
1473
|
route.viewId = viewId;
|
|
1426
1474
|
}
|
|
1427
|
-
const
|
|
1475
|
+
const manifest = getManifestCache().get(route.serviceId);
|
|
1476
|
+
const manifestView = manifest?.viewIndex[route.viewId];
|
|
1428
1477
|
if (manifestView) {
|
|
1429
1478
|
route.methods = routeMethodsFromManifest(manifestView.methods);
|
|
1430
1479
|
route.targetPath = manifestView.path;
|
|
1431
1480
|
if (manifestView.renderable === false) {
|
|
1432
|
-
route.
|
|
1481
|
+
route.kind = "api";
|
|
1482
|
+
route.path = apiRoutePath(manifest?.serviceId ?? route.serviceId, manifestView.path);
|
|
1433
1483
|
route.title = manifestView.viewId;
|
|
1434
1484
|
delete route.query;
|
|
1435
1485
|
}
|
|
1486
|
+
else {
|
|
1487
|
+
route.kind = "page";
|
|
1488
|
+
}
|
|
1436
1489
|
}
|
|
1437
1490
|
if (body.targetPath !== undefined) {
|
|
1438
1491
|
const targetPath = trimmedString(body, "targetPath");
|
|
@@ -1443,7 +1496,9 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1443
1496
|
}
|
|
1444
1497
|
if (body.query !== undefined) {
|
|
1445
1498
|
const query = trimmedString(body, "query");
|
|
1446
|
-
if (
|
|
1499
|
+
if (isApiRoute(route, manifestView?.renderable))
|
|
1500
|
+
delete route.query;
|
|
1501
|
+
else if (query)
|
|
1447
1502
|
route.query = query.replace(/^\?+/, "");
|
|
1448
1503
|
else
|
|
1449
1504
|
delete route.query;
|
|
@@ -1452,7 +1507,8 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1452
1507
|
const title = trimmedString(body, "title");
|
|
1453
1508
|
if (!title)
|
|
1454
1509
|
return validationError(event, "Display title is required.");
|
|
1455
|
-
route
|
|
1510
|
+
if (!isApiRoute(route, manifestView?.renderable))
|
|
1511
|
+
route.title = title;
|
|
1456
1512
|
}
|
|
1457
1513
|
if (body.enabled !== undefined)
|
|
1458
1514
|
route.enabled = body.enabled === true || body.enabled === "true" || body.enabled === "on";
|
|
@@ -1530,7 +1586,7 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1530
1586
|
// Browser-mediated: the admin UI fetches the manifest from the service
|
|
1531
1587
|
// (CM cannot reach services) and POSTs the parsed payload here.
|
|
1532
1588
|
app.post(`${API_BASE}/wizard/verify`, async (event) => {
|
|
1533
|
-
const adminApiBase =
|
|
1589
|
+
const adminApiBase = API_BASE;
|
|
1534
1590
|
const form = await readFormBody(event);
|
|
1535
1591
|
const tenantId = form.tenantId ?? "";
|
|
1536
1592
|
const hostname = normalizeHostname(form.hostname);
|
|
@@ -1568,17 +1624,22 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1568
1624
|
});
|
|
1569
1625
|
// HTMX wizard: register service
|
|
1570
1626
|
app.post(`${API_BASE}/wizard/register`, async (event) => {
|
|
1571
|
-
const
|
|
1572
|
-
const
|
|
1573
|
-
|
|
1574
|
-
const
|
|
1627
|
+
const body = await readFormOrJsonBody(event);
|
|
1628
|
+
const jsonMode = (event.req.headers.get("accept") ?? "").includes("application/json")
|
|
1629
|
+
|| (event.req.headers.get("content-type") ?? "").includes("application/json");
|
|
1630
|
+
const registerError = (message, status = 400) => jsonMode
|
|
1631
|
+
? jsonResponse({ error: message }, status)
|
|
1632
|
+
: htmlResponse(`<div class="alert alert-danger">${escapeHtml(message)}</div>`, 200, "text/html; mode=fragment");
|
|
1633
|
+
const tenantId = typeof body.tenantId === "string" ? body.tenantId : "";
|
|
1634
|
+
const hostname = (typeof body.hostname === "string" ? body.hostname : "").replace(/\/+$/, "");
|
|
1635
|
+
const title = (typeof body.title === "string" && body.title.trim().length > 0 ? body.title.trim() : hostname);
|
|
1575
1636
|
if (!tenantId || !hostname) {
|
|
1576
|
-
return
|
|
1637
|
+
return registerError("Missing tenantId or hostname");
|
|
1577
1638
|
}
|
|
1578
1639
|
const config = await store.loadConfig();
|
|
1579
1640
|
const tenant = config.tenants.find((t) => t.id === tenantId);
|
|
1580
1641
|
if (!tenant) {
|
|
1581
|
-
return
|
|
1642
|
+
return registerError("Tenant not found", 404);
|
|
1582
1643
|
}
|
|
1583
1644
|
// Schema is fetched by the browser from the service (CM cannot reach services)
|
|
1584
1645
|
// and posted to us as a JSON string in form.schema.
|
|
@@ -1586,19 +1647,27 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1586
1647
|
let capabilities = [];
|
|
1587
1648
|
let serviceRoutes = [];
|
|
1588
1649
|
let viewMeta = new Map();
|
|
1589
|
-
|
|
1650
|
+
const schemaText = typeof body.schema === "string" ? body.schema : "";
|
|
1651
|
+
if (schemaText) {
|
|
1590
1652
|
try {
|
|
1591
|
-
const schema = JSON.parse(
|
|
1653
|
+
const schema = JSON.parse(schemaText);
|
|
1592
1654
|
serviceId = schema.manifest?.pluginId;
|
|
1593
1655
|
capabilities = Array.isArray(schema.manifest?.capabilities) ? schema.manifest.capabilities.filter((value) => typeof value === "string") : [];
|
|
1594
1656
|
serviceRoutes = schema.routes ?? [];
|
|
1595
|
-
viewMeta = new Map((schema.manifest?.views ?? []).map((v) => [v.viewId,
|
|
1657
|
+
viewMeta = new Map((schema.manifest?.views ?? []).map((v) => [v.viewId, {
|
|
1658
|
+
title: v.title,
|
|
1659
|
+
renderable: v.renderable !== false,
|
|
1660
|
+
pageRenderable: hasPageRenderer(v),
|
|
1661
|
+
methods: Array.isArray(v.methods)
|
|
1662
|
+
? v.methods.filter((value) => typeof value === "string")
|
|
1663
|
+
: []
|
|
1664
|
+
}]));
|
|
1596
1665
|
}
|
|
1597
1666
|
catch { /* malformed schema - register without routes */ }
|
|
1598
1667
|
}
|
|
1599
1668
|
const duplicate = duplicateTenantService(tenant, hostname, serviceId);
|
|
1600
1669
|
if (duplicate) {
|
|
1601
|
-
return
|
|
1670
|
+
return registerError(duplicate, 409);
|
|
1602
1671
|
}
|
|
1603
1672
|
const newServiceId = uuidv7();
|
|
1604
1673
|
const service = {
|
|
@@ -1621,30 +1690,37 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1621
1690
|
const groupChildren = [];
|
|
1622
1691
|
const existingPaths = new Set(appDef.routes.map((r) => r.path));
|
|
1623
1692
|
for (const r of serviceRoutes) {
|
|
1693
|
+
const meta = viewMeta.get(r.viewId);
|
|
1694
|
+
const renderable = meta?.renderable ?? r.renderable !== false;
|
|
1624
1695
|
// Default mounting path is the service's own path; skip collisions
|
|
1625
|
-
const mountPath =
|
|
1696
|
+
const mountPath = renderable
|
|
1697
|
+
? (existingPaths.has(r.path) ? `/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}${r.path}` : r.path)
|
|
1698
|
+
: apiRoutePath(serviceId ?? newServiceId, r.path);
|
|
1626
1699
|
if (existingPaths.has(mountPath))
|
|
1627
1700
|
continue;
|
|
1628
1701
|
const routeId = uuidv7();
|
|
1629
|
-
const routeTitle =
|
|
1702
|
+
const routeTitle = meta?.title ?? r.viewId;
|
|
1630
1703
|
appDef.routes.push({
|
|
1631
1704
|
id: routeId,
|
|
1705
|
+
kind: renderable ? "page" : "api",
|
|
1632
1706
|
path: mountPath,
|
|
1633
1707
|
serviceId: newServiceId,
|
|
1634
1708
|
viewId: r.viewId,
|
|
1635
1709
|
targetPath: r.path,
|
|
1636
1710
|
title: routeTitle,
|
|
1637
1711
|
enabled: true,
|
|
1638
|
-
methods:
|
|
1712
|
+
methods: routeMethodsFromManifest(r.methods)
|
|
1639
1713
|
});
|
|
1640
1714
|
existingPaths.add(mountPath);
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1715
|
+
if (meta?.pageRenderable === true && !isApiRoute({ kind: renderable ? "page" : "api", path: mountPath }, renderable)) {
|
|
1716
|
+
groupChildren.push({
|
|
1717
|
+
id: uuidv7(),
|
|
1718
|
+
type: "link",
|
|
1719
|
+
title: routeTitle,
|
|
1720
|
+
routeId,
|
|
1721
|
+
enabled: true
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1648
1724
|
}
|
|
1649
1725
|
if (groupChildren.length > 0) {
|
|
1650
1726
|
const menu = (appDef.menu ?? []);
|
|
@@ -1660,7 +1736,17 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1660
1736
|
}
|
|
1661
1737
|
}
|
|
1662
1738
|
await store.saveConfig(config);
|
|
1663
|
-
|
|
1739
|
+
if (jsonMode) {
|
|
1740
|
+
return jsonResponse({
|
|
1741
|
+
ok: true,
|
|
1742
|
+
tenantId,
|
|
1743
|
+
serviceInstanceId: newServiceId,
|
|
1744
|
+
serviceUrl: hostname,
|
|
1745
|
+
title,
|
|
1746
|
+
deploymentMode: service.deploymentMode
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
const adminApiBase = API_BASE;
|
|
1664
1750
|
return htmlResponse(renderWizardStep3({
|
|
1665
1751
|
apiKey: "",
|
|
1666
1752
|
deploymentMode: service.deploymentMode,
|
|
@@ -1691,7 +1777,7 @@ export function registerAdminApiRoutes(app, store, cpState) {
|
|
|
1691
1777
|
const tenantId = url.searchParams.get("tenantId") ?? undefined;
|
|
1692
1778
|
const hostname = url.searchParams.get("hostname") ?? undefined;
|
|
1693
1779
|
const config = await store.loadConfig();
|
|
1694
|
-
return htmlResponse(renderWizardStep1(config, undefined, { tenantId, hostname },
|
|
1780
|
+
return htmlResponse(renderWizardStep1(config, undefined, { tenantId, hostname }, API_BASE), 200, "text/html; mode=fragment");
|
|
1695
1781
|
});
|
|
1696
1782
|
// HTMX configure: load form
|
|
1697
1783
|
app.get(`${API_BASE}/configure`, async (event) => {
|