@antelopejs/dms-frontend 0.9.2 → 0.10.0
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 +18 -24
- package/dist/commands/build-action.js +3 -2
- package/dist/commands/dev-action.js +2 -1
- package/dist/commands/prepare-action.js +1 -1
- package/dist/commands/start-action.js +3 -24
- package/dist/commands/workspace-task.js +2 -1
- package/dist/config.js +3 -0
- package/dist/derived-outputs.js +3 -3
- package/dist/discovery.js +17 -6
- package/dist/entry-weight.js +15 -0
- package/dist/fs-sync.js +7 -4
- package/dist/index.js +2 -1
- package/dist/internal/built-workspace.d.ts +4 -0
- package/dist/internal/built-workspace.js +43 -0
- package/dist/internal/ensure.d.ts +1 -0
- package/dist/internal/ensure.js +8 -0
- package/dist/internal/locale-catalogs.d.ts +8 -3
- package/dist/internal/locale-catalogs.js +16 -6
- package/dist/internal/manifest-decoder.d.ts +7 -0
- package/dist/internal/manifest-decoder.js +81 -0
- package/dist/internal/own-release.d.ts +5 -0
- package/dist/internal/own-release.js +20 -0
- package/dist/internal/plain-object.d.ts +1 -0
- package/dist/internal/plain-object.js +6 -0
- package/dist/internal/text-list.d.ts +1 -0
- package/dist/internal/text-list.js +10 -0
- package/dist/internal/vite-manifest.d.ts +6 -0
- package/dist/internal/vite-manifest.js +24 -0
- package/dist/layer-watch.js +25 -24
- package/dist/layers.d.ts +1 -1
- package/dist/layers.js +3 -1
- package/dist/locale-files.d.ts +2 -1
- package/dist/locale-files.js +4 -0
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +44 -31
- package/dist/materialize.js +6 -2
- package/dist/module-set.js +2 -1
- package/dist/node-options.d.ts +1 -0
- package/dist/node-options.js +8 -0
- package/dist/output.d.ts +15 -9
- package/dist/output.js +30 -18
- package/dist/private-values.d.ts +1 -1
- package/dist/private-values.js +5 -3
- package/dist/project-modules.js +13 -8
- package/dist/renderer-range.js +5 -3
- package/dist/server-process.js +1 -1
- package/dist/verify-source-build.js +10 -2
- package/dist/verify-source-client-bundle.d.ts +1 -0
- package/dist/verify-source-client-bundle.js +30 -0
- package/dist/verify-source-runner.js +44 -60
- package/dist/verify-source-sources.js +49 -11
- package/dist/workspace-setup.js +1 -1
- package/package.json +6 -4
- package/skills/dms-frontend/SKILL.md +1 -1
- package/templates/vue/app-runtime.ts +90 -16
- package/templates/vue/client-server-guard.mjs +16 -0
- package/templates/vue/compress-assets.mjs +9 -1
- package/templates/vue/entry-weight.mjs +22 -0
- package/templates/vue/frontend-module.ts +1 -0
- package/templates/vue/frontend-runtime/module-registration.ts +2 -2
- package/templates/vue/frontend-runtime/state.ts +2 -2
- package/templates/vue/frontend-runtime/types.ts +8 -2
- package/templates/vue/globals.d.ts +5 -0
- package/templates/vue/head-order.mjs +7 -0
- package/templates/vue/icon-bundle.ts +31 -0
- package/templates/vue/icon-scan.mjs +4 -0
- package/templates/vue/message-subset.ts +65 -0
- package/templates/vue/network-error.ts +4 -0
- package/templates/vue/server/auth/backend.mjs +41 -4
- package/templates/vue/server/auth/client-ip.mjs +52 -4
- package/templates/vue/server/auth/establish-endpoints.mjs +10 -6
- package/templates/vue/server/auth/session.mjs +81 -2
- package/templates/vue/server/auth-hooks.mjs +15 -5
- package/templates/vue/server/backend-proxies.mjs +65 -9
- package/templates/vue/server/backend-request.mjs +61 -0
- package/templates/vue/server/backend-response.mjs +23 -6
- package/templates/vue/server/built-files.mjs +7 -0
- package/templates/vue/server/cli-report.mjs +53 -11
- package/templates/vue/server/client-manifest.mjs +23 -1
- package/templates/vue/server/content.mjs +18 -1
- package/templates/vue/server/dev-private-files.mjs +17 -1
- package/templates/vue/server/dev-styles.mjs +38 -0
- package/templates/vue/server/email.mjs +9 -3
- package/templates/vue/server/favicon.mjs +3 -0
- package/templates/vue/server/generated-files.mjs +211 -0
- package/templates/vue/server/homepage.mjs +21 -9
- package/templates/vue/server/html-tag.mjs +4 -0
- package/templates/vue/server/icons.mjs +80 -7
- package/templates/vue/server/in-place-render.mjs +35 -0
- package/templates/vue/server/inertia.mjs +61 -2
- package/templates/vue/server/module-event.mjs +98 -17
- package/templates/vue/server/module-route-types.mjs +78 -0
- package/templates/vue/server/module-routes.mjs +138 -31
- package/templates/vue/server/module-server.mjs +98 -27
- package/templates/vue/server/module-testing.mjs +14 -5
- package/templates/vue/server/page-props.mjs +92 -2
- package/templates/vue/server/page-redirects.mjs +37 -0
- package/templates/vue/server/path-patterns.mjs +13 -1
- package/templates/vue/server/proxy-compression.mjs +22 -0
- package/templates/vue/server/proxy-headers.mjs +11 -1
- package/templates/vue/server/proxy-redirects.mjs +20 -5
- package/templates/vue/server/proxy-request.mjs +57 -0
- package/templates/vue/server/proxy-transfers.mjs +33 -5
- package/templates/vue/server/public-endpoints.mjs +138 -23
- package/templates/vue/server/public-options.mjs +20 -6
- package/templates/vue/server/request-failure.mjs +23 -0
- package/templates/vue/server/request-routing.mjs +26 -9
- package/templates/vue/server/request-target.mjs +9 -3
- package/templates/vue/server/route-rules.mjs +39 -15
- package/templates/vue/server/ssr-module.mjs +32 -0
- package/templates/vue/server/static-files.mjs +24 -1
- package/templates/vue/server/type-guards.mjs +71 -0
- package/templates/vue/server/vite-errors.mjs +32 -5
- package/templates/vue/server/web-body.mjs +3 -0
- package/templates/vue/server-module.ts +10 -1
- package/templates/vue/server.mjs +132 -148
- package/templates/vue/sfc-global-types.mjs +112 -13
- package/templates/vue/ssr-renderer.ts +12 -3
- package/templates/vue/ui-inertia-page.mjs +16 -1
- package/templates/vue/ui-kbd.mjs +2 -1
- package/templates/vue/ui-lazy-icons.mjs +44 -0
- package/templates/vue/ui-request-state.mjs +2 -1
- package/templates/vue/vite.config.ts +2 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
|
|
3
|
+
/** @typedef {import("../server-module.ts").DmsServerMethod} ServerMethod */
|
|
4
|
+
/**
|
|
5
|
+
* What `registerAuth` declared. The hooks are read as plain functions, as the
|
|
6
|
+
* server calls them.
|
|
7
|
+
*
|
|
8
|
+
* @typedef {object} AuthDeclaration
|
|
9
|
+
* @property {string} [signInPath]
|
|
10
|
+
* @property {readonly string[]} [signInExempt]
|
|
11
|
+
* @property {(event: import("../server-module.ts").DmsServerEvent, session: import("../server-module.ts").DmsSession) => Promise<import("../server-module.ts").DmsSession | undefined>} [refreshSession]
|
|
12
|
+
* @property {(session: import("../server-module.ts").DmsSession) => import("../server-module.ts").DmsPublicSession} [publicSession]
|
|
13
|
+
*/
|
|
14
|
+
/** @typedef {import("../server-module.ts").DmsRouteRule} RouteRule */
|
|
15
|
+
/**
|
|
16
|
+
* A module that has a `dms.server.ts`.
|
|
17
|
+
*
|
|
18
|
+
* @typedef {object} ServerModuleDeclaration
|
|
19
|
+
* @property {string} id
|
|
20
|
+
* @property {number} [priority]
|
|
21
|
+
* @property {import("../server-module.ts").DmsServerSetup} setup
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* One `registerRoute` call.
|
|
25
|
+
*
|
|
26
|
+
* @typedef {object} RouteRegistration
|
|
27
|
+
* @property {ServerMethod | readonly ServerMethod[]} method
|
|
28
|
+
* @property {string} path
|
|
29
|
+
* @property {import("../server-module.ts").DmsServerHandler} handler
|
|
30
|
+
* @property {import("../server-module.ts").DmsServerRouteOptions} [options]
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* What a module's setup declared, by kind, in declaration order.
|
|
34
|
+
*
|
|
35
|
+
* @typedef {object} ModuleDeclared
|
|
36
|
+
* @property {RouteRegistration[]} routes
|
|
37
|
+
* @property {AuthDeclaration[]} auth
|
|
38
|
+
* @property {Readonly<Record<string, RouteRule>>[]} rules
|
|
39
|
+
* @property {{ pattern: string, options?: import("./backend-proxies.mjs").ProxyOptions }[]} proxies
|
|
40
|
+
*/
|
|
41
|
+
/** @typedef {ServerModuleDeclaration & { declared: ModuleDeclared }} DeclaredModule */
|
|
42
|
+
/**
|
|
43
|
+
* A route a module serves, one per method.
|
|
44
|
+
*
|
|
45
|
+
* @typedef {object} ServerRoute
|
|
46
|
+
* @property {string} path The normalized path
|
|
47
|
+
* @property {string} pathIdentity The path with its parameters made anonymous
|
|
48
|
+
* @property {string[]} params The parameter names, in path order
|
|
49
|
+
* @property {RegExp} matcher
|
|
50
|
+
* @property {string} id The serving module
|
|
51
|
+
* @property {number} priority
|
|
52
|
+
* @property {number} order The declaration's rank in its module
|
|
53
|
+
* @property {string} method
|
|
54
|
+
* @property {import("../server-module.ts").DmsServerHandler} handler
|
|
55
|
+
* @property {boolean} sameOrigin
|
|
56
|
+
* @property {number} bodyLimit
|
|
57
|
+
* @property {boolean} overridesBackend
|
|
58
|
+
*/
|
|
59
|
+
/**
|
|
60
|
+
* The auth hooks of the module that provides them.
|
|
61
|
+
*
|
|
62
|
+
* @typedef {object} AuthProvider
|
|
63
|
+
* @property {string} id
|
|
64
|
+
* @property {number} priority
|
|
65
|
+
* @property {string} [signInPath]
|
|
66
|
+
* @property {import("./path-patterns.mjs").CompiledPathPattern[]} [signInExempt]
|
|
67
|
+
* @property {AuthDeclaration["refreshSession"]} refreshSession
|
|
68
|
+
* @property {AuthDeclaration["publicSession"]} publicSession
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* What the modules declared, ready to serve.
|
|
72
|
+
*
|
|
73
|
+
* @typedef {object} ServerDeclarations
|
|
74
|
+
* @property {ServerRoute[]} routes
|
|
75
|
+
* @property {AuthProvider | undefined} auth
|
|
76
|
+
* @property {import("./route-rules.mjs").ResolvedRouteRule[]} rules
|
|
77
|
+
* @property {import("./backend-proxies.mjs").BackendProxy[]} proxies
|
|
78
|
+
*/
|
|
@@ -2,6 +2,21 @@ import { resolveBackendProxies } from "./backend-proxies.mjs";
|
|
|
2
2
|
import { compilePathPattern } from "./path-patterns.mjs";
|
|
3
3
|
import { matchPublicEndpoint } from "./public-endpoints.mjs";
|
|
4
4
|
import { ruleRejection } from "./route-rules.mjs";
|
|
5
|
+
import {
|
|
6
|
+
isBoolean,
|
|
7
|
+
isFunction,
|
|
8
|
+
isNonNullObject,
|
|
9
|
+
isString,
|
|
10
|
+
} from "./type-guards.mjs";
|
|
11
|
+
|
|
12
|
+
/** @typedef {(message: string) => void} Warn */
|
|
13
|
+
/**
|
|
14
|
+
* @import {
|
|
15
|
+
* AuthProvider, DeclaredModule, ModuleDeclared, RouteRegistration,
|
|
16
|
+
* ServerDeclarations, ServerModuleDeclaration, ServerRoute
|
|
17
|
+
* } from "./module-route-types.mjs"
|
|
18
|
+
* @import { PublicEndpoint } from "./public-endpoints.mjs"
|
|
19
|
+
*/
|
|
5
20
|
|
|
6
21
|
const METHODS = new Set([
|
|
7
22
|
"GET",
|
|
@@ -29,6 +44,8 @@ const MODULE_API_PREFIX = /^\/api\/_[A-Za-z0-9-]+(?:\/|$)/;
|
|
|
29
44
|
* Whether `pathname` names one of the files the renderer serves: Vite's URLs,
|
|
30
45
|
* the built assets and the dependencies. No server route is ever there, and a
|
|
31
46
|
* development page requests hundreds of them.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} pathname
|
|
32
49
|
*/
|
|
33
50
|
export function isRendererFilePath(pathname) {
|
|
34
51
|
return ["/@", "/assets/", "/node_modules/"].some((prefix) =>
|
|
@@ -36,20 +53,25 @@ export function isRendererFilePath(pathname) {
|
|
|
36
53
|
);
|
|
37
54
|
}
|
|
38
55
|
|
|
39
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Whether a module route may serve `pathname`: never the renderer's own.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} pathname
|
|
60
|
+
*/
|
|
40
61
|
export function mayHaveModuleRoute(pathname) {
|
|
41
62
|
return !RESERVED_PREFIXES.some(
|
|
42
63
|
(prefix) => pathname === prefix.slice(0, -1) || pathname.startsWith(prefix),
|
|
43
64
|
);
|
|
44
65
|
}
|
|
45
66
|
|
|
67
|
+
/** @param {string} path */
|
|
46
68
|
function normalizedPath(path) {
|
|
47
69
|
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
48
70
|
}
|
|
49
71
|
|
|
72
|
+
/** @param {string} path */
|
|
50
73
|
function pathRejection(path) {
|
|
51
|
-
if (
|
|
52
|
-
return "a path starts with /";
|
|
74
|
+
if (!isString(path) || !path.startsWith("/")) return "a path starts with /";
|
|
53
75
|
const normalized = normalizedPath(path);
|
|
54
76
|
if (!mayHaveModuleRoute(normalized))
|
|
55
77
|
return `${RESERVED_PREFIXES.join(", ")} are the renderer's own paths`;
|
|
@@ -71,14 +93,11 @@ function pathRejection(path) {
|
|
|
71
93
|
return undefined;
|
|
72
94
|
}
|
|
73
95
|
|
|
96
|
+
/** @param {RouteRegistration["options"]} options */
|
|
74
97
|
function optionsRejection(options) {
|
|
75
98
|
if (options === undefined) return undefined;
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
options.sameOrigin !== undefined &&
|
|
80
|
-
typeof options.sameOrigin !== "boolean"
|
|
81
|
-
)
|
|
99
|
+
if (!isNonNullObject(options)) return "its options are not an object";
|
|
100
|
+
if (options.sameOrigin !== undefined && !isBoolean(options.sameOrigin))
|
|
82
101
|
return "sameOrigin is not a boolean";
|
|
83
102
|
if (
|
|
84
103
|
options.bodyLimit !== undefined &&
|
|
@@ -90,11 +109,14 @@ function optionsRejection(options) {
|
|
|
90
109
|
|
|
91
110
|
/**
|
|
92
111
|
* Two declarations of one path whatever their parameters are named share a
|
|
93
|
-
*
|
|
112
|
+
* path identity.
|
|
113
|
+
*
|
|
114
|
+
* @param {string} path
|
|
94
115
|
*/
|
|
95
116
|
function compilePath(path) {
|
|
96
117
|
const normalized = normalizedPath(path);
|
|
97
118
|
const segments = normalized === "/" ? [] : normalized.slice(1).split("/");
|
|
119
|
+
/** @type {string[]} */
|
|
98
120
|
const params = [];
|
|
99
121
|
const pattern = segments
|
|
100
122
|
.map((segment) => {
|
|
@@ -106,7 +128,7 @@ function compilePath(path) {
|
|
|
106
128
|
.join("");
|
|
107
129
|
return {
|
|
108
130
|
path: normalized,
|
|
109
|
-
|
|
131
|
+
pathIdentity: segments
|
|
110
132
|
.map((segment) => (PARAM_SEGMENT.test(segment) ? ":" : segment))
|
|
111
133
|
.join("/"),
|
|
112
134
|
params,
|
|
@@ -114,8 +136,14 @@ function compilePath(path) {
|
|
|
114
136
|
};
|
|
115
137
|
}
|
|
116
138
|
|
|
117
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* What a module's setup declares, by kind, in declaration order.
|
|
141
|
+
*
|
|
142
|
+
* @param {ServerModuleDeclaration["setup"]} setup
|
|
143
|
+
* @returns {ModuleDeclared}
|
|
144
|
+
*/
|
|
118
145
|
function collectDeclarations(setup) {
|
|
146
|
+
/** @type {ModuleDeclared} */
|
|
119
147
|
const declared = { routes: [], auth: [], rules: [], proxies: [] };
|
|
120
148
|
setup({
|
|
121
149
|
registerRoute: (method, path, handler, options) =>
|
|
@@ -128,27 +156,37 @@ function collectDeclarations(setup) {
|
|
|
128
156
|
return declared;
|
|
129
157
|
}
|
|
130
158
|
|
|
159
|
+
/** @param {unknown} method */
|
|
131
160
|
function methodsOf(method) {
|
|
161
|
+
/** @type {readonly unknown[]} */
|
|
132
162
|
const methods = Array.isArray(method) ? method : [method];
|
|
133
163
|
return methods.length && methods.every((name) => METHODS.has(name))
|
|
134
164
|
? methods
|
|
135
165
|
: undefined;
|
|
136
166
|
}
|
|
137
167
|
|
|
168
|
+
/** @param {RouteRegistration} registration */
|
|
138
169
|
function registrationRejection(registration) {
|
|
139
170
|
if (!methodsOf(registration.method))
|
|
140
171
|
return `the method is not one of ${[...METHODS].join(", ")}`;
|
|
141
|
-
if (
|
|
142
|
-
return "its handler is not a function";
|
|
172
|
+
if (!isFunction(registration.handler)) return "its handler is not a function";
|
|
143
173
|
return (
|
|
144
174
|
pathRejection(registration.path) ?? optionsRejection(registration.options)
|
|
145
175
|
);
|
|
146
176
|
}
|
|
147
177
|
|
|
178
|
+
/**
|
|
179
|
+
* @param {RouteRegistration["method"]} method
|
|
180
|
+
* @param {string} path
|
|
181
|
+
*/
|
|
148
182
|
function describeRoute(method, path) {
|
|
149
183
|
return `"${[method].flat().join(", ")} ${path}"`;
|
|
150
184
|
}
|
|
151
185
|
|
|
186
|
+
/**
|
|
187
|
+
* @param {string} id
|
|
188
|
+
* @param {ServerRoute} route
|
|
189
|
+
*/
|
|
152
190
|
function backendShadowWarning(id, route) {
|
|
153
191
|
if (
|
|
154
192
|
!BACKEND_PREFIX.test(route.path) ||
|
|
@@ -163,6 +201,11 @@ function backendShadowWarning(id, route) {
|
|
|
163
201
|
);
|
|
164
202
|
}
|
|
165
203
|
|
|
204
|
+
/**
|
|
205
|
+
* @param {string} id
|
|
206
|
+
* @param {ServerRoute} route
|
|
207
|
+
* @param {PublicEndpoint[]} publicEndpoints
|
|
208
|
+
*/
|
|
166
209
|
function publicEndpointWarning(id, route, publicEndpoints) {
|
|
167
210
|
const sample = route.path.replaceAll(/\/:[^/]+/g, "/x");
|
|
168
211
|
if (!matchPublicEndpoint(route.method, sample, publicEndpoints))
|
|
@@ -173,7 +216,12 @@ function publicEndpointWarning(id, route, publicEndpoints) {
|
|
|
173
216
|
);
|
|
174
217
|
}
|
|
175
218
|
|
|
176
|
-
/**
|
|
219
|
+
/**
|
|
220
|
+
* Runs a module's setup; a setup that throws declares nothing.
|
|
221
|
+
*
|
|
222
|
+
* @param {ServerModuleDeclaration} declaration
|
|
223
|
+
* @param {Warn} warn
|
|
224
|
+
*/
|
|
177
225
|
function declarationsOfModule(declaration, warn) {
|
|
178
226
|
try {
|
|
179
227
|
return collectDeclarations(declaration.setup);
|
|
@@ -185,6 +233,11 @@ function declarationsOfModule(declaration, warn) {
|
|
|
185
233
|
}
|
|
186
234
|
}
|
|
187
235
|
|
|
236
|
+
/**
|
|
237
|
+
* @param {DeclaredModule} module
|
|
238
|
+
* @param {Warn} warn
|
|
239
|
+
* @returns {ServerRoute[]}
|
|
240
|
+
*/
|
|
188
241
|
function routesOfModule(module, warn) {
|
|
189
242
|
const { id, priority = 0 } = module;
|
|
190
243
|
return module.declared.routes.flatMap((registration, order) => {
|
|
@@ -210,6 +263,10 @@ function routesOfModule(module, warn) {
|
|
|
210
263
|
});
|
|
211
264
|
}
|
|
212
265
|
|
|
266
|
+
/**
|
|
267
|
+
* @param {{ id: string, priority?: number }} left
|
|
268
|
+
* @param {{ id: string, priority?: number }} right
|
|
269
|
+
*/
|
|
213
270
|
function byPriority(left, right) {
|
|
214
271
|
return (
|
|
215
272
|
(right.priority ?? 0) - (left.priority ?? 0) ||
|
|
@@ -217,6 +274,10 @@ function byPriority(left, right) {
|
|
|
217
274
|
);
|
|
218
275
|
}
|
|
219
276
|
|
|
277
|
+
/**
|
|
278
|
+
* @param {ServerRoute} kept
|
|
279
|
+
* @param {ServerRoute} shadowed
|
|
280
|
+
*/
|
|
220
281
|
function shadowWarning(kept, shadowed) {
|
|
221
282
|
const settled =
|
|
222
283
|
kept.priority === shadowed.priority
|
|
@@ -228,6 +289,7 @@ function shadowWarning(kept, shadowed) {
|
|
|
228
289
|
);
|
|
229
290
|
}
|
|
230
291
|
|
|
292
|
+
/** @param {ServerRoute} route */
|
|
231
293
|
function parameterCount(route) {
|
|
232
294
|
return route.params.length;
|
|
233
295
|
}
|
|
@@ -235,10 +297,15 @@ function parameterCount(route) {
|
|
|
235
297
|
/**
|
|
236
298
|
* Whether one request path can match both routes: as many segments, and at
|
|
237
299
|
* each position the same literal or a parameter on either side.
|
|
300
|
+
*
|
|
301
|
+
* @param {ServerRoute} left
|
|
302
|
+
* @param {ServerRoute} right
|
|
238
303
|
*/
|
|
239
304
|
function routesOverlap(left, right) {
|
|
240
|
-
const leftSegments =
|
|
241
|
-
|
|
305
|
+
const leftSegments =
|
|
306
|
+
left.pathIdentity === "" ? [] : left.pathIdentity.split("/");
|
|
307
|
+
const rightSegments =
|
|
308
|
+
right.pathIdentity === "" ? [] : right.pathIdentity.split("/");
|
|
242
309
|
return (
|
|
243
310
|
leftSegments.length === rightSegments.length &&
|
|
244
311
|
leftSegments.every(
|
|
@@ -250,7 +317,12 @@ function routesOverlap(left, right) {
|
|
|
250
317
|
);
|
|
251
318
|
}
|
|
252
319
|
|
|
253
|
-
/**
|
|
320
|
+
/**
|
|
321
|
+
* `first` is tried before `second`: it answers what both can match.
|
|
322
|
+
*
|
|
323
|
+
* @param {ServerRoute} first
|
|
324
|
+
* @param {ServerRoute} second
|
|
325
|
+
*/
|
|
254
326
|
function overlapWarning(first, second) {
|
|
255
327
|
const settled =
|
|
256
328
|
parameterCount(first) < parameterCount(second)
|
|
@@ -265,6 +337,7 @@ function overlapWarning(first, second) {
|
|
|
265
337
|
);
|
|
266
338
|
}
|
|
267
339
|
|
|
340
|
+
/** @param {ServerRoute} route */
|
|
268
341
|
function rootParameterWarning(route) {
|
|
269
342
|
return (
|
|
270
343
|
`Frontend module ${route.id} serves ${describeRoute(route.method, route.path)}, whose first ` +
|
|
@@ -276,10 +349,13 @@ function rootParameterWarning(route) {
|
|
|
276
349
|
/**
|
|
277
350
|
* Reports what the order of `routes` settles silently: two modules' routes
|
|
278
351
|
* that can match one request, and a route that catches every first segment.
|
|
352
|
+
*
|
|
353
|
+
* @param {ServerRoute[]} routes
|
|
354
|
+
* @param {Warn} warn
|
|
279
355
|
*/
|
|
280
356
|
function warnOverlaps(routes, warn) {
|
|
281
357
|
for (const [index, route] of routes.entries()) {
|
|
282
|
-
if (route.
|
|
358
|
+
if (route.pathIdentity.startsWith(":")) warn(rootParameterWarning(route));
|
|
283
359
|
for (const later of routes.slice(index + 1))
|
|
284
360
|
if (
|
|
285
361
|
later.method === route.method &&
|
|
@@ -290,11 +366,17 @@ function warnOverlaps(routes, warn) {
|
|
|
290
366
|
}
|
|
291
367
|
}
|
|
292
368
|
|
|
369
|
+
/**
|
|
370
|
+
* @param {DeclaredModule[]} modules
|
|
371
|
+
* @param {Warn} warn
|
|
372
|
+
* @param {PublicEndpoint[]} publicEndpoints
|
|
373
|
+
*/
|
|
293
374
|
function resolveRoutes(modules, warn, publicEndpoints) {
|
|
375
|
+
/** @type {Map<string, ServerRoute>} */
|
|
294
376
|
const kept = new Map();
|
|
295
377
|
for (const module of modules) {
|
|
296
378
|
for (const route of routesOfModule(module, warn)) {
|
|
297
|
-
const key = `${route.method} ${route.
|
|
379
|
+
const key = `${route.method} ${route.pathIdentity}`;
|
|
298
380
|
const current = kept.get(key);
|
|
299
381
|
if (current) {
|
|
300
382
|
warn(shadowWarning(current, route));
|
|
@@ -319,14 +401,15 @@ function resolveRoutes(modules, warn, publicEndpoints) {
|
|
|
319
401
|
|
|
320
402
|
const AUTH_HOOKS = ["refreshSession", "publicSession"];
|
|
321
403
|
|
|
404
|
+
/** @param {unknown} auth */
|
|
322
405
|
function authRejection(auth) {
|
|
323
|
-
if (
|
|
406
|
+
if (!isNonNullObject(auth)) return "it is not an object";
|
|
324
407
|
for (const hook of AUTH_HOOKS)
|
|
325
|
-
if (auth[hook] !== undefined &&
|
|
408
|
+
if (auth[hook] !== undefined && !isFunction(auth[hook]))
|
|
326
409
|
return `${hook} is not a function`;
|
|
327
410
|
if (
|
|
328
411
|
auth.signInPath !== undefined &&
|
|
329
|
-
(
|
|
412
|
+
(!isString(auth.signInPath) ||
|
|
330
413
|
!compilePathPattern(auth.signInPath) ||
|
|
331
414
|
auth.signInPath.includes("*"))
|
|
332
415
|
)
|
|
@@ -345,8 +428,12 @@ function authRejection(auth) {
|
|
|
345
428
|
/**
|
|
346
429
|
* The auth hooks: those of the highest-priority module that registers them.
|
|
347
430
|
* A module registering them twice, or after another one, is reported.
|
|
431
|
+
*
|
|
432
|
+
* @param {DeclaredModule[]} modules
|
|
433
|
+
* @param {Warn} warn
|
|
348
434
|
*/
|
|
349
435
|
function resolveAuth(modules, warn) {
|
|
436
|
+
/** @type {AuthProvider | undefined} */
|
|
350
437
|
let provider;
|
|
351
438
|
for (const module of modules) {
|
|
352
439
|
for (const auth of module.declared.auth) {
|
|
@@ -379,12 +466,16 @@ function resolveAuth(modules, warn) {
|
|
|
379
466
|
/**
|
|
380
467
|
* The route rules: of two declarations of the same pattern, the module of
|
|
381
468
|
* higher priority keeps it, with a warning.
|
|
469
|
+
*
|
|
470
|
+
* @param {DeclaredModule[]} modules
|
|
471
|
+
* @param {Warn} warn
|
|
382
472
|
*/
|
|
383
473
|
function resolveRules(modules, warn) {
|
|
474
|
+
/** @type {Map<string, import("./route-rules.mjs").ResolvedRouteRule>} */
|
|
384
475
|
const kept = new Map();
|
|
385
476
|
for (const module of modules) {
|
|
386
477
|
for (const rules of module.declared.rules) {
|
|
387
|
-
if (
|
|
478
|
+
if (!isNonNullObject(rules)) {
|
|
388
479
|
warn(
|
|
389
480
|
`Frontend module ${module.id} declares route rules that are ignored: they are not an object.`,
|
|
390
481
|
);
|
|
@@ -435,12 +526,13 @@ function resolveRules(modules, warn) {
|
|
|
435
526
|
* request reaches. Pure: the server hands it the declarations it loaded, and
|
|
436
527
|
* `module-event.mjs` runs the handler a request reaches.
|
|
437
528
|
*
|
|
438
|
-
* @param declarations `{ id, priority, setup }` per module with a dms.server.ts
|
|
439
|
-
* @param warn Reports a declaration problem
|
|
440
|
-
* @param publicEndpoints The deployment's public endpoints (#108), to report a
|
|
529
|
+
* @param {readonly ServerModuleDeclaration[]} declarations `{ id, priority, setup }` per module with a dms.server.ts
|
|
530
|
+
* @param {Warn} warn Reports a declaration problem
|
|
531
|
+
* @param {PublicEndpoint[]} [publicEndpoints] The deployment's public endpoints (#108), to report a
|
|
441
532
|
* module route answering one
|
|
442
|
-
* @param manifestProxies `{ module, path, auth? }`, the backend proxies the
|
|
533
|
+
* @param {readonly import("./backend-proxies.mjs").ManifestProxy[]} [manifestProxies] `{ module, path, auth? }`, the backend proxies the
|
|
443
534
|
* backend modules declare in the manifest
|
|
535
|
+
* @returns {ServerDeclarations}
|
|
444
536
|
*/
|
|
445
537
|
export function resolveServerDeclarations(
|
|
446
538
|
declarations,
|
|
@@ -466,7 +558,12 @@ export function resolveServerDeclarations(
|
|
|
466
558
|
};
|
|
467
559
|
}
|
|
468
560
|
|
|
561
|
+
/**
|
|
562
|
+
* @param {ServerRoute} route
|
|
563
|
+
* @param {RegExpExecArray} match
|
|
564
|
+
*/
|
|
469
565
|
function decodedParams(route, match) {
|
|
566
|
+
/** @type {Record<string, string>} */
|
|
470
567
|
const params = {};
|
|
471
568
|
for (const [index, name] of route.params.entries()) {
|
|
472
569
|
try {
|
|
@@ -483,9 +580,9 @@ function decodedParams(route, match) {
|
|
|
483
580
|
*
|
|
484
581
|
* A `HEAD` no route declares is the `GET`'s, without its body.
|
|
485
582
|
*
|
|
486
|
-
* @param routes What `resolveServerDeclarations` returned
|
|
487
|
-
* @param method The request's method
|
|
488
|
-
* @param pathname The request's normalized path, without its query string
|
|
583
|
+
* @param {ServerRoute[]} routes What `resolveServerDeclarations` returned
|
|
584
|
+
* @param {string} method The request's method
|
|
585
|
+
* @param {string} pathname The request's normalized path, without its query string
|
|
489
586
|
*/
|
|
490
587
|
export function matchModuleRoute(routes, method, pathname) {
|
|
491
588
|
const reached = matchMethod(routes, method, pathname);
|
|
@@ -493,6 +590,12 @@ export function matchModuleRoute(routes, method, pathname) {
|
|
|
493
590
|
return matchMethod(routes, "GET", pathname);
|
|
494
591
|
}
|
|
495
592
|
|
|
593
|
+
/**
|
|
594
|
+
* @param {ServerRoute[]} routes
|
|
595
|
+
* @param {string} method
|
|
596
|
+
* @param {string} pathname
|
|
597
|
+
* @returns {{ route: ServerRoute, params: Record<string, string> } | undefined}
|
|
598
|
+
*/
|
|
496
599
|
function matchMethod(routes, method, pathname) {
|
|
497
600
|
for (const route of routes) {
|
|
498
601
|
if (route.method !== method) continue;
|
|
@@ -507,8 +610,12 @@ function matchMethod(routes, method, pathname) {
|
|
|
507
610
|
/**
|
|
508
611
|
* The methods the module routes answer on `pathname`: a path a module route
|
|
509
612
|
* serves is that module's for every method, the others answered `405`.
|
|
613
|
+
*
|
|
614
|
+
* @param {ServerRoute[]} routes
|
|
615
|
+
* @param {string} pathname
|
|
510
616
|
*/
|
|
511
617
|
export function moduleRouteMethods(routes, pathname) {
|
|
618
|
+
/** @type {Set<string>} */
|
|
512
619
|
const methods = new Set();
|
|
513
620
|
for (const route of routes)
|
|
514
621
|
if (route.matcher.test(pathname)) methods.add(route.method);
|