@betterportal/config-manager 11.0.3 → 11.0.5
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/bp-contracts/org.betterportal.config-manager.json +1 -1
- package/lib/plugins/service-betterportal-config-manager/adminApi.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/adminApi.js +49 -27
- package/lib/plugins/service-betterportal-config-manager/adminApi.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/appQueries.d.ts +202 -4
- package/lib/plugins/service-betterportal-config-manager/appQueries.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/appQueries.js +22 -6
- package/lib/plugins/service-betterportal-config-manager/appQueries.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_renderer.bootstrap5/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_renderer.bootstrap5/GET.js +8 -5
- package/lib/plugins/service-betterportal-config-manager/bp-routes/routes/_renderer.bootstrap5/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/index.d.ts +1 -0
- package/lib/plugins/service-betterportal-config-manager/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/index.js +15 -12
- 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 +3 -2
- package/lib/plugins/service-betterportal-config-manager/menuEditor.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/previewEnvironments.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/previewEnvironments.js +2 -1
- package/lib/plugins/service-betterportal-config-manager/previewEnvironments.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/routeMounts.d.ts +5 -0
- package/lib/plugins/service-betterportal-config-manager/routeMounts.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/routeMounts.js +3 -0
- package/lib/plugins/service-betterportal-config-manager/routeMounts.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 +180 -141
- package/lib/plugins/service-betterportal-config-manager/syncApi.js.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/tenantManagement.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-config-manager/tenantManagement.js +3 -1
- package/lib/plugins/service-betterportal-config-manager/tenantManagement.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 11.0.
|
|
4
|
+
* @version 11.0.5
|
|
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 11.0.
|
|
4
|
+
* @version 11.0.5
|
|
5
5
|
*/
|
|
6
6
|
import { ServiceClient, importPortableSchema, createFireAndForgetEvent, createBroadcastEvent, createEventSchemas } from "@bsb/base";
|
|
7
7
|
const _webhookDeliveryAvailableSchema = importPortableSchema(JSON.parse("{\"anyvaliVersion\":\"1.0\",\"schemaVersion\":\"1.1\",\"root\":{\"kind\":\"object\",\"properties\":{},\"required\":[],\"unknownKeys\":\"strip\"},\"definitions\":{},\"extensions\":{}}"));
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"pluginId": "org.betterportal.config-manager",
|
|
5
5
|
"title": "BetterPortal Config Manager",
|
|
6
6
|
"description": "Admin-facing BetterPortal service for discovering and managing service config surfaces.",
|
|
7
|
-
"version": "11.0.
|
|
7
|
+
"version": "11.0.5",
|
|
8
8
|
"category": "service",
|
|
9
9
|
"deploymentModes": [
|
|
10
10
|
"self-hosted"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminApi.d.ts","sourceRoot":"","sources":["../../../src/plugins/service-betterportal-config-manager/adminApi.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"adminApi.d.ts","sourceRoot":"","sources":["../../../src/plugins/service-betterportal-config-manager/adminApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isPageOperation } from "./routeMounts.js";
|
|
1
2
|
import { eventObservability } from "@betterportal/framework";
|
|
2
3
|
import { editAppRows, readApp, readRequestConfig } from "./appQueries.js";
|
|
3
4
|
import { isMenuRouteExcluded } from "./routeMounts.js";
|
|
4
5
|
import * as av from "anyvali";
|
|
5
6
|
import { AppAuthRoleSchema, eventHeaders, htmlResponse, jsonResponse, readBoundedJsonBody, resolveEmbeddedRequestContext, signServiceConfigTicket, uuidv7, BetterPortalMenuItemSchema, BetterPortalThemeConfigSchema } from "@betterportal/framework";
|
|
6
7
|
import { generateApiKey, hashApiKey } from "./storage/index.js";
|
|
7
|
-
import { getManifestCache } from "./syncApi.js";
|
|
8
|
+
import { getCachedManifestForService, getManifestCache, reconcileCachedServiceRoutes } from "./syncApi.js";
|
|
8
9
|
import { apiRoutePath, appRoutePatternKey, isApiRoute, pageRoutePath } from "./routeMounts.js";
|
|
9
10
|
import { M2MConnectionError, approveM2MConnections, buildM2MConnectionModel, revokeM2MConnection } from "./m2mConnections.js";
|
|
10
11
|
import { isPreviewApp } from "./previewEnvironments.js";
|
|
@@ -77,7 +78,7 @@ function validationError(event, message) {
|
|
|
77
78
|
}
|
|
78
79
|
// PostgreSQL edits read current rows under an app-scoped transaction.
|
|
79
80
|
// File stores retain their existing single-process save semantics.
|
|
80
|
-
async function editApp(store, appId, action, database, event) {
|
|
81
|
+
async function editApp(store, appId, action, database, event, includeManifests = false) {
|
|
81
82
|
const apply = async (config) => {
|
|
82
83
|
const response = await action(config);
|
|
83
84
|
if (!response.ok)
|
|
@@ -86,7 +87,7 @@ async function editApp(store, appId, action, database, event) {
|
|
|
86
87
|
};
|
|
87
88
|
try {
|
|
88
89
|
if (database)
|
|
89
|
-
return await editAppRows(database, appId, event ? eventObservability(event) : undefined, action);
|
|
90
|
+
return await editAppRows(database, appId, event ? eventObservability(event) : undefined, action, includeManifests);
|
|
90
91
|
if (store.mutateApp)
|
|
91
92
|
return await store.mutateApp(appId, apply);
|
|
92
93
|
const config = await store.loadConfig();
|
|
@@ -373,7 +374,7 @@ export function renderAutomationLlmsApi(catalog) {
|
|
|
373
374
|
}
|
|
374
375
|
return lines.join("\n");
|
|
375
376
|
}
|
|
376
|
-
function parseRouteCreateBody(body) {
|
|
377
|
+
function parseRouteCreateBody(body, config) {
|
|
377
378
|
const serviceId = requiredRouteString(body, "serviceId", "Service");
|
|
378
379
|
if (serviceId.error)
|
|
379
380
|
return { error: serviceId.error };
|
|
@@ -383,12 +384,16 @@ function parseRouteCreateBody(body) {
|
|
|
383
384
|
const operationId = requiredRouteString(body, "operationId", "Operation");
|
|
384
385
|
if (operationId.error)
|
|
385
386
|
return { error: operationId.error };
|
|
386
|
-
const
|
|
387
|
+
const manifest = getCachedManifestForService(config, serviceId.value);
|
|
388
|
+
if (!manifest)
|
|
389
|
+
return { error: "Service manifest is not synced yet. Wait for service manifest sync before adding a route." };
|
|
390
|
+
const manifestView = manifest.viewIndex[viewId.value];
|
|
391
|
+
if (!manifestView)
|
|
392
|
+
return { error: "Selected view is not available in the synced service manifest." };
|
|
387
393
|
const manifestOperation = manifestView?.operations.find((operation) => operation.operationId === operationId.value);
|
|
388
394
|
if (manifestView && !manifestOperation)
|
|
389
395
|
return { error: "Selected operation is not available for this view." };
|
|
390
|
-
const renderable = manifestOperation
|
|
391
|
-
const manifest = getManifestCache().get(serviceId.value);
|
|
396
|
+
const renderable = manifestOperation ? isPageOperation(manifestOperation) : false;
|
|
392
397
|
const servicePathVariant = trimmedString(body, "servicePathVariant") ?? manifestView?.path ?? `/${viewId.value}`;
|
|
393
398
|
if (manifestView && ![manifestView.path, ...manifestView.pathVariants].includes(servicePathVariant)) {
|
|
394
399
|
return { error: "Selected service path is not available for this view." };
|
|
@@ -486,8 +491,8 @@ function cleanupProvisionalTenantService(config, tenantId, serviceInstanceId) {
|
|
|
486
491
|
}
|
|
487
492
|
return { removed: true };
|
|
488
493
|
}
|
|
489
|
-
function addRouteDependencies(appDef, route) {
|
|
490
|
-
const manifest =
|
|
494
|
+
function addRouteDependencies(config, appDef, route) {
|
|
495
|
+
const manifest = getCachedManifestForService(config, route.serviceId);
|
|
491
496
|
const view = manifest?.viewIndex[route.viewId];
|
|
492
497
|
if (!manifest || !view)
|
|
493
498
|
return;
|
|
@@ -503,8 +508,12 @@ function addRouteDependencies(appDef, route) {
|
|
|
503
508
|
continue;
|
|
504
509
|
if (!dependency)
|
|
505
510
|
continue;
|
|
506
|
-
|
|
511
|
+
const existing = appDef.routes.find((candidate) => candidate.serviceId === route.serviceId && candidate.operations.includes(requirement.operationId));
|
|
512
|
+
if (existing) {
|
|
513
|
+
if (existing.enablement !== "disabled")
|
|
514
|
+
existing.enabled = true;
|
|
507
515
|
continue;
|
|
516
|
+
}
|
|
508
517
|
appDef.routes.push({
|
|
509
518
|
id: uuidv7(),
|
|
510
519
|
kind: "api",
|
|
@@ -1080,6 +1089,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1080
1089
|
if (!shared)
|
|
1081
1090
|
return jsonResponse({ error: "Shared service not found or disabled" }, 404);
|
|
1082
1091
|
let activation = config.sharedServiceActivations.find((entry) => entry.sharedServiceId === sharedServiceId && entry.tenantId === appDef.tenantId && entry.appId === appDef.id);
|
|
1092
|
+
const wasEnabled = activation?.enabled === true;
|
|
1083
1093
|
if (!activation) {
|
|
1084
1094
|
activation = {
|
|
1085
1095
|
id: uuidv7(),
|
|
@@ -1090,8 +1100,14 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1090
1100
|
enabled: true
|
|
1091
1101
|
};
|
|
1092
1102
|
config.sharedServiceActivations.push(activation);
|
|
1093
|
-
await store.saveConfig(config);
|
|
1094
1103
|
}
|
|
1104
|
+
else if (!activation.enabled) {
|
|
1105
|
+
activation.enabled = true;
|
|
1106
|
+
activation.activatedAt = new Date().toISOString();
|
|
1107
|
+
}
|
|
1108
|
+
const routesChanged = reconcileCachedServiceRoutes(config, [activation.id]);
|
|
1109
|
+
if (!wasEnabled || routesChanged)
|
|
1110
|
+
await store.saveConfig(config);
|
|
1095
1111
|
return jsonResponse({ ok: true, activation }, 201);
|
|
1096
1112
|
});
|
|
1097
1113
|
app.get("/.well-known/bp/manage/routes", async (event) => {
|
|
@@ -1105,13 +1121,13 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1105
1121
|
if (!appDef)
|
|
1106
1122
|
return jsonResponse({ error: "Unable to resolve current BetterPortal app" }, 404);
|
|
1107
1123
|
const body = await readFormOrJsonBody(event);
|
|
1108
|
-
const parsed = parseRouteCreateBody(body);
|
|
1109
|
-
if (parsed.error || !parsed.route)
|
|
1110
|
-
return validationError(event, parsed.error ?? "Invalid route");
|
|
1111
1124
|
return editApp(store, appDef.id, async (data) => {
|
|
1112
1125
|
const current = data.apps.find(app => app.id === appDef.id);
|
|
1113
1126
|
if (!current || isPreviewApp(data, current.id))
|
|
1114
1127
|
return jsonResponse({ error: "App not found" }, 404);
|
|
1128
|
+
const parsed = parseRouteCreateBody(body, data);
|
|
1129
|
+
if (parsed.error || !parsed.route)
|
|
1130
|
+
return validationError(event, parsed.error ?? "Invalid route");
|
|
1115
1131
|
const serviceError = validateRegisteredRouteService(data, current, parsed.route.serviceId);
|
|
1116
1132
|
if (serviceError)
|
|
1117
1133
|
return validationError(event, serviceError);
|
|
@@ -1120,9 +1136,9 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1120
1136
|
}
|
|
1121
1137
|
const route = { id: uuidv7(), ...parsed.route };
|
|
1122
1138
|
current.routes.push(route);
|
|
1123
|
-
addRouteDependencies(current, route);
|
|
1139
|
+
addRouteDependencies(data, current, route);
|
|
1124
1140
|
return jsonResponse({ ok: true }, 201);
|
|
1125
|
-
}, database, event);
|
|
1141
|
+
}, database, event, true);
|
|
1126
1142
|
});
|
|
1127
1143
|
app.get("/.well-known/bp/manage/fragments", async (event) => {
|
|
1128
1144
|
const { appDef } = await readCurrentApp(event);
|
|
@@ -1313,13 +1329,14 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1313
1329
|
const existing = config.sharedServiceActivations.find((activation) => activation.sharedServiceId === sharedServiceId
|
|
1314
1330
|
&& activation.tenantId === tenantId
|
|
1315
1331
|
&& activation.appId === appId);
|
|
1332
|
+
const activationId = existing?.id ?? uuidv7();
|
|
1316
1333
|
if (existing) {
|
|
1317
1334
|
existing.enabled = true;
|
|
1318
1335
|
existing.activatedAt = new Date().toISOString();
|
|
1319
1336
|
}
|
|
1320
1337
|
else {
|
|
1321
1338
|
config.sharedServiceActivations.push({
|
|
1322
|
-
id:
|
|
1339
|
+
id: activationId,
|
|
1323
1340
|
tenantId,
|
|
1324
1341
|
appId,
|
|
1325
1342
|
sharedServiceId,
|
|
@@ -1327,6 +1344,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1327
1344
|
enabled: true
|
|
1328
1345
|
});
|
|
1329
1346
|
}
|
|
1347
|
+
reconcileCachedServiceRoutes(config, [activationId]);
|
|
1330
1348
|
await store.saveConfig(config);
|
|
1331
1349
|
if (wantsHtmx(event))
|
|
1332
1350
|
return htmxReload(`/services?tenantId=${encodeURIComponent(tenantId)}`);
|
|
@@ -1443,6 +1461,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1443
1461
|
enabled: true
|
|
1444
1462
|
};
|
|
1445
1463
|
tenant.services.push(service);
|
|
1464
|
+
reconcileCachedServiceRoutes(config, [service.id]);
|
|
1446
1465
|
await store.saveConfig(config);
|
|
1447
1466
|
return jsonResponse({ id: service.id, hostname: service.hostname, serviceId: service.serviceId, apiKey }, 201);
|
|
1448
1467
|
});
|
|
@@ -1563,10 +1582,13 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
1563
1582
|
const tenant = config.tenants.find((t) => t.id === tenantId);
|
|
1564
1583
|
if (!tenant)
|
|
1565
1584
|
return jsonResponse({ error: "Tenant not found" }, 404);
|
|
1566
|
-
|
|
1585
|
+
const wasActivated = tenant.activatedPlatformServices.includes(psId);
|
|
1586
|
+
if (!wasActivated) {
|
|
1567
1587
|
tenant.activatedPlatformServices.push(psId);
|
|
1568
|
-
await store.saveConfig(config);
|
|
1569
1588
|
}
|
|
1589
|
+
const routesChanged = reconcileCachedServiceRoutes(config, [psId]);
|
|
1590
|
+
if (!wasActivated || routesChanged)
|
|
1591
|
+
await store.saveConfig(config);
|
|
1570
1592
|
return jsonResponse({ ok: true });
|
|
1571
1593
|
});
|
|
1572
1594
|
app.delete(`${API_BASE}/tenants/:tenantId/activate/:platformServiceId`, async (event) => {
|
|
@@ -2040,7 +2062,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
2040
2062
|
const appDef = config.apps.find((a) => a.id === appId);
|
|
2041
2063
|
if (!appDef)
|
|
2042
2064
|
return wantsHtmx(event) ? htmxError("App not found", 404) : jsonResponse({ error: "App not found" }, 404);
|
|
2043
|
-
const parsed = parseRouteCreateBody(body);
|
|
2065
|
+
const parsed = parseRouteCreateBody(body, config);
|
|
2044
2066
|
if (parsed.error || !parsed.route)
|
|
2045
2067
|
return validationError(event, parsed.error ?? "Invalid route.");
|
|
2046
2068
|
if (parsed.route.kind === "api")
|
|
@@ -2053,11 +2075,11 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
2053
2075
|
}
|
|
2054
2076
|
const route = { ...parsed.route, id: uuidv7() };
|
|
2055
2077
|
appDef.routes.push(route);
|
|
2056
|
-
addRouteDependencies(appDef, route);
|
|
2078
|
+
addRouteDependencies(config, appDef, route);
|
|
2057
2079
|
if (wantsHtmx(event))
|
|
2058
2080
|
return htmxReload(routesReloadPath(appId));
|
|
2059
2081
|
return jsonResponse({ ok: true, id: route.id }, 201);
|
|
2060
|
-
}, database, event);
|
|
2082
|
+
}, database, event, true);
|
|
2061
2083
|
});
|
|
2062
2084
|
app.put(`${API_BASE}/apps/:appId/routes/:routeId`, async (event) => {
|
|
2063
2085
|
const appId = getParam(event, "appId");
|
|
@@ -2110,7 +2132,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
2110
2132
|
return validationError(event, "Operation is required.");
|
|
2111
2133
|
route.operations = [operationId];
|
|
2112
2134
|
}
|
|
2113
|
-
const manifest =
|
|
2135
|
+
const manifest = getCachedManifestForService(config, route.serviceId);
|
|
2114
2136
|
const manifestView = manifest?.viewIndex[route.viewId];
|
|
2115
2137
|
if (manifestView) {
|
|
2116
2138
|
const manifestOperation = manifestView.operations.find((operation) => route.operations.includes(operation.operationId));
|
|
@@ -2127,7 +2149,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
2127
2149
|
if (servicePathError)
|
|
2128
2150
|
return validationError(event, servicePathError);
|
|
2129
2151
|
const submittedFixed = fixedParamsFromBody(body);
|
|
2130
|
-
const pageRenderable = manifestOperation
|
|
2152
|
+
const pageRenderable = isPageOperation(manifestOperation);
|
|
2131
2153
|
const mappedAppPath = !pageRenderable
|
|
2132
2154
|
? apiRoutePath(manifest?.serviceId ?? route.serviceId, requestedServicePath)
|
|
2133
2155
|
: route.path;
|
|
@@ -2164,7 +2186,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
2164
2186
|
}
|
|
2165
2187
|
if (body.query !== undefined) {
|
|
2166
2188
|
const query = trimmedString(body, "query");
|
|
2167
|
-
const renderable = manifestView?.operations.some((operation) => route.operations.includes(operation.operationId) && operation
|
|
2189
|
+
const renderable = manifestView?.operations.some((operation) => route.operations.includes(operation.operationId) && isPageOperation(operation));
|
|
2168
2190
|
if (isApiRoute(route, renderable))
|
|
2169
2191
|
delete route.query;
|
|
2170
2192
|
else if (query)
|
|
@@ -2176,7 +2198,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
2176
2198
|
const title = trimmedString(body, "title");
|
|
2177
2199
|
if (!title)
|
|
2178
2200
|
return validationError(event, "Display title is required.");
|
|
2179
|
-
const renderable = manifestView?.operations.some((operation) => route.operations.includes(operation.operationId) && operation
|
|
2201
|
+
const renderable = manifestView?.operations.some((operation) => route.operations.includes(operation.operationId) && isPageOperation(operation));
|
|
2180
2202
|
if (!isApiRoute(route, renderable))
|
|
2181
2203
|
route.title = title;
|
|
2182
2204
|
}
|
|
@@ -2190,7 +2212,7 @@ export function registerAdminApiRoutes(app, store, cpState, database) {
|
|
|
2190
2212
|
if (wantsHtmx(event))
|
|
2191
2213
|
return htmxReload(routesReloadPath(appId, route.kind === "api" ? route.serviceId : undefined));
|
|
2192
2214
|
return jsonResponse({ ok: true });
|
|
2193
|
-
}, database, event);
|
|
2215
|
+
}, database, event, true);
|
|
2194
2216
|
});
|
|
2195
2217
|
app.delete(`${API_BASE}/apps/:appId/routes/:routeId`, async (event) => {
|
|
2196
2218
|
const appId = getParam(event, "appId");
|