@jskit-ai/kernel 0.1.244 → 0.1.246
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 +18 -76
- package/client/index.js +7 -2
- package/client/logging.js +8 -2
- package/client/moduleBootstrap.js +41 -33
- package/client/moduleBootstrap.test.js +35 -0
- package/client/shellBootstrap.js +38 -10
- package/client/shellBootstrap.test.js +85 -6
- 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 +14 -58
- 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 +16 -20
- package/shared/support/returnToPath.test.js +5 -33
- 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 +5 -8
- 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
|
@@ -3,7 +3,7 @@ import test from "node:test";
|
|
|
3
3
|
import { createSchema } from "json-rest-schema";
|
|
4
4
|
|
|
5
5
|
import { createRouter } from "./router.js";
|
|
6
|
-
import { compileRouteValidator,
|
|
6
|
+
import { compileRouteValidator, resolveRouteValidatorOptions } from "./routeValidator.js";
|
|
7
7
|
|
|
8
8
|
function stripJsonRestTransportExtensions(value) {
|
|
9
9
|
if (Array.isArray(value)) {
|
|
@@ -45,7 +45,7 @@ function createMockJsonRestSchema() {
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
test("
|
|
48
|
+
test("compileRouteValidator compiles body/query/params and maps query schema to querystring", () => {
|
|
49
49
|
const bodySchema = createSchema({
|
|
50
50
|
name: {
|
|
51
51
|
type: "string",
|
|
@@ -82,7 +82,7 @@ test("defineRouteValidator compiles body/query/params and maps query schema to q
|
|
|
82
82
|
type: "object"
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
const
|
|
85
|
+
const compiled = compileRouteValidator({
|
|
86
86
|
meta: {
|
|
87
87
|
tags: ["contacts", "intake"],
|
|
88
88
|
summary: "Create contact intake"
|
|
@@ -104,8 +104,6 @@ test("defineRouteValidator compiles body/query/params and maps query schema to q
|
|
|
104
104
|
}
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
const compiled = validator.toRouteOptions();
|
|
108
|
-
|
|
109
107
|
assert.deepEqual(compiled.schema, {
|
|
110
108
|
tags: ["contacts", "intake"],
|
|
111
109
|
summary: "Create contact intake",
|
|
@@ -344,7 +342,7 @@ test("resolveRouteValidatorOptions rejects validator wrapper", () => {
|
|
|
344
342
|
method: "POST",
|
|
345
343
|
path: "/contacts",
|
|
346
344
|
options: {
|
|
347
|
-
validator:
|
|
345
|
+
validator: {},
|
|
348
346
|
middleware: ["api"]
|
|
349
347
|
}
|
|
350
348
|
}),
|
|
@@ -352,10 +350,10 @@ test("resolveRouteValidatorOptions rejects validator wrapper", () => {
|
|
|
352
350
|
);
|
|
353
351
|
});
|
|
354
352
|
|
|
355
|
-
test("
|
|
353
|
+
test("compileRouteValidator rejects unsupported advanced.jskitInput", () => {
|
|
356
354
|
assert.throws(
|
|
357
355
|
() =>
|
|
358
|
-
|
|
356
|
+
compileRouteValidator({
|
|
359
357
|
advanced: {
|
|
360
358
|
jskitInput: {}
|
|
361
359
|
}
|
|
@@ -364,24 +362,24 @@ test("defineRouteValidator rejects unsupported advanced.jskitInput", () => {
|
|
|
364
362
|
);
|
|
365
363
|
});
|
|
366
364
|
|
|
367
|
-
test("
|
|
365
|
+
test("compileRouteValidator rejects unsupported top-level keys generically", () => {
|
|
368
366
|
assert.throws(
|
|
369
367
|
() =>
|
|
370
|
-
|
|
368
|
+
compileRouteValidator({
|
|
371
369
|
unsupportedContract: {
|
|
372
370
|
schema: {
|
|
373
371
|
type: "object"
|
|
374
372
|
}
|
|
375
373
|
}
|
|
376
374
|
}),
|
|
377
|
-
/
|
|
375
|
+
/route validator\.unsupportedContract is not supported/
|
|
378
376
|
);
|
|
379
377
|
});
|
|
380
378
|
|
|
381
|
-
test("
|
|
379
|
+
test("compileRouteValidator validates meta fields", () => {
|
|
382
380
|
assert.throws(
|
|
383
381
|
() =>
|
|
384
|
-
|
|
382
|
+
compileRouteValidator({
|
|
385
383
|
meta: {
|
|
386
384
|
tags: ["ok", ""]
|
|
387
385
|
}
|
|
@@ -391,7 +389,7 @@ test("defineRouteValidator validates meta fields", () => {
|
|
|
391
389
|
|
|
392
390
|
assert.throws(
|
|
393
391
|
() =>
|
|
394
|
-
|
|
392
|
+
compileRouteValidator({
|
|
395
393
|
meta: {
|
|
396
394
|
summary: ""
|
|
397
395
|
}
|
|
@@ -407,7 +405,7 @@ test("HttpRouter.register rejects validator wrapper options", () => {
|
|
|
407
405
|
"POST",
|
|
408
406
|
"/contacts",
|
|
409
407
|
{
|
|
410
|
-
validator:
|
|
408
|
+
validator: {}
|
|
411
409
|
},
|
|
412
410
|
async () => {}
|
|
413
411
|
),
|
|
@@ -425,7 +423,7 @@ test("HttpRouter.register rejects compiled route option payloads", () => {
|
|
|
425
423
|
}
|
|
426
424
|
});
|
|
427
425
|
|
|
428
|
-
const
|
|
426
|
+
const compiled = compileRouteValidator({
|
|
429
427
|
query: {
|
|
430
428
|
schema: querySchema
|
|
431
429
|
}
|
|
@@ -434,7 +432,7 @@ test("HttpRouter.register rejects compiled route option payloads", () => {
|
|
|
434
432
|
assert.throws(
|
|
435
433
|
() => router.get(
|
|
436
434
|
"/contacts",
|
|
437
|
-
|
|
435
|
+
compiled,
|
|
438
436
|
async () => {}
|
|
439
437
|
),
|
|
440
438
|
/uses unsupported validator options: schema, input/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ensureNonEmptyText, normalizeObject, normalizeText } from "../../../shared/support/normalize.js";
|
|
2
2
|
import { RouteDefinitionError } from "./errors.js";
|
|
3
3
|
import { resolveRouteValidatorOptions } from "./routeValidator.js";
|
|
4
|
-
import { normalizeMiddlewareStack as normalizeSharedMiddlewareStack } from "./routeSupport.js";
|
|
4
|
+
import { normalizeMiddlewareStack as normalizeSharedMiddlewareStack, resolveRouteLabel } from "./routeSupport.js";
|
|
5
5
|
import { normalizeRouteOutputTransform, normalizeRouteTransport } from "./routeTransport.js";
|
|
6
6
|
|
|
7
7
|
function normalizeMethod(method) {
|
|
@@ -13,17 +13,7 @@ function normalizePath(pathname) {
|
|
|
13
13
|
if (!value.startsWith("/")) {
|
|
14
14
|
throw new RouteDefinitionError(`Route path must start with '/': ${value || "<empty>"}`);
|
|
15
15
|
}
|
|
16
|
-
return value.replace(/\/+/g, "/");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function joinPath(left, right) {
|
|
20
|
-
const leftPath = normalizeText(left);
|
|
21
|
-
const rightPath = normalizeText(right);
|
|
22
|
-
|
|
23
|
-
const normalizedLeft = leftPath ? `/${leftPath.replace(/^\/+|\/+$/g, "")}` : "";
|
|
24
|
-
const normalizedRight = rightPath ? `/${rightPath.replace(/^\/+|\/+$/g, "")}` : "";
|
|
25
|
-
const joined = `${normalizedLeft}${normalizedRight}`.replace(/\/+/g, "/");
|
|
26
|
-
return joined || "/";
|
|
16
|
+
return value.replace(/\/+/g, "/").replace(/(.)\/$/, "$1");
|
|
27
17
|
}
|
|
28
18
|
|
|
29
19
|
function normalizeRouterMiddlewareStack(value, { context = "middleware" } = {}) {
|
|
@@ -40,9 +30,7 @@ function normalizeRouteInternal(value, { method = "", path = "" } = {}) {
|
|
|
40
30
|
return false;
|
|
41
31
|
}
|
|
42
32
|
if (typeof value !== "boolean") {
|
|
43
|
-
throw new RouteDefinitionError(
|
|
44
|
-
`Route ${String(method || "<unknown>")} ${String(path || "<unknown>")} internal must be a boolean.`
|
|
45
|
-
);
|
|
33
|
+
throw new RouteDefinitionError(`Route ${resolveRouteLabel({ method, path })} internal must be a boolean.`);
|
|
46
34
|
}
|
|
47
35
|
return value;
|
|
48
36
|
}
|
|
@@ -74,12 +62,8 @@ function normalizeRouteInput(method, path, optionsOrHandler, maybeHandler) {
|
|
|
74
62
|
}
|
|
75
63
|
|
|
76
64
|
class HttpRouter {
|
|
77
|
-
constructor(
|
|
78
|
-
this._routes =
|
|
79
|
-
this._prefix = normalizeText(prefix);
|
|
80
|
-
this._middleware = normalizeRouterMiddlewareStack(middleware, {
|
|
81
|
-
context: "router middleware"
|
|
82
|
-
});
|
|
65
|
+
constructor() {
|
|
66
|
+
this._routes = [];
|
|
83
67
|
}
|
|
84
68
|
|
|
85
69
|
register(method, path, optionsOrHandler, maybeHandler) {
|
|
@@ -111,7 +95,7 @@ class HttpRouter {
|
|
|
111
95
|
const route = Object.freeze({
|
|
112
96
|
id: normalizeText(resolvedOptions.id),
|
|
113
97
|
method: input.method,
|
|
114
|
-
path:
|
|
98
|
+
path: input.path,
|
|
115
99
|
schema: resolvedOptions.schema,
|
|
116
100
|
input: routeInput,
|
|
117
101
|
output: routeOutput,
|
|
@@ -131,7 +115,7 @@ class HttpRouter {
|
|
|
131
115
|
ownerResolver: resolvedOptions.ownerResolver,
|
|
132
116
|
csrfProtection: resolvedOptions.csrfProtection,
|
|
133
117
|
bodyLimit: resolvedOptions.bodyLimit,
|
|
134
|
-
middleware: Object.freeze(
|
|
118
|
+
middleware: Object.freeze(routeMiddleware),
|
|
135
119
|
handler: input.handler
|
|
136
120
|
});
|
|
137
121
|
|
|
@@ -159,81 +143,13 @@ class HttpRouter {
|
|
|
159
143
|
return this.register("DELETE", path, optionsOrHandler, maybeHandler);
|
|
160
144
|
}
|
|
161
145
|
|
|
162
|
-
group({ prefix = "", middleware = [] } = {}, defineRoutes = null) {
|
|
163
|
-
if (typeof defineRoutes !== "function") {
|
|
164
|
-
throw new RouteDefinitionError("group() requires a callback.");
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const nestedRouter = new HttpRouter({
|
|
168
|
-
routes: this._routes,
|
|
169
|
-
prefix: joinPath(this._prefix, prefix || ""),
|
|
170
|
-
middleware: [
|
|
171
|
-
...this._middleware,
|
|
172
|
-
...normalizeRouterMiddlewareStack(middleware, {
|
|
173
|
-
context: "group middleware"
|
|
174
|
-
})
|
|
175
|
-
]
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
defineRoutes(nestedRouter);
|
|
179
|
-
return this;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
resource(name, controller, options = {}) {
|
|
183
|
-
this._resource(name, controller, {
|
|
184
|
-
...normalizeObject(options),
|
|
185
|
-
apiOnly: false
|
|
186
|
-
});
|
|
187
|
-
return this;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
apiResource(name, controller, options = {}) {
|
|
191
|
-
this._resource(name, controller, {
|
|
192
|
-
...normalizeObject(options),
|
|
193
|
-
apiOnly: true
|
|
194
|
-
});
|
|
195
|
-
return this;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
_resource(name, controller, options = {}) {
|
|
199
|
-
const resourceName = ensureNonEmptyText(name, "resource name");
|
|
200
|
-
const idParam = normalizeText(options.idParam, { fallback: "id" });
|
|
201
|
-
const basePath = `/${resourceName}`;
|
|
202
|
-
const itemPath = `/${resourceName}/:${idParam}`;
|
|
203
|
-
|
|
204
|
-
const methods = normalizeObject(controller);
|
|
205
|
-
const routeOptions = {
|
|
206
|
-
...normalizeObject(options)
|
|
207
|
-
};
|
|
208
|
-
delete routeOptions.idParam;
|
|
209
|
-
delete routeOptions.apiOnly;
|
|
210
|
-
|
|
211
|
-
const requireMethod = (methodName) => {
|
|
212
|
-
const handler = methods[methodName];
|
|
213
|
-
if (typeof handler !== "function") {
|
|
214
|
-
throw new RouteDefinitionError(`resource controller for ${resourceName} is missing method ${methodName}().`);
|
|
215
|
-
}
|
|
216
|
-
return handler;
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
this.get(basePath, routeOptions, requireMethod("index"));
|
|
220
|
-
if (!options.apiOnly) {
|
|
221
|
-
this.get(`${basePath}/create`, routeOptions, requireMethod("create"));
|
|
222
|
-
this.get(`${itemPath}/edit`, routeOptions, requireMethod("edit"));
|
|
223
|
-
}
|
|
224
|
-
this.post(basePath, routeOptions, requireMethod("store"));
|
|
225
|
-
this.get(itemPath, routeOptions, requireMethod("show"));
|
|
226
|
-
this.put(itemPath, routeOptions, requireMethod("update"));
|
|
227
|
-
this.delete(itemPath, routeOptions, requireMethod("destroy"));
|
|
228
|
-
}
|
|
229
|
-
|
|
230
146
|
list() {
|
|
231
147
|
return Object.freeze([...this._routes]);
|
|
232
148
|
}
|
|
233
149
|
}
|
|
234
150
|
|
|
235
|
-
function createRouter(
|
|
236
|
-
return new HttpRouter(
|
|
151
|
+
function createRouter() {
|
|
152
|
+
return new HttpRouter();
|
|
237
153
|
}
|
|
238
154
|
|
|
239
|
-
export { HttpRouter, createRouter
|
|
155
|
+
export { HttpRouter, createRouter };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
import { defineProvider } from "../../../shared/capabilities/defineProvider.js";
|
|
4
|
-
import { fileExists
|
|
4
|
+
import { fileExists } from "../../../internal/node/fileSystem.js";
|
|
5
|
+
import { isIdentifier, isInsidePackageRoot } from "./helpers.js";
|
|
5
6
|
|
|
6
7
|
function declaredProviderEntrypoints(packageEntry) {
|
|
7
8
|
const runtime = packageEntry?.packageMetadata?.runtime;
|
|
@@ -1,45 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { escapeRegExp } from "../../../shared/surface/escapeRegExp.js";
|
|
3
|
-
import { fileExists } from "../../../internal/node/fileSystem.js";
|
|
4
2
|
|
|
5
3
|
function isIdentifier(value) {
|
|
6
4
|
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(String(value || ""));
|
|
7
5
|
}
|
|
8
6
|
|
|
9
|
-
function createWildcardMatcher(pattern) {
|
|
10
|
-
const rawPattern = String(pattern || "").trim();
|
|
11
|
-
if (!rawPattern) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const escapedPattern = escapeRegExp(rawPattern).replace(/\\\*/g, ".*");
|
|
16
|
-
return new RegExp(`^${escapedPattern}$`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function normalizeRelativePath(fromPath, targetPath) {
|
|
20
|
-
const relative = path.relative(path.resolve(fromPath), path.resolve(targetPath));
|
|
21
|
-
return relative.split(path.sep).join("/");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
7
|
function isInsidePackageRoot(packageRoot, candidatePath) {
|
|
25
8
|
const relative = path.relative(path.resolve(packageRoot), path.resolve(candidatePath));
|
|
26
9
|
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
27
10
|
}
|
|
28
11
|
|
|
29
|
-
|
|
30
|
-
const source = Array.isArray(values) ? values : [];
|
|
31
|
-
return Object.freeze(
|
|
32
|
-
[...new Set(source.map((entry) => path.resolve(entry)).filter(Boolean))].sort((left, right) =>
|
|
33
|
-
left.localeCompare(right)
|
|
34
|
-
)
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export {
|
|
39
|
-
isIdentifier,
|
|
40
|
-
createWildcardMatcher,
|
|
41
|
-
normalizeRelativePath,
|
|
42
|
-
fileExists,
|
|
43
|
-
isInsidePackageRoot,
|
|
44
|
-
toAbsoluteSortedUniquePaths
|
|
45
|
-
};
|
|
12
|
+
export { isIdentifier, isInsidePackageRoot };
|
|
@@ -26,7 +26,7 @@ function resolveRequireMode(value) {
|
|
|
26
26
|
return mode;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function normalizeRequireAuthOptions(options = {}
|
|
29
|
+
function normalizeRequireAuthOptions(options = {}) {
|
|
30
30
|
const source = normalizeObject(options);
|
|
31
31
|
const mode = resolveRequireMode(source.require);
|
|
32
32
|
const permissions = normalizePermissionList(source.permissions);
|
|
@@ -35,8 +35,7 @@ function normalizeRequireAuthOptions(options = {}, { context = "requireAuth opti
|
|
|
35
35
|
require: mode,
|
|
36
36
|
permissions: Object.freeze(permissions),
|
|
37
37
|
message: normalizeText(source.message),
|
|
38
|
-
code: normalizeText(source.code)
|
|
39
|
-
context
|
|
38
|
+
code: normalizeText(source.code)
|
|
40
39
|
});
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -71,7 +70,7 @@ function requireAuth(source = {}, options = {}) {
|
|
|
71
70
|
return actor;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
const requiredPermissions =
|
|
73
|
+
const requiredPermissions = settings.permissions;
|
|
75
74
|
if (requiredPermissions.length < 1) {
|
|
76
75
|
return actor;
|
|
77
76
|
}
|
|
@@ -106,8 +105,4 @@ function requireAuth(source = {}, options = {}) {
|
|
|
106
105
|
return actor;
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
export {
|
|
110
|
-
resolveServiceContext,
|
|
111
|
-
hasPermission,
|
|
112
|
-
requireAuth
|
|
113
|
-
};
|
|
108
|
+
export { requireAuth };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeObject, normalizeText } from "../../shared/support/normalize.js";
|
|
2
|
+
import { normalizeMobileConfig } from "../../shared/support/mobileConfig.js";
|
|
2
3
|
import { normalizeSurfaceId } from "../../shared/surface/registry.js";
|
|
3
4
|
|
|
4
5
|
function resolveAppConfig(scope = null) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
2
|
import { fileExists } from "../../internal/node/fileSystem.js";
|
|
4
3
|
import { importFreshModuleFromAbsolutePath } from "./importFreshModuleFromAbsolutePath.js";
|
|
5
4
|
|
|
@@ -10,27 +9,6 @@ function normalizeConfigObject(value) {
|
|
|
10
9
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
async function resolveAppRootFromModuleUrl(
|
|
14
|
-
moduleUrl,
|
|
15
|
-
{ publicConfigRelativePath = PUBLIC_CONFIG_RELATIVE_PATH } = {}
|
|
16
|
-
) {
|
|
17
|
-
const moduleDirectory = path.dirname(fileURLToPath(moduleUrl));
|
|
18
|
-
let currentDirectory = path.resolve(moduleDirectory);
|
|
19
|
-
|
|
20
|
-
while (true) {
|
|
21
|
-
const candidateConfigPath = path.join(currentDirectory, publicConfigRelativePath);
|
|
22
|
-
if (await fileExists(candidateConfigPath)) {
|
|
23
|
-
return currentDirectory;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const parentDirectory = path.dirname(currentDirectory);
|
|
27
|
-
if (parentDirectory === currentDirectory) {
|
|
28
|
-
throw new Error(`Unable to locate app root (missing ${publicConfigRelativePath}).`);
|
|
29
|
-
}
|
|
30
|
-
currentDirectory = parentDirectory;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
12
|
async function loadConfigModuleAtPath(absolutePath) {
|
|
35
13
|
if (!(await fileExists(absolutePath))) {
|
|
36
14
|
return {};
|
|
@@ -62,19 +40,4 @@ async function loadAppConfigFromAppRoot({
|
|
|
62
40
|
});
|
|
63
41
|
}
|
|
64
42
|
|
|
65
|
-
|
|
66
|
-
moduleUrl = import.meta.url,
|
|
67
|
-
publicConfigRelativePath = PUBLIC_CONFIG_RELATIVE_PATH,
|
|
68
|
-
serverConfigRelativePath = SERVER_CONFIG_RELATIVE_PATH
|
|
69
|
-
} = {}) {
|
|
70
|
-
const appRoot = await resolveAppRootFromModuleUrl(moduleUrl, {
|
|
71
|
-
publicConfigRelativePath
|
|
72
|
-
});
|
|
73
|
-
return loadAppConfigFromAppRoot({
|
|
74
|
-
appRoot,
|
|
75
|
-
publicConfigRelativePath,
|
|
76
|
-
serverConfigRelativePath
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export { loadAppConfigFromAppRoot, loadAppConfigFromModuleUrl };
|
|
43
|
+
export { loadAppConfigFromAppRoot };
|
|
@@ -3,32 +3,7 @@ import { mkdtemp, mkdir, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import test from "node:test";
|
|
6
|
-
import {
|
|
7
|
-
import { loadAppConfigFromAppRoot, loadAppConfigFromModuleUrl } from "./appConfigFiles.js";
|
|
8
|
-
|
|
9
|
-
async function createModuleUrlAt(absolutePath) {
|
|
10
|
-
await mkdir(path.dirname(absolutePath), { recursive: true });
|
|
11
|
-
await writeFile(absolutePath, "export {};\n", "utf8");
|
|
12
|
-
return pathToFileURL(absolutePath).href;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
test("loadAppConfigFromModuleUrl merges public and server config", async () => {
|
|
16
|
-
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "kernel-app-config-"));
|
|
17
|
-
const appRoot = path.join(tempRoot, "app");
|
|
18
|
-
await mkdir(path.join(appRoot, "config"), { recursive: true });
|
|
19
|
-
await writeFile(path.join(appRoot, "config", "public.js"), "export const config = { a: 1, shared: 'public' };", "utf8");
|
|
20
|
-
await writeFile(path.join(appRoot, "config", "server.js"), "export const config = { b: 2, shared: 'server' };", "utf8");
|
|
21
|
-
const moduleUrl = await createModuleUrlAt(path.join(appRoot, "packages", "main", "src", "server", "MainServiceProvider.js"));
|
|
22
|
-
|
|
23
|
-
const loaded = await loadAppConfigFromModuleUrl({ moduleUrl });
|
|
24
|
-
|
|
25
|
-
assert.deepEqual(loaded, {
|
|
26
|
-
a: 1,
|
|
27
|
-
b: 2,
|
|
28
|
-
shared: "server"
|
|
29
|
-
});
|
|
30
|
-
assert.equal(Object.isFrozen(loaded), true);
|
|
31
|
-
});
|
|
6
|
+
import { loadAppConfigFromAppRoot } from "./appConfigFiles.js";
|
|
32
7
|
|
|
33
8
|
test("loadAppConfigFromAppRoot merges public and server config", async () => {
|
|
34
9
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "kernel-app-config-"));
|
|
@@ -69,26 +44,15 @@ test("loadAppConfigFromAppRoot requires an explicit appRoot", async () => {
|
|
|
69
44
|
);
|
|
70
45
|
});
|
|
71
46
|
|
|
72
|
-
test("
|
|
47
|
+
test("loadAppConfigFromAppRoot tolerates missing server config", async () => {
|
|
73
48
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "kernel-app-config-"));
|
|
74
49
|
const appRoot = path.join(tempRoot, "app");
|
|
75
50
|
await mkdir(path.join(appRoot, "config"), { recursive: true });
|
|
76
51
|
await writeFile(path.join(appRoot, "config", "public.js"), "export const config = { a: 1 };", "utf8");
|
|
77
|
-
const moduleUrl = await createModuleUrlAt(path.join(appRoot, "packages", "main", "src", "server", "MainServiceProvider.js"));
|
|
78
52
|
|
|
79
|
-
const loaded = await
|
|
53
|
+
const loaded = await loadAppConfigFromAppRoot({ appRoot });
|
|
80
54
|
|
|
81
55
|
assert.deepEqual(loaded, {
|
|
82
56
|
a: 1
|
|
83
57
|
});
|
|
84
58
|
});
|
|
85
|
-
|
|
86
|
-
test("loadAppConfigFromModuleUrl throws when app root cannot be resolved", async () => {
|
|
87
|
-
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "kernel-app-config-"));
|
|
88
|
-
const moduleUrl = await createModuleUrlAt(path.join(tempRoot, "missing", "packages", "main", "src", "server", "MainServiceProvider.js"));
|
|
89
|
-
|
|
90
|
-
await assert.rejects(
|
|
91
|
-
loadAppConfigFromModuleUrl({ moduleUrl }),
|
|
92
|
-
/Unable to locate app root/
|
|
93
|
-
);
|
|
94
|
-
});
|
package/server/support/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { symlinkSafeRequire } from "./symlinkSafeRequire.js";
|
|
2
2
|
export { resolveAppConfig, resolveMobileConfig, resolveClientAssetMode, resolveMobileCallbackUrls } from "./appConfig.js";
|
|
3
|
-
export { loadAppConfigFromAppRoot
|
|
3
|
+
export { loadAppConfigFromAppRoot } from "./appConfigFiles.js";
|
|
4
4
|
export { importFreshModuleFromAbsolutePath } from "./importFreshModuleFromAbsolutePath.js";
|
|
5
5
|
export {
|
|
6
6
|
collectPackageDependencyIds,
|
|
@@ -9,23 +9,4 @@ export {
|
|
|
9
9
|
discoverInstalledPackages
|
|
10
10
|
} from "../../internal/node/installedPackages.js";
|
|
11
11
|
export { resolveRequiredAppRoot, toPosixPath } from "./path.js";
|
|
12
|
-
export {
|
|
13
|
-
DEFAULT_PAGE_LINK_COMPONENT_TOKEN,
|
|
14
|
-
DEFAULT_SUBPAGE_LINK_COMPONENT_TOKEN,
|
|
15
|
-
listSurfacePageRoots,
|
|
16
|
-
normalizePagesRelativeTargetFile,
|
|
17
|
-
normalizePagesRelativeTargetRoot,
|
|
18
|
-
resolveBestSurfaceMatchFromPageFile,
|
|
19
|
-
resolvePageTargetDetails,
|
|
20
|
-
deriveDefaultSubpagesHost,
|
|
21
|
-
resolveNearestParentSubpagesHost,
|
|
22
|
-
resolvePageLinkTargetDetails
|
|
23
|
-
} from "./pageTargets.js";
|
|
24
|
-
export {
|
|
25
|
-
discoverPlacementTopologyFromApp,
|
|
26
|
-
discoverShellOutletSourcePathsFromApp,
|
|
27
|
-
discoverShellOutletTargetsFromApp,
|
|
28
|
-
resolveSemanticPlacementTargetFromApp,
|
|
29
|
-
resolveShellOutletPlacementTargetFromApp
|
|
30
|
-
} from "./shellOutlets.js";
|
|
31
12
|
export { tryAcquireExclusiveFileLock } from "./fileLock.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { defineProvider } from "./defineProvider.js";
|
|
1
|
+
export { ARCHITECTURE_ID_PATTERN, defineProvider } from "./defineProvider.js";
|
|
2
2
|
export { createCapabilityRuntime } from "./runtime.js";
|
package/shared/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { resolveLinkPath } from "./support/linkPath.js";
|
|
2
|
-
export { normalizePathname } from "./surface/
|
|
2
|
+
export { normalizePathname } from "./surface/paths.js";
|
package/shared/support/index.js
CHANGED
|
@@ -3,10 +3,7 @@ export { pickOwnProperties } from "./pickOwnProperties.js";
|
|
|
3
3
|
export { formatDateTime } from "./formatDateTime.js";
|
|
4
4
|
export { appendQueryString, splitPathQueryAndHash } from "./queryPath.js";
|
|
5
5
|
export { normalizePermissionList, hasPermission } from "./permissions.js";
|
|
6
|
-
export {
|
|
7
|
-
normalizeReturnToPath,
|
|
8
|
-
resolveAllowedOriginsFromPlacementContext
|
|
9
|
-
} from "./returnToPath.js";
|
|
6
|
+
export { normalizeReturnToPath } from "./returnToPath.js";
|
|
10
7
|
export { toCamelCase, toSnakeCase } from "./stringCase.js";
|
|
11
8
|
export {
|
|
12
9
|
isTransientQueryError,
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasValue,
|
|
3
|
+
normalizeBoolean,
|
|
4
|
+
normalizeLowerText,
|
|
5
|
+
normalizeObject,
|
|
6
|
+
normalizePositiveInteger,
|
|
7
|
+
normalizeText,
|
|
8
|
+
normalizeUniqueTextList
|
|
9
|
+
} from "./normalize.js";
|
|
10
|
+
|
|
11
|
+
const MOBILE_ASSET_MODES = Object.freeze(["bundled", "dev_server"]);
|
|
12
|
+
const MOBILE_STRATEGIES = Object.freeze(["capacitor"]);
|
|
13
|
+
const DEFAULT_MOBILE_AUTH_CONFIG = Object.freeze({
|
|
14
|
+
callbackPath: "/auth/login",
|
|
15
|
+
customScheme: "",
|
|
16
|
+
appLinkDomains: Object.freeze([])
|
|
17
|
+
});
|
|
18
|
+
const DEFAULT_MOBILE_ANDROID_CONFIG = Object.freeze({
|
|
19
|
+
packageName: "",
|
|
20
|
+
minSdk: 26,
|
|
21
|
+
targetSdk: 35,
|
|
22
|
+
versionCode: 1,
|
|
23
|
+
versionName: "1.0.0"
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function normalizeMobileStrategy(value = "", { fallback = "" } = {}) {
|
|
27
|
+
const normalized = normalizeLowerText(value);
|
|
28
|
+
return MOBILE_STRATEGIES.includes(normalized) ? normalized : normalizeLowerText(fallback);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function normalizeMobileAssetMode(value = "", { fallback = "bundled" } = {}) {
|
|
32
|
+
const normalized = normalizeLowerText(value);
|
|
33
|
+
if (!normalized) {
|
|
34
|
+
return normalizeLowerText(fallback, {
|
|
35
|
+
fallback: "bundled"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (!MOBILE_ASSET_MODES.includes(normalized)) {
|
|
39
|
+
throw new TypeError('config.mobile.assetMode must be "bundled" or "dev_server".');
|
|
40
|
+
}
|
|
41
|
+
return normalized;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizeMobileCallbackPath(value = "", { fallback = "/auth/login" } = {}) {
|
|
45
|
+
const normalized = normalizeText(value, {
|
|
46
|
+
fallback
|
|
47
|
+
});
|
|
48
|
+
if (!normalized) {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return normalized.startsWith("/") ? normalized : `/${normalized}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function normalizeMobileConfig(source = {}) {
|
|
56
|
+
const mobile = normalizeObject(source);
|
|
57
|
+
const auth = normalizeObject(mobile.auth);
|
|
58
|
+
const android = normalizeObject(mobile.android);
|
|
59
|
+
|
|
60
|
+
return Object.freeze({
|
|
61
|
+
enabled: hasValue(mobile.enabled) ? normalizeBoolean(mobile.enabled) : false,
|
|
62
|
+
strategy: normalizeMobileStrategy(mobile.strategy),
|
|
63
|
+
appId: normalizeText(mobile.appId),
|
|
64
|
+
appName: normalizeText(mobile.appName),
|
|
65
|
+
assetMode: normalizeMobileAssetMode(mobile.assetMode),
|
|
66
|
+
devServerUrl: normalizeText(mobile.devServerUrl),
|
|
67
|
+
apiBaseUrl: normalizeText(mobile.apiBaseUrl),
|
|
68
|
+
auth: Object.freeze({
|
|
69
|
+
callbackPath: normalizeMobileCallbackPath(auth.callbackPath, {
|
|
70
|
+
fallback: DEFAULT_MOBILE_AUTH_CONFIG.callbackPath
|
|
71
|
+
}),
|
|
72
|
+
customScheme: normalizeLowerText(auth.customScheme),
|
|
73
|
+
appLinkDomains: Object.freeze([
|
|
74
|
+
...new Set(
|
|
75
|
+
normalizeUniqueTextList(auth.appLinkDomains, {
|
|
76
|
+
acceptSingle: true
|
|
77
|
+
}).map((entry) => normalizeLowerText(entry))
|
|
78
|
+
)
|
|
79
|
+
])
|
|
80
|
+
}),
|
|
81
|
+
android: Object.freeze({
|
|
82
|
+
packageName: normalizeText(android.packageName),
|
|
83
|
+
minSdk: normalizePositiveInteger(android.minSdk, {
|
|
84
|
+
fallback: DEFAULT_MOBILE_ANDROID_CONFIG.minSdk
|
|
85
|
+
}),
|
|
86
|
+
targetSdk: normalizePositiveInteger(android.targetSdk, {
|
|
87
|
+
fallback: DEFAULT_MOBILE_ANDROID_CONFIG.targetSdk
|
|
88
|
+
}),
|
|
89
|
+
versionCode: normalizePositiveInteger(android.versionCode, {
|
|
90
|
+
fallback: DEFAULT_MOBILE_ANDROID_CONFIG.versionCode
|
|
91
|
+
}),
|
|
92
|
+
versionName: normalizeText(android.versionName, {
|
|
93
|
+
fallback: DEFAULT_MOBILE_ANDROID_CONFIG.versionName
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { normalizeMobileCallbackPath, normalizeMobileConfig };
|