@antelopejs/dms-frontend 0.10.0 → 0.10.1

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 (74) hide show
  1. package/README.md +34 -11
  2. package/dist/commands/build-action.d.ts +3 -0
  3. package/dist/commands/build-action.js +74 -6
  4. package/dist/commands/build.js +7 -0
  5. package/dist/commands/clean-action.js +1 -1
  6. package/dist/commands/clean.js +1 -1
  7. package/dist/commands/dev-action.js +2 -2
  8. package/dist/commands/dev.js +1 -1
  9. package/dist/config.js +1 -0
  10. package/dist/derived-outputs.d.ts +1 -0
  11. package/dist/derived-outputs.js +3 -1
  12. package/dist/help.js +1 -1
  13. package/dist/internal/prepared-workspace.d.ts +12 -0
  14. package/dist/internal/prepared-workspace.js +74 -0
  15. package/dist/layer-watch.js +1 -1
  16. package/dist/locale-files.d.ts +4 -2
  17. package/dist/locale-files.js +11 -9
  18. package/dist/manifest.js +2 -1
  19. package/dist/ports.d.ts +3 -1
  20. package/dist/ports.js +1 -1
  21. package/dist/project-modules.d.ts +5 -1
  22. package/dist/project-modules.js +10 -7
  23. package/dist/verify-source-runner.js +2 -44
  24. package/dist/verify-source-workspace.d.ts +2 -0
  25. package/dist/verify-source-workspace.js +111 -0
  26. package/dist/workspace-setup.d.ts +1 -0
  27. package/dist/workspace-setup.js +3 -2
  28. package/package.json +7 -5
  29. package/templates/vue/backend-boundary.mjs +132 -0
  30. package/templates/vue/client-chunking.mjs +2 -0
  31. package/templates/vue/entry-weight.mjs +9 -5
  32. package/templates/vue/frontend-build.ts +4 -3
  33. package/templates/vue/head-order.mjs +3 -2
  34. package/templates/vue/icon-api.mjs +2 -0
  35. package/templates/vue/server/auth/backend.mjs +4 -4
  36. package/templates/vue/server/auth/establish-endpoints.mjs +2 -2
  37. package/templates/vue/server/auth/session.mjs +5 -2
  38. package/templates/vue/server/auth-declarations.mjs +46 -0
  39. package/templates/vue/server/auth-hooks.mjs +41 -3
  40. package/templates/vue/server/backend-proxies.mjs +16 -12
  41. package/templates/vue/server/backend-response.mjs +3 -3
  42. package/templates/vue/server/cli-report.mjs +22 -1
  43. package/templates/vue/server/client-error.mjs +5 -0
  44. package/templates/vue/server/content.mjs +24 -11
  45. package/templates/vue/server/email-bundle-watch.mjs +9 -3
  46. package/templates/vue/server/email.mjs +5 -3
  47. package/templates/vue/server/generated-files.mjs +16 -6
  48. package/templates/vue/server/icons.mjs +15 -11
  49. package/templates/vue/server/in-place-render.mjs +3 -3
  50. package/templates/vue/server/inertia.mjs +17 -3
  51. package/templates/vue/server/module-event.mjs +28 -16
  52. package/templates/vue/server/module-route-types.mjs +2 -2
  53. package/templates/vue/server/module-routes.mjs +24 -76
  54. package/templates/vue/server/module-server.mjs +27 -17
  55. package/templates/vue/server/module-testing.mjs +23 -8
  56. package/templates/vue/server/page-props.mjs +6 -5
  57. package/templates/vue/server/page-redirects.mjs +1 -1
  58. package/templates/vue/server/path-patterns.mjs +22 -11
  59. package/templates/vue/server/proxy-headers.mjs +1 -1
  60. package/templates/vue/server/proxy-redirects.mjs +1 -0
  61. package/templates/vue/server/proxy-request.mjs +2 -1
  62. package/templates/vue/server/proxy-transfers.mjs +17 -11
  63. package/templates/vue/server/public-endpoints.mjs +12 -16
  64. package/templates/vue/server/request-failure.mjs +1 -1
  65. package/templates/vue/server/request-routing.mjs +6 -1
  66. package/templates/vue/server/request-target.mjs +22 -9
  67. package/templates/vue/server/route-rules.mjs +12 -6
  68. package/templates/vue/server/static-files.mjs +12 -7
  69. package/templates/vue/server/vite-errors.mjs +13 -2
  70. package/templates/vue/server/web-body.mjs +2 -1
  71. package/templates/vue/server-module.ts +2 -1
  72. package/templates/vue/server.mjs +41 -20
  73. package/templates/vue/ui-inertia-page.mjs +1 -1
  74. package/templates/vue/vite.config.ts +9 -0
@@ -17,6 +17,7 @@ import { handleClientError } from "./server/client-error.mjs";
17
17
  import {
18
18
  reportListenError,
19
19
  reportReady,
20
+ reportRouting,
20
21
  reportStartError,
21
22
  } from "./server/cli-report.mjs";
22
23
  import { publicBuildFile } from "./server/built-files.mjs";
@@ -64,7 +65,10 @@ import * as icons from "./server/icons.mjs";
64
65
  import { ssrRenderer } from "./server/ssr-module.mjs";
65
66
  import * as requestFailure from "./server/request-failure.mjs";
66
67
  import { proxy } from "./server/proxy-request.mjs";
67
- import { refuseForeignTarget } from "./server/request-target.mjs";
68
+ import {
69
+ hasOriginFormTarget,
70
+ isServerRequest,
71
+ } from "./server/request-target.mjs";
68
72
  import { SERVER_OPTIONS } from "./server/proxy-transfers.mjs";
69
73
  import {
70
74
  createInertiaPage,
@@ -74,10 +78,12 @@ import {
74
78
  isFrontendVisit,
75
79
  redirectFrontendVisit,
76
80
  handleAssetVersionMismatch,
81
+ isSsrPage,
77
82
  } from "./server/inertia.mjs";
78
83
  export * from "./server/inertia.mjs";
79
84
 
80
85
  /** @typedef {import("node:http").IncomingMessage} IncomingMessage */
86
+ /** @typedef {import("./server/request-target.mjs").ServerRequest} ServerRequest */
81
87
  /** @typedef {import("node:http").ServerResponse} ServerResponse */
82
88
  /** @typedef {import("vite").ViteDevServer} ViteDevServer */
83
89
  /** @typedef {import("./server/inertia.mjs").InertiaPage} InertiaPage */
@@ -86,6 +92,12 @@ export * from "./server/inertia.mjs";
86
92
  const INERTIA_HEADER = "x-inertia";
87
93
  const JSON_TYPE = "application/json";
88
94
  const PROJECT_ROOT = fileURLToPath(new URL(".", import.meta.url));
95
+ /**
96
+ * @type {[
97
+ * (pathname: string) => boolean,
98
+ * (request: ServerRequest, response: ServerResponse) => Promise<void>
99
+ * ][]}
100
+ */
89
101
  const LOCAL_ROUTES = [[icons.isIconRequest, icons.handleIcons]];
90
102
  const CLIENT_ROOT = join(PROJECT_ROOT, "dist/client");
91
103
  const SOURCE_TEMPLATE_PATH = join(PROJECT_ROOT, "index.html");
@@ -97,7 +109,9 @@ const SOURCE_TEMPLATE_PATH = join(PROJECT_ROOT, "index.html");
97
109
  * NODE_ENV=production throws a ReferenceError on the first render.
98
110
  */
99
111
  function defineVueCompileFlags() {
100
- globalThis.__VUE_PROD_DEVTOOLS__ ??= false;
112
+ /** @type {typeof globalThis & { __VUE_PROD_DEVTOOLS__?: boolean }} */
113
+ const vueGlobals = globalThis;
114
+ vueGlobals.__VUE_PROD_DEVTOOLS__ ??= false;
101
115
  }
102
116
 
103
117
  defineVueCompileFlags();
@@ -145,7 +159,7 @@ async function currentAuth() {
145
159
  }
146
160
 
147
161
  /**
148
- * @param {IncomingMessage} request
162
+ * @param {ServerRequest} request
149
163
  * @returns {import("./server/page-props.mjs").PageBackend}
150
164
  */
151
165
  function pageBackend(request) {
@@ -159,7 +173,7 @@ function pageBackend(request) {
159
173
  }
160
174
 
161
175
  /**
162
- * @param {IncomingMessage} request
176
+ * @param {ServerRequest} request
163
177
  * @param {import("./server/page-props.mjs").PageAuth} auth
164
178
  */
165
179
  function pageProps(request, auth) {
@@ -207,6 +221,8 @@ function clientRenderedShell(page) {
207
221
  async function serverRendered(page, serverFetch, requestCookies, devServer) {
208
222
  try {
209
223
  const renderer = await ssrRenderer(devServer);
224
+ if (!isSsrPage(page))
225
+ throw new TypeError("The page has no path and no page props to render");
210
226
  return await renderer.renderDmsPage(page, serverFetch, requestCookies);
211
227
  } catch (error) {
212
228
  console.error(
@@ -222,7 +238,7 @@ async function serverRendered(page, serverFetch, requestCookies, devServer) {
222
238
  * renders the page from the shell instead.
223
239
  *
224
240
  * @param {InertiaPage} page
225
- * @param {string | undefined} requestUrl
241
+ * @param {string} requestUrl
226
242
  * @param {ServerReads} serverFetch
227
243
  * @param {string | undefined} requestCookies
228
244
  * @param {{ ssr?: false }} [options]
@@ -271,7 +287,7 @@ export async function renderHtml(
271
287
 
272
288
  /**
273
289
  * @param {InertiaPage} page
274
- * @param {IncomingMessage} request
290
+ * @param {ServerRequest} request
275
291
  * @param {Pick<import("./server/route-rules.mjs").RouteRule, "ssr">} [rule]
276
292
  * @param {ServerReads} [reads]
277
293
  */
@@ -287,7 +303,7 @@ function renderRequestHtml(page, request, rule = {}, reads) {
287
303
  * see `renderInPlace`.
288
304
  *
289
305
  * @param {InertiaPage} page
290
- * @param {IncomingMessage} request
306
+ * @param {ServerRequest} request
291
307
  * @param {import("./server/route-rules.mjs").MergedRouteRule} rule
292
308
  * @param {import("./server/page-props.mjs").PageAuth} auth
293
309
  */
@@ -304,7 +320,7 @@ function renderDocument(page, request, rule, auth) {
304
320
 
305
321
  /**
306
322
  * @param {unknown} error
307
- * @param {IncomingMessage} request
323
+ * @param {ServerRequest} request
308
324
  * @param {ServerResponse} response
309
325
  */
310
326
  async function writeBackendError(error, request, response) {
@@ -422,7 +438,7 @@ function writeNotFound(response) {
422
438
  }
423
439
 
424
440
  /**
425
- * @param {IncomingMessage} request
441
+ * @param {ServerRequest} request
426
442
  * @param {ServerResponse} response
427
443
  */
428
444
  export async function handleRequest(request, response) {
@@ -488,6 +504,8 @@ export async function handleRequest(request, response) {
488
504
  */
489
505
  async function writeRequestFailure(error, request, response) {
490
506
  if (requestFailure.isResponseGone(error, response)) return;
507
+ if (!isServerRequest(request))
508
+ return requestFailure.abandonResponse(error, response);
491
509
  if (
492
510
  error instanceof BackendResponseError &&
493
511
  error.status === 401 &&
@@ -513,7 +531,10 @@ async function writeRequestFailure(error, request, response) {
513
531
  */
514
532
  export async function handleRequestSafely(request, response) {
515
533
  try {
516
- if (refuseForeignTarget(request, response)) return;
534
+ if (!hasOriginFormTarget(request)) {
535
+ requestFailure.writeBadRequest(response);
536
+ return;
537
+ }
517
538
  await handleRequest(request, response);
518
539
  } catch (error) {
519
540
  await writeRequestFailure(error, request, response).catch(
@@ -528,26 +549,26 @@ if (
528
549
  import.meta.url === new URL(`file://${process.argv[1]}`).href
529
550
  ) {
530
551
  frontendHttpServer = createServer(SERVER_OPTIONS, handleRequestSafely);
531
- frontendHttpServer.on("clientError", (error, socket) =>
552
+ const server = frontendHttpServer;
553
+ server.on("clientError", (error, socket) =>
532
554
  handleClientError(error, socket, maxHeaderSize),
533
555
  );
534
556
  const port = Number(process.env.PORT ?? 3001);
535
557
  const host = listenHost();
536
558
  /** @param {NodeJS.ErrnoException} error */
537
559
  const onListenError = (error) => void reportListenError(error, host, port);
538
- frontendHttpServer.once("error", onListenError);
539
- frontendHttpServer.listen(port, host, () => {
540
- frontendHttpServer.off("error", onListenError);
560
+ server.once("error", onListenError);
561
+ server.listen(port, host, () => {
562
+ server.off("error", onListenError);
541
563
  void announceReady();
542
564
  });
543
565
  }
544
566
 
545
567
  /** Prints who owns which paths, once the server is up. */
546
- async function reportRouting() {
568
+ async function reportServerModules() {
547
569
  try {
548
570
  const modules = await loadServerModules(await developmentServer());
549
- for (const line of routingReport(modules.proxies, modules.routes.length))
550
- console.log(line);
571
+ reportRouting(routingReport(modules.proxies, modules.routes.length));
551
572
  } catch (error) {
552
573
  console.error("DMS server modules failed to load", error);
553
574
  }
@@ -568,11 +589,11 @@ async function announceReady() {
568
589
  await reportStartError(error);
569
590
  return;
570
591
  }
571
- const listening = frontendHttpServer.address();
572
- if (listening === null || isString(listening))
592
+ const listening = frontendHttpServer?.address();
593
+ if (!listening || isString(listening))
573
594
  throw new TypeError("The DMS server is not listening on a port");
574
595
  const { address, port } = listening;
575
596
  await reportReady(address, port);
576
- await reportRouting();
597
+ await reportServerModules();
577
598
  if (process.env.DMS_DEV === "true") watchEmailBundle();
578
599
  }
@@ -13,7 +13,7 @@ const ANY_INERTIA_PAGE_IMPORT =
13
13
  * name: string,
14
14
  * enforce: "pre",
15
15
  * transform: (
16
- * this: import("vite").Rollup.TransformPluginContext,
16
+ * this: Pick<import("vite").Rollup.TransformPluginContext, "error">,
17
17
  * code: string,
18
18
  * id: string,
19
19
  * ) => { code: string, map: null } | null,
@@ -11,6 +11,7 @@ import {
11
11
  } from "vite";
12
12
  import { clientCodeSplitting, onBuildLog } from "./client-chunking.mjs";
13
13
  import { recordEntryWeight } from "./entry-weight.mjs";
14
+ import { rejectBackendSources } from "./backend-boundary.mjs";
14
15
  import { rejectServerSourcesInClient } from "./client-server-guard.mjs";
15
16
  import { uiInertiaPage } from "./ui-inertia-page.mjs";
16
17
  import { uiKbd } from "./ui-kbd.mjs";
@@ -29,6 +30,7 @@ interface FrontendModuleRegistryEntry {
29
30
  id: string;
30
31
  name?: string;
31
32
  packageName?: string;
33
+ backendPackage?: string;
32
34
  root: string;
33
35
  priority: number;
34
36
  }
@@ -45,6 +47,9 @@ const registry = JSON.parse(
45
47
  readFileSync(registryPath, "utf8"),
46
48
  ) as FrontendModuleRegistry;
47
49
  const moduleRoots = registry.modules.map((module) => module.root);
50
+ const backendPackages = registry.modules.flatMap((module) =>
51
+ module.backendPackage === undefined ? [] : [module.backendPackage],
52
+ );
48
53
  const frontendSourceRoots = moduleRoots.flatMap((root) => {
49
54
  const layersRoot = resolve(root, "layers");
50
55
  if (!existsSync(layersRoot)) return [root];
@@ -175,6 +180,9 @@ export default defineConfig({
175
180
  // Fails a client build that imports a dms.server.ts or a file under a
176
181
  // module's server/ directory, however it is imported.
177
182
  rejectServerSourcesInClient(moduleRoots),
183
+ // Fails a build, a worker build or a dev request that resolves a file
184
+ // under the src of the package that ships a module.
185
+ rejectBackendSources(backendPackages),
178
186
  // What each module adds to the client entry, which `ajs dms build` reports.
179
187
  recordEntryWeight(registry.modules),
180
188
  {
@@ -267,6 +275,7 @@ export default defineConfig({
267
275
  paintBeforeHydrate(),
268
276
  ...vitePlugins(registry.modules, frontendBuilds),
269
277
  ],
278
+ worker: { plugins: () => vitePlugins(registry.modules, frontendBuilds) },
270
279
  resolve: {
271
280
  // `@iconify/vue` keeps its API providers in module state: `main.ts` and
272
281
  // Nuxt UI's `Icon` must share one copy for the same-origin provider to apply.