@antelopejs/dms-frontend 0.9.3 → 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.
Files changed (116) hide show
  1. package/README.md +18 -24
  2. package/dist/commands/build-action.js +3 -2
  3. package/dist/commands/dev-action.js +2 -1
  4. package/dist/commands/prepare-action.js +1 -1
  5. package/dist/commands/start-action.js +3 -24
  6. package/dist/commands/workspace-task.js +2 -1
  7. package/dist/derived-outputs.js +3 -3
  8. package/dist/discovery.js +17 -6
  9. package/dist/entry-weight.js +15 -0
  10. package/dist/fs-sync.js +7 -4
  11. package/dist/index.js +2 -1
  12. package/dist/internal/built-workspace.d.ts +4 -0
  13. package/dist/internal/built-workspace.js +43 -0
  14. package/dist/internal/ensure.d.ts +1 -0
  15. package/dist/internal/ensure.js +8 -0
  16. package/dist/internal/locale-catalogs.d.ts +8 -3
  17. package/dist/internal/locale-catalogs.js +16 -6
  18. package/dist/internal/manifest-decoder.d.ts +7 -0
  19. package/dist/internal/manifest-decoder.js +81 -0
  20. package/dist/internal/own-release.d.ts +5 -0
  21. package/dist/internal/own-release.js +20 -0
  22. package/dist/internal/plain-object.d.ts +1 -0
  23. package/dist/internal/plain-object.js +6 -0
  24. package/dist/internal/text-list.d.ts +1 -0
  25. package/dist/internal/text-list.js +10 -0
  26. package/dist/internal/vite-manifest.d.ts +6 -0
  27. package/dist/internal/vite-manifest.js +24 -0
  28. package/dist/layer-watch.js +25 -24
  29. package/dist/layers.d.ts +1 -1
  30. package/dist/layers.js +3 -1
  31. package/dist/locale-files.d.ts +2 -1
  32. package/dist/locale-files.js +4 -0
  33. package/dist/manifest.d.ts +1 -1
  34. package/dist/manifest.js +44 -31
  35. package/dist/materialize.js +6 -2
  36. package/dist/module-set.js +2 -1
  37. package/dist/node-options.d.ts +1 -0
  38. package/dist/node-options.js +8 -0
  39. package/dist/output.d.ts +15 -9
  40. package/dist/output.js +30 -18
  41. package/dist/private-values.d.ts +1 -1
  42. package/dist/private-values.js +5 -3
  43. package/dist/project-modules.js +13 -8
  44. package/dist/renderer-range.js +5 -3
  45. package/dist/server-process.js +1 -1
  46. package/dist/verify-source-build.js +10 -2
  47. package/dist/verify-source-client-bundle.d.ts +1 -0
  48. package/dist/verify-source-client-bundle.js +30 -0
  49. package/dist/verify-source-runner.js +44 -60
  50. package/dist/verify-source-sources.js +49 -11
  51. package/dist/workspace-setup.js +1 -1
  52. package/package.json +6 -4
  53. package/skills/dms-frontend/SKILL.md +1 -1
  54. package/templates/vue/app-runtime.ts +2 -9
  55. package/templates/vue/client-server-guard.mjs +16 -0
  56. package/templates/vue/compress-assets.mjs +9 -1
  57. package/templates/vue/entry-weight.mjs +22 -0
  58. package/templates/vue/frontend-module.ts +1 -0
  59. package/templates/vue/frontend-runtime/module-registration.ts +2 -2
  60. package/templates/vue/frontend-runtime/state.ts +2 -2
  61. package/templates/vue/frontend-runtime/types.ts +8 -2
  62. package/templates/vue/head-order.mjs +7 -0
  63. package/templates/vue/icon-scan.mjs +4 -0
  64. package/templates/vue/server/auth/backend.mjs +41 -4
  65. package/templates/vue/server/auth/client-ip.mjs +52 -4
  66. package/templates/vue/server/auth/establish-endpoints.mjs +10 -6
  67. package/templates/vue/server/auth/session.mjs +81 -2
  68. package/templates/vue/server/auth-hooks.mjs +15 -5
  69. package/templates/vue/server/backend-proxies.mjs +65 -9
  70. package/templates/vue/server/backend-request.mjs +61 -0
  71. package/templates/vue/server/backend-response.mjs +23 -6
  72. package/templates/vue/server/built-files.mjs +7 -0
  73. package/templates/vue/server/cli-report.mjs +53 -11
  74. package/templates/vue/server/client-manifest.mjs +23 -1
  75. package/templates/vue/server/content.mjs +18 -1
  76. package/templates/vue/server/dev-private-files.mjs +17 -1
  77. package/templates/vue/server/dev-styles.mjs +38 -0
  78. package/templates/vue/server/email.mjs +9 -3
  79. package/templates/vue/server/favicon.mjs +3 -0
  80. package/templates/vue/server/generated-files.mjs +211 -0
  81. package/templates/vue/server/homepage.mjs +21 -9
  82. package/templates/vue/server/html-tag.mjs +4 -0
  83. package/templates/vue/server/icons.mjs +80 -7
  84. package/templates/vue/server/in-place-render.mjs +35 -0
  85. package/templates/vue/server/inertia.mjs +61 -2
  86. package/templates/vue/server/module-event.mjs +98 -17
  87. package/templates/vue/server/module-route-types.mjs +78 -0
  88. package/templates/vue/server/module-routes.mjs +138 -31
  89. package/templates/vue/server/module-server.mjs +98 -27
  90. package/templates/vue/server/module-testing.mjs +14 -5
  91. package/templates/vue/server/page-props.mjs +92 -2
  92. package/templates/vue/server/page-redirects.mjs +37 -0
  93. package/templates/vue/server/path-patterns.mjs +13 -1
  94. package/templates/vue/server/proxy-compression.mjs +22 -0
  95. package/templates/vue/server/proxy-headers.mjs +11 -1
  96. package/templates/vue/server/proxy-redirects.mjs +20 -5
  97. package/templates/vue/server/proxy-request.mjs +57 -0
  98. package/templates/vue/server/proxy-transfers.mjs +33 -5
  99. package/templates/vue/server/public-endpoints.mjs +138 -23
  100. package/templates/vue/server/public-options.mjs +20 -6
  101. package/templates/vue/server/request-failure.mjs +23 -0
  102. package/templates/vue/server/request-routing.mjs +26 -9
  103. package/templates/vue/server/request-target.mjs +9 -3
  104. package/templates/vue/server/route-rules.mjs +39 -15
  105. package/templates/vue/server/ssr-module.mjs +32 -0
  106. package/templates/vue/server/static-files.mjs +24 -1
  107. package/templates/vue/server/type-guards.mjs +71 -0
  108. package/templates/vue/server/vite-errors.mjs +32 -5
  109. package/templates/vue/server/web-body.mjs +3 -0
  110. package/templates/vue/server-module.ts +10 -1
  111. package/templates/vue/server.mjs +132 -148
  112. package/templates/vue/sfc-global-types.mjs +112 -13
  113. package/templates/vue/ssr-renderer.ts +2 -2
  114. package/templates/vue/ui-inertia-page.mjs +16 -1
  115. package/templates/vue/ui-kbd.mjs +2 -1
  116. package/templates/vue/ui-request-state.mjs +2 -1
@@ -5,6 +5,7 @@ import { fileURLToPath } from "node:url";
5
5
  const CLIENT_MANIFEST_PATH = fileURLToPath(
6
6
  new URL("../dist/client/.vite/manifest.json", import.meta.url),
7
7
  );
8
+ /** @type {string | undefined} */
8
9
  let productionAssetVersion;
9
10
 
10
11
  /**
@@ -27,6 +28,10 @@ export function assetVersion() {
27
28
  return productionAssetVersion;
28
29
  }
29
30
 
31
+ /**
32
+ * @param {InertiaPage} page
33
+ * @returns {string}
34
+ */
30
35
  export function inertiaAppHtml(page) {
31
36
  const serialized = JSON.stringify(page).replaceAll("/", "\\/");
32
37
  return `<script data-page="app" type="application/json">${serialized}</script><div id="app"></div>`;
@@ -35,6 +40,32 @@ export function inertiaAppHtml(page) {
35
40
  /** The one Inertia component every DMS page renders through. */
36
41
  export const DMS_PAGE_COMPONENT = "DmsDynamicPage";
37
42
 
43
+ /**
44
+ * The once props a page declares, by key: the prop each stands for, and when
45
+ * the browser's copy expires (`null`: never).
46
+ *
47
+ * @typedef {Record<string, { prop: string, expiresAt: number | null }>} OnceProps
48
+ */
49
+
50
+ /**
51
+ * The Inertia page object of a visit.
52
+ *
53
+ * @typedef {{
54
+ * component: string,
55
+ * props: Record<string, unknown>,
56
+ * url: string | undefined,
57
+ * version: string,
58
+ * onceProps?: OnceProps
59
+ * }} InertiaPage
60
+ */
61
+
62
+ /**
63
+ * @param {string | undefined} url
64
+ * @param {Record<string, unknown> | undefined} props
65
+ * @param {string} [version]
66
+ * @param {OnceProps} [onceProps]
67
+ * @returns {InertiaPage}
68
+ */
38
69
  export function createInertiaPage(
39
70
  url,
40
71
  props,
@@ -51,6 +82,11 @@ export function createInertiaPage(
51
82
  return page;
52
83
  }
53
84
 
85
+ /**
86
+ * @param {import("node:http").IncomingMessage} request
87
+ * @param {string} name
88
+ * @returns {string[]}
89
+ */
54
90
  function headerList(request, name) {
55
91
  return String(request.headers[name] ?? "")
56
92
  .split(",")
@@ -63,6 +99,9 @@ function headerList(request, name) {
63
99
  * A partial reload (`router.reload({ only, except })`) of the page on screen
64
100
  * names them: a nested path selects its top-level prop, which is sent whole,
65
101
  * and only a top-level name excludes one.
102
+ *
103
+ * @param {import("node:http").IncomingMessage} request
104
+ * @returns {{ partial: boolean, wants: (prop: string) => boolean }}
66
105
  */
67
106
  export function requestedProps(request) {
68
107
  const partial =
@@ -81,11 +120,16 @@ export function requestedProps(request) {
81
120
  };
82
121
  }
83
122
 
84
- /** The once props the browser already holds, unexpired, by key. */
123
+ /**
124
+ * The once props the browser already holds, unexpired, by key.
125
+ *
126
+ * @param {import("node:http").IncomingMessage} request
127
+ */
85
128
  export function heldOnceProps(request) {
86
129
  return new Set(headerList(request, "x-inertia-except-once-props"));
87
130
  }
88
131
 
132
+ /** @param {string} [version] */
89
133
  export function inertiaHeaders(version = assetVersion()) {
90
134
  return {
91
135
  "cache-control": PRIVATE_CACHE_CONTROL,
@@ -105,6 +149,11 @@ export function htmlHeaders() {
105
149
  };
106
150
  }
107
151
 
152
+ /**
153
+ * @param {import("node:http").IncomingMessage} request
154
+ * @param {import("node:http").ServerResponse} response
155
+ * @returns {boolean}
156
+ */
108
157
  export function handleAssetVersionMismatch(request, response) {
109
158
  if (
110
159
  !request.headers["x-inertia"] ||
@@ -121,7 +170,12 @@ export function handleAssetVersionMismatch(request, response) {
121
170
  return true;
122
171
  }
123
172
 
124
- /** A page visit: a document or Inertia request, as opposed to an API call. */
173
+ /**
174
+ * A page visit: a document or Inertia request, as opposed to an API call.
175
+ *
176
+ * @param {import("node:http").IncomingMessage} request
177
+ * @returns {boolean}
178
+ */
125
179
  export function isFrontendVisit(request) {
126
180
  if (request.method !== "GET") return false;
127
181
  return (
@@ -130,6 +184,11 @@ export function isFrontendVisit(request) {
130
184
  );
131
185
  }
132
186
 
187
+ /**
188
+ * @param {import("node:http").IncomingMessage} request
189
+ * @param {import("node:http").ServerResponse} response
190
+ * @param {string} location
191
+ */
133
192
  export function redirectFrontendVisit(request, response, location) {
134
193
  const vary = { vary: "X-Inertia" };
135
194
  if (!request.headers["x-inertia"]) {
@@ -23,14 +23,40 @@ import {
23
23
  relayedLocation,
24
24
  } from "./proxy-redirects.mjs";
25
25
  import { backendUrl } from "./request-target.mjs";
26
+ import {
27
+ isFunction,
28
+ isNonNullObject,
29
+ isNumber,
30
+ isString,
31
+ } from "./type-guards.mjs";
26
32
  import { pipeWebBody } from "./web-body.mjs";
27
33
 
34
+ /** @typedef {import("node:http").IncomingMessage} IncomingMessage */
35
+ /** @typedef {import("node:http").ServerResponse} ServerResponse */
36
+ /** @typedef {import("../server-module.ts").DmsServerEvent} ServerEvent */
37
+ /** @typedef {import("../server-module.ts").DmsSession} Session */
38
+ /** @typedef {(session: Session | undefined) => import("../server-module.ts").DmsPublicSession} SessionView */
39
+ /**
40
+ * What an event is made from.
41
+ *
42
+ * @typedef {object} EventContext
43
+ * @property {IncomingMessage} request
44
+ * @property {ServerResponse} response
45
+ * @property {Pick<import("./module-route-types.mjs").ServerRoute, "bodyLimit">} route
46
+ * @property {Readonly<Record<string, string>>} params
47
+ * @property {{ id: string, options?: unknown, privateOptions?: unknown }} module
48
+ * @property {{ authEstablishEndpoints?: readonly string[] }} [app]
49
+ * @property {SessionView} [view] What a session shows a page
50
+ * @property {string} [authOwner] The module that owns sign-in
51
+ */
52
+
28
53
  const SAFE_METHODS = new Set(["GET", "HEAD", "OPTIONS"]);
29
54
  const COOKIE_NAME = /^[A-Za-z0-9_-]{1,64}$/;
30
55
  /** The sealed cookies of the module that owns sign-in: session, accounts, flows. */
31
56
  const RESERVED_COOKIE_PREFIX = "dms_";
32
57
  const BODY_TOO_LARGE = "Request body too large";
33
58
 
59
+ /** @param {IncomingMessage} request */
34
60
  function requestOrigin(request) {
35
61
  const host = request.headers.host;
36
62
  try {
@@ -40,6 +66,7 @@ function requestOrigin(request) {
40
66
  }
41
67
  }
42
68
 
69
+ /** @param {IncomingMessage} request */
43
70
  function requestHeaders(request) {
44
71
  const headers = new Headers();
45
72
  for (const [name, value] of Object.entries(request.headers)) {
@@ -49,12 +76,17 @@ function requestHeaders(request) {
49
76
  return headers;
50
77
  }
51
78
 
52
- /** The request body as a Web stream that errors past `limit` bytes. */
79
+ /**
80
+ * The request body as a Web stream that errors past `limit` bytes.
81
+ *
82
+ * @param {IncomingMessage} request
83
+ * @param {number} limit
84
+ */
53
85
  function limitedBody(request, limit) {
54
86
  let size = 0;
55
87
  return Readable.toWeb(request).pipeThrough(
56
88
  new TransformStream({
57
- transform(chunk, controller) {
89
+ transform(/** @type {Uint8Array} */ chunk, controller) {
58
90
  size += chunk.byteLength;
59
91
  if (size > limit)
60
92
  controller.error(new RequestBodyError(413, BODY_TOO_LARGE));
@@ -64,6 +96,10 @@ function limitedBody(request, limit) {
64
96
  );
65
97
  }
66
98
 
99
+ /**
100
+ * @param {IncomingMessage} request
101
+ * @param {EventContext["route"]} route
102
+ */
67
103
  function webRequest(request, route) {
68
104
  const url = new URL(request.url, requestOrigin(request));
69
105
  const hasBody = !["GET", "HEAD"].includes(request.method);
@@ -78,8 +114,13 @@ function webRequest(request, route) {
78
114
  });
79
115
  }
80
116
 
117
+ /**
118
+ * @param {Request} webRequestValue
119
+ * @returns {Promise<unknown>}
120
+ */
81
121
  async function readJson(webRequestValue) {
82
122
  if (!webRequestValue.body) return {};
123
+ /** @type {Uint8Array[]} */
83
124
  const chunks = [];
84
125
  const reader = webRequestValue.body.getReader();
85
126
  for (;;) {
@@ -95,8 +136,9 @@ async function readJson(webRequestValue) {
95
136
  }
96
137
  }
97
138
 
139
+ /** @param {unknown} name */
98
140
  function checkedCookieName(name) {
99
- if (typeof name !== "string" || !COOKIE_NAME.test(name))
141
+ if (!isString(name) || !COOKIE_NAME.test(name))
100
142
  throw new Error(`Invalid cookie name: ${String(name)}`);
101
143
  if (name === SESSION_COOKIE)
102
144
  throw new Error(
@@ -105,6 +147,12 @@ function checkedCookieName(name) {
105
147
  return name;
106
148
  }
107
149
 
150
+ /**
151
+ * @param {IncomingMessage} request
152
+ * @param {ServerResponse} response
153
+ * @param {SessionView | undefined} view
154
+ * @returns {ServerEvent["session"]}
155
+ */
108
156
  function sessionAccess(request, response, view) {
109
157
  return {
110
158
  read: () => readSession(request),
@@ -124,6 +172,10 @@ function sessionAccess(request, response, view) {
124
172
  * module's are prefixed with its id and a dot, which no name of the owner's
125
173
  * holds, so no module reads or overwrites another's, nor the owner's session
126
174
  * and account cookies.
175
+ *
176
+ * @param {unknown} name
177
+ * @param {string} moduleId
178
+ * @param {string | undefined} authOwner
127
179
  */
128
180
  function moduleCookieName(name, moduleId, authOwner) {
129
181
  const checked = checkedCookieName(name);
@@ -131,15 +183,26 @@ function moduleCookieName(name, moduleId, authOwner) {
131
183
  if (checked.startsWith(RESERVED_COOKIE_PREFIX))
132
184
  throw new Error(
133
185
  `The ${RESERVED_COOKIE_PREFIX}* cookies belong to the module that owns sign-in` +
134
- `${authOwner ? ` (${authOwner})` : ""}: choose another name than ${name}`,
186
+ `${authOwner ? ` (${authOwner})` : ""}: choose another name than ${checked}`,
135
187
  );
136
188
  return `${String(moduleId).replaceAll(/[^A-Za-z0-9_-]/g, "-")}.${checked}`;
137
189
  }
138
190
 
191
+ /**
192
+ * @param {IncomingMessage} request
193
+ * @param {ServerResponse} response
194
+ * @param {string} moduleId
195
+ * @param {string | undefined} authOwner
196
+ * @returns {ServerEvent["cookies"]}
197
+ */
139
198
  function cookieAccess(request, response, moduleId, authOwner) {
140
- const named = (name) => moduleCookieName(name, moduleId, authOwner);
199
+ const named = (/** @type {unknown} */ name) =>
200
+ moduleCookieName(name, moduleId, authOwner);
141
201
  return {
142
- readSealed: (name) => readSealedCookie(request, named(name)),
202
+ readSealed: (name, accepts) => {
203
+ const value = readSealedCookie(request, named(name));
204
+ return value !== undefined && accepts(value) ? value : undefined;
205
+ },
143
206
  writeSealed: (name, value, options = {}) =>
144
207
  writeSealedCookie(
145
208
  response,
@@ -153,6 +216,7 @@ function cookieAccess(request, response, moduleId, authOwner) {
153
216
  };
154
217
  }
155
218
 
219
+ /** @param {unknown} value */
156
220
  function frozenCopy(value) {
157
221
  return Object.freeze(structuredClone(value ?? {}));
158
222
  }
@@ -165,10 +229,11 @@ function frozenCopy(value) {
165
229
  * the defaults every route gets once (same-origin on unsafe methods, a body
166
230
  * limit, `no-store`). See `server-module.ts` for the types a module reads.
167
231
  *
168
- * @param context `{ request, response, route, params, module, app, view,
232
+ * @param {EventContext} context `{ request, response, route, params, module, app, view,
169
233
  * authOwner }`, where `module` is `{ id, options, privateOptions }`, `app`
170
234
  * the deployment's read-only data, `view` what a session shows a page and
171
235
  * `authOwner` the id of the module that owns sign-in
236
+ * @returns {ServerEvent}
172
237
  */
173
238
  export function createServerEvent(context) {
174
239
  const { request, response, route, params } = context;
@@ -182,16 +247,20 @@ export function createServerEvent(context) {
182
247
  context.module.id,
183
248
  context.authOwner,
184
249
  ),
185
- backend: (path, init = {}) => backend(path, request, init),
186
- backendUrl: (path) => backendUrl(path),
250
+ backend: (/** @type {string} */ path, init = {}) =>
251
+ backend(path, request, init),
252
+ backendUrl: (/** @type {string} */ path) => backendUrl(path),
187
253
  clientIp: () => clientIp(request),
188
254
  module: Object.freeze({
189
255
  id: context.module.id,
190
256
  options: frozenCopy(context.module.options),
191
257
  privateOptions: frozenCopy(context.module.privateOptions),
192
258
  }),
193
- renderEmail: (template, props, options = {}) =>
194
- renderEmailTemplate(template, props, options),
259
+ renderEmail: (
260
+ /** @type {string} */ template,
261
+ /** @type {Record<string, unknown>} */ props,
262
+ options = {},
263
+ ) => renderEmailTemplate(template, props, options),
195
264
  app: Object.freeze({
196
265
  authEstablishEndpoints: Object.freeze([
197
266
  ...(context.app?.authEstablishEndpoints ?? []),
@@ -203,19 +272,26 @@ export function createServerEvent(context) {
203
272
  return event;
204
273
  }
205
274
 
275
+ /** @param {unknown} value */
206
276
  function isResponse(value) {
207
277
  return (
208
278
  value instanceof Response ||
209
- (typeof value === "object" &&
210
- value !== null &&
211
- typeof value.status === "number" &&
212
- typeof value.headers?.get === "function" &&
279
+ (isNonNullObject(value) &&
280
+ isNumber(value.status) &&
281
+ isFunction(value.headers?.get) &&
213
282
  "body" in value)
214
283
  );
215
284
  }
216
285
 
286
+ /**
287
+ * @param {any} result What a handler answered: any value, of which only
288
+ * `isResponse` looks
289
+ * @returns {Response}
290
+ */
217
291
  function asResponse(result) {
218
- if (isResponse(result)) return result;
292
+ if (isResponse(result))
293
+ // oxlint-disable-next-line typescript/no-unsafe-return -- `isResponse` also accepts a `Response` of another realm by its members (`status`, `headers.get`, `body`), so it cannot be a `value is Response` predicate without claiming members it does not check.
294
+ return result;
219
295
  if (result === undefined || result === null)
220
296
  return new Response(null, { status: 204 });
221
297
  return Response.json(result);
@@ -227,6 +303,11 @@ function asResponse(result) {
227
303
  * answer the handler relays goes out as the proxy relays one: its `Location`
228
304
  * on the frontend's origin when the frontend proxies its path, no cookie of
229
305
  * another site its fetch reached.
306
+ *
307
+ * @param {IncomingMessage} request
308
+ * @param {ServerResponse} response
309
+ * @param {unknown} result
310
+ * @param {(path: string) => boolean} isProxiedPath
230
311
  */
231
312
  async function writeServerResponse(request, response, result, isProxiedPath) {
232
313
  const answer = asResponse(result);
@@ -261,7 +342,7 @@ async function writeServerResponse(request, response, result, isProxiedPath) {
261
342
  * through reaches the server's error handling with the cookies written so
262
343
  * far.
263
344
  *
264
- * @param context See `createServerEvent`, plus `isProxiedPath(pathname)`:
345
+ * @param {Omit<EventContext, "route"> & { route: import("./module-route-types.mjs").ServerRoute, isProxiedPath: (path: string) => boolean }} context See `createServerEvent`, plus `isProxiedPath(pathname)`:
265
346
  * whether the frontend sends that path to the backend
266
347
  */
267
348
  export async function answerModuleRoute(context) {
@@ -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
+ */