@jskit-ai/kernel 0.1.245 → 0.1.247
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/client/appConfig.js +2 -1
- package/client/asyncModuleRecovery.js +2 -4
- package/client/index.d.ts +13 -75
- package/client/index.js +1 -1
- package/client/logging.js +8 -2
- package/client/moduleBootstrap.js +41 -33
- package/client/moduleBootstrap.test.js +35 -0
- package/client/shellBootstrap.js +1 -8
- package/client/shellBootstrap.test.js +32 -5
- package/client/shellRouting.js +16 -61
- package/client/shellRouting.test.js +30 -1
- package/client/vite/clientBootstrapPlugin.js +0 -6
- package/client/vite/clientBootstrapPlugin.test.js +2 -3
- package/internal/node/installedPackages.js +19 -62
- package/internal/node/installedPackages.test.js +33 -0
- package/package.json +2 -4
- package/server/actions/actionCatalogue.js +13 -34
- package/{shared → server}/actions/actionContributorHelpers.js +0 -5
- package/{shared → server}/actions/actionDefinitions.js +24 -131
- package/{shared → server}/actions/actionDefinitions.test.js +75 -21
- package/server/actions/actionEvents.js +97 -2
- package/server/actions/actionEvents.test.js +79 -0
- package/{shared → server}/actions/executionContext.js +3 -13
- package/server/actions/idempotency.js +24 -0
- package/server/actions/pipeline.js +87 -0
- package/{shared → server}/actions/policies.js +20 -33
- package/{shared → server}/actions/policies.test.js +6 -6
- package/{shared → server}/actions/registry.js +3 -22
- package/{shared → server}/actions/registry.test.js +70 -32
- package/server/actions/requestMeta.js +17 -0
- package/server/http/capabilityHttpRuntime.js +1 -1
- package/server/http/capabilityHttpRuntime.test.js +56 -0
- package/server/http/errorHandling.js +291 -0
- package/server/{runtime/fastifyBootstrap.test.js → http/errorHandling.test.js} +72 -120
- package/server/http/lib/routeRegistration.js +36 -150
- package/server/http/lib/routeTransport.js +2 -0
- package/server/http/lib/routeValidator.js +5 -47
- package/server/http/lib/routeValidator.test.js +15 -17
- package/server/http/lib/router.js +10 -94
- package/server/platform/providerRuntime/capabilityProviderLoader.js +2 -1
- package/server/platform/providerRuntime/helpers.js +1 -34
- package/server/runtime/integers.js +1 -5
- package/server/runtime/serviceAuthorization.js +4 -9
- package/server/support/appConfig.js +2 -1
- package/server/support/appConfigFiles.js +1 -38
- package/server/support/appConfigFiles.test.js +3 -39
- package/server/support/index.js +1 -20
- package/shared/capabilities/defineProvider.js +1 -1
- package/shared/capabilities/index.js +1 -1
- package/shared/index.js +1 -1
- package/shared/support/index.js +1 -4
- package/shared/support/mobileConfig.js +99 -0
- package/shared/support/mobileConfig.test.js +113 -0
- package/shared/support/normalize.js +0 -108
- package/shared/support/normalize.test.js +0 -134
- package/shared/{actions/actionContributorHelpers.test.js → support/permissions.test.js} +1 -1
- package/shared/support/returnToPath.js +1 -20
- package/shared/support/returnToPath.test.js +1 -36
- package/shared/support/shellLayoutTargets.js +2 -140
- package/shared/support/shellLayoutTargets.test.js +1 -110
- package/shared/support/sorting.js +1 -9
- package/shared/surface/apiPaths.js +1 -82
- package/shared/surface/paths.js +38 -171
- package/shared/surface/registry.js +2 -1
- package/shared/surface/runtime.js +18 -109
- package/shared/surface/runtime.test.js +57 -0
- package/shared/validators/index.js +1 -4
- package/shared/validators/jsonRestSchemaSupport.js +0 -9
- package/shared/validators/recordIdParamsValidator.js +0 -6
- package/shared/validators/schemaDefinitions.js +4 -30
- package/shared/validators/schemaPayloadValidation.js +2 -6
- package/test/barrelExposure.test.js +3 -7
- package/test/exportsContract.test.js +1 -3
- package/client/mobileLaunchRouting.js +0 -231
- package/client/mobileLaunchRouting.test.js +0 -230
- package/server/http/lib/controller.js +0 -183
- package/server/http/lib/controller.test.js +0 -143
- package/server/http/lib/index.js +0 -5
- package/server/runtime/canonicalJson.js +0 -74
- package/server/runtime/entityChangeEvents.js +0 -307
- package/server/runtime/entityChangeEvents.test.js +0 -274
- package/server/runtime/fastifyBootstrap.js +0 -553
- package/server/runtime/moduleConfig.js +0 -223
- package/server/runtime/moduleConfig.test.js +0 -165
- package/server/runtime/pagination.js +0 -13
- package/server/runtime/realtimeNormalization.js +0 -21
- package/server/runtime/routeUtils.js +0 -20
- package/server/runtime/securityAudit.js +0 -269
- package/server/runtime/securityAudit.test.js +0 -41
- package/server/support/pageTargets.js +0 -772
- package/server/support/pageTargets.test.js +0 -659
- package/server/support/shellOutlets.js +0 -576
- package/server/support/shellOutlets.test.js +0 -336
- package/server/surface/index.js +0 -18
- package/shared/actions/audit.js +0 -7
- package/shared/actions/idempotency.js +0 -62
- package/shared/actions/observability.js +0 -10
- package/shared/actions/pipeline.js +0 -309
- package/shared/actions/requestMeta.js +0 -36
- package/shared/actions/textNormalization.js +0 -3
- package/shared/actions/withActionDefaults.js +0 -34
- /package/{shared → server}/actions/executionContext.test.js +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { normalizeObject } from "../../shared/support/normalize.js";
|
|
4
4
|
import { sortStrings } from "../../shared/support/sorting.js";
|
|
5
|
-
import { fileExists } from "./fileSystem.js";
|
|
5
|
+
import { fileExists, readJsonFile } from "./fileSystem.js";
|
|
6
6
|
|
|
7
7
|
const ROOT_DEPENDENCY_SECTIONS = Object.freeze([
|
|
8
8
|
"dependencies",
|
|
@@ -18,14 +18,6 @@ const JSKIT_PACKAGE_CONFIG_KEYS = Object.freeze([
|
|
|
18
18
|
"vite"
|
|
19
19
|
]);
|
|
20
20
|
|
|
21
|
-
async function readJsonFile(filePath, fallback = {}) {
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(await readFile(filePath, "utf8"));
|
|
24
|
-
} catch {
|
|
25
|
-
return fallback;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
21
|
function collectRootDependencySpecifiers(packageJson = {}) {
|
|
30
22
|
const specifiers = new Map();
|
|
31
23
|
for (const sectionName of ROOT_DEPENDENCY_SECTIONS) {
|
|
@@ -42,7 +34,7 @@ function collectRootDependencySpecifiers(packageJson = {}) {
|
|
|
42
34
|
|
|
43
35
|
function collectPackageDependencyIds(packageJson = {}) {
|
|
44
36
|
const dependencyIds = new Set();
|
|
45
|
-
for (const sectionName of
|
|
37
|
+
for (const sectionName of ROOT_DEPENDENCY_SECTIONS) {
|
|
46
38
|
for (const packageId of Object.keys(normalizeObject(packageJson?.[sectionName]))) {
|
|
47
39
|
const normalizedPackageId = String(packageId || "").trim();
|
|
48
40
|
if (normalizedPackageId) {
|
|
@@ -175,56 +167,27 @@ async function discoverInstalledPackages({ appRoot } = {}) {
|
|
|
175
167
|
const rootPackageJson = await readJsonFile(path.resolve(normalizedAppRoot, "package.json"), {});
|
|
176
168
|
const directSpecifiers = collectRootDependencySpecifiers(rootPackageJson);
|
|
177
169
|
const directPackageIds = new Set(directSpecifiers.keys());
|
|
178
|
-
const runtimeRootPackageIds = new Set(
|
|
179
|
-
["dependencies", "optionalDependencies", "peerDependencies"]
|
|
180
|
-
.flatMap((sectionName) => Object.keys(normalizeObject(rootPackageJson?.[sectionName])))
|
|
181
|
-
);
|
|
182
170
|
const visited = new Set();
|
|
171
|
+
// Breadth-first walk of the dependency graph; the queue stays ordered by packageId.
|
|
183
172
|
const queue = [];
|
|
184
|
-
const queued = new
|
|
173
|
+
const queued = new Set();
|
|
185
174
|
const packages = [];
|
|
186
175
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
if (left.traverseDependencies !== right.traverseDependencies) {
|
|
190
|
-
return left.traverseDependencies ? -1 : 1;
|
|
191
|
-
}
|
|
192
|
-
return left.packageId.localeCompare(right.packageId);
|
|
193
|
-
});
|
|
194
|
-
};
|
|
195
|
-
const enqueue = ({ packageId, parentPackageRoot = "", traverseDependencies = false }) => {
|
|
196
|
-
const normalizedPackageId = String(packageId || "").trim();
|
|
197
|
-
if (!normalizedPackageId || visited.has(normalizedPackageId)) {
|
|
176
|
+
const enqueue = ({ packageId, parentPackageRoot = "" }) => {
|
|
177
|
+
if (!packageId || visited.has(packageId) || queued.has(packageId)) {
|
|
198
178
|
return;
|
|
199
179
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
existing.traverseDependencies = true;
|
|
204
|
-
existing.parentPackageRoot = parentPackageRoot || existing.parentPackageRoot;
|
|
205
|
-
sortQueue();
|
|
206
|
-
}
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
const entry = {
|
|
210
|
-
packageId: normalizedPackageId,
|
|
211
|
-
parentPackageRoot,
|
|
212
|
-
traverseDependencies: Boolean(traverseDependencies)
|
|
213
|
-
};
|
|
214
|
-
queue.push(entry);
|
|
215
|
-
queued.set(normalizedPackageId, entry);
|
|
216
|
-
sortQueue();
|
|
180
|
+
queue.push({ packageId, parentPackageRoot });
|
|
181
|
+
queued.add(packageId);
|
|
182
|
+
queue.sort((left, right) => left.packageId.localeCompare(right.packageId));
|
|
217
183
|
};
|
|
218
184
|
|
|
219
185
|
for (const packageId of sortStrings([...directPackageIds])) {
|
|
220
|
-
enqueue({
|
|
221
|
-
packageId,
|
|
222
|
-
traverseDependencies: runtimeRootPackageIds.has(packageId)
|
|
223
|
-
});
|
|
186
|
+
enqueue({ packageId });
|
|
224
187
|
}
|
|
225
188
|
|
|
226
189
|
while (queue.length > 0) {
|
|
227
|
-
const { packageId, parentPackageRoot
|
|
190
|
+
const { packageId, parentPackageRoot } = queue.shift();
|
|
228
191
|
queued.delete(packageId);
|
|
229
192
|
if (!packageId || visited.has(packageId)) {
|
|
230
193
|
continue;
|
|
@@ -244,26 +207,20 @@ async function discoverInstalledPackages({ appRoot } = {}) {
|
|
|
244
207
|
}
|
|
245
208
|
|
|
246
209
|
const packageJson = await readJsonFile(packageJsonPath, {});
|
|
247
|
-
const
|
|
248
|
-
|
|
210
|
+
const packageMetadata = createPackageMetadata(packageJson);
|
|
211
|
+
// An npm alias ("alias": "npm:real@1") installs another package under the alias name,
|
|
212
|
+
// which is only an error for JSKIT packages.
|
|
213
|
+
if (packageMetadata && packageMetadata.packageId !== packageId) {
|
|
249
214
|
throw new Error(
|
|
250
|
-
`Installed package manifest mismatch: expected ${packageId}, received ${
|
|
215
|
+
`Installed package manifest mismatch: expected ${packageId}, received ${packageMetadata.packageId}.`
|
|
251
216
|
);
|
|
252
217
|
}
|
|
253
218
|
|
|
254
219
|
const dependencyIds = collectPackageDependencyIds(packageJson);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const normalizedDependencyId = String(dependencyId || "").trim();
|
|
258
|
-
enqueue({
|
|
259
|
-
packageId: normalizedDependencyId,
|
|
260
|
-
parentPackageRoot: roots.packageRoot,
|
|
261
|
-
traverseDependencies: true
|
|
262
|
-
});
|
|
263
|
-
}
|
|
220
|
+
for (const dependencyId of dependencyIds) {
|
|
221
|
+
enqueue({ packageId: dependencyId, parentPackageRoot: roots.packageRoot });
|
|
264
222
|
}
|
|
265
223
|
|
|
266
|
-
const packageMetadata = createPackageMetadata(packageJson);
|
|
267
224
|
if (!packageMetadata) {
|
|
268
225
|
continue;
|
|
269
226
|
}
|
|
@@ -115,3 +115,36 @@ test("discoverInstalledPackages excludes development-only packages from runtime
|
|
|
115
115
|
const packages = await discoverInstalledPackages({ appRoot });
|
|
116
116
|
assert.deepEqual(packages.map((entry) => entry.packageId), ["@example/runtime"]);
|
|
117
117
|
});
|
|
118
|
+
|
|
119
|
+
test("discoverInstalledPackages walks npm alias dependencies but rejects aliased JSKIT packages", async (context) => {
|
|
120
|
+
const appRoot = await mkdtemp(path.join(tmpdir(), "jskit-installed-package-alias-"));
|
|
121
|
+
context.after(() => rm(appRoot, { recursive: true, force: true }));
|
|
122
|
+
const aliasRoot = path.join(appRoot, "node_modules", "@example", "sdk-v0_3");
|
|
123
|
+
const runtimeRoot = path.join(appRoot, "node_modules", "@example", "runtime");
|
|
124
|
+
await mkdir(aliasRoot, { recursive: true });
|
|
125
|
+
await mkdir(runtimeRoot, { recursive: true });
|
|
126
|
+
await writeFile(
|
|
127
|
+
path.join(appRoot, "package.json"),
|
|
128
|
+
JSON.stringify({ dependencies: { "@example/sdk-v0_3": "npm:@example/sdk@0.3.0" } })
|
|
129
|
+
);
|
|
130
|
+
await writeFile(
|
|
131
|
+
path.join(aliasRoot, "package.json"),
|
|
132
|
+
JSON.stringify({ name: "@example/sdk", version: "0.3.0", dependencies: { "@example/runtime": "1.0.0" } })
|
|
133
|
+
);
|
|
134
|
+
await writeFile(
|
|
135
|
+
path.join(runtimeRoot, "package.json"),
|
|
136
|
+
JSON.stringify({ name: "@example/runtime", version: "1.0.0", jskit: { kind: "runtime" } })
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const packages = await discoverInstalledPackages({ appRoot });
|
|
140
|
+
assert.deepEqual(packages.map((entry) => entry.packageId), ["@example/runtime"]);
|
|
141
|
+
|
|
142
|
+
await writeFile(
|
|
143
|
+
path.join(aliasRoot, "package.json"),
|
|
144
|
+
JSON.stringify({ name: "@example/sdk", version: "0.3.0", jskit: { kind: "runtime" } })
|
|
145
|
+
);
|
|
146
|
+
await assert.rejects(
|
|
147
|
+
() => discoverInstalledPackages({ appRoot }),
|
|
148
|
+
/Installed package manifest mismatch: expected @example\/sdk-v0_3, received @example\/sdk\./
|
|
149
|
+
);
|
|
150
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/kernel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.247",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"json-rest-schema": "^1.0.17"
|
|
@@ -25,18 +25,16 @@
|
|
|
25
25
|
"./client/moduleBootstrap": "./client/moduleBootstrap.js",
|
|
26
26
|
"./client/vite": "./client/vite/index.js",
|
|
27
27
|
"./server/actions": "./server/actions/index.js",
|
|
28
|
+
"./server/actions/actionContributorHelpers": "./server/actions/actionContributorHelpers.js",
|
|
28
29
|
"./server/features": "./server/features/index.js",
|
|
29
30
|
"./server/http": "./server/http/index.js",
|
|
30
31
|
"./server/platform": "./server/platform/index.js",
|
|
31
32
|
"./server/runtime": "./server/runtime/index.js",
|
|
32
|
-
"./server/runtime/entityChangeEvents": "./server/runtime/entityChangeEvents.js",
|
|
33
33
|
"./server/runtime/errors": "./server/runtime/errors.js",
|
|
34
34
|
"./server/runtime/requestUrl": "./server/runtime/requestUrl.js",
|
|
35
35
|
"./server/support": "./server/support/index.js",
|
|
36
36
|
"./shared": "./shared/index.js",
|
|
37
37
|
"./shared/capabilities": "./shared/capabilities/index.js",
|
|
38
|
-
"./shared/actions/actionContributorHelpers": "./shared/actions/actionContributorHelpers.js",
|
|
39
|
-
"./shared/actions/textNormalization": "./shared/actions/textNormalization.js",
|
|
40
38
|
"./shared/validators": "./shared/validators/index.js",
|
|
41
39
|
"./shared/validators/inputNormalization": "./shared/validators/inputNormalization.js",
|
|
42
40
|
"./shared/support": "./shared/support/index.js",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createActionRegistry } from "
|
|
1
|
+
import { createActionRegistry } from "./registry.js";
|
|
2
2
|
import { isRecord } from "../../shared/support/normalize.js";
|
|
3
3
|
|
|
4
4
|
function normalizeRegistration(value) {
|
|
@@ -9,21 +9,12 @@ function normalizeRegistration(value) {
|
|
|
9
9
|
return value;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
function createActionCatalogue({
|
|
13
|
-
idempotencyAdapter,
|
|
14
|
-
auditAdapter,
|
|
15
|
-
observabilityAdapter,
|
|
16
|
-
events,
|
|
17
|
-
logger = null
|
|
18
|
-
} = {}) {
|
|
12
|
+
function createActionCatalogue({ events, logger = null } = {}) {
|
|
19
13
|
const contributors = [];
|
|
20
14
|
const contextContributors = [];
|
|
21
15
|
const contextContributorIds = new Set();
|
|
22
16
|
let registry = createActionRegistry({
|
|
23
17
|
contributors,
|
|
24
|
-
idempotencyAdapter,
|
|
25
|
-
auditAdapter,
|
|
26
|
-
observabilityAdapter,
|
|
27
18
|
events,
|
|
28
19
|
logger
|
|
29
20
|
});
|
|
@@ -36,9 +27,6 @@ function createActionCatalogue({
|
|
|
36
27
|
const nextContributors = [...contributors, normalizeRegistration(contributor)];
|
|
37
28
|
const nextRegistry = createActionRegistry({
|
|
38
29
|
contributors: nextContributors,
|
|
39
|
-
idempotencyAdapter,
|
|
40
|
-
auditAdapter,
|
|
41
|
-
observabilityAdapter,
|
|
42
30
|
events,
|
|
43
31
|
logger
|
|
44
32
|
});
|
|
@@ -104,40 +92,31 @@ function createActionCatalogue({
|
|
|
104
92
|
return Object.freeze(enriched);
|
|
105
93
|
}
|
|
106
94
|
|
|
107
|
-
async function
|
|
95
|
+
async function run(method, payload = {}) {
|
|
108
96
|
const source = payload && typeof payload === "object" ? payload : {};
|
|
109
97
|
const input = source.input && typeof source.input === "object" ? source.input : {};
|
|
98
|
+
const version = source.version == null ? null : source.version;
|
|
110
99
|
const context = await buildExecutionContext({
|
|
111
100
|
actionId: source.actionId,
|
|
112
|
-
version
|
|
101
|
+
version,
|
|
113
102
|
input,
|
|
114
103
|
context: source.context
|
|
115
104
|
});
|
|
116
|
-
return currentRegistry()
|
|
105
|
+
return currentRegistry()[method]({
|
|
117
106
|
actionId: source.actionId,
|
|
118
|
-
version
|
|
107
|
+
version,
|
|
119
108
|
input,
|
|
120
109
|
context,
|
|
121
110
|
deps: isRecord(source.deps) ? source.deps : {}
|
|
122
111
|
});
|
|
123
112
|
}
|
|
124
113
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
input,
|
|
132
|
-
context: source.context
|
|
133
|
-
});
|
|
134
|
-
return currentRegistry().executeStream({
|
|
135
|
-
actionId: source.actionId,
|
|
136
|
-
version: source.version == null ? null : source.version,
|
|
137
|
-
input,
|
|
138
|
-
context,
|
|
139
|
-
deps: isRecord(source.deps) ? source.deps : {}
|
|
140
|
-
});
|
|
114
|
+
function execute(payload) {
|
|
115
|
+
return run("execute", payload);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function executeStream(payload) {
|
|
119
|
+
return run("executeStream", payload);
|
|
141
120
|
}
|
|
142
121
|
|
|
143
122
|
function listDefinitions() {
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { createSchema } from "json-rest-schema";
|
|
2
|
-
import { normalizeObject, normalizePositiveInteger as toPositiveInteger } from "../support/normalize.js";
|
|
3
|
-
import { hasPermission } from "../support/permissions.js";
|
|
4
2
|
|
|
5
3
|
function requireServiceMethod(service, methodName, contributorId, { serviceLabel } = {}) {
|
|
6
4
|
if (!service || typeof service[methodName] !== "function") {
|
|
@@ -19,10 +17,7 @@ const emptyInputValidator = Object.freeze({
|
|
|
19
17
|
});
|
|
20
18
|
|
|
21
19
|
export {
|
|
22
|
-
normalizeObject,
|
|
23
|
-
toPositiveInteger,
|
|
24
20
|
requireServiceMethod,
|
|
25
21
|
resolveRequest,
|
|
26
|
-
hasPermission,
|
|
27
22
|
emptyInputValidator
|
|
28
23
|
};
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "
|
|
4
|
-
import {
|
|
5
|
-
import { normalizePermissionList } from "../support/permissions.js";
|
|
6
|
-
import { normalizeText } from "./textNormalization.js";
|
|
1
|
+
import { normalizeSingleSchemaDefinition } from "../../shared/validators/index.js";
|
|
2
|
+
import { isRecord as isPlainObject, normalizePositiveInteger, normalizeText } from "../../shared/support/normalize.js";
|
|
3
|
+
import { normalizePermissionList } from "../../shared/support/permissions.js";
|
|
4
|
+
import { ARCHITECTURE_ID_PATTERN } from "../../shared/capabilities/defineProvider.js";
|
|
7
5
|
|
|
8
6
|
const ACTION_KINDS = Object.freeze(["query", "command", "stream"]);
|
|
9
7
|
const ACTION_IDEMPOTENCY_POLICIES = Object.freeze(["none", "optional", "required", "domain_native"]);
|
|
@@ -12,7 +10,6 @@ const ACTION_PERMISSION_REQUIRE_MODES = Object.freeze(["none", "authenticated",
|
|
|
12
10
|
const ACTION_KIND_SET = new Set(ACTION_KINDS);
|
|
13
11
|
const ACTION_IDEMPOTENCY_SET = new Set(ACTION_IDEMPOTENCY_POLICIES);
|
|
14
12
|
const ACTION_PERMISSION_REQUIRE_SET = new Set(ACTION_PERMISSION_REQUIRE_MODES);
|
|
15
|
-
const ACTION_DOMAIN_PATTERN = /^[a-z][a-z0-9_.-]*$/;
|
|
16
13
|
|
|
17
14
|
class ActionRuntimeError extends Error {
|
|
18
15
|
constructor(status, message, options = {}) {
|
|
@@ -38,10 +35,10 @@ function normalizeActionDomain(value, { context = "domain", errorCode = "ACTION_
|
|
|
38
35
|
code: errorCode
|
|
39
36
|
});
|
|
40
37
|
}
|
|
41
|
-
if (!
|
|
38
|
+
if (!ARCHITECTURE_ID_PATTERN.test(domain)) {
|
|
42
39
|
throw createActionRuntimeError(
|
|
43
40
|
500,
|
|
44
|
-
`${context} must match ${
|
|
41
|
+
`${context} must match ${ARCHITECTURE_ID_PATTERN.toString()} (lowercase letters, digits, _, -, .).`,
|
|
45
42
|
{
|
|
46
43
|
code: errorCode
|
|
47
44
|
}
|
|
@@ -51,23 +48,13 @@ function normalizeActionDomain(value, { context = "domain", errorCode = "ACTION_
|
|
|
51
48
|
return domain;
|
|
52
49
|
}
|
|
53
50
|
|
|
54
|
-
function normalizeStringArray(value,
|
|
51
|
+
function normalizeStringArray(value, fieldName) {
|
|
55
52
|
const source = Array.isArray(value) ? value : [];
|
|
56
53
|
const normalized = Array.from(
|
|
57
|
-
new Set(
|
|
58
|
-
source
|
|
59
|
-
.map((entry) => normalizeText(entry).toLowerCase())
|
|
60
|
-
.filter(Boolean)
|
|
61
|
-
.filter((entry) => {
|
|
62
|
-
if (!(allowedSet instanceof Set)) {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
return allowedSet.has(entry);
|
|
66
|
-
})
|
|
67
|
-
)
|
|
54
|
+
new Set(source.map((entry) => normalizeText(entry).toLowerCase()).filter(Boolean))
|
|
68
55
|
);
|
|
69
56
|
|
|
70
|
-
if (
|
|
57
|
+
if (normalized.length < 1) {
|
|
71
58
|
throw createActionRuntimeError(500, `Action definition ${fieldName} must include at least one value.`, {
|
|
72
59
|
code: "ACTION_DEFINITION_INVALID"
|
|
73
60
|
});
|
|
@@ -76,7 +63,7 @@ function normalizeStringArray(value, { fieldName, allowedSet, allowEmpty = false
|
|
|
76
63
|
return normalized;
|
|
77
64
|
}
|
|
78
65
|
|
|
79
|
-
function
|
|
66
|
+
function normalizeActionSchema(value, fieldName, { required = false, defaultMode = "" } = {}) {
|
|
80
67
|
if (value == null) {
|
|
81
68
|
if (!required) {
|
|
82
69
|
return null;
|
|
@@ -87,6 +74,12 @@ function normalizeSingleActionSchema(value, fieldName, { required = false, defau
|
|
|
87
74
|
});
|
|
88
75
|
}
|
|
89
76
|
|
|
77
|
+
if (Array.isArray(value)) {
|
|
78
|
+
throw createActionRuntimeError(500, `Action definition ${fieldName} must be a single schema definition.`, {
|
|
79
|
+
code: "ACTION_DEFINITION_INVALID"
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
90
83
|
if (!isPlainObject(value)) {
|
|
91
84
|
throw createActionRuntimeError(500, `Action definition ${fieldName} must be a json-rest-schema schema definition.`, {
|
|
92
85
|
code: "ACTION_DEFINITION_INVALID"
|
|
@@ -105,52 +98,6 @@ function normalizeSingleActionSchema(value, fieldName, { required = false, defau
|
|
|
105
98
|
}
|
|
106
99
|
}
|
|
107
100
|
|
|
108
|
-
function normalizeActionInputDefinition(value, fieldName, { required = false } = {}) {
|
|
109
|
-
if (value == null) {
|
|
110
|
-
if (!required) {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
throw createActionRuntimeError(500, `Action definition ${fieldName} is required.`, {
|
|
115
|
-
code: "ACTION_DEFINITION_INVALID"
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (Array.isArray(value)) {
|
|
120
|
-
throw createActionRuntimeError(500, `Action definition ${fieldName} must be a single schema definition.`, {
|
|
121
|
-
code: "ACTION_DEFINITION_INVALID"
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return normalizeSingleActionSchema(value, fieldName, {
|
|
126
|
-
required,
|
|
127
|
-
defaultMode: "patch"
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function normalizeActionOutputDefinition(value, fieldName, { required = false } = {}) {
|
|
132
|
-
if (value == null) {
|
|
133
|
-
if (!required) {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
throw createActionRuntimeError(500, `Action definition ${fieldName} is required.`, {
|
|
138
|
-
code: "ACTION_DEFINITION_INVALID"
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (Array.isArray(value)) {
|
|
143
|
-
throw createActionRuntimeError(500, `Action definition ${fieldName} must be a single schema definition.`, {
|
|
144
|
-
code: "ACTION_DEFINITION_INVALID"
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return normalizeSingleActionSchema(value, fieldName, {
|
|
149
|
-
required,
|
|
150
|
-
defaultMode: "replace"
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
101
|
function normalizeActionPermission(permission, actionId) {
|
|
155
102
|
if (permission == null) {
|
|
156
103
|
return Object.freeze({
|
|
@@ -190,42 +137,6 @@ function normalizeActionPermission(permission, actionId) {
|
|
|
190
137
|
});
|
|
191
138
|
}
|
|
192
139
|
|
|
193
|
-
function normalizeAuditConfig(audit, { actionId }) {
|
|
194
|
-
const source = audit && typeof audit === "object" ? audit : {};
|
|
195
|
-
const actionName = normalizeText(source.actionName || actionId);
|
|
196
|
-
const metadataBuilder = source.metadataBuilder;
|
|
197
|
-
const piiTags = normalizeStringArray(source.piiTags, {
|
|
198
|
-
fieldName: "audit.piiTags",
|
|
199
|
-
allowEmpty: true
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
if (metadataBuilder != null && typeof metadataBuilder !== "function") {
|
|
203
|
-
throw createActionRuntimeError(500, "Action definition audit.metadataBuilder must be a function when provided.", {
|
|
204
|
-
code: "ACTION_DEFINITION_INVALID"
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return Object.freeze({
|
|
209
|
-
actionName,
|
|
210
|
-
metadataBuilder: typeof metadataBuilder === "function" ? metadataBuilder : null,
|
|
211
|
-
piiTags
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function normalizeObservabilityConfig(observability) {
|
|
216
|
-
const source = observability && typeof observability === "object" ? observability : {};
|
|
217
|
-
const metricTags = normalizeStringArray(source.metricTags, {
|
|
218
|
-
fieldName: "observability.metricTags",
|
|
219
|
-
allowEmpty: true
|
|
220
|
-
});
|
|
221
|
-
const sampleRate = Number(source.sampleRate);
|
|
222
|
-
|
|
223
|
-
return Object.freeze({
|
|
224
|
-
metricTags,
|
|
225
|
-
sampleRate: Number.isFinite(sampleRate) && sampleRate >= 0 && sampleRate <= 1 ? sampleRate : null
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
140
|
function normalizeActionExtensions(value) {
|
|
230
141
|
if (value == null) {
|
|
231
142
|
return Object.freeze({});
|
|
@@ -286,13 +197,8 @@ function normalizeActionDefinition(definition, { contributorId = "", contributor
|
|
|
286
197
|
});
|
|
287
198
|
}
|
|
288
199
|
|
|
289
|
-
const channels = normalizeStringArray(source.channels,
|
|
290
|
-
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
const surfaces = normalizeStringArray(source.surfaces, {
|
|
294
|
-
fieldName: "surfaces"
|
|
295
|
-
});
|
|
200
|
+
const channels = normalizeStringArray(source.channels, "channels");
|
|
201
|
+
const surfaces = normalizeStringArray(source.surfaces, "surfaces");
|
|
296
202
|
|
|
297
203
|
const idempotency = normalizeText(source.idempotency || "none").toLowerCase();
|
|
298
204
|
if (!ACTION_IDEMPOTENCY_SET.has(idempotency)) {
|
|
@@ -318,18 +224,15 @@ function normalizeActionDefinition(definition, { contributorId = "", contributor
|
|
|
318
224
|
kind,
|
|
319
225
|
channels,
|
|
320
226
|
surfaces,
|
|
321
|
-
input:
|
|
322
|
-
required: true
|
|
227
|
+
input: normalizeActionSchema(source.input, "input", {
|
|
228
|
+
required: true,
|
|
229
|
+
defaultMode: "patch"
|
|
323
230
|
}),
|
|
324
|
-
output:
|
|
325
|
-
|
|
231
|
+
output: normalizeActionSchema(source.output, "output", {
|
|
232
|
+
defaultMode: "replace"
|
|
326
233
|
}),
|
|
327
234
|
idempotency,
|
|
328
235
|
permission: normalizeActionPermission(source.permission, id),
|
|
329
|
-
audit: normalizeAuditConfig(source.audit, {
|
|
330
|
-
actionId: id
|
|
331
|
-
}),
|
|
332
|
-
observability: normalizeObservabilityConfig(source.observability),
|
|
333
236
|
extensions: normalizeActionExtensions(source.extensions),
|
|
334
237
|
events: normalizeActionEvents(source.events, id),
|
|
335
238
|
execute: source.execute,
|
|
@@ -371,15 +274,7 @@ function createActionVersionKey(actionId, version) {
|
|
|
371
274
|
}
|
|
372
275
|
|
|
373
276
|
const __testables = {
|
|
374
|
-
|
|
375
|
-
isPlainObject,
|
|
376
|
-
normalizeStringArray,
|
|
377
|
-
normalizeSingleActionSchema,
|
|
378
|
-
normalizeActionInputDefinition,
|
|
379
|
-
normalizeActionOutputDefinition,
|
|
380
|
-
normalizeActionPermission,
|
|
381
|
-
normalizeAuditConfig,
|
|
382
|
-
normalizeObservabilityConfig,
|
|
277
|
+
normalizeActionSchema,
|
|
383
278
|
normalizeActionExtensions
|
|
384
279
|
};
|
|
385
280
|
|
|
@@ -388,8 +283,6 @@ export {
|
|
|
388
283
|
createActionRuntimeError,
|
|
389
284
|
normalizeActionDefinition,
|
|
390
285
|
normalizeActionContributor,
|
|
391
|
-
normalizeActionDomain,
|
|
392
286
|
createActionVersionKey,
|
|
393
|
-
isPlainObject,
|
|
394
287
|
__testables
|
|
395
288
|
};
|