@jskit-ai/console-core 0.1.122 → 0.1.124
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/package.json +26 -48
- package/src/server/ConsoleFeature.js +67 -0
- package/src/server/consoleSettings/bootConsoleSettingsRoutes.js +4 -6
- package/src/server/consoleSettings/consoleSettingsActions.js +37 -8
- package/test/consoleRouteRequestInputValidator.test.js +3 -25
- package/test/exportsContract.test.js +5 -1
- package/test/featureRuntime.test.js +59 -0
- package/src/server/ConsoleCoreServiceProvider.js +0 -22
- package/src/server/consoleSettings/registerConsoleSettings.js +0 -56
- package/src/server/registerConsoleBootstrap.js +0 -16
- package/src/server/registerConsoleCore.js +0 -25
- package/src/server/support/consoleActionSurfaces.js +0 -62
- package/test/bootstrapPayloadIntegration.test.js +0 -78
- package/test/consoleActionSurfaces.test.js +0 -24
- package/test/registerConsoleCore.test.js +0 -55
- package/test/registerServiceRealtimeEvents.test.js +0 -38
- /package/{templates/migrations → migrations}/console_core_generic_initial.cjs +0 -0
package/package.json
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/console-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.124",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
7
7
|
},
|
|
8
|
+
"exports": {
|
|
9
|
+
"./server/ConsoleFeature": "./src/server/ConsoleFeature.js",
|
|
10
|
+
"./shared/resources/consoleSettingsResource": "./src/shared/resources/consoleSettingsResource.js"
|
|
11
|
+
},
|
|
8
12
|
"dependencies": {
|
|
9
|
-
"@jskit-ai/auth-core": "0.1.
|
|
10
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
11
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
12
|
-
"@jskit-ai/kernel": "0.1.
|
|
13
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
14
|
-
"@jskit-ai/users-core": "0.1.
|
|
13
|
+
"@jskit-ai/auth-core": "0.1.159",
|
|
14
|
+
"@jskit-ai/database-runtime": "0.1.161",
|
|
15
|
+
"@jskit-ai/http-runtime": "0.1.159",
|
|
16
|
+
"@jskit-ai/kernel": "0.1.161",
|
|
17
|
+
"@jskit-ai/resource-crud-core": "0.1.103",
|
|
18
|
+
"@jskit-ai/users-core": "0.1.174",
|
|
15
19
|
"json-rest-schema": "^1.0.17"
|
|
16
20
|
},
|
|
17
21
|
"description": "Console runtime: console settings schema, bootstrap flags, actions, and HTTP routes.",
|
|
@@ -19,21 +23,22 @@
|
|
|
19
23
|
"kind": "runtime",
|
|
20
24
|
"capabilities": {
|
|
21
25
|
"provides": [
|
|
22
|
-
"console.core"
|
|
23
|
-
"console.server-routes"
|
|
26
|
+
"console.core"
|
|
24
27
|
],
|
|
25
28
|
"requires": [
|
|
29
|
+
"auth.extensions",
|
|
26
30
|
"runtime.actions",
|
|
31
|
+
"runtime.bootstrap",
|
|
27
32
|
"runtime.database",
|
|
28
|
-
"
|
|
33
|
+
"runtime.http"
|
|
29
34
|
]
|
|
30
35
|
},
|
|
31
36
|
"runtime": {
|
|
32
37
|
"server": {
|
|
33
38
|
"providers": [
|
|
34
39
|
{
|
|
35
|
-
"entrypoint": "src/server/
|
|
36
|
-
"export": "
|
|
40
|
+
"entrypoint": "src/server/ConsoleFeature.js",
|
|
41
|
+
"export": "ConsoleFeature"
|
|
37
42
|
}
|
|
38
43
|
]
|
|
39
44
|
},
|
|
@@ -46,9 +51,7 @@
|
|
|
46
51
|
"tableOwnership": {
|
|
47
52
|
"tables": [
|
|
48
53
|
{
|
|
49
|
-
"tableName": "console_settings"
|
|
50
|
-
"provenance": "runtime-package",
|
|
51
|
-
"ownerKind": "package-runtime"
|
|
54
|
+
"tableName": "console_settings"
|
|
52
55
|
}
|
|
53
56
|
]
|
|
54
57
|
}
|
|
@@ -57,7 +60,7 @@
|
|
|
57
60
|
"surfaces": [
|
|
58
61
|
{
|
|
59
62
|
"subpath": "./server",
|
|
60
|
-
"summary": "Exports
|
|
63
|
+
"summary": "Exports the explicit Console feature with owner access, settings actions, bootstrap, and routes."
|
|
61
64
|
},
|
|
62
65
|
{
|
|
63
66
|
"subpath": "./shared",
|
|
@@ -68,10 +71,9 @@
|
|
|
68
71
|
"summary": "Exports no runtime API today (reserved client entrypoint)."
|
|
69
72
|
}
|
|
70
73
|
],
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
}
|
|
74
|
+
"capabilities": [
|
|
75
|
+
"console.core"
|
|
76
|
+
]
|
|
75
77
|
},
|
|
76
78
|
"server": {
|
|
77
79
|
"routes": [
|
|
@@ -88,34 +90,10 @@
|
|
|
88
90
|
]
|
|
89
91
|
}
|
|
90
92
|
},
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
"@jskit-ai/database-runtime": "0.1.159",
|
|
96
|
-
"@jskit-ai/http-runtime": "0.1.157",
|
|
97
|
-
"@jskit-ai/kernel": "0.1.159",
|
|
98
|
-
"@jskit-ai/resource-crud-core": "0.1.101",
|
|
99
|
-
"@jskit-ai/users-core": "0.1.172"
|
|
100
|
-
},
|
|
101
|
-
"dev": {}
|
|
102
|
-
},
|
|
103
|
-
"packageJson": {
|
|
104
|
-
"scripts": {}
|
|
105
|
-
},
|
|
106
|
-
"procfile": {},
|
|
107
|
-
"files": [
|
|
108
|
-
{
|
|
109
|
-
"op": "install-migration",
|
|
110
|
-
"from": "templates/migrations/console_core_generic_initial.cjs",
|
|
111
|
-
"toDir": "migrations",
|
|
112
|
-
"extension": ".cjs",
|
|
113
|
-
"reason": "Install console settings schema migration.",
|
|
114
|
-
"category": "migration",
|
|
115
|
-
"id": "console-core-generic-initial-schema"
|
|
116
|
-
}
|
|
117
|
-
],
|
|
118
|
-
"text": []
|
|
93
|
+
"migrations": {
|
|
94
|
+
"directories": [
|
|
95
|
+
"migrations"
|
|
96
|
+
]
|
|
119
97
|
}
|
|
120
98
|
}
|
|
121
99
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { defineFeature } from "@jskit-ai/kernel/server/features";
|
|
2
|
+
import { createConsoleAuthServiceDecorator } from "./consoleAuthServiceDecorator.js";
|
|
3
|
+
import { createConsoleBootstrapContributor } from "./consoleBootstrapContributor.js";
|
|
4
|
+
import { registerConsoleSettingsRoutes } from "./consoleSettings/bootConsoleSettingsRoutes.js";
|
|
5
|
+
import { buildConsoleSettingsActions } from "./consoleSettings/consoleSettingsActions.js";
|
|
6
|
+
import { createService as createConsoleService } from "./consoleSettings/consoleService.js";
|
|
7
|
+
import { createRepository as createConsoleSettingsRepository } from "./consoleSettings/consoleSettingsRepository.js";
|
|
8
|
+
import { createService as createConsoleSettingsService } from "./consoleSettings/consoleSettingsService.js";
|
|
9
|
+
|
|
10
|
+
function createConsoleRuntime({ database } = {}) {
|
|
11
|
+
if (!database || typeof database.knex !== "function") {
|
|
12
|
+
throw new TypeError("ConsoleFeature requires runtime.database.knex.");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const consoleSettingsRepository = createConsoleSettingsRepository(database.knex);
|
|
16
|
+
const consoleService = createConsoleService({ consoleSettingsRepository });
|
|
17
|
+
const consoleSettingsService = createConsoleSettingsService({
|
|
18
|
+
consoleService,
|
|
19
|
+
consoleSettingsRepository
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
repositories: Object.freeze({ settings: consoleSettingsRepository }),
|
|
24
|
+
services: Object.freeze({
|
|
25
|
+
access: consoleService,
|
|
26
|
+
settings: consoleSettingsService
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const ConsoleFeature = defineFeature({
|
|
32
|
+
id: "console.core",
|
|
33
|
+
domain: "console",
|
|
34
|
+
requires: {
|
|
35
|
+
authExtensions: "auth.extensions",
|
|
36
|
+
bootstrap: "runtime.bootstrap",
|
|
37
|
+
database: "runtime.database",
|
|
38
|
+
http: "runtime.http"
|
|
39
|
+
},
|
|
40
|
+
provides: {
|
|
41
|
+
console: "console.core"
|
|
42
|
+
},
|
|
43
|
+
setup({ authExtensions, bootstrap, database, http }) {
|
|
44
|
+
const console = createConsoleRuntime({ database });
|
|
45
|
+
|
|
46
|
+
authExtensions.registerServiceDecorator(
|
|
47
|
+
createConsoleAuthServiceDecorator({ consoleService: console.services.access })
|
|
48
|
+
);
|
|
49
|
+
bootstrap.register({
|
|
50
|
+
id: "console.bootstrap",
|
|
51
|
+
order: 300,
|
|
52
|
+
contribute: createConsoleBootstrapContributor({
|
|
53
|
+
consoleService: console.services.access
|
|
54
|
+
}).contribute
|
|
55
|
+
});
|
|
56
|
+
registerConsoleSettingsRoutes(http.router);
|
|
57
|
+
|
|
58
|
+
return { console };
|
|
59
|
+
},
|
|
60
|
+
actions({ console }) {
|
|
61
|
+
return buildConsoleSettingsActions({
|
|
62
|
+
consoleSettingsService: console.services.settings
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export { ConsoleFeature, createConsoleRuntime };
|
|
@@ -5,13 +5,11 @@ function resolveConsoleSettingsRecordId() {
|
|
|
5
5
|
return "console-settings";
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
function
|
|
9
|
-
if (!
|
|
10
|
-
throw new
|
|
8
|
+
function registerConsoleSettingsRoutes(router) {
|
|
9
|
+
if (!router || typeof router.register !== "function") {
|
|
10
|
+
throw new TypeError("registerConsoleSettingsRoutes requires router.register().");
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const router = app.make("jskit.http.router");
|
|
14
|
-
|
|
15
13
|
router.register(
|
|
16
14
|
"GET",
|
|
17
15
|
"/api/console/settings",
|
|
@@ -68,4 +66,4 @@ function bootConsoleSettingsRoutes(app) {
|
|
|
68
66
|
);
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
export {
|
|
69
|
+
export { registerConsoleSettingsRoutes };
|
|
@@ -2,15 +2,16 @@ import {
|
|
|
2
2
|
emptyInputValidator
|
|
3
3
|
} from "@jskit-ai/kernel/shared/actions/actionContributorHelpers";
|
|
4
4
|
import { returnJsonApiData } from "@jskit-ai/http-runtime/shared";
|
|
5
|
+
import { createEntityChangedActionEvent } from "@jskit-ai/kernel/server/actions";
|
|
5
6
|
import { consoleSettingsResource } from "../../shared/resources/consoleSettingsResource.js";
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
+
const consoleSettingsActionSpecifications = Object.freeze([
|
|
8
9
|
{
|
|
9
10
|
id: "console.settings.read",
|
|
10
11
|
version: 1,
|
|
11
12
|
kind: "query",
|
|
12
13
|
channels: ["api", "automation", "internal"],
|
|
13
|
-
|
|
14
|
+
surfaces: ["console"],
|
|
14
15
|
permission: {
|
|
15
16
|
require: "authenticated"
|
|
16
17
|
},
|
|
@@ -21,8 +22,8 @@ const consoleSettingsActions = Object.freeze([
|
|
|
21
22
|
actionName: "console.settings.read"
|
|
22
23
|
},
|
|
23
24
|
observability: {},
|
|
24
|
-
async
|
|
25
|
-
return returnJsonApiData(await
|
|
25
|
+
async run(consoleSettingsService, _input, context) {
|
|
26
|
+
return returnJsonApiData(await consoleSettingsService.getSettings({
|
|
26
27
|
context
|
|
27
28
|
}));
|
|
28
29
|
}
|
|
@@ -32,7 +33,7 @@ const consoleSettingsActions = Object.freeze([
|
|
|
32
33
|
version: 1,
|
|
33
34
|
kind: "command",
|
|
34
35
|
channels: ["api", "automation", "internal"],
|
|
35
|
-
|
|
36
|
+
surfaces: ["console"],
|
|
36
37
|
permission: {
|
|
37
38
|
require: "authenticated"
|
|
38
39
|
},
|
|
@@ -43,12 +44,40 @@ const consoleSettingsActions = Object.freeze([
|
|
|
43
44
|
actionName: "console.settings.update"
|
|
44
45
|
},
|
|
45
46
|
observability: {},
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
extensions: {
|
|
48
|
+
realtime: {
|
|
49
|
+
event: "console.settings.changed",
|
|
50
|
+
audience: "all_users"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
events: [createEntityChangedActionEvent({
|
|
54
|
+
source: "console",
|
|
55
|
+
entity: "settings",
|
|
56
|
+
operation: "updated",
|
|
57
|
+
entityId: 1,
|
|
58
|
+
realtime: {
|
|
59
|
+
event: "console.settings.changed",
|
|
60
|
+
audience: "all_users"
|
|
61
|
+
}
|
|
62
|
+
})],
|
|
63
|
+
async run(consoleSettingsService, input, context) {
|
|
64
|
+
return returnJsonApiData(await consoleSettingsService.updateSettings(input, {
|
|
48
65
|
context
|
|
49
66
|
}));
|
|
50
67
|
}
|
|
51
68
|
}
|
|
52
69
|
]);
|
|
53
70
|
|
|
54
|
-
|
|
71
|
+
function buildConsoleSettingsActions({ consoleSettingsService } = {}) {
|
|
72
|
+
if (!consoleSettingsService) {
|
|
73
|
+
throw new TypeError("buildConsoleSettingsActions requires consoleSettingsService.");
|
|
74
|
+
}
|
|
75
|
+
return consoleSettingsActionSpecifications.map(({ run, ...definition }) => Object.freeze({
|
|
76
|
+
...definition,
|
|
77
|
+
execute(input, context) {
|
|
78
|
+
return run(consoleSettingsService, input, context);
|
|
79
|
+
}
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { consoleSettingsActionSpecifications, buildConsoleSettingsActions };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
|
-
import {
|
|
3
|
+
import { registerConsoleSettingsRoutes } from "../src/server/consoleSettings/bootConsoleSettingsRoutes.js";
|
|
4
4
|
|
|
5
5
|
function createReplyDouble() {
|
|
6
6
|
return {
|
|
@@ -26,9 +26,7 @@ function findRoute(routes, { method, path }) {
|
|
|
26
26
|
return routes.find((route) => route.method === method && route.path === path) || null;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
async function registerRoutes({
|
|
30
|
-
consoleService = {}
|
|
31
|
-
} = {}) {
|
|
29
|
+
async function registerRoutes() {
|
|
32
30
|
const registeredRoutes = [];
|
|
33
31
|
const router = {
|
|
34
32
|
register(method, path, route, handler) {
|
|
@@ -41,27 +39,7 @@ async function registerRoutes({
|
|
|
41
39
|
}
|
|
42
40
|
};
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
["jskit.http.router", router],
|
|
46
|
-
["actionExecutor", {}]
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
bindings.set("consoleService", consoleService);
|
|
50
|
-
|
|
51
|
-
const app = {
|
|
52
|
-
has(token) {
|
|
53
|
-
return bindings.has(token);
|
|
54
|
-
},
|
|
55
|
-
make(token) {
|
|
56
|
-
if (!bindings.has(token)) {
|
|
57
|
-
throw new Error(`Missing test binding for token: ${String(token)}`);
|
|
58
|
-
}
|
|
59
|
-
return bindings.get(token);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const provider = new ConsoleCoreServiceProvider();
|
|
64
|
-
await provider.boot(app);
|
|
42
|
+
registerConsoleSettingsRoutes(router);
|
|
65
43
|
|
|
66
44
|
return registeredRoutes;
|
|
67
45
|
}
|
|
@@ -12,7 +12,11 @@ test("console-core exports are explicit and aligned with production/template usa
|
|
|
12
12
|
const result = evaluatePackageExportsContract({
|
|
13
13
|
repoRoot: REPO_ROOT,
|
|
14
14
|
packageDir: PACKAGE_DIR,
|
|
15
|
-
packageId: "@jskit-ai/console-core"
|
|
15
|
+
packageId: "@jskit-ai/console-core",
|
|
16
|
+
requiredExports: [
|
|
17
|
+
"./server/ConsoleFeature",
|
|
18
|
+
"./shared/resources/consoleSettingsResource"
|
|
19
|
+
]
|
|
16
20
|
});
|
|
17
21
|
|
|
18
22
|
assert.deepEqual(result.wildcardExports, [], `console-core exports must be explicit. Remove wildcard keys: ${result.wildcardExports.join(", ")}`);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createAuthExtensions } from "@jskit-ai/auth-core/server/authExtensions";
|
|
4
|
+
import { createActionProvider } from "@jskit-ai/kernel/server/actions";
|
|
5
|
+
import { createCapabilityRuntime, defineProvider } from "@jskit-ai/kernel/shared/capabilities";
|
|
6
|
+
import { createBootstrapRuntime } from "@jskit-ai/kernel/server/runtime";
|
|
7
|
+
import { ConsoleFeature } from "../src/server/ConsoleFeature.js";
|
|
8
|
+
|
|
9
|
+
test("ConsoleFeature assembles owner access, settings, routes, actions, and bootstrap explicitly", async () => {
|
|
10
|
+
const routes = [];
|
|
11
|
+
const authExtensions = createAuthExtensions();
|
|
12
|
+
const bootstrap = createBootstrapRuntime();
|
|
13
|
+
let actions = null;
|
|
14
|
+
let console = null;
|
|
15
|
+
const probe = defineProvider({
|
|
16
|
+
id: "test.console.probe",
|
|
17
|
+
requires: {
|
|
18
|
+
actionCatalogue: "runtime.actions",
|
|
19
|
+
consoleCapability: "console.core"
|
|
20
|
+
},
|
|
21
|
+
setup({ actionCatalogue, consoleCapability }) {
|
|
22
|
+
actions = actionCatalogue;
|
|
23
|
+
console = consoleCapability;
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
const runtime = createCapabilityRuntime({
|
|
28
|
+
inputs: {
|
|
29
|
+
"auth.extensions": authExtensions,
|
|
30
|
+
"runtime.bootstrap": bootstrap,
|
|
31
|
+
"runtime.database": { knex() {} },
|
|
32
|
+
"runtime.http": {
|
|
33
|
+
router: {
|
|
34
|
+
register(method, path) {
|
|
35
|
+
routes.push(`${method} ${path}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
providers: [createActionProvider(), ConsoleFeature, probe]
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await runtime.start();
|
|
44
|
+
|
|
45
|
+
assert.equal(typeof console.services.access.requireConsoleOwner, "function");
|
|
46
|
+
assert.equal(typeof console.services.settings.updateSettings, "function");
|
|
47
|
+
assert.deepEqual(routes, [
|
|
48
|
+
"GET /api/console/settings",
|
|
49
|
+
"PATCH /api/console/settings"
|
|
50
|
+
]);
|
|
51
|
+
assert.deepEqual(
|
|
52
|
+
actions.listDefinitions().map((definition) => definition.id),
|
|
53
|
+
["console.settings.read", "console.settings.update"]
|
|
54
|
+
);
|
|
55
|
+
assert.deepEqual(bootstrap.diagnostics().contributorIds, ["console.bootstrap"]);
|
|
56
|
+
assert.deepEqual(authExtensions.diagnostics().serviceDecoratorIds, [
|
|
57
|
+
"console.core.authServiceDecorator"
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { bootConsoleSettingsRoutes } from "./consoleSettings/bootConsoleSettingsRoutes.js";
|
|
2
|
-
import { registerConsoleCore } from "./registerConsoleCore.js";
|
|
3
|
-
import { registerConsoleBootstrap } from "./registerConsoleBootstrap.js";
|
|
4
|
-
import { registerConsoleSettings } from "./consoleSettings/registerConsoleSettings.js";
|
|
5
|
-
|
|
6
|
-
class ConsoleCoreServiceProvider {
|
|
7
|
-
static id = "console.core";
|
|
8
|
-
|
|
9
|
-
static startsAfter = ["runtime.actions"];
|
|
10
|
-
|
|
11
|
-
register(app) {
|
|
12
|
-
registerConsoleCore(app);
|
|
13
|
-
registerConsoleBootstrap(app);
|
|
14
|
-
registerConsoleSettings(app);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async boot(app) {
|
|
18
|
-
bootConsoleSettingsRoutes(app);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export { ConsoleCoreServiceProvider };
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { withActionDefaults } from "@jskit-ai/kernel/shared/actions";
|
|
2
|
-
import { createService as createConsoleSettingsService } from "./consoleSettingsService.js";
|
|
3
|
-
import { createService as createConsoleService } from "./consoleService.js";
|
|
4
|
-
import { consoleSettingsActions } from "./consoleSettingsActions.js";
|
|
5
|
-
|
|
6
|
-
function registerConsoleSettings(app) {
|
|
7
|
-
if (!app || typeof app.singleton !== "function" || typeof app.service !== "function" || typeof app.actions !== "function") {
|
|
8
|
-
throw new Error("registerConsoleSettings requires application singleton()/service()/actions().");
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const hasConsoleService = typeof app.has === "function" ? app.has("consoleService") : false;
|
|
12
|
-
if (!hasConsoleService) {
|
|
13
|
-
app.singleton("consoleService", (scope) =>
|
|
14
|
-
createConsoleService({
|
|
15
|
-
consoleSettingsRepository: scope.make("consoleSettingsRepository")
|
|
16
|
-
})
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
app.service(
|
|
21
|
-
"console.settings.service",
|
|
22
|
-
(scope) =>
|
|
23
|
-
createConsoleSettingsService({
|
|
24
|
-
consoleSettingsRepository: scope.make("consoleSettingsRepository"),
|
|
25
|
-
consoleService: scope.make("consoleService")
|
|
26
|
-
}),
|
|
27
|
-
{
|
|
28
|
-
events: Object.freeze({
|
|
29
|
-
updateSettings: Object.freeze([
|
|
30
|
-
Object.freeze({
|
|
31
|
-
type: "entity.changed",
|
|
32
|
-
source: "console",
|
|
33
|
-
entity: "settings",
|
|
34
|
-
operation: "updated",
|
|
35
|
-
entityId: 1,
|
|
36
|
-
realtime: Object.freeze({
|
|
37
|
-
event: "console.settings.changed",
|
|
38
|
-
audience: "all_users"
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
])
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
app.actions(
|
|
47
|
-
withActionDefaults(consoleSettingsActions, {
|
|
48
|
-
domain: "console",
|
|
49
|
-
dependencies: {
|
|
50
|
-
consoleSettingsService: "console.settings.service"
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export { registerConsoleSettings };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { registerBootstrapPayloadContributor } from "@jskit-ai/kernel/server/runtime";
|
|
2
|
-
import { createConsoleBootstrapContributor } from "./consoleBootstrapContributor.js";
|
|
3
|
-
|
|
4
|
-
function registerConsoleBootstrap(app) {
|
|
5
|
-
if (!app || typeof app.singleton !== "function") {
|
|
6
|
-
throw new Error("registerConsoleBootstrap requires application singleton().");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
registerBootstrapPayloadContributor(app, "console.core.bootstrap.payloadContributor", (scope) => {
|
|
10
|
-
return createConsoleBootstrapContributor({
|
|
11
|
-
consoleService: scope.make("consoleService")
|
|
12
|
-
});
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export { registerConsoleBootstrap };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { registerAuthServiceDecorator } from "@jskit-ai/auth-core/server/authServiceDecoratorRegistry";
|
|
2
|
-
import { createConsoleAuthServiceDecorator } from "./consoleAuthServiceDecorator.js";
|
|
3
|
-
import { createRepository as createConsoleSettingsRepository } from "./consoleSettings/consoleSettingsRepository.js";
|
|
4
|
-
import { registerConsoleCoreActionSurfaceSources } from "./support/consoleActionSurfaces.js";
|
|
5
|
-
|
|
6
|
-
function registerConsoleCore(app) {
|
|
7
|
-
if (!app || typeof app.singleton !== "function") {
|
|
8
|
-
throw new Error("registerConsoleCore requires application singleton().");
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
registerConsoleCoreActionSurfaceSources(app);
|
|
12
|
-
|
|
13
|
-
registerAuthServiceDecorator(app, "console.core.authServiceDecorator", (scope) =>
|
|
14
|
-
createConsoleAuthServiceDecorator({
|
|
15
|
-
consoleService: scope.make("consoleService")
|
|
16
|
-
})
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
app.singleton("consoleSettingsRepository", (scope) => {
|
|
20
|
-
const knex = scope.make("jskit.database.knex");
|
|
21
|
-
return createConsoleSettingsRepository(knex);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export { registerConsoleCore };
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { normalizeSurfaceId } from "@jskit-ai/kernel/shared/surface/registry";
|
|
2
|
-
import { isRecord, normalizeLowerText } from "@jskit-ai/kernel/shared/support/normalize";
|
|
3
|
-
|
|
4
|
-
const CONSOLE_OWNER_ACCESS_POLICY_ID = "console_owner";
|
|
5
|
-
|
|
6
|
-
function normalizeSurfaceIds(surfaceIds = []) {
|
|
7
|
-
const source = Array.isArray(surfaceIds) ? surfaceIds : [];
|
|
8
|
-
const seen = new Set();
|
|
9
|
-
const normalized = [];
|
|
10
|
-
|
|
11
|
-
for (const candidate of source) {
|
|
12
|
-
const surfaceId = normalizeSurfaceId(candidate);
|
|
13
|
-
if (!surfaceId || seen.has(surfaceId)) {
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
seen.add(surfaceId);
|
|
17
|
-
normalized.push(surfaceId);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return normalized;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function resolveConsoleSurfaceIdsFromAppConfig(appConfig = {}) {
|
|
24
|
-
const source = isRecord(appConfig?.surfaceDefinitions) ? appConfig.surfaceDefinitions : {};
|
|
25
|
-
const resolved = [];
|
|
26
|
-
|
|
27
|
-
for (const [key, value] of Object.entries(source)) {
|
|
28
|
-
const definition = isRecord(value) ? value : {};
|
|
29
|
-
const surfaceId = normalizeSurfaceId(definition.id || key);
|
|
30
|
-
if (!surfaceId) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
if (definition.enabled === false) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (definition.requiresWorkspace === true) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (normalizeLowerText(definition.accessPolicyId) !== CONSOLE_OWNER_ACCESS_POLICY_ID) {
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
resolved.push(surfaceId);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return normalizeSurfaceIds(resolved);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function registerConsoleCoreActionSurfaceSources(app) {
|
|
49
|
-
if (!app || typeof app.actionSurfaceSource !== "function") {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
app.actionSurfaceSource("console", ({ scope }) => {
|
|
54
|
-
const appConfig = scope?.has?.("appConfig") ? scope.make("appConfig") : {};
|
|
55
|
-
return resolveConsoleSurfaceIdsFromAppConfig(appConfig);
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export {
|
|
60
|
-
resolveConsoleSurfaceIdsFromAppConfig,
|
|
61
|
-
registerConsoleCoreActionSurfaceSources
|
|
62
|
-
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { createContainer } from "../../kernel/server/container/index.js";
|
|
4
|
-
import { resolveBootstrapPayload } from "../../kernel/server/registries/bootstrapPayloadContributorRegistry.js";
|
|
5
|
-
import { registerUsersBootstrap } from "../../users-core/src/server/registerUsersBootstrap.js";
|
|
6
|
-
import { registerConsoleBootstrap } from "../src/server/registerConsoleBootstrap.js";
|
|
7
|
-
|
|
8
|
-
function createAuthenticatedProfile(overrides = {}) {
|
|
9
|
-
return {
|
|
10
|
-
id: "12",
|
|
11
|
-
authProvider: "local",
|
|
12
|
-
authProviderUserSid: "user-12",
|
|
13
|
-
username: "consoleowner",
|
|
14
|
-
displayName: "Console Owner",
|
|
15
|
-
email: "owner@example.com",
|
|
16
|
-
...overrides
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
test("bootstrap payload preserves consoleowner for authenticated users after users bootstrap runs", async () => {
|
|
21
|
-
const profile = createAuthenticatedProfile();
|
|
22
|
-
const app = createContainer();
|
|
23
|
-
|
|
24
|
-
app.instance("internal.repository.user-profiles", {
|
|
25
|
-
async findById(userId) {
|
|
26
|
-
return String(userId || "") === profile.id ? profile : null;
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
app.instance("internal.repository.user-settings", {
|
|
30
|
-
async ensureForUserId() {
|
|
31
|
-
return {};
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
app.instance("authService", {
|
|
35
|
-
getOAuthProviderCatalog() {
|
|
36
|
-
return {
|
|
37
|
-
providers: [],
|
|
38
|
-
defaultProvider: null
|
|
39
|
-
};
|
|
40
|
-
},
|
|
41
|
-
writeSessionCookies() {},
|
|
42
|
-
clearSessionCookies() {}
|
|
43
|
-
});
|
|
44
|
-
app.instance("consoleService", {
|
|
45
|
-
async isConsoleOwnerUserId(userId) {
|
|
46
|
-
return String(userId || "") === profile.id;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
registerConsoleBootstrap(app);
|
|
51
|
-
registerUsersBootstrap(app);
|
|
52
|
-
|
|
53
|
-
const payload = await resolveBootstrapPayload(app, {
|
|
54
|
-
request: {
|
|
55
|
-
async executeAction({ actionId }) {
|
|
56
|
-
assert.equal(actionId, "auth.session.read");
|
|
57
|
-
return {
|
|
58
|
-
authenticated: true,
|
|
59
|
-
actor: {
|
|
60
|
-
id: profile.id,
|
|
61
|
-
displayName: profile.displayName,
|
|
62
|
-
email: profile.email
|
|
63
|
-
},
|
|
64
|
-
session: {
|
|
65
|
-
csrfToken: "csrf-1"
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
reply: {}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
assert.equal(payload.session.authenticated, true);
|
|
74
|
-
assert.equal(payload.session.userId, "12");
|
|
75
|
-
assert.deepEqual(payload.surfaceAccess, {
|
|
76
|
-
consoleowner: true
|
|
77
|
-
});
|
|
78
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import {
|
|
4
|
-
resolveConsoleSurfaceIdsFromAppConfig
|
|
5
|
-
} from "../src/server/support/consoleActionSurfaces.js";
|
|
6
|
-
|
|
7
|
-
test("resolveConsoleSurfaceIdsFromAppConfig resolves all enabled console-owner surfaces", () => {
|
|
8
|
-
const surfaceIds = resolveConsoleSurfaceIdsFromAppConfig({
|
|
9
|
-
surfaceDefinitions: {
|
|
10
|
-
home: { id: "home", enabled: true, requiresWorkspace: false, accessPolicyId: "public" },
|
|
11
|
-
console: { id: "console", enabled: true, requiresWorkspace: false, accessPolicyId: "console_owner" },
|
|
12
|
-
opsConsole: { id: "opsConsole", enabled: true, requiresWorkspace: false, accessPolicyId: "console_owner" },
|
|
13
|
-
app: { id: "app", enabled: true, requiresWorkspace: true, accessPolicyId: "workspace_member" },
|
|
14
|
-
disabledConsole: {
|
|
15
|
-
id: "disabledConsole",
|
|
16
|
-
enabled: false,
|
|
17
|
-
requiresWorkspace: false,
|
|
18
|
-
accessPolicyId: "console_owner"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
assert.deepEqual(surfaceIds, ["console", "opsconsole"]);
|
|
24
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { registerConsoleCore } from "../src/server/registerConsoleCore.js";
|
|
4
|
-
|
|
5
|
-
test("registerConsoleCore registers the console action surface alias when action runtime is available", () => {
|
|
6
|
-
const calls = [];
|
|
7
|
-
const tags = [];
|
|
8
|
-
const app = {
|
|
9
|
-
singleton() {
|
|
10
|
-
return this;
|
|
11
|
-
},
|
|
12
|
-
tag(token, tagName) {
|
|
13
|
-
tags.push({
|
|
14
|
-
token: String(token || ""),
|
|
15
|
-
tagName: String(tagName || "")
|
|
16
|
-
});
|
|
17
|
-
return this;
|
|
18
|
-
},
|
|
19
|
-
actionSurfaceSource(sourceName, resolver) {
|
|
20
|
-
calls.push({
|
|
21
|
-
sourceName: String(sourceName || ""),
|
|
22
|
-
resolverType: typeof resolver
|
|
23
|
-
});
|
|
24
|
-
return this;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
registerConsoleCore(app);
|
|
29
|
-
|
|
30
|
-
assert.deepEqual(calls, [
|
|
31
|
-
{
|
|
32
|
-
sourceName: "console",
|
|
33
|
-
resolverType: "function"
|
|
34
|
-
}
|
|
35
|
-
]);
|
|
36
|
-
assert.deepEqual(tags, [
|
|
37
|
-
{
|
|
38
|
-
token: "console.core.authServiceDecorator",
|
|
39
|
-
tagName: "jskit.auth.service.decorators"
|
|
40
|
-
}
|
|
41
|
-
]);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("registerConsoleCore still works when action runtime has not installed actionSurfaceSource yet", () => {
|
|
45
|
-
const app = {
|
|
46
|
-
singleton() {
|
|
47
|
-
return this;
|
|
48
|
-
},
|
|
49
|
-
tag() {
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
assert.doesNotThrow(() => registerConsoleCore(app));
|
|
55
|
-
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { registerConsoleSettings } from "../src/server/consoleSettings/registerConsoleSettings.js";
|
|
4
|
-
|
|
5
|
-
function createAppDouble() {
|
|
6
|
-
const serviceCalls = [];
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
serviceCalls,
|
|
10
|
-
app: {
|
|
11
|
-
singleton() {
|
|
12
|
-
return this;
|
|
13
|
-
},
|
|
14
|
-
service(token, factory, metadata) {
|
|
15
|
-
serviceCalls.push({
|
|
16
|
-
token,
|
|
17
|
-
factory,
|
|
18
|
-
metadata
|
|
19
|
-
});
|
|
20
|
-
return this;
|
|
21
|
-
},
|
|
22
|
-
actions() {
|
|
23
|
-
return this;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function findServiceCall(serviceCalls, token) {
|
|
30
|
-
return serviceCalls.find((entry) => entry.token === token) || null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
test("console settings register publishes console.settings.changed", () => {
|
|
34
|
-
const payload = createAppDouble();
|
|
35
|
-
registerConsoleSettings(payload.app);
|
|
36
|
-
const consoleSettings = findServiceCall(payload.serviceCalls, "console.settings.service");
|
|
37
|
-
assert.equal(consoleSettings?.metadata?.events?.updateSettings?.[0]?.realtime?.event, "console.settings.changed");
|
|
38
|
-
});
|
|
File without changes
|