@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.
Files changed (123) 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/config.js +3 -0
  8. package/dist/derived-outputs.js +3 -3
  9. package/dist/discovery.js +17 -6
  10. package/dist/entry-weight.js +15 -0
  11. package/dist/fs-sync.js +7 -4
  12. package/dist/index.js +2 -1
  13. package/dist/internal/built-workspace.d.ts +4 -0
  14. package/dist/internal/built-workspace.js +43 -0
  15. package/dist/internal/ensure.d.ts +1 -0
  16. package/dist/internal/ensure.js +8 -0
  17. package/dist/internal/locale-catalogs.d.ts +8 -3
  18. package/dist/internal/locale-catalogs.js +16 -6
  19. package/dist/internal/manifest-decoder.d.ts +7 -0
  20. package/dist/internal/manifest-decoder.js +81 -0
  21. package/dist/internal/own-release.d.ts +5 -0
  22. package/dist/internal/own-release.js +20 -0
  23. package/dist/internal/plain-object.d.ts +1 -0
  24. package/dist/internal/plain-object.js +6 -0
  25. package/dist/internal/text-list.d.ts +1 -0
  26. package/dist/internal/text-list.js +10 -0
  27. package/dist/internal/vite-manifest.d.ts +6 -0
  28. package/dist/internal/vite-manifest.js +24 -0
  29. package/dist/layer-watch.js +25 -24
  30. package/dist/layers.d.ts +1 -1
  31. package/dist/layers.js +3 -1
  32. package/dist/locale-files.d.ts +2 -1
  33. package/dist/locale-files.js +4 -0
  34. package/dist/manifest.d.ts +1 -1
  35. package/dist/manifest.js +44 -31
  36. package/dist/materialize.js +6 -2
  37. package/dist/module-set.js +2 -1
  38. package/dist/node-options.d.ts +1 -0
  39. package/dist/node-options.js +8 -0
  40. package/dist/output.d.ts +15 -9
  41. package/dist/output.js +30 -18
  42. package/dist/private-values.d.ts +1 -1
  43. package/dist/private-values.js +5 -3
  44. package/dist/project-modules.js +13 -8
  45. package/dist/renderer-range.js +5 -3
  46. package/dist/server-process.js +1 -1
  47. package/dist/verify-source-build.js +10 -2
  48. package/dist/verify-source-client-bundle.d.ts +1 -0
  49. package/dist/verify-source-client-bundle.js +30 -0
  50. package/dist/verify-source-runner.js +44 -60
  51. package/dist/verify-source-sources.js +49 -11
  52. package/dist/workspace-setup.js +1 -1
  53. package/package.json +6 -4
  54. package/skills/dms-frontend/SKILL.md +1 -1
  55. package/templates/vue/app-runtime.ts +90 -16
  56. package/templates/vue/client-server-guard.mjs +16 -0
  57. package/templates/vue/compress-assets.mjs +9 -1
  58. package/templates/vue/entry-weight.mjs +22 -0
  59. package/templates/vue/frontend-module.ts +1 -0
  60. package/templates/vue/frontend-runtime/module-registration.ts +2 -2
  61. package/templates/vue/frontend-runtime/state.ts +2 -2
  62. package/templates/vue/frontend-runtime/types.ts +8 -2
  63. package/templates/vue/globals.d.ts +5 -0
  64. package/templates/vue/head-order.mjs +7 -0
  65. package/templates/vue/icon-bundle.ts +31 -0
  66. package/templates/vue/icon-scan.mjs +4 -0
  67. package/templates/vue/message-subset.ts +65 -0
  68. package/templates/vue/network-error.ts +4 -0
  69. package/templates/vue/server/auth/backend.mjs +41 -4
  70. package/templates/vue/server/auth/client-ip.mjs +52 -4
  71. package/templates/vue/server/auth/establish-endpoints.mjs +10 -6
  72. package/templates/vue/server/auth/session.mjs +81 -2
  73. package/templates/vue/server/auth-hooks.mjs +15 -5
  74. package/templates/vue/server/backend-proxies.mjs +65 -9
  75. package/templates/vue/server/backend-request.mjs +61 -0
  76. package/templates/vue/server/backend-response.mjs +23 -6
  77. package/templates/vue/server/built-files.mjs +7 -0
  78. package/templates/vue/server/cli-report.mjs +53 -11
  79. package/templates/vue/server/client-manifest.mjs +23 -1
  80. package/templates/vue/server/content.mjs +18 -1
  81. package/templates/vue/server/dev-private-files.mjs +17 -1
  82. package/templates/vue/server/dev-styles.mjs +38 -0
  83. package/templates/vue/server/email.mjs +9 -3
  84. package/templates/vue/server/favicon.mjs +3 -0
  85. package/templates/vue/server/generated-files.mjs +211 -0
  86. package/templates/vue/server/homepage.mjs +21 -9
  87. package/templates/vue/server/html-tag.mjs +4 -0
  88. package/templates/vue/server/icons.mjs +80 -7
  89. package/templates/vue/server/in-place-render.mjs +35 -0
  90. package/templates/vue/server/inertia.mjs +61 -2
  91. package/templates/vue/server/module-event.mjs +98 -17
  92. package/templates/vue/server/module-route-types.mjs +78 -0
  93. package/templates/vue/server/module-routes.mjs +138 -31
  94. package/templates/vue/server/module-server.mjs +98 -27
  95. package/templates/vue/server/module-testing.mjs +14 -5
  96. package/templates/vue/server/page-props.mjs +92 -2
  97. package/templates/vue/server/page-redirects.mjs +37 -0
  98. package/templates/vue/server/path-patterns.mjs +13 -1
  99. package/templates/vue/server/proxy-compression.mjs +22 -0
  100. package/templates/vue/server/proxy-headers.mjs +11 -1
  101. package/templates/vue/server/proxy-redirects.mjs +20 -5
  102. package/templates/vue/server/proxy-request.mjs +57 -0
  103. package/templates/vue/server/proxy-transfers.mjs +33 -5
  104. package/templates/vue/server/public-endpoints.mjs +138 -23
  105. package/templates/vue/server/public-options.mjs +20 -6
  106. package/templates/vue/server/request-failure.mjs +23 -0
  107. package/templates/vue/server/request-routing.mjs +26 -9
  108. package/templates/vue/server/request-target.mjs +9 -3
  109. package/templates/vue/server/route-rules.mjs +39 -15
  110. package/templates/vue/server/ssr-module.mjs +32 -0
  111. package/templates/vue/server/static-files.mjs +24 -1
  112. package/templates/vue/server/type-guards.mjs +71 -0
  113. package/templates/vue/server/vite-errors.mjs +32 -5
  114. package/templates/vue/server/web-body.mjs +3 -0
  115. package/templates/vue/server-module.ts +10 -1
  116. package/templates/vue/server.mjs +132 -148
  117. package/templates/vue/sfc-global-types.mjs +112 -13
  118. package/templates/vue/ssr-renderer.ts +12 -3
  119. package/templates/vue/ui-inertia-page.mjs +16 -1
  120. package/templates/vue/ui-kbd.mjs +2 -1
  121. package/templates/vue/ui-lazy-icons.mjs +44 -0
  122. package/templates/vue/ui-request-state.mjs +2 -1
  123. package/templates/vue/vite.config.ts +2 -0
package/README.md CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  <picture>
4
4
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/AntelopeJS/dms/main/packages/dms/frontend-vue/layers/dms-layout/public/images/antelope-logo/dark.svg">
5
- <img alt="Antelope DMS" src="https://raw.githubusercontent.com/AntelopeJS/dms/main/packages/dms/frontend-vue/layers/dms-layout/public/images/antelope-logo/light.svg" height="72">
5
+ <img alt="AntelopeJS DMS" src="https://raw.githubusercontent.com/AntelopeJS/dms/main/packages/dms/frontend-vue/layers/dms-layout/public/images/antelope-logo/light.svg" data-illustration height="72">
6
6
  </picture>
7
7
 
8
- # @antelopejs/dms-frontend
8
+ # `@antelopejs/dms-frontend`
9
9
 
10
- <a href="https://www.npmjs.com/package/@antelopejs/dms-frontend"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/dms-frontend?style=for-the-badge&labelColor=000000&color=000000"></a>
11
- <a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/dms-frontend?style=for-the-badge&labelColor=000000&color=000000"></a>
12
- <a href="https://discord.gg/sjK28QHrA7"><img alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
13
- <a href="https://dms.antelopejs.com/docs/frontend"><img alt="Documentation" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
10
+ <a href="https://www.npmjs.com/package/@antelopejs/dms-frontend"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/dms-frontend?style=for-the-badge&labelColor=000000&color=000000" data-illustration></a>
11
+ <a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/dms-frontend?style=for-the-badge&labelColor=000000&color=000000" data-illustration></a>
12
+ <a href="https://discord.gg/g4pFt6eXqu"><img alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000" data-illustration></a>
13
+ <a href="https://dms.antelopejs.com/docs/frontend"><img alt="Documentation" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000" data-illustration></a>
14
14
 
15
15
  **The frontend of the AntelopeJS DMS: the `ajs dms` CLI, the Vue renderer and the frontend-module SDK.**
16
16
 
@@ -18,19 +18,19 @@
18
18
 
19
19
  </div>
20
20
 
21
- ![The browser talks to the frontend server, which renders pages, answers module routes and proxies declared backend prefixes to the DMS backend; at build time ajs dms fetches the manifest and writes a workspace](./docs/images/architecture.svg)
21
+ ![The browser talks to the frontend server, which renders pages, answers module routes and proxies declared backend prefixes to the DMS backend, while the development and prepare commands fetch the manifest and write a workspace](./docs/images/architecture.svg "illustration")
22
22
 
23
23
  ## What it does
24
24
 
25
- - Asks a DMS backend which frontend modules it loads, materializes them into a generated workspace, builds it, and runs the frontend server.
26
- - Renders the dashboard with Vue 3, Vite, Inertia and server-side rendering.
27
- - Keeps the backend token on the server: the browser only holds a sealed, `HttpOnly` session cookie, and declared backend prefixes are proxied with the session's token.
25
+ - Reads the frontend modules of an AntelopeJS project, materializes them into a generated workspace, builds it, and runs the frontend server.
26
+ - Renders the dashboard with Vue, Vite, Inertia and server-side rendering.
27
+ - Keeps the backend token on the server. The browser only holds a sealed, `HttpOnly` session cookie, and the server adds the session's token to each request it proxies to a declared backend prefix.
28
28
  - Lets a module extend the dashboard with pages, components and plugins (`dms.frontend.ts`), server routes (`dms.server.ts`) and build-time declarations (`dms.frontend.build.ts`).
29
29
  - Serves development with hot reload, and production with pre-compressed assets.
30
30
 
31
31
  ## Install
32
32
 
33
- Add the package next to `@antelopejs/core`; the core `ajs` command runs it as `ajs dms`:
33
+ Add the package next to `@antelopejs/core`. The core `ajs` command runs it as `ajs dms`.
34
34
 
35
35
  ```bash
36
36
  pnpm add -D @antelopejs/core @antelopejs/dms-frontend
@@ -38,20 +38,20 @@ pnpm add -D @antelopejs/core @antelopejs/dms-frontend
38
38
 
39
39
  ## Quick start
40
40
 
41
- In a DMS project started with `ajs project run -w`, serve the dashboard with hot reload:
41
+ In a DMS project started with `ajs project dev -w`, serve the dashboard with hot reload:
42
42
 
43
43
  ```bash
44
44
  pnpm exec ajs dms dev
45
45
  ```
46
46
 
47
- For production, build from the project root, without the backend, then start the frontend server with `DMS_SESSION_SECRET` and the backend's secrets set:
47
+ For production, build from the project root, without the backend. Then start the frontend server with `DMS_SESSION_SECRET` and the backend's secrets set:
48
48
 
49
49
  ```bash
50
50
  pnpm exec ajs dms build
51
51
  pnpm exec ajs dms start -b https://api.example.com -p 3001
52
52
  ```
53
53
 
54
- `ajs dms --help` lists every command, and `ajs dms help environment` every environment variable.
54
+ `ajs dms --help` lists every command, and `ajs dms help environment` lists every environment variable.
55
55
 
56
56
  ## Compatibility
57
57
 
@@ -59,17 +59,11 @@ pnpm exec ajs dms start -b https://api.example.com -p 3001
59
59
 
60
60
  | Package | Supported | Tested with |
61
61
  | ------------------ | ------------- | ----------- |
62
- | `@antelopejs/core` | `>=1.16.0 <2` | `1.16.0` |
62
+ | `@antelopejs/core` | `>=1.16.0 <2` | `1.20.0` |
63
63
 
64
64
  <!-- antelopejs-docs-compat:end -->
65
65
 
66
- | `@antelopejs/dms` | `@antelopejs/dms-frontend` |
67
- | --- | --- |
68
- | 0.9.1 and later | `>=0.6.1 <0.7.0` |
69
- | 0.9.0 | `>=0.6.0 <0.7.0` |
70
- | 0.6.0 – 0.8.3 | 0.5 (exact floor per release in the full table) |
71
-
72
- The 0.6 line needs Node.js 20.19 or later and `@antelopejs/core` `>=1.13.2 <2`. The [compatibility table](https://dms.antelopejs.com/docs/frontend/introduction#compatibility) lists every release.
66
+ Each DMS release declares the renderer releases it runs on in `engines["@antelopejs/dms-frontend"]` of its frontend module's `package.json`. The `ajs dms` CLI refuses to build a module whose range excludes the installed renderer. To find the renderer releases that match a DMS release, read that `engines` range in the installed DMS frontend module, as the [Compatibility](https://dms.antelopejs.com/docs/frontend/introduction#compatibility) section of the introduction explains. The renderer needs the `@antelopejs/core` range in the table above, and the `engines` field of its `package.json` sets the Node.js versions it runs on.
73
67
 
74
68
  ## Documentation
75
69
 
@@ -90,12 +84,12 @@ Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a pull request.
90
84
  ```bash
91
85
  pnpm install
92
86
  pnpm build
93
- pnpm lint # oxlint, oxfmt, interface ranges and the docs reference check
87
+ pnpm lint # oxlint, interface ranges, the docs reference check and the source checks
94
88
  pnpm typecheck
95
89
  pnpm test
96
90
  ```
97
91
 
98
- `pnpm docs:reference` regenerates the environment-variable table of `docs/4.configuration.md` from the list `ajs dms help environment` prints; `pnpm lint` fails when the table is stale.
92
+ `pnpm docs:reference` regenerates the environment-variable table of `docs/4.configuration.md` from the list `ajs dms help environment` prints. `pnpm lint` fails when the table is stale.
99
93
 
100
94
  ## License
101
95
 
@@ -12,6 +12,7 @@ const output_1 = require("../output");
12
12
  const vite_output_1 = require("../vite-output");
13
13
  const entry_weight_1 = require("../entry-weight");
14
14
  const workspace_task_1 = require("./workspace-task");
15
+ const node_options_1 = require("../node-options");
15
16
  exports.DEFAULT_WORKSPACE_DIR = ".dms-frontend";
16
17
  function productionWorkspace(options) {
17
18
  return options.workspace ?? (0, node_path_1.join)(options.project, exports.DEFAULT_WORKSPACE_DIR);
@@ -87,7 +88,7 @@ async function runBuildStep(step, context) {
87
88
  });
88
89
  }
89
90
  catch (error) {
90
- (0, output_1.endInterruptedTask)(task, error, step.stopped);
91
+ (0, output_1.endInterruptedTask)(task, error instanceof common_1.CancelledError ? error : undefined, step.stopped);
91
92
  throw error;
92
93
  }
93
94
  if (result.code !== 0) {
@@ -130,7 +131,7 @@ async function buildProduction(options, startedAt) {
130
131
  nameFile: (0, child_output_1.createFileNamer)(layers),
131
132
  env: {
132
133
  ...process.env,
133
- NODE_OPTIONS: "--max-old-space-size=4096",
134
+ NODE_OPTIONS: (0, node_options_1.serverNodeOptions)(process.env.NODE_OPTIONS),
134
135
  NODE_PATH: (0, node_path_1.join)(workspaceDir, "node_modules"),
135
136
  [vite_output_1.VITE_LOG_LEVEL_VARIABLE]: (0, vite_output_1.viteLogLevel)(isVerbose),
136
137
  },
@@ -14,6 +14,7 @@ const manifest_1 = require("../manifest");
14
14
  const module_set_1 = require("../module-set");
15
15
  const project_modules_1 = require("../project-modules");
16
16
  const workspace_task_1 = require("./workspace-task");
17
+ const node_options_1 = require("../node-options");
17
18
  const BASE_ENVIRONMENT = "default";
18
19
  function clientHost() {
19
20
  const host = process.env.HOST?.trim();
@@ -175,7 +176,7 @@ function runDevServer(session, setup, stopSignal) {
175
176
  DMS_BOOTSTRAP_SECRET: session.bootstrapSecret,
176
177
  DMS_SESSION_SECRET: session.sessionSecret,
177
178
  ...secrets.env,
178
- NODE_OPTIONS: "--max-old-space-size=4096",
179
+ NODE_OPTIONS: (0, node_options_1.serverNodeOptions)(process.env.NODE_OPTIONS),
179
180
  NODE_PATH: nodeModulesDir,
180
181
  },
181
182
  onReady: (address) => {
@@ -44,7 +44,7 @@ async function runPrepare(options) {
44
44
  catch (err) {
45
45
  if (err instanceof common_1.CancelledError || strict)
46
46
  throw err;
47
- const [title, ...details] = (0, output_1.failureDetails)(err, ui);
47
+ const [title, ...details] = (0, output_1.failureDetails)((0, output_1.classifyFailure)(err), ui);
48
48
  const outcome = isSkip(err) ? "Skipped prepare" : "Prepare failed";
49
49
  ui.message("warn", `${outcome}: ${title}`, {
50
50
  details: [...details, NOT_GENERATED, STRICT_HINT],
@@ -11,22 +11,13 @@ const server_process_1 = require("../server-process");
11
11
  const update_check_1 = require("../update-check");
12
12
  const module_set_1 = require("../module-set");
13
13
  const project_modules_1 = require("../project-modules");
14
- const config_1 = require("../config");
14
+ const built_workspace_1 = require("../internal/built-workspace");
15
15
  const manifest_secrets_1 = require("../manifest-secrets");
16
16
  const private_values_1 = require("../private-values");
17
17
  const build_action_1 = require("./build-action");
18
18
  const PUBLIC_OPTIONS_VARIABLE = "DMS_PUBLIC_OPTIONS";
19
- function builtPrivateOptions(workspaceDir) {
20
- try {
21
- const { modules } = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(workspaceDir, config_1.SERVER_OPTIONS_FILE), "utf8"));
22
- return modules ?? {};
23
- }
24
- catch {
25
- return {};
26
- }
27
- }
28
19
  function reportUnfilledPrivateValues(workspaceDir) {
29
- const unfilled = (0, private_values_1.unfilledPrivateValues)(builtPrivateOptions(workspaceDir), (0, private_values_1.parsePrivateOptions)(process.env[private_values_1.PRIVATE_OPTIONS_VARIABLE]), Object.values(manifest_secrets_1.MANIFEST_SECRET_ENV));
20
+ const unfilled = (0, private_values_1.unfilledPrivateValues)((0, built_workspace_1.readBuiltPrivateOptions)(workspaceDir), (0, private_values_1.parsePrivateOptions)(process.env[private_values_1.PRIVATE_OPTIONS_VARIABLE]), Object.values(manifest_secrets_1.MANIFEST_SECRET_ENV));
30
21
  const ui = (0, cli_1.getProcessUi)();
31
22
  unfilled.forEach(({ module, path }, index) => {
32
23
  const isLast = index === unfilled.length - 1;
@@ -61,18 +52,6 @@ function publicOptionsById(modules) {
61
52
  ];
62
53
  }));
63
54
  }
64
- function builtModules(workspaceDir) {
65
- try {
66
- const { modules } = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(workspaceDir, "generated-frontend-modules.json"), "utf8"));
67
- return (modules ?? []).map((module) => ({
68
- name: module.name ?? module.id,
69
- version: module.version,
70
- }));
71
- }
72
- catch {
73
- return [];
74
- }
75
- }
76
55
  function reportModuleSetDrift(built, modules) {
77
56
  const builtNames = new Set(built.map(({ name }) => name));
78
57
  const currentNames = new Set(modules.map(({ layer }) => layer.name ?? layer.path));
@@ -145,7 +124,7 @@ async function runStart(options) {
145
124
  projectDir: options.project,
146
125
  environment: options.env,
147
126
  });
148
- const built = builtModules(workspaceDir);
127
+ const built = (0, built_workspace_1.readBuiltModules)(workspaceDir);
149
128
  reportModuleSetDrift(built, modules);
150
129
  const secrets = (0, common_1.resolveManifestSecrets)({ published: {}, conflicts: [] });
151
130
  (0, common_1.reportManifestSecrets)(secrets, (count) => `Set ${count === 1 ? "it" : "them"} in the server's environment, with the value${count === 1 ? "" : "s"} the backend uses`);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setUpWorkspace = setUpWorkspace;
4
4
  const cli_1 = require("@antelopejs/core/cli");
5
+ const cancellation_1 = require("../cancellation");
5
6
  const common_1 = require("../common");
6
7
  const output_1 = require("../output");
7
8
  async function setUpWorkspace(options) {
@@ -20,7 +21,7 @@ async function setUpWorkspace(options) {
20
21
  return result;
21
22
  }
22
23
  catch (error) {
23
- (0, output_1.endInterruptedTask)(task, error, "Workspace setup stopped");
24
+ (0, output_1.endInterruptedTask)(task, error instanceof cancellation_1.CancelledError ? error : undefined, "Workspace setup stopped");
24
25
  throw error;
25
26
  }
26
27
  }
package/dist/config.js CHANGED
@@ -50,6 +50,7 @@ exports.TEMPLATE_FILES = [
50
50
  ["index.html", "index.html"],
51
51
  ["main.ts", "main.ts"],
52
52
  ["app-runtime.ts", "app-runtime.ts"],
53
+ ["message-subset.ts", "message-subset.ts"],
53
54
  ["network-error.ts", "network-error.ts"],
54
55
  ["ui-app-config.ts", "ui-app-config.ts"],
55
56
  ["layer-app-config.ts", "layer-app-config.ts"],
@@ -60,6 +61,7 @@ exports.TEMPLATE_FILES = [
60
61
  ["frontend-build-loader.ts", "frontend-build-loader.ts"],
61
62
  ["server-module.ts", "server-module.ts"],
62
63
  ["icon-hydration.ts", "icon-hydration.ts"],
64
+ ["icon-bundle.ts", "icon-bundle.ts"],
63
65
  ["globals.d.ts", "globals.d.ts"],
64
66
  ["compress-assets.mjs", "compress-assets.mjs"],
65
67
  ["head-order.mjs", "head-order.mjs"],
@@ -72,6 +74,7 @@ exports.TEMPLATE_FILES = [
72
74
  ["icon-api.mjs", "icon-api.mjs"],
73
75
  ["icon-scan.mjs", "icon-scan.mjs"],
74
76
  ["ui-kbd.mjs", "ui-kbd.mjs"],
77
+ ["ui-lazy-icons.mjs", "ui-lazy-icons.mjs"],
75
78
  ["email-renderer.ts", "email-renderer.ts"],
76
79
  ["email-runtime.ts", "email-runtime.ts"],
77
80
  ["email-locales.ts", "email-locales.ts"],
@@ -140,16 +140,16 @@ function discoverAssets(registry, directory, extensions) {
140
140
  const LOCALE_DIRECTORY = "i18n/locales";
141
141
  function readLocaleMessages(assets, registry) {
142
142
  const roots = new Map(registry.modules.map((module) => [module.id, module.root]));
143
- const messages = {};
143
+ const messages = new Map();
144
144
  for (const asset of assets) {
145
145
  const locale = asset.relativePath.match(/(?:^|[/-])([a-z]{2})-[A-Z]{2}\.json$/)?.[1];
146
146
  const root = roots.get(asset.moduleId);
147
147
  if (!locale || !root)
148
148
  continue;
149
149
  const value = (0, locale_files_1.readLocaleFile)((0, node_path_1.join)(root, asset.relativePath));
150
- messages[locale] = (0, locale_catalogs_1.mergeLocaleMessages)(value, messages[locale] ?? {});
150
+ messages.set(locale, (0, locale_catalogs_1.mergeLocaleMessages)(value, messages.get(locale) ?? {}));
151
151
  }
152
- return messages;
152
+ return Object.fromEntries(messages);
153
153
  }
154
154
  function affectsLocaleMessages(relativePath) {
155
155
  return (0, asset_roots_1.affectsAssetDirectory)(LOCALE_DIRECTORY, relativePath);
package/dist/discovery.js CHANGED
@@ -10,6 +10,7 @@ const node_fs_1 = require("node:fs");
10
10
  const node_path_1 = require("node:path");
11
11
  const output_1 = require("./output");
12
12
  const guards_1 = require("./internal/guards");
13
+ const plain_object_1 = require("./internal/plain-object");
13
14
  exports.DEV_REGISTRY_RELATIVE_PATH = (0, node_path_1.join)(".antelope", "dev.json");
14
15
  function isPidAlive(pid) {
15
16
  if (!Number.isInteger(pid) || pid <= 0)
@@ -22,13 +23,23 @@ function isPidAlive(pid) {
22
23
  return err?.code === "EPERM";
23
24
  }
24
25
  }
26
+ function isEndpoint(value) {
27
+ return ((0, plain_object_1.isPlainObject)(value) &&
28
+ (0, guards_1.isText)(value.protocol) &&
29
+ (0, guards_1.isText)(value.host) &&
30
+ (0, guards_1.isNumber)(value.port));
31
+ }
32
+ function isServer(value) {
33
+ return ((0, plain_object_1.isPlainObject)(value) &&
34
+ Array.isArray(value.endpoints) &&
35
+ value.endpoints.every(isEndpoint));
36
+ }
25
37
  function isDevRegistry(value) {
26
- return ((0, guards_1.isObjectLike)(value) &&
27
- "pid" in value &&
28
- typeof value.pid === "number" &&
29
- "servers" in value &&
30
- typeof value.servers === "object" &&
31
- value.servers !== null);
38
+ return ((0, plain_object_1.isPlainObject)(value) &&
39
+ (0, guards_1.isNumber)(value.pid) &&
40
+ (value.startedAt === undefined || (0, guards_1.isText)(value.startedAt)) &&
41
+ (0, plain_object_1.isPlainObject)(value.servers) &&
42
+ Object.values(value.servers).every(isServer));
32
43
  }
33
44
  function parseRegistry(file) {
34
45
  try {
@@ -10,6 +10,8 @@ const node_fs_1 = require("node:fs");
10
10
  const node_path_1 = require("node:path");
11
11
  const node_zlib_1 = require("node:zlib");
12
12
  const cli_1 = require("@antelopejs/core/cli");
13
+ const guards_1 = require("./internal/guards");
14
+ const plain_object_1 = require("./internal/plain-object");
13
15
  const output_1 = require("./output");
14
16
  exports.ENTRY_WEIGHT_VARIABLE = "DMS_ENTRY_WEIGHT_WARNING";
15
17
  exports.DEFAULT_ENTRY_WEIGHT_WARNING_KB = 50;
@@ -18,6 +20,14 @@ const SHARED_OWNER = "shared";
18
20
  const TRANSLATIONS_OWNER = "translations";
19
21
  const NON_MODULE_OWNERS = new Set([SHARED_OWNER, TRANSLATIONS_OWNER]);
20
22
  const BYTES_PER_KB = 1024;
23
+ function isRecordedEntryWeight(value) {
24
+ return ((0, plain_object_1.isPlainObject)(value) &&
25
+ Array.isArray(value.files) &&
26
+ value.files.every(guards_1.isText) &&
27
+ (0, guards_1.isNumber)(value.bytes) &&
28
+ (0, plain_object_1.isPlainObject)(value.owners) &&
29
+ Object.values(value.owners).every(guards_1.isNumber));
30
+ }
21
31
  function brotliSize(file) {
22
32
  const compressed = `${file}.br`;
23
33
  if ((0, node_fs_1.existsSync)(compressed))
@@ -31,6 +41,11 @@ function readEntryWeight(workspaceDir) {
31
41
  if (!(0, node_fs_1.existsSync)(path))
32
42
  return undefined;
33
43
  const recorded = JSON.parse((0, node_fs_1.readFileSync)(path, "utf8"));
44
+ if (!isRecordedEntryWeight(recorded))
45
+ throw new cli_1.CliError({
46
+ title: "The client build recorded an entry weight this CLI cannot read",
47
+ fixes: ["Build again"],
48
+ });
34
49
  const brotli = recorded.files.reduce((sum, file) => sum + brotliSize((0, node_path_1.join)(workspaceDir, "dist", "client", file)), 0);
35
50
  const ratio = recorded.bytes ? brotli / recorded.bytes : 0;
36
51
  const shares = Object.entries(recorded.owners)
package/dist/fs-sync.js CHANGED
@@ -18,6 +18,7 @@ const node_fs_1 = require("node:fs");
18
18
  const node_path_1 = require("node:path");
19
19
  const ignore_1 = __importDefault(require("ignore"));
20
20
  const config_1 = require("./config");
21
+ const plain_object_1 = require("./internal/plain-object");
21
22
  function stripExtendedLengthPrefix(p) {
22
23
  return p.replace(/^\\\\\?\\/, "");
23
24
  }
@@ -32,10 +33,12 @@ function isBlocklistedCopyPath(src, srcPath) {
32
33
  }
33
34
  function sanitizedPackageContent(raw) {
34
35
  const pkg = JSON.parse(raw);
35
- delete pkg.devDependencies;
36
- if (pkg.scripts) {
37
- for (const name of config_1.PNPM_LIFECYCLE_SCRIPTS) {
38
- delete pkg.scripts[name];
36
+ if ((0, plain_object_1.isPlainObject)(pkg)) {
37
+ delete pkg.devDependencies;
38
+ if ((0, plain_object_1.isPlainObject)(pkg.scripts)) {
39
+ for (const name of config_1.PNPM_LIFECYCLE_SCRIPTS) {
40
+ delete pkg.scripts[name];
41
+ }
39
42
  }
40
43
  }
41
44
  return `${JSON.stringify(pkg, null, 2)}\n`;
package/dist/index.js CHANGED
@@ -12,10 +12,11 @@ const start_1 = require("./commands/start");
12
12
  const verify_source_1 = require("./commands/verify-source");
13
13
  const workspaces_1 = require("./commands/workspaces");
14
14
  const env_file_1 = require("./env-file");
15
+ const own_release_1 = require("./internal/own-release");
15
16
  const help_1 = require("./help");
16
17
  const output_1 = require("./output");
17
18
  const update_check_1 = require("./update-check");
18
- const { version } = require("../package.json");
19
+ const { version } = own_release_1.ownRelease;
19
20
  const QUIET_FLAGS = ["-q", "--quiet"];
20
21
  const GLOBAL_FLAGS = ["--no-color", ...QUIET_FLAGS];
21
22
  const VERBOSE_FLAG = "--verbose";
@@ -0,0 +1,4 @@
1
+ import type { ServedModule } from "../module-set";
2
+ import type { FrontendModuleOptions } from "../workspace";
3
+ export declare function readBuiltPrivateOptions(workspaceDir: string): Record<string, FrontendModuleOptions>;
4
+ export declare function readBuiltModules(workspaceDir: string): ServedModule[];
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readBuiltPrivateOptions = readBuiltPrivateOptions;
4
+ exports.readBuiltModules = readBuiltModules;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const config_1 = require("../config");
8
+ const guards_1 = require("./guards");
9
+ const manifest_decoder_1 = require("./manifest-decoder");
10
+ const plain_object_1 = require("./plain-object");
11
+ function isOptionsById(value) {
12
+ return (0, plain_object_1.isPlainObject)(value) && Object.values(value).every(manifest_decoder_1.isModuleOptions);
13
+ }
14
+ function readBuiltPrivateOptions(workspaceDir) {
15
+ try {
16
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(workspaceDir, config_1.SERVER_OPTIONS_FILE), "utf8"));
17
+ const modules = (0, plain_object_1.isPlainObject)(parsed) ? parsed.modules : undefined;
18
+ return isOptionsById(modules) ? modules : {};
19
+ }
20
+ catch {
21
+ return {};
22
+ }
23
+ }
24
+ function readBuiltModules(workspaceDir) {
25
+ try {
26
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(workspaceDir, "generated-frontend-modules.json"), "utf8"));
27
+ const modules = (0, plain_object_1.isPlainObject)(parsed) ? parsed.modules : undefined;
28
+ if (!Array.isArray(modules))
29
+ return [];
30
+ const listed = modules;
31
+ return listed.flatMap((module) => (0, plain_object_1.isPlainObject)(module) && (0, guards_1.isText)(module.id)
32
+ ? [
33
+ {
34
+ name: (0, guards_1.isText)(module.name) ? module.name : module.id,
35
+ version: (0, guards_1.isText)(module.version) ? module.version : undefined,
36
+ },
37
+ ]
38
+ : []);
39
+ }
40
+ catch {
41
+ return [];
42
+ }
43
+ }
@@ -0,0 +1 @@
1
+ export declare function ensure(condition: boolean, title: string, reason?: string): asserts condition;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensure = ensure;
4
+ const cli_1 = require("@antelopejs/core/cli");
5
+ function ensure(condition, title, reason) {
6
+ if (!condition)
7
+ throw new cli_1.CliError({ title, reason });
8
+ }
@@ -1,6 +1,11 @@
1
- export declare function isRecord(value: unknown): value is Record<string, unknown>;
2
- export declare function mergeLocaleMessages(source: Record<string, unknown>, existing: Record<string, unknown>): Record<string, unknown>;
1
+ export type LocaleValue = string | number | boolean | null | LocaleValue[] | LocaleMessages;
2
+ export interface LocaleMessages {
3
+ [key: string]: LocaleValue;
4
+ }
5
+ export declare function isLocaleValue(value: unknown): value is LocaleValue;
6
+ export declare function isMessageGroup(value: LocaleValue): value is LocaleMessages;
7
+ export declare function mergeLocaleMessages(source: LocaleMessages, existing: LocaleMessages): LocaleMessages;
3
8
  export declare const FALLBACK_LOCALE = "en";
4
9
  export declare const RENDERER_TRANSLATED_KEYS: string[];
5
- export declare function withoutMessage(messages: Record<string, unknown>, key: string): Record<string, unknown>;
10
+ export declare function withoutMessage(messages: LocaleMessages, key: string): LocaleMessages;
6
11
  export declare function localeModuleSource(supportedLocales: string[]): string;
@@ -1,19 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RENDERER_TRANSLATED_KEYS = exports.FALLBACK_LOCALE = void 0;
4
- exports.isRecord = isRecord;
4
+ exports.isLocaleValue = isLocaleValue;
5
+ exports.isMessageGroup = isMessageGroup;
5
6
  exports.mergeLocaleMessages = mergeLocaleMessages;
6
7
  exports.withoutMessage = withoutMessage;
7
8
  exports.localeModuleSource = localeModuleSource;
8
- function isRecord(value) {
9
- return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ const guards_1 = require("./guards");
10
+ function isLocaleValue(value) {
11
+ if (value === null || (0, guards_1.isText)(value) || (0, guards_1.isNumber)(value) || (0, guards_1.isFlag)(value)) {
12
+ return true;
13
+ }
14
+ if (Array.isArray(value))
15
+ return value.every(isLocaleValue);
16
+ return (0, guards_1.isObjectLike)(value) && Object.values(value).every(isLocaleValue);
17
+ }
18
+ function isMessageGroup(value) {
19
+ return (0, guards_1.isObjectLike)(value) && !Array.isArray(value);
10
20
  }
11
21
  function mergeLocaleMessages(source, existing) {
12
22
  const merged = { ...source };
13
23
  for (const [key, value] of Object.entries(existing)) {
14
24
  const sourceValue = merged[key];
15
25
  merged[key] =
16
- isRecord(sourceValue) && isRecord(value)
26
+ isMessageGroup(sourceValue) && isMessageGroup(value)
17
27
  ? mergeLocaleMessages(sourceValue, value)
18
28
  : value;
19
29
  }
@@ -23,12 +33,12 @@ exports.FALLBACK_LOCALE = "en";
23
33
  exports.RENDERER_TRANSLATED_KEYS = ["error.network"];
24
34
  function withoutMessage(messages, key) {
25
35
  const [head, ...rest] = key.split(".");
26
- if (!(head in messages))
36
+ if (!Object.prototype.hasOwnProperty.call(messages, head))
27
37
  return messages;
28
38
  const { [head]: value, ...others } = messages;
29
39
  if (!rest.length)
30
40
  return others;
31
- if (!isRecord(value))
41
+ if (!isMessageGroup(value))
32
42
  return messages;
33
43
  const remaining = withoutMessage(value, rest.join("."));
34
44
  return Object.keys(remaining).length
@@ -0,0 +1,7 @@
1
+ import type { FrontendModuleOptions, Manifest, ManifestModule } from "../workspace";
2
+ export declare function isModuleOptions(value: unknown): value is FrontendModuleOptions;
3
+ export declare function isManifestModule(value: unknown): value is ManifestModule;
4
+ export declare function isManifest(value: unknown): value is Manifest;
5
+ export declare function hasManifestVersion(value: unknown): value is {
6
+ version: number;
7
+ };
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isModuleOptions = isModuleOptions;
4
+ exports.isManifestModule = isManifestModule;
5
+ exports.isManifest = isManifest;
6
+ exports.hasManifestVersion = hasManifestVersion;
7
+ const guards_1 = require("./guards");
8
+ const plain_object_1 = require("./plain-object");
9
+ function isList(value) {
10
+ return Array.isArray(value);
11
+ }
12
+ function isTextList(value) {
13
+ return isList(value) && value.every(guards_1.isText);
14
+ }
15
+ function isModuleValue(value) {
16
+ if (value === null || (0, guards_1.isText)(value) || (0, guards_1.isNumber)(value) || (0, guards_1.isFlag)(value))
17
+ return true;
18
+ return isList(value) ? value.every(isModuleValue) : isModuleOptions(value);
19
+ }
20
+ function isModuleOptions(value) {
21
+ return (0, plain_object_1.isPlainObject)(value) && Object.values(value).every(isModuleValue);
22
+ }
23
+ function isPublicEndpoint(value) {
24
+ return ((0, plain_object_1.isPlainObject)(value) &&
25
+ (0, guards_1.isText)(value.path) &&
26
+ (value.methods === undefined || isTextList(value.methods)) &&
27
+ (value.headers === undefined || isTextList(value.headers)));
28
+ }
29
+ function isBackendProxy(value) {
30
+ return ((0, plain_object_1.isPlainObject)(value) &&
31
+ (0, guards_1.isText)(value.path) &&
32
+ (value.auth === undefined ||
33
+ value.auth === "session" ||
34
+ value.auth === "none") &&
35
+ (value.maxBodyBytes === undefined || (0, guards_1.isNumber)(value.maxBodyBytes)));
36
+ }
37
+ function isRenderer(value) {
38
+ return (0, plain_object_1.isPlainObject)(value) && (0, guards_1.isText)(value.name) && (0, guards_1.isText)(value.version);
39
+ }
40
+ function hasOptionalFields(value) {
41
+ return ((0, plain_object_1.isPlainObject)(value) &&
42
+ (value.renderer === undefined || isRenderer(value.renderer)) &&
43
+ (value.path === undefined || (0, guards_1.isText)(value.path)) &&
44
+ (value.options === undefined || isModuleOptions(value.options)) &&
45
+ (value.privateOptions === undefined ||
46
+ isModuleOptions(value.privateOptions)) &&
47
+ (value.configKey === undefined || (0, guards_1.isText)(value.configKey)));
48
+ }
49
+ function hasOptionalLists(value) {
50
+ return ((0, plain_object_1.isPlainObject)(value) &&
51
+ (value.authEstablishEndpoints === undefined ||
52
+ isTextList(value.authEstablishEndpoints)) &&
53
+ (value.publicEndpoints === undefined ||
54
+ (isList(value.publicEndpoints) &&
55
+ value.publicEndpoints.every(isPublicEndpoint))) &&
56
+ (value.backendProxies === undefined ||
57
+ (isList(value.backendProxies) &&
58
+ value.backendProxies.every(isBackendProxy))));
59
+ }
60
+ function isManifestModule(value) {
61
+ return ((0, plain_object_1.isPlainObject)(value) &&
62
+ (0, guards_1.isText)(value.name) &&
63
+ (0, guards_1.isNumber)(value.priority) &&
64
+ hasOptionalFields(value) &&
65
+ hasOptionalLists(value));
66
+ }
67
+ function isOriginRewrite(value) {
68
+ return (0, plain_object_1.isPlainObject)(value) && (0, guards_1.isText)(value.from) && (0, guards_1.isText)(value.to);
69
+ }
70
+ function isManifest(value) {
71
+ return ((0, plain_object_1.isPlainObject)(value) &&
72
+ isList(value.modules) &&
73
+ value.modules.every(isManifestModule) &&
74
+ (value.settling === undefined || (0, guards_1.isFlag)(value.settling)) &&
75
+ (value.originRewrites === undefined ||
76
+ (isList(value.originRewrites) &&
77
+ value.originRewrites.every(isOriginRewrite))));
78
+ }
79
+ function hasManifestVersion(value) {
80
+ return (0, plain_object_1.isPlainObject)(value) && (0, guards_1.isNumber)(value.version);
81
+ }
@@ -0,0 +1,5 @@
1
+ export interface OwnRelease {
2
+ name: string;
3
+ version: string;
4
+ }
5
+ export declare const ownRelease: OwnRelease;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ownRelease = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const guards_1 = require("./guards");
7
+ function isOwnRelease(value) {
8
+ return ((0, guards_1.isObjectLike)(value) &&
9
+ "name" in value &&
10
+ (0, guards_1.isText)(value.name) &&
11
+ "version" in value &&
12
+ (0, guards_1.isText)(value.version));
13
+ }
14
+ function readOwnRelease() {
15
+ const manifest = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, "..", "..", "package.json"), "utf8"));
16
+ if (!isOwnRelease(manifest))
17
+ throw new Error("The package.json of dms-frontend has no name or version");
18
+ return manifest;
19
+ }
20
+ exports.ownRelease = readOwnRelease();
@@ -0,0 +1 @@
1
+ export declare function isPlainObject(value: unknown): value is Record<string, unknown>;