@jskit-ai/kernel 0.1.4
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/README.md +24 -0
- package/_testable/index.js +4 -0
- package/client/appConfig.js +33 -0
- package/client/componentInteraction.js +51 -0
- package/client/componentInteraction.test.js +111 -0
- package/client/descriptorSections.js +75 -0
- package/client/index.d.ts +70 -0
- package/client/index.js +3 -0
- package/client/logging.js +38 -0
- package/client/moduleBootstrap.js +670 -0
- package/client/moduleBootstrap.test.js +403 -0
- package/client/shellBootstrap.js +233 -0
- package/client/shellBootstrap.test.js +185 -0
- package/client/shellRouting.js +321 -0
- package/client/shellRouting.test.js +113 -0
- package/client/vite/clientBootstrapPlugin.js +259 -0
- package/client/vite/clientBootstrapPlugin.test.js +563 -0
- package/client/vite/index.js +3 -0
- package/internal/node/fileSystem.js +21 -0
- package/internal/node/installedPackageDescriptor.js +104 -0
- package/package.json +43 -0
- package/server/actions/ActionRuntimeServiceProvider.js +309 -0
- package/server/actions/ActionRuntimeServiceProvider.test.js +551 -0
- package/server/actions/index.js +8 -0
- package/server/container/ContainerCoreServiceProvider.js +27 -0
- package/server/container/index.js +10 -0
- package/server/exportPolicy.test.js +68 -0
- package/server/http/HttpFastifyServiceProvider.js +25 -0
- package/server/http/_testable/index.js +2 -0
- package/server/http/index.js +1 -0
- package/server/http/lib/controller.js +183 -0
- package/server/http/lib/controller.test.js +143 -0
- package/server/http/lib/errors.js +12 -0
- package/server/http/lib/httpRuntime.js +82 -0
- package/server/http/lib/index.js +18 -0
- package/server/http/lib/kernel.js +15 -0
- package/server/http/lib/kernel.test.js +880 -0
- package/server/http/lib/middlewareRuntime.js +149 -0
- package/server/http/lib/requestActionExecutor.js +258 -0
- package/server/http/lib/requestScope.js +59 -0
- package/server/http/lib/routeRegistration.js +165 -0
- package/server/http/lib/routeSupport.js +45 -0
- package/server/http/lib/routeValidator.js +469 -0
- package/server/http/lib/routeValidator.test.js +474 -0
- package/server/http/lib/router.js +206 -0
- package/server/kernel/KernelCoreServiceProvider.js +27 -0
- package/server/kernel/index.js +10 -0
- package/server/platform/PlatformServerRuntimeServiceProvider.js +30 -0
- package/server/platform/index.js +5 -0
- package/server/platform/providerRuntime/descriptorCatalog.js +170 -0
- package/server/platform/providerRuntime/helpers.js +45 -0
- package/server/platform/providerRuntime/lockfile.js +27 -0
- package/server/platform/providerRuntime/providerLoader.js +283 -0
- package/server/platform/providerRuntime.js +142 -0
- package/server/platform/providerRuntime.test.js +217 -0
- package/server/platform/runtime.js +40 -0
- package/server/platform/surfaceRuntime.js +150 -0
- package/server/platform/surfaceRuntime.test.js +136 -0
- package/server/registries/actionSurfaceSourceRegistry.js +150 -0
- package/server/registries/bootstrapPayloadContributorRegistry.js +41 -0
- package/server/registries/domainEventListenerRegistry.js +61 -0
- package/server/registries/index.js +36 -0
- package/server/registries/primitives.js +63 -0
- package/server/registries/routeVisibilityResolverRegistry.js +87 -0
- package/server/registries/serviceRegistrationRegistry.js +431 -0
- package/server/runtime/ServerRuntimeCoreServiceProvider.js +65 -0
- package/server/runtime/ServerRuntimeCoreServiceProvider.test.js +53 -0
- package/server/runtime/apiRoutePolicyParity.test.js +109 -0
- package/server/runtime/apiRouteRegistration.js +65 -0
- package/server/runtime/bootBootstrapRoutes.js +46 -0
- package/server/runtime/bootBootstrapRoutes.test.js +79 -0
- package/server/runtime/bootstrapContributors.test.js +114 -0
- package/server/runtime/canonicalJson.js +74 -0
- package/server/runtime/composition.js +142 -0
- package/server/runtime/domainEvents.test.js +114 -0
- package/server/runtime/domainRules.js +50 -0
- package/server/runtime/domainRules.test.js +87 -0
- package/server/runtime/entityChangeEvents.js +182 -0
- package/server/runtime/entityChangeEvents.test.js +211 -0
- package/server/runtime/errors.js +68 -0
- package/server/runtime/errors.test.js +73 -0
- package/server/runtime/fastifyBootstrap.js +372 -0
- package/server/runtime/fastifyBootstrap.test.js +194 -0
- package/server/runtime/index.js +6 -0
- package/server/runtime/integers.js +13 -0
- package/server/runtime/moduleConfig.js +269 -0
- package/server/runtime/moduleConfig.test.js +141 -0
- package/server/runtime/pagination.js +13 -0
- package/server/runtime/realtimeNormalization.js +21 -0
- package/server/runtime/requestUrl.js +38 -0
- package/server/runtime/routeUtils.js +20 -0
- package/server/runtime/runtimeAssembly.js +113 -0
- package/server/runtime/runtimeKernel.js +55 -0
- package/server/runtime/securityAudit.js +269 -0
- package/server/runtime/securityAudit.test.js +41 -0
- package/server/runtime/serviceAuthorization.js +113 -0
- package/server/runtime/serviceAuthorization.test.js +100 -0
- package/server/runtime/serviceRegistration.test.js +197 -0
- package/server/support/SupportCoreServiceProvider.js +25 -0
- package/server/support/appConfig.js +37 -0
- package/server/support/appConfig.test.js +94 -0
- package/server/support/defaultMissingHandler.js +7 -0
- package/server/support/index.js +2 -0
- package/server/support/routePolicyConfig.js +51 -0
- package/server/support/symlinkSafeRequire.js +78 -0
- package/server/support/symlinkSafeRequire.test.js +27 -0
- package/server/surface/SurfaceRoutingServiceProvider.js +27 -0
- package/server/surface/index.js +19 -0
- package/shared/actions/actionContributorHelpers.js +34 -0
- package/shared/actions/actionContributorHelpers.test.js +16 -0
- package/shared/actions/actionDefinitions.js +488 -0
- package/shared/actions/actionDefinitions.test.js +212 -0
- package/shared/actions/audit.js +7 -0
- package/shared/actions/executionContext.js +97 -0
- package/shared/actions/executionContext.test.js +66 -0
- package/shared/actions/idempotency.js +62 -0
- package/shared/actions/index.js +2 -0
- package/shared/actions/observability.js +10 -0
- package/shared/actions/pipeline.js +287 -0
- package/shared/actions/policies.js +342 -0
- package/shared/actions/policies.test.js +233 -0
- package/shared/actions/registry.js +187 -0
- package/shared/actions/registry.test.js +381 -0
- package/shared/actions/requestMeta.js +36 -0
- package/shared/actions/textNormalization.js +3 -0
- package/shared/actions/withActionDefaults.js +34 -0
- package/shared/index.js +2 -0
- package/shared/runtime/application.js +323 -0
- package/shared/runtime/container.js +261 -0
- package/shared/runtime/containerErrors.js +22 -0
- package/shared/runtime/index.js +18 -0
- package/shared/runtime/kernelErrors.js +20 -0
- package/shared/runtime/serviceProvider.js +13 -0
- package/shared/support/formatDateTime.js +10 -0
- package/shared/support/formatDateTime.test.js +15 -0
- package/shared/support/index.js +14 -0
- package/shared/support/linkPath.js +67 -0
- package/shared/support/linkPath.test.js +35 -0
- package/shared/support/normalize.js +116 -0
- package/shared/support/normalize.test.js +48 -0
- package/shared/support/packageDescriptor.test.js +121 -0
- package/shared/support/permissions.js +50 -0
- package/shared/support/pickOwnProperties.js +17 -0
- package/shared/support/pickOwnProperties.test.js +25 -0
- package/shared/support/policies.js +11 -0
- package/shared/support/queryPath.js +33 -0
- package/shared/support/queryPath.test.js +19 -0
- package/shared/support/queryResilience.js +34 -0
- package/shared/support/queryResilience.test.js +33 -0
- package/shared/support/returnToPath.js +153 -0
- package/shared/support/returnToPath.test.js +123 -0
- package/shared/support/sorting.js +15 -0
- package/shared/support/tokens.js +23 -0
- package/shared/support/tokens.test.js +17 -0
- package/shared/support/visibility.js +56 -0
- package/shared/support/visibility.test.js +45 -0
- package/shared/surface/apiPaths.js +84 -0
- package/shared/surface/escapeRegExp.js +5 -0
- package/shared/surface/index.js +6 -0
- package/shared/surface/paths.js +273 -0
- package/shared/surface/registry.js +135 -0
- package/shared/surface/registry.test.js +44 -0
- package/shared/surface/runtime.js +357 -0
- package/shared/surface/runtime.test.js +319 -0
- package/shared/validators/createCursorListValidator.js +42 -0
- package/shared/validators/createCursorListValidator.test.js +34 -0
- package/shared/validators/cursorPaginationQueryValidator.js +31 -0
- package/shared/validators/cursorPaginationQueryValidator.test.js +21 -0
- package/shared/validators/index.js +12 -0
- package/shared/validators/inputNormalization.js +13 -0
- package/shared/validators/mergeObjectSchemas.js +31 -0
- package/shared/validators/mergeObjectSchemas.test.js +67 -0
- package/shared/validators/mergeValidators.js +89 -0
- package/shared/validators/mergeValidators.test.js +116 -0
- package/shared/validators/nestValidator.js +53 -0
- package/shared/validators/nestValidator.test.js +60 -0
- package/shared/validators/recordIdParamsValidator.js +36 -0
- package/shared/validators/recordIdParamsValidator.test.js +20 -0
- package/shared/validators/resourceRequiredMetadata.js +41 -0
- package/shared/validators/resourceRequiredMetadata.test.js +49 -0
- package/test/barrelExposure.test.js +106 -0
- package/test/dynamicImportPolicy.test.js +89 -0
- package/test/exportsContract.test.js +168 -0
- package/test/routeInputContractGuard.test.js +78 -0
- package/test/surfaceIndependence.test.js +109 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createSurfaceRuntime } from "../shared/surface/runtime.js";
|
|
4
|
+
import { bootClientModules } from "./moduleBootstrap.js";
|
|
5
|
+
|
|
6
|
+
function createRouterStub() {
|
|
7
|
+
const routes = [];
|
|
8
|
+
return {
|
|
9
|
+
routes,
|
|
10
|
+
addRoute(route) {
|
|
11
|
+
routes.push(route);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function createSurfaceRuntimeFixture() {
|
|
17
|
+
return createSurfaceRuntime({
|
|
18
|
+
allMode: "all",
|
|
19
|
+
surfaces: {
|
|
20
|
+
app: { id: "app", pagesRoot: "app", enabled: true },
|
|
21
|
+
admin: { id: "admin", pagesRoot: "admin", enabled: true }
|
|
22
|
+
},
|
|
23
|
+
defaultSurfaceId: "app"
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test("bootClientModules registers global routes regardless of surface mode", async () => {
|
|
28
|
+
const router = createRouterStub();
|
|
29
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
30
|
+
|
|
31
|
+
const result = await bootClientModules({
|
|
32
|
+
clientModules: [
|
|
33
|
+
{
|
|
34
|
+
packageId: "@example/auth",
|
|
35
|
+
descriptorUiRoutes: [
|
|
36
|
+
{
|
|
37
|
+
id: "auth.login",
|
|
38
|
+
path: "/auth/login",
|
|
39
|
+
scope: "global",
|
|
40
|
+
autoRegister: false
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
module: {
|
|
44
|
+
clientRoutes: [
|
|
45
|
+
{
|
|
46
|
+
id: "auth.login",
|
|
47
|
+
name: "auth-login",
|
|
48
|
+
path: "/auth/login",
|
|
49
|
+
scope: "global",
|
|
50
|
+
component: {}
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
router,
|
|
57
|
+
surfaceRuntime,
|
|
58
|
+
surfaceMode: "admin",
|
|
59
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
assert.equal(result.routeResults.length, 1);
|
|
63
|
+
assert.equal(result.routeResults[0].declaredCount, 1);
|
|
64
|
+
assert.equal(result.routeResults[0].registeredCount, 1);
|
|
65
|
+
assert.equal(router.routes.length, 1);
|
|
66
|
+
assert.equal(router.routes[0].path, "/auth/login");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("bootClientModules filters surface routes by mode", async () => {
|
|
70
|
+
const router = createRouterStub();
|
|
71
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
72
|
+
|
|
73
|
+
const result = await bootClientModules({
|
|
74
|
+
clientModules: [
|
|
75
|
+
{
|
|
76
|
+
packageId: "@example/admin",
|
|
77
|
+
module: {
|
|
78
|
+
clientRoutes: [
|
|
79
|
+
{
|
|
80
|
+
id: "admin.dashboard",
|
|
81
|
+
name: "admin-dashboard",
|
|
82
|
+
path: "/admin/dashboard",
|
|
83
|
+
scope: "surface",
|
|
84
|
+
component: {}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "app.dashboard",
|
|
88
|
+
name: "app-dashboard",
|
|
89
|
+
path: "/app/dashboard",
|
|
90
|
+
scope: "surface",
|
|
91
|
+
component: {}
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
router,
|
|
98
|
+
surfaceRuntime,
|
|
99
|
+
surfaceMode: "admin",
|
|
100
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
assert.equal(result.routeResults.length, 1);
|
|
104
|
+
assert.equal(result.routeResults[0].declaredCount, 2);
|
|
105
|
+
assert.equal(result.routeResults[0].registeredCount, 1);
|
|
106
|
+
assert.equal(router.routes.length, 1);
|
|
107
|
+
assert.equal(router.routes[0].path, "/admin/dashboard");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("bootClientModules registers descriptor and clientRoutes with providers only", async () => {
|
|
111
|
+
const router = createRouterStub();
|
|
112
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
113
|
+
const events = [];
|
|
114
|
+
const loginComponent = {};
|
|
115
|
+
class ExampleClientProvider {
|
|
116
|
+
static id = "example.client";
|
|
117
|
+
register(app) {
|
|
118
|
+
events.push("register");
|
|
119
|
+
app.instance("example.value", 42);
|
|
120
|
+
}
|
|
121
|
+
boot() {
|
|
122
|
+
events.push("boot");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const result = await bootClientModules({
|
|
127
|
+
clientModules: [
|
|
128
|
+
{
|
|
129
|
+
packageId: "@example/alpha",
|
|
130
|
+
module: {
|
|
131
|
+
clientProviders: [ExampleClientProvider],
|
|
132
|
+
ExampleClientProvider
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
packageId: "@example/zeta",
|
|
137
|
+
descriptorUiRoutes: [
|
|
138
|
+
{
|
|
139
|
+
id: "auth.default-login-2",
|
|
140
|
+
name: "auth-default-login-2",
|
|
141
|
+
path: "/auth/default-login-2",
|
|
142
|
+
scope: "global",
|
|
143
|
+
componentKey: "auth-login",
|
|
144
|
+
autoRegister: true
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: "auth.skipped",
|
|
148
|
+
path: "/auth/skipped",
|
|
149
|
+
scope: "global",
|
|
150
|
+
componentKey: "auth-login",
|
|
151
|
+
autoRegister: false
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "auth.login",
|
|
155
|
+
path: "/auth/login",
|
|
156
|
+
scope: "global",
|
|
157
|
+
autoRegister: false
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: "auth.callback",
|
|
161
|
+
path: "/auth/callback",
|
|
162
|
+
scope: "global",
|
|
163
|
+
autoRegister: false
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
module: {
|
|
167
|
+
routeComponents: {
|
|
168
|
+
"auth-login": loginComponent
|
|
169
|
+
},
|
|
170
|
+
clientRoutes: [
|
|
171
|
+
{
|
|
172
|
+
id: "auth.login",
|
|
173
|
+
name: "auth-login",
|
|
174
|
+
path: "/auth/login",
|
|
175
|
+
scope: "global",
|
|
176
|
+
component: loginComponent
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
router,
|
|
183
|
+
surfaceRuntime,
|
|
184
|
+
surfaceMode: "all",
|
|
185
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
assert.deepEqual(events, ["register", "boot"]);
|
|
189
|
+
assert.equal(result.providerCount, 1);
|
|
190
|
+
assert.equal(result.routeCount, 2);
|
|
191
|
+
assert.equal(router.routes.length, 2);
|
|
192
|
+
assert.equal(router.routes[0].path, "/auth/default-login-2");
|
|
193
|
+
assert.equal(router.routes[0].component, loginComponent);
|
|
194
|
+
assert.equal(router.routes[1].path, "/auth/login");
|
|
195
|
+
assert.equal(router.routes[1].component, loginComponent);
|
|
196
|
+
assert.equal(result.runtimeApp.make("example.value"), 42);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("bootClientModules does not auto-discover providers from module exports", async () => {
|
|
200
|
+
const router = createRouterStub();
|
|
201
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
202
|
+
const events = [];
|
|
203
|
+
|
|
204
|
+
class ExampleClientProvider {
|
|
205
|
+
static id = "example.client";
|
|
206
|
+
register() {
|
|
207
|
+
events.push("register");
|
|
208
|
+
}
|
|
209
|
+
boot() {
|
|
210
|
+
events.push("boot");
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const result = await bootClientModules({
|
|
215
|
+
clientModules: [
|
|
216
|
+
{
|
|
217
|
+
packageId: "@example/no-provider-declaration",
|
|
218
|
+
module: {
|
|
219
|
+
ExampleClientProvider
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
],
|
|
223
|
+
router,
|
|
224
|
+
surfaceRuntime,
|
|
225
|
+
surfaceMode: "all",
|
|
226
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
assert.equal(result.providerCount, 0);
|
|
230
|
+
assert.deepEqual(events, []);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("bootClientModules rejects clientRoutes without components", async () => {
|
|
234
|
+
const router = createRouterStub();
|
|
235
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
236
|
+
|
|
237
|
+
await assert.rejects(
|
|
238
|
+
bootClientModules({
|
|
239
|
+
clientModules: [
|
|
240
|
+
{
|
|
241
|
+
packageId: "@example/missing",
|
|
242
|
+
module: {
|
|
243
|
+
clientRoutes: [
|
|
244
|
+
{
|
|
245
|
+
id: "auth.login",
|
|
246
|
+
path: "/auth/login",
|
|
247
|
+
scope: "global",
|
|
248
|
+
component: null
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
],
|
|
254
|
+
router,
|
|
255
|
+
surfaceRuntime,
|
|
256
|
+
surfaceMode: "all",
|
|
257
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
258
|
+
}),
|
|
259
|
+
/Client route "auth.login" from @example\/missing requires component\./
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test("bootClientModules rejects non-declared global clientRoutes", async () => {
|
|
264
|
+
const router = createRouterStub();
|
|
265
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
266
|
+
const loginComponent = {};
|
|
267
|
+
|
|
268
|
+
await assert.rejects(
|
|
269
|
+
bootClientModules({
|
|
270
|
+
clientModules: [
|
|
271
|
+
{
|
|
272
|
+
packageId: "@example/strict",
|
|
273
|
+
descriptorUiRoutes: [
|
|
274
|
+
{
|
|
275
|
+
id: "auth.default-login-2",
|
|
276
|
+
path: "/auth/default-login-2",
|
|
277
|
+
scope: "global",
|
|
278
|
+
componentKey: "auth-login",
|
|
279
|
+
autoRegister: true
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
module: {
|
|
283
|
+
routeComponents: {
|
|
284
|
+
"auth-login": loginComponent
|
|
285
|
+
},
|
|
286
|
+
clientRoutes: [
|
|
287
|
+
{
|
|
288
|
+
id: "auth.callback",
|
|
289
|
+
name: "auth-callback",
|
|
290
|
+
path: "/auth/callback",
|
|
291
|
+
scope: "global",
|
|
292
|
+
component: loginComponent
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
router,
|
|
299
|
+
surfaceRuntime,
|
|
300
|
+
surfaceMode: "all",
|
|
301
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
302
|
+
}),
|
|
303
|
+
/must be declared in metadata\.ui\.routes/
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("bootClientModules allows non-declared surface clientRoutes", async () => {
|
|
308
|
+
const router = createRouterStub();
|
|
309
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
310
|
+
const dashboardComponent = {};
|
|
311
|
+
|
|
312
|
+
const result = await bootClientModules({
|
|
313
|
+
clientModules: [
|
|
314
|
+
{
|
|
315
|
+
packageId: "@example/surface-programmatic",
|
|
316
|
+
descriptorUiRoutes: [],
|
|
317
|
+
module: {
|
|
318
|
+
clientRoutes: [
|
|
319
|
+
{
|
|
320
|
+
id: "admin.projects",
|
|
321
|
+
name: "admin-projects",
|
|
322
|
+
path: "/admin/projects",
|
|
323
|
+
scope: "surface",
|
|
324
|
+
component: dashboardComponent
|
|
325
|
+
}
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
],
|
|
330
|
+
router,
|
|
331
|
+
surfaceRuntime,
|
|
332
|
+
surfaceMode: "admin",
|
|
333
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
assert.equal(result.routeCount, 1);
|
|
337
|
+
assert.equal(router.routes.length, 1);
|
|
338
|
+
assert.equal(router.routes[0].path, "/admin/projects");
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("bootClientModules loads client providers declared in descriptorClientProviders", async () => {
|
|
342
|
+
const router = createRouterStub();
|
|
343
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
344
|
+
const events = [];
|
|
345
|
+
|
|
346
|
+
await bootClientModules({
|
|
347
|
+
clientModules: [
|
|
348
|
+
{
|
|
349
|
+
packageId: "@example/descriptor-providers",
|
|
350
|
+
descriptorClientProviders: [
|
|
351
|
+
{
|
|
352
|
+
entrypoint: "src/client/providers/ExampleProvider.js",
|
|
353
|
+
export: "ExampleProvider"
|
|
354
|
+
}
|
|
355
|
+
],
|
|
356
|
+
module: {
|
|
357
|
+
ExampleProvider: class {
|
|
358
|
+
static id = "example.descriptor.provider";
|
|
359
|
+
register() {
|
|
360
|
+
events.push("register");
|
|
361
|
+
}
|
|
362
|
+
boot() {
|
|
363
|
+
events.push("boot");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
],
|
|
369
|
+
router,
|
|
370
|
+
surfaceRuntime,
|
|
371
|
+
surfaceMode: "all",
|
|
372
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
assert.deepEqual(events, ["register", "boot"]);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
test("bootClientModules throws when descriptorClientProviders export is missing", async () => {
|
|
379
|
+
const router = createRouterStub();
|
|
380
|
+
const surfaceRuntime = createSurfaceRuntimeFixture();
|
|
381
|
+
|
|
382
|
+
await assert.rejects(
|
|
383
|
+
bootClientModules({
|
|
384
|
+
clientModules: [
|
|
385
|
+
{
|
|
386
|
+
packageId: "@example/missing-provider-export",
|
|
387
|
+
descriptorClientProviders: [
|
|
388
|
+
{
|
|
389
|
+
entrypoint: "src/client/providers/MissingProvider.js",
|
|
390
|
+
export: "MissingProvider"
|
|
391
|
+
}
|
|
392
|
+
],
|
|
393
|
+
module: {}
|
|
394
|
+
}
|
|
395
|
+
],
|
|
396
|
+
router,
|
|
397
|
+
surfaceRuntime,
|
|
398
|
+
surfaceMode: "all",
|
|
399
|
+
logger: { info() {}, warn() {}, error() {} }
|
|
400
|
+
}),
|
|
401
|
+
/descriptor provider export "MissingProvider" is missing or invalid/
|
|
402
|
+
);
|
|
403
|
+
});
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { buildSurfaceAwareRoutes, createFallbackNotFoundRoute, createShellBeforeEachGuard } from "./shellRouting.js";
|
|
2
|
+
import { isRecord } from "../shared/support/normalize.js";
|
|
3
|
+
import { setClientAppConfig } from "./appConfig.js";
|
|
4
|
+
import { createStructuredLogger, summarizeRouterRoutes } from "./logging.js";
|
|
5
|
+
|
|
6
|
+
function resolveClientBootstrapDebugEnabled({
|
|
7
|
+
env = {},
|
|
8
|
+
debugEnabled = undefined,
|
|
9
|
+
debugEnvKey = "VITE_JSKIT_CLIENT_DEBUG"
|
|
10
|
+
} = {}) {
|
|
11
|
+
if (typeof debugEnabled === "boolean") {
|
|
12
|
+
return debugEnabled;
|
|
13
|
+
}
|
|
14
|
+
if (!isRecord(env)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return String(env[debugEnvKey] || "").trim() === "1";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createClientBootstrapLogger({
|
|
21
|
+
env = {},
|
|
22
|
+
logger = console,
|
|
23
|
+
debugEnabled = undefined,
|
|
24
|
+
debugEnvKey = "VITE_JSKIT_CLIENT_DEBUG"
|
|
25
|
+
} = {}) {
|
|
26
|
+
const baseLogger = createStructuredLogger(logger);
|
|
27
|
+
const isDebugEnabled = resolveClientBootstrapDebugEnabled({
|
|
28
|
+
env,
|
|
29
|
+
debugEnabled,
|
|
30
|
+
debugEnvKey
|
|
31
|
+
});
|
|
32
|
+
return Object.freeze({
|
|
33
|
+
info: baseLogger.info,
|
|
34
|
+
warn: baseLogger.warn,
|
|
35
|
+
error: baseLogger.error,
|
|
36
|
+
debug: isDebugEnabled ? baseLogger.info : () => {},
|
|
37
|
+
isDebugEnabled
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function installAppPlugins(app, appPlugins = []) {
|
|
42
|
+
const plugins = Array.isArray(appPlugins) ? appPlugins : [];
|
|
43
|
+
for (const pluginEntry of plugins) {
|
|
44
|
+
if (!pluginEntry) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(pluginEntry)) {
|
|
48
|
+
const [plugin, ...pluginArgs] = pluginEntry;
|
|
49
|
+
if (!plugin) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
app.use(plugin, ...pluginArgs);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
app.use(pluginEntry);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function createSurfaceShellRouter({
|
|
60
|
+
createRouter,
|
|
61
|
+
history,
|
|
62
|
+
routes = [],
|
|
63
|
+
surfaceRuntime,
|
|
64
|
+
surfaceMode,
|
|
65
|
+
fallbackRoute = null,
|
|
66
|
+
notFoundComponent = null,
|
|
67
|
+
guard = false
|
|
68
|
+
} = {}) {
|
|
69
|
+
if (typeof createRouter !== "function") {
|
|
70
|
+
throw new TypeError("createSurfaceShellRouter requires createRouter().");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const effectiveFallbackRoute = fallbackRoute || (notFoundComponent ? createFallbackNotFoundRoute(notFoundComponent) : null);
|
|
74
|
+
const activeRoutes = buildSurfaceAwareRoutes({
|
|
75
|
+
routes,
|
|
76
|
+
surfaceRuntime,
|
|
77
|
+
surfaceMode,
|
|
78
|
+
fallbackRoute: effectiveFallbackRoute
|
|
79
|
+
});
|
|
80
|
+
const router = createRouter({
|
|
81
|
+
history,
|
|
82
|
+
routes: activeRoutes
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (guard !== false) {
|
|
86
|
+
if (!router || typeof router.beforeEach !== "function") {
|
|
87
|
+
throw new TypeError("createSurfaceShellRouter requires router.beforeEach() when guard is enabled.");
|
|
88
|
+
}
|
|
89
|
+
const beforeEachGuard =
|
|
90
|
+
typeof guard === "function"
|
|
91
|
+
? guard
|
|
92
|
+
: createShellBeforeEachGuard({
|
|
93
|
+
surfaceRuntime,
|
|
94
|
+
...(isRecord(guard) ? guard : {})
|
|
95
|
+
});
|
|
96
|
+
router.beforeEach(beforeEachGuard);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return Object.freeze({
|
|
100
|
+
router,
|
|
101
|
+
activeRoutes: Object.freeze([...activeRoutes]),
|
|
102
|
+
fallbackRoute: effectiveFallbackRoute
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function bootstrapClientShellApp({
|
|
107
|
+
createApp,
|
|
108
|
+
rootComponent,
|
|
109
|
+
appConfig = {},
|
|
110
|
+
appPlugins = [],
|
|
111
|
+
router,
|
|
112
|
+
bootClientModules,
|
|
113
|
+
surfaceRuntime,
|
|
114
|
+
surfaceMode,
|
|
115
|
+
env = {},
|
|
116
|
+
fallbackRoute = null,
|
|
117
|
+
logger = console,
|
|
118
|
+
createBootstrapLogger = null,
|
|
119
|
+
debugEnabled = undefined,
|
|
120
|
+
debugEnvKey = "VITE_JSKIT_CLIENT_DEBUG",
|
|
121
|
+
debugMessage = "Client modules bootstrapped before router install.",
|
|
122
|
+
onAfterModulesBootstrapped = null,
|
|
123
|
+
mountSelector = "#app"
|
|
124
|
+
} = {}) {
|
|
125
|
+
if (typeof createApp !== "function") {
|
|
126
|
+
throw new TypeError("bootstrapClientShellApp requires createApp().");
|
|
127
|
+
}
|
|
128
|
+
if (!router || typeof router.addRoute !== "function") {
|
|
129
|
+
throw new TypeError("bootstrapClientShellApp requires router.addRoute().");
|
|
130
|
+
}
|
|
131
|
+
if (typeof bootClientModules !== "function") {
|
|
132
|
+
throw new TypeError("bootstrapClientShellApp requires bootClientModules().");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const app = createApp(rootComponent);
|
|
136
|
+
if (!app || typeof app.use !== "function" || typeof app.mount !== "function") {
|
|
137
|
+
throw new TypeError("bootstrapClientShellApp requires createApp() to return a Vue app with use() and mount().");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
installAppPlugins(app, appPlugins);
|
|
141
|
+
setClientAppConfig(appConfig);
|
|
142
|
+
|
|
143
|
+
const resolvedLogger =
|
|
144
|
+
typeof createBootstrapLogger === "function"
|
|
145
|
+
? createBootstrapLogger({
|
|
146
|
+
env,
|
|
147
|
+
logger,
|
|
148
|
+
debugEnabled,
|
|
149
|
+
debugEnvKey
|
|
150
|
+
})
|
|
151
|
+
: createClientBootstrapLogger({
|
|
152
|
+
env,
|
|
153
|
+
logger,
|
|
154
|
+
debugEnabled,
|
|
155
|
+
debugEnvKey
|
|
156
|
+
});
|
|
157
|
+
const bootstrapLogger = createStructuredLogger(resolvedLogger);
|
|
158
|
+
|
|
159
|
+
const clientBootstrap = await bootClientModules({
|
|
160
|
+
app,
|
|
161
|
+
router,
|
|
162
|
+
surfaceRuntime,
|
|
163
|
+
surfaceMode,
|
|
164
|
+
env,
|
|
165
|
+
logger: bootstrapLogger
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const isDebugEnabled =
|
|
169
|
+
typeof resolvedLogger?.isDebugEnabled === "boolean"
|
|
170
|
+
? resolvedLogger.isDebugEnabled
|
|
171
|
+
: resolveClientBootstrapDebugEnabled({
|
|
172
|
+
env,
|
|
173
|
+
debugEnabled,
|
|
174
|
+
debugEnvKey
|
|
175
|
+
});
|
|
176
|
+
if (isDebugEnabled) {
|
|
177
|
+
bootstrapLogger.info(
|
|
178
|
+
{
|
|
179
|
+
bootstrap: {
|
|
180
|
+
modules: clientBootstrap?.modules || [],
|
|
181
|
+
providerCount: Number(clientBootstrap?.providerCount || 0),
|
|
182
|
+
routeCount: Number(clientBootstrap?.routeCount || 0)
|
|
183
|
+
},
|
|
184
|
+
routerRoutesBeforeInstall: summarizeRouterRoutes(router),
|
|
185
|
+
currentPath: typeof window !== "undefined" ? String(window.location?.pathname || "") : ""
|
|
186
|
+
},
|
|
187
|
+
String(debugMessage || "").trim() || "Client modules bootstrapped before router install."
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (fallbackRoute?.name && typeof router.addRoute === "function") {
|
|
192
|
+
if (typeof router.hasRoute === "function" && router.hasRoute(fallbackRoute.name) && typeof router.removeRoute === "function") {
|
|
193
|
+
router.removeRoute(fallbackRoute.name);
|
|
194
|
+
}
|
|
195
|
+
router.addRoute(fallbackRoute);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (typeof onAfterModulesBootstrapped === "function") {
|
|
199
|
+
await onAfterModulesBootstrapped(
|
|
200
|
+
Object.freeze({
|
|
201
|
+
app,
|
|
202
|
+
router,
|
|
203
|
+
clientBootstrap,
|
|
204
|
+
surfaceRuntime,
|
|
205
|
+
surfaceMode,
|
|
206
|
+
env: isRecord(env) ? { ...env } : {},
|
|
207
|
+
logger: bootstrapLogger,
|
|
208
|
+
debugEnabled: isDebugEnabled
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
app.use(router);
|
|
214
|
+
if (typeof router.isReady === "function") {
|
|
215
|
+
await router.isReady();
|
|
216
|
+
}
|
|
217
|
+
app.mount(mountSelector);
|
|
218
|
+
|
|
219
|
+
return Object.freeze({
|
|
220
|
+
app,
|
|
221
|
+
router,
|
|
222
|
+
clientBootstrap,
|
|
223
|
+
logger: bootstrapLogger,
|
|
224
|
+
debugEnabled: isDebugEnabled
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export {
|
|
229
|
+
resolveClientBootstrapDebugEnabled,
|
|
230
|
+
createClientBootstrapLogger,
|
|
231
|
+
createSurfaceShellRouter,
|
|
232
|
+
bootstrapClientShellApp
|
|
233
|
+
};
|