@antelopejs/dms-frontend 0.9.3 → 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 (140) hide show
  1. package/README.md +46 -29
  2. package/dist/commands/build-action.d.ts +3 -0
  3. package/dist/commands/build-action.js +77 -8
  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 +4 -3
  8. package/dist/commands/dev.js +1 -1
  9. package/dist/commands/prepare-action.js +1 -1
  10. package/dist/commands/start-action.js +3 -24
  11. package/dist/commands/workspace-task.js +2 -1
  12. package/dist/config.js +1 -0
  13. package/dist/derived-outputs.d.ts +1 -0
  14. package/dist/derived-outputs.js +6 -4
  15. package/dist/discovery.js +17 -6
  16. package/dist/entry-weight.js +15 -0
  17. package/dist/fs-sync.js +7 -4
  18. package/dist/help.js +1 -1
  19. package/dist/index.js +2 -1
  20. package/dist/internal/built-workspace.d.ts +4 -0
  21. package/dist/internal/built-workspace.js +43 -0
  22. package/dist/internal/ensure.d.ts +1 -0
  23. package/dist/internal/ensure.js +8 -0
  24. package/dist/internal/locale-catalogs.d.ts +8 -3
  25. package/dist/internal/locale-catalogs.js +16 -6
  26. package/dist/internal/manifest-decoder.d.ts +7 -0
  27. package/dist/internal/manifest-decoder.js +81 -0
  28. package/dist/internal/own-release.d.ts +5 -0
  29. package/dist/internal/own-release.js +20 -0
  30. package/dist/internal/plain-object.d.ts +1 -0
  31. package/dist/internal/plain-object.js +6 -0
  32. package/dist/internal/prepared-workspace.d.ts +12 -0
  33. package/dist/internal/prepared-workspace.js +74 -0
  34. package/dist/internal/text-list.d.ts +1 -0
  35. package/dist/internal/text-list.js +10 -0
  36. package/dist/internal/vite-manifest.d.ts +6 -0
  37. package/dist/internal/vite-manifest.js +24 -0
  38. package/dist/layer-watch.js +25 -24
  39. package/dist/layers.d.ts +1 -1
  40. package/dist/layers.js +3 -1
  41. package/dist/locale-files.d.ts +6 -3
  42. package/dist/locale-files.js +15 -9
  43. package/dist/manifest.d.ts +1 -1
  44. package/dist/manifest.js +46 -32
  45. package/dist/materialize.js +6 -2
  46. package/dist/module-set.js +2 -1
  47. package/dist/node-options.d.ts +1 -0
  48. package/dist/node-options.js +8 -0
  49. package/dist/output.d.ts +15 -9
  50. package/dist/output.js +30 -18
  51. package/dist/ports.d.ts +3 -1
  52. package/dist/ports.js +1 -1
  53. package/dist/private-values.d.ts +1 -1
  54. package/dist/private-values.js +5 -3
  55. package/dist/project-modules.d.ts +5 -1
  56. package/dist/project-modules.js +23 -15
  57. package/dist/renderer-range.js +5 -3
  58. package/dist/server-process.js +1 -1
  59. package/dist/verify-source-build.js +10 -2
  60. package/dist/verify-source-client-bundle.d.ts +1 -0
  61. package/dist/verify-source-client-bundle.js +30 -0
  62. package/dist/verify-source-runner.js +36 -94
  63. package/dist/verify-source-sources.js +49 -11
  64. package/dist/verify-source-workspace.d.ts +2 -0
  65. package/dist/verify-source-workspace.js +111 -0
  66. package/dist/workspace-setup.d.ts +1 -0
  67. package/dist/workspace-setup.js +4 -3
  68. package/package.json +11 -7
  69. package/skills/dms-frontend/SKILL.md +1 -1
  70. package/templates/vue/app-runtime.ts +2 -9
  71. package/templates/vue/backend-boundary.mjs +132 -0
  72. package/templates/vue/client-chunking.mjs +2 -0
  73. package/templates/vue/client-server-guard.mjs +16 -0
  74. package/templates/vue/compress-assets.mjs +9 -1
  75. package/templates/vue/entry-weight.mjs +29 -3
  76. package/templates/vue/frontend-build.ts +4 -3
  77. package/templates/vue/frontend-module.ts +1 -0
  78. package/templates/vue/frontend-runtime/module-registration.ts +2 -2
  79. package/templates/vue/frontend-runtime/state.ts +2 -2
  80. package/templates/vue/frontend-runtime/types.ts +8 -2
  81. package/templates/vue/head-order.mjs +10 -2
  82. package/templates/vue/icon-api.mjs +2 -0
  83. package/templates/vue/icon-scan.mjs +4 -0
  84. package/templates/vue/server/auth/backend.mjs +42 -5
  85. package/templates/vue/server/auth/client-ip.mjs +52 -4
  86. package/templates/vue/server/auth/establish-endpoints.mjs +11 -7
  87. package/templates/vue/server/auth/session.mjs +86 -4
  88. package/templates/vue/server/auth-declarations.mjs +46 -0
  89. package/templates/vue/server/auth-hooks.mjs +55 -7
  90. package/templates/vue/server/backend-proxies.mjs +78 -18
  91. package/templates/vue/server/backend-request.mjs +61 -0
  92. package/templates/vue/server/backend-response.mjs +23 -6
  93. package/templates/vue/server/built-files.mjs +7 -0
  94. package/templates/vue/server/cli-report.mjs +75 -12
  95. package/templates/vue/server/client-error.mjs +5 -0
  96. package/templates/vue/server/client-manifest.mjs +23 -1
  97. package/templates/vue/server/content.mjs +40 -10
  98. package/templates/vue/server/dev-private-files.mjs +17 -1
  99. package/templates/vue/server/dev-styles.mjs +38 -0
  100. package/templates/vue/server/email-bundle-watch.mjs +9 -3
  101. package/templates/vue/server/email.mjs +14 -6
  102. package/templates/vue/server/favicon.mjs +3 -0
  103. package/templates/vue/server/generated-files.mjs +221 -0
  104. package/templates/vue/server/homepage.mjs +21 -9
  105. package/templates/vue/server/html-tag.mjs +4 -0
  106. package/templates/vue/server/icons.mjs +93 -16
  107. package/templates/vue/server/in-place-render.mjs +35 -0
  108. package/templates/vue/server/inertia.mjs +76 -3
  109. package/templates/vue/server/module-event.mjs +118 -25
  110. package/templates/vue/server/module-route-types.mjs +78 -0
  111. package/templates/vue/server/module-routes.mjs +151 -96
  112. package/templates/vue/server/module-server.mjs +121 -40
  113. package/templates/vue/server/module-testing.mjs +36 -12
  114. package/templates/vue/server/page-props.mjs +94 -3
  115. package/templates/vue/server/page-redirects.mjs +37 -0
  116. package/templates/vue/server/path-patterns.mjs +35 -12
  117. package/templates/vue/server/proxy-compression.mjs +22 -0
  118. package/templates/vue/server/proxy-headers.mjs +12 -2
  119. package/templates/vue/server/proxy-redirects.mjs +21 -5
  120. package/templates/vue/server/proxy-request.mjs +58 -0
  121. package/templates/vue/server/proxy-transfers.mjs +44 -10
  122. package/templates/vue/server/public-endpoints.mjs +139 -28
  123. package/templates/vue/server/public-options.mjs +20 -6
  124. package/templates/vue/server/request-failure.mjs +24 -1
  125. package/templates/vue/server/request-routing.mjs +32 -10
  126. package/templates/vue/server/request-target.mjs +30 -11
  127. package/templates/vue/server/route-rules.mjs +48 -18
  128. package/templates/vue/server/ssr-module.mjs +32 -0
  129. package/templates/vue/server/static-files.mjs +35 -7
  130. package/templates/vue/server/type-guards.mjs +71 -0
  131. package/templates/vue/server/vite-errors.mjs +45 -7
  132. package/templates/vue/server/web-body.mjs +5 -1
  133. package/templates/vue/server-module.ts +12 -2
  134. package/templates/vue/server.mjs +162 -157
  135. package/templates/vue/sfc-global-types.mjs +112 -13
  136. package/templates/vue/ssr-renderer.ts +2 -2
  137. package/templates/vue/ui-inertia-page.mjs +16 -1
  138. package/templates/vue/ui-kbd.mjs +2 -1
  139. package/templates/vue/ui-request-state.mjs +2 -1
  140. package/templates/vue/vite.config.ts +9 -0
package/dist/manifest.js CHANGED
@@ -17,6 +17,9 @@ const config_1 = require("./config");
17
17
  const output_1 = require("./output");
18
18
  const workspace_1 = require("./workspace");
19
19
  const guards_1 = require("./internal/guards");
20
+ const plain_object_1 = require("./internal/plain-object");
21
+ const manifest_decoder_1 = require("./internal/manifest-decoder");
22
+ const own_release_1 = require("./internal/own-release");
20
23
  class ManifestUnauthorizedError extends cli_1.CliError {
21
24
  constructor(url, status, credentialSent) {
22
25
  super({
@@ -34,22 +37,23 @@ class ManifestUnauthorizedError extends cli_1.CliError {
34
37
  }
35
38
  }
36
39
  exports.ManifestUnauthorizedError = ManifestUnauthorizedError;
37
- const UNREACHABLE_REASONS = {
38
- ECONNREFUSED: "Connection refused",
39
- ECONNRESET: "Connection reset",
40
- ENOTFOUND: "Unknown host",
41
- EAI_AGAIN: "Host name lookup failed",
42
- ETIMEDOUT: "Connection timed out",
43
- UND_ERR_CONNECT_TIMEOUT: "Connection timed out",
44
- };
40
+ const UNREACHABLE_REASONS = new Map([
41
+ ["ECONNREFUSED", "Connection refused"],
42
+ ["ECONNRESET", "Connection reset"],
43
+ ["ENOTFOUND", "Unknown host"],
44
+ ["EAI_AGAIN", "Host name lookup failed"],
45
+ ["ETIMEDOUT", "Connection timed out"],
46
+ ["UND_ERR_CONNECT_TIMEOUT", "Connection timed out"],
47
+ ]);
45
48
  const UNKNOWN_HOST_CODES = ["ENOTFOUND", "EAI_AGAIN"];
46
49
  class BackendUnreachableError extends cli_1.CliError {
47
50
  constructor(url, failure) {
48
51
  const cause = (hasProperties(failure) ? failure.cause : undefined) ?? failure;
49
- const code = errorCode(cause);
52
+ const code = hasProperties(cause) ? errorCode(cause) : undefined;
53
+ const message = () => cause instanceof Error ? cause.message : String(cause);
50
54
  const detail = code
51
- ? (UNREACHABLE_REASONS[code] ?? errorMessage(cause))
52
- : `The request failed: ${errorMessage(cause)}`;
55
+ ? (UNREACHABLE_REASONS.get(code) ?? message())
56
+ : `The request failed: ${message()}`;
53
57
  const fix = code && UNKNOWN_HOST_CODES.includes(code)
54
58
  ? `Check the host name '${new URL(url).hostname}' in -b <url> or DMS_API_BASE_URL`
55
59
  : "Start the backend (`ajs project dev` for a local one), or pass its URL with -b <url>";
@@ -68,15 +72,13 @@ function hasProperties(value) {
68
72
  return (value !== null && (typeof value === "object" || typeof value === "function"));
69
73
  }
70
74
  function errorCode(err) {
71
- if (!hasProperties(err))
72
- return undefined;
73
75
  const { code, errors } = err;
74
76
  if ((0, guards_1.isText)(code))
75
77
  return code;
76
- return Array.isArray(errors) ? errorCode(errors[0]) : undefined;
77
- }
78
- function errorMessage(err) {
79
- return err instanceof Error ? err.message : String(err);
78
+ if (!Array.isArray(errors))
79
+ return undefined;
80
+ const first = errors[0];
81
+ return hasProperties(first) ? errorCode(first) : undefined;
80
82
  }
81
83
  function displayUrl(url) {
82
84
  const { origin, pathname } = new URL(url);
@@ -84,7 +86,8 @@ function displayUrl(url) {
84
86
  }
85
87
  function backendEndpoint(backendUrl, path) {
86
88
  try {
87
- return new URL(`${(0, config_1.parseBackendUrl)(backendUrl)}${path}`);
89
+ const base = (0, config_1.parseBackendUrl)(backendUrl).replace(/\/+$/, "");
90
+ return new URL(`${base}${path}`);
88
91
  }
89
92
  catch (err) {
90
93
  if (!(err instanceof config_1.UsageError))
@@ -112,13 +115,12 @@ class ManifestRefusedError extends cli_1.CliError {
112
115
  }
113
116
  }
114
117
  exports.ManifestRefusedError = ManifestRefusedError;
115
- const OWN_RELEASE = require("../package.json");
116
118
  const BACKEND_PACKAGE = "@antelopejs/dms";
117
119
  const LOADER_UPDATE_COMMAND = "ajs update dms";
118
120
  function describeManifestVersion(version) {
119
- const loader = `${OWN_RELEASE.name} ${OWN_RELEASE.version}`;
121
+ const loader = `${own_release_1.ownRelease.name} ${own_release_1.ownRelease.version}`;
120
122
  const supported = `This loader reads version ${workspace_1.FRONTEND_MANIFEST_VERSION}`;
121
- if (!(0, guards_1.isNumber)(version)) {
123
+ if (version === undefined) {
122
124
  return {
123
125
  title: "The backend served a frontend manifest without a protocol version",
124
126
  reason: `${supported}; the answer does not look like one from ${BACKEND_PACKAGE}.`,
@@ -141,7 +143,7 @@ function describeManifestVersion(version) {
141
143
  title,
142
144
  reason: `${supported}; the backend's ${BACKEND_PACKAGE} is older than this loader.`,
143
145
  fixes: [
144
- `Upgrade ${BACKEND_PACKAGE} on the backend, or use a ${OWN_RELEASE.name} release that reads version ${version}`,
146
+ `Upgrade ${BACKEND_PACKAGE} on the backend, or use a ${own_release_1.ownRelease.name} release that reads version ${version}`,
145
147
  ],
146
148
  };
147
149
  }
@@ -192,19 +194,29 @@ async function fetchManifest(backendUrl, clientUrl, bootstrapSecret) {
192
194
  if (!response.ok) {
193
195
  throw new BackendResponseError("the frontend manifest", frontendUrl, response);
194
196
  }
195
- const manifest = (await response.json());
196
- if (manifest.version !== workspace_1.FRONTEND_MANIFEST_VERSION) {
197
- throw new ManifestRefusedError(describeManifestVersion(manifest.version));
197
+ const body = await response.json();
198
+ const version = (0, manifest_decoder_1.hasManifestVersion)(body) ? body.version : undefined;
199
+ if (version !== workspace_1.FRONTEND_MANIFEST_VERSION) {
200
+ throw new ManifestRefusedError(describeManifestVersion(version));
198
201
  }
199
- const incompatible = manifest.modules.filter((module) => module.renderer?.name !== "vue" || module.renderer?.version !== "3");
202
+ if (!(0, manifest_decoder_1.isManifest)(body)) {
203
+ throw new ManifestRefusedError({
204
+ title: "The backend served a frontend manifest this loader cannot read",
205
+ reason: `It states version ${workspace_1.FRONTEND_MANIFEST_VERSION}, but its modules, settling flag or origin rewrites do not have the shape ${own_release_1.ownRelease.name} ${own_release_1.ownRelease.version} reads.`,
206
+ fixes: [
207
+ `Check that -b <url> points at a DMS backend running ${BACKEND_PACKAGE}`,
208
+ ],
209
+ });
210
+ }
211
+ const incompatible = body.modules.filter((module) => module.renderer?.name !== "vue" || module.renderer?.version !== "3");
200
212
  if (incompatible.length) {
201
213
  throw new ManifestRefusedError(`Frontend manifest contains incompatible renderer modules: ${incompatible.map((module) => module.name).join(", ")}`);
202
214
  }
203
- const resolved = { modules: manifest.modules };
204
- if (manifest.settling)
215
+ const resolved = { modules: body.modules };
216
+ if (body.settling)
205
217
  resolved.settling = true;
206
- if (manifest.originRewrites)
207
- resolved.originRewrites = manifest.originRewrites;
218
+ if (body.originRewrites)
219
+ resolved.originRewrites = body.originRewrites;
208
220
  return resolved;
209
221
  }
210
222
  const MANIFEST_CACHE_FILE = ".manifest-cache.json";
@@ -214,9 +226,11 @@ function readCachedManifest(workspaceDir) {
214
226
  return undefined;
215
227
  try {
216
228
  const parsed = JSON.parse((0, node_fs_1.readFileSync)(file, "utf-8"));
217
- if (!parsed?.manifest)
229
+ if (!(0, plain_object_1.isPlainObject)(parsed) || !(0, guards_1.isText)(parsed.fetchedAt))
230
+ return undefined;
231
+ if (!(0, manifest_decoder_1.isManifest)(parsed.manifest))
218
232
  return undefined;
219
- return parsed;
233
+ return { manifest: parsed.manifest, fetchedAt: parsed.fetchedAt };
220
234
  }
221
235
  catch {
222
236
  return undefined;
@@ -16,6 +16,7 @@ const layers_1 = require("./layers");
16
16
  const manifest_secrets_1 = require("./manifest-secrets");
17
17
  const fs_sync_1 = require("./fs-sync");
18
18
  const guards_1 = require("./internal/guards");
19
+ const plain_object_1 = require("./internal/plain-object");
19
20
  function getPackageRoot() {
20
21
  return (0, node_path_1.resolve)(__dirname, "..");
21
22
  }
@@ -43,11 +44,14 @@ function copyStaticTemplates(workspaceDir) {
43
44
  function writeWorkspacePackageJson(workspaceDir, layers) {
44
45
  const templatePath = (0, node_path_1.join)(getTemplateDir(), "package.json");
45
46
  const pkg = JSON.parse((0, node_fs_1.readFileSync)(templatePath, "utf-8"));
46
- pkg.dependencies ??= {};
47
+ if (!(0, plain_object_1.isPlainObject)(pkg))
48
+ throw new Error(`${templatePath} is not a JSON object`);
49
+ const dependencies = (0, plain_object_1.isPlainObject)(pkg.dependencies) ? pkg.dependencies : {};
50
+ pkg.dependencies = dependencies;
47
51
  for (const layer of layers) {
48
52
  if (!layer.packageName)
49
53
  continue;
50
- pkg.dependencies[layer.packageName] = "workspace:*";
54
+ dependencies[layer.packageName] = "workspace:*";
51
55
  }
52
56
  (0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspaceDir, "package.json"), `${JSON.stringify(pkg, null, 2)}\n`);
53
57
  }
@@ -7,12 +7,13 @@ exports.reportFrontendReady = reportFrontendReady;
7
7
  exports.reportFrontendReadyOnceAnswered = reportFrontendReadyOnceAnswered;
8
8
  const promises_1 = require("node:timers/promises");
9
9
  const manifest_1 = require("./manifest");
10
+ const own_release_1 = require("./internal/own-release");
10
11
  const workspace_1 = require("./workspace");
11
12
  exports.MODULE_SET_POLL_INTERVAL_MS = 3000;
12
13
  const READY_ENDPOINT = "/dms/frontend/ready";
13
14
  const READY_TIMEOUT_MS = 5000;
14
15
  const JSON_CONTENT_TYPE = "application/json";
15
- exports.OWN_RELEASE = require("../package.json");
16
+ exports.OWN_RELEASE = own_release_1.ownRelease;
16
17
  function moduleSetFingerprint(modules) {
17
18
  return JSON.stringify([...modules]
18
19
  .sort((left, right) => left.name.localeCompare(right.name))
@@ -0,0 +1 @@
1
+ export declare function serverNodeOptions(inherited: string | undefined): string;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serverNodeOptions = serverNodeOptions;
4
+ const HEAP_OPTION = "--max-old-space-size=4096";
5
+ function serverNodeOptions(inherited) {
6
+ const own = inherited?.trim();
7
+ return own ? `${HEAP_OPTION} ${own}` : HEAP_OPTION;
8
+ }
package/dist/output.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type TaskHandle, type Ui } from "@antelopejs/core/cli";
1
+ import { CliError, type TaskHandle, type Ui } from "@antelopejs/core/cli";
2
2
  import { CancelledError } from "./cancellation";
3
3
  export declare function exitOnBrokenPipe(stream?: NodeJS.WriteStream): void;
4
4
  export declare function isTerminalFeedback(): boolean;
@@ -15,8 +15,19 @@ export declare function workspaceId(dir: string, isTerminal: boolean): string;
15
15
  export declare function formatSize(bytes: number): string;
16
16
  export declare function formatAge(iso: string, now?: number): string;
17
17
  export declare function cachedAge(fetchedAt: string | undefined): string;
18
- export declare function failureDetails(error: unknown, ui?: Ui): string[];
19
- export declare function endInterruptedTask(task: TaskHandle, error: unknown, stopped: string): void;
18
+ export type Failure = {
19
+ kind: "cli";
20
+ error: CliError;
21
+ } | {
22
+ kind: "error";
23
+ error: Error;
24
+ } | {
25
+ kind: "thrown";
26
+ text: string;
27
+ };
28
+ export declare function classifyFailure(thrown: unknown): Failure;
29
+ export declare function failureDetails(failure: Failure, ui?: Ui): string[];
30
+ export declare function endInterruptedTask(task: TaskHandle, error: CancelledError | undefined, stopped: string): void;
20
31
  export declare function reportStopped(stop: CancelledError, ui?: Ui): void;
21
32
  export interface ReadyLine {
22
33
  label: string;
@@ -31,12 +42,7 @@ export interface ReadyBlock {
31
42
  }
32
43
  export declare function formatReadyBlock(block: ReadyBlock, ui?: Ui, isQuiet?: boolean, columns?: number | undefined): string[];
33
44
  export declare function writeReadyBlock(block: ReadyBlock, ui?: Ui): void;
34
- declare const TIMED_LEVEL_COLORS: {
35
- readonly success: "green";
36
- readonly info: "blue";
37
- readonly warn: "yellow";
38
- };
39
- type TimedLevel = keyof typeof TIMED_LEVEL_COLORS;
45
+ type TimedLevel = "success" | "info" | "warn";
40
46
  export interface TimedMessageOptions {
41
47
  details?: readonly string[];
42
48
  fixes?: readonly string[];
package/dist/output.js CHANGED
@@ -15,6 +15,7 @@ exports.workspaceId = workspaceId;
15
15
  exports.formatSize = formatSize;
16
16
  exports.formatAge = formatAge;
17
17
  exports.cachedAge = cachedAge;
18
+ exports.classifyFailure = classifyFailure;
18
19
  exports.failureDetails = failureDetails;
19
20
  exports.endInterruptedTask = endInterruptedTask;
20
21
  exports.reportStopped = reportStopped;
@@ -25,7 +26,6 @@ const node_os_1 = require("node:os");
25
26
  const node_path_1 = require("node:path");
26
27
  const node_util_1 = require("node:util");
27
28
  const cli_1 = require("@antelopejs/core/cli");
28
- const cancellation_1 = require("./cancellation");
29
29
  const HOME_PREFIX = "~";
30
30
  const CURRENT_DIRECTORY = ".";
31
31
  const WORKSPACE_ID_LENGTH = 8;
@@ -140,17 +140,24 @@ function formatAge(iso, now = Date.now()) {
140
140
  function cachedAge(fetchedAt) {
141
141
  return fetchedAt ? ` cached ${formatAge(fetchedAt)}` : "";
142
142
  }
143
- function describeProblem(error) {
144
- if (error instanceof cli_1.CliError)
145
- return error.problem;
146
- const message = error instanceof Error ? error.message : String(error);
147
- return { title: message.split(LINE_BREAK)[0] };
148
- }
149
- function failureDetails(error, ui = (0, cli_1.getProcessUi)()) {
150
- const { title, reason, fixes = [], details = [] } = describeProblem(error);
143
+ function classifyFailure(thrown) {
144
+ if (thrown instanceof cli_1.CliError)
145
+ return { kind: "cli", error: thrown };
146
+ if (thrown instanceof Error)
147
+ return { kind: "error", error: thrown };
148
+ return { kind: "thrown", text: String(thrown) };
149
+ }
150
+ function failureDetails(failure, ui = (0, cli_1.getProcessUi)()) {
151
+ const { title, reason, fixes = [], details = [], } = failure.kind === "cli"
152
+ ? failure.error.problem
153
+ : {
154
+ title: (failure.kind === "error"
155
+ ? failure.error.message
156
+ : failure.text).split(LINE_BREAK)[0],
157
+ };
151
158
  const hint = ui.symbols.levels.hint;
152
- const stack = (0, cli_1.isVerboseRun)() && error instanceof Error && !(error instanceof cli_1.CliError)
153
- ? (error.stack ?? "").split(LINE_BREAK).slice(1)
159
+ const stack = (0, cli_1.isVerboseRun)() && failure.kind === "error"
160
+ ? (failure.error.stack ?? "").split(LINE_BREAK).slice(1)
154
161
  : [];
155
162
  return [
156
163
  title,
@@ -164,7 +171,7 @@ function lineStartAfter(signal) {
164
171
  return signal === "SIGINT" && process.stderr.isTTY ? CARRIAGE_RETURN : "";
165
172
  }
166
173
  function endInterruptedTask(task, error, stopped) {
167
- if (!(error instanceof cancellation_1.CancelledError))
174
+ if (!error)
168
175
  return task.dismiss();
169
176
  const lineStart = lineStartAfter(error.signal);
170
177
  if (lineStart)
@@ -212,18 +219,23 @@ function writeReadyBlock(block, ui = (0, cli_1.getProcessUi)()) {
212
219
  writeFeedback(line);
213
220
  writeInfo("");
214
221
  }
215
- const TIMED_LEVEL_COLORS = {
216
- success: "green",
217
- info: "blue",
218
- warn: "yellow",
219
- };
222
+ function timedLevelColor(level) {
223
+ switch (level) {
224
+ case "success":
225
+ return "green";
226
+ case "info":
227
+ return "blue";
228
+ case "warn":
229
+ return "yellow";
230
+ }
231
+ }
220
232
  function clockTime(date) {
221
233
  return date.toTimeString().slice(0, TIME_LENGTH);
222
234
  }
223
235
  function formatTimedMessage(level, text, options = {}, ui = (0, cli_1.getProcessUi)(), now = new Date()) {
224
236
  const { details = [], fixes = [], columns = feedbackColumns() } = options;
225
237
  const palette = ui.palette();
226
- const paint = palette[TIMED_LEVEL_COLORS[level]];
238
+ const paint = palette[timedLevelColor(level)];
227
239
  const hint = palette.cyan(ui.symbols.levels.hint);
228
240
  const indent = " ".repeat(TIME_LENGTH + 1) + BLOCK_INDENT;
229
241
  return [
package/dist/ports.d.ts CHANGED
@@ -4,5 +4,7 @@ export interface ReservedPort {
4
4
  port: number;
5
5
  release: () => Promise<void>;
6
6
  }
7
- export declare function reserveFreePort(preferred: number, range?: number): Promise<ReservedPort>;
7
+ export declare function reserveFreePort(preferred: number, range?: number): Promise<ReservedPort & {
8
+ isFallback: boolean;
9
+ }>;
8
10
  export declare function reservePort(port: number): Promise<ReservedPort | undefined>;
package/dist/ports.js CHANGED
@@ -21,7 +21,7 @@ async function reserveFreePort(preferred, range = exports.PORT_FALLBACK_RANGE) {
21
21
  for (let port = preferred; port <= end; port++) {
22
22
  const reserved = await reservePort(port);
23
23
  if (reserved)
24
- return reserved;
24
+ return { ...reserved, isFallback: port !== preferred };
25
25
  }
26
26
  throw new cli_1.CliError({
27
27
  title: `No free port found between ${preferred} and ${end}`,
@@ -1,6 +1,6 @@
1
1
  import type { FrontendModuleOptions } from "./workspace";
2
2
  export declare function emptiedOptions(options: FrontendModuleOptions): FrontendModuleOptions;
3
- export declare function filledOptions(shape: FrontendModuleOptions, values: FrontendModuleOptions | undefined): FrontendModuleOptions;
3
+ export declare function filledOptions(declared: FrontendModuleOptions, values: FrontendModuleOptions | undefined): FrontendModuleOptions;
4
4
  export declare const PRIVATE_OPTIONS_VARIABLE = "DMS_PRIVATE_OPTIONS";
5
5
  export interface UnfilledPrivateValue {
6
6
  module: string;
@@ -34,8 +34,8 @@ function filled(declared, value) {
34
34
  return filledOptions(declared, isOptions(value) ? value : undefined);
35
35
  return declared;
36
36
  }
37
- function filledOptions(shape, values) {
38
- return Object.fromEntries(Object.entries(shape).map(([key, value]) => [
37
+ function filledOptions(declared, values) {
38
+ return Object.fromEntries(Object.entries(declared).map(([key, value]) => [
39
39
  key,
40
40
  filled(value, values?.[key]),
41
41
  ]));
@@ -90,7 +90,9 @@ function unfilledPrivateValues(modules, given, covered) {
90
90
  return Object.entries(modules).flatMap(([module, options]) => [...emptyStrings(options)]
91
91
  .filter((path) => path.length > 0 && !isCovered(path))
92
92
  .filter((path) => {
93
- const value = readPath(given[module], path);
93
+ const value = readPath(Object.prototype.hasOwnProperty.call(given, module)
94
+ ? given[module]
95
+ : undefined, path);
94
96
  return !(0, guards_1.isText)(value) || value === "";
95
97
  })
96
98
  .map((path) => ({ module, path })));
@@ -42,6 +42,10 @@ export interface ProjectModulesOptions {
42
42
  dev?: boolean;
43
43
  }
44
44
  export declare function loadProjectConfig(projectDir: string, environment: string): Promise<ProjectConfig>;
45
- export declare function readShippingVersion(sourcePath: string): string | undefined;
45
+ export interface ShippingPackage {
46
+ name?: string;
47
+ version?: string;
48
+ }
49
+ export declare function readShippingPackage(sourcePath: string): ShippingPackage;
46
50
  export declare function readProjectFrontendModules(options: ProjectModulesOptions): Promise<ProjectFrontendModule[]>;
47
51
  export {};
@@ -35,7 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.FRONTEND_DECLARATION_FIELD = void 0;
37
37
  exports.loadProjectConfig = loadProjectConfig;
38
- exports.readShippingVersion = readShippingVersion;
38
+ exports.readShippingPackage = readShippingPackage;
39
39
  exports.readProjectFrontendModules = readProjectFrontendModules;
40
40
  const node_fs_1 = require("node:fs");
41
41
  const fsPromises = __importStar(require("node:fs/promises"));
@@ -107,26 +107,31 @@ function computeConfigVars(id, provider, config) {
107
107
  reason: error instanceof Error ? error.message : String(error),
108
108
  }, { cause: error });
109
109
  }
110
- return Object.fromEntries(provider.declared
111
- .filter((name) => name in computed)
112
- .map((name) => [name, computed[name]]));
110
+ return Object.fromEntries(provider.declared.flatMap((name) => Object.prototype.hasOwnProperty.call(computed, name)
111
+ ? [[name, computed[name]]]
112
+ : []));
113
113
  }
114
114
  function configVarLookup(modules) {
115
115
  const published = new Map();
116
116
  const lookup = (id, name) => {
117
117
  if (!published.has(id)) {
118
118
  published.set(id, undefined);
119
- const module = modules[id];
119
+ const module = Object.prototype.hasOwnProperty.call(modules, id)
120
+ ? modules[id]
121
+ : undefined;
120
122
  const provider = module?.folder && configVarsProvider(id, module.folder);
121
- if (provider)
123
+ if (module && provider)
122
124
  published.set(id, computeConfigVars(id, provider, substituteConfigVars(module.config, lookup)));
123
125
  }
124
- return published.get(id)?.[name];
126
+ const variables = published.get(id);
127
+ return variables && Object.prototype.hasOwnProperty.call(variables, name)
128
+ ? variables[name]
129
+ : undefined;
125
130
  };
126
131
  return lookup;
127
132
  }
128
133
  function substituteConfigVars(value, lookup) {
129
- if (typeof value === "string") {
134
+ if ((0, guards_1.isText)(value)) {
130
135
  const pure = value.match(PURE_CONFIG_VAR);
131
136
  if (pure)
132
137
  return lookup(pure[1], pure[2]);
@@ -137,7 +142,7 @@ function substituteConfigVars(value, lookup) {
137
142
  }
138
143
  if (Array.isArray(value))
139
144
  return value.map((item) => substituteConfigVars(item, lookup));
140
- if (value && typeof value === "object") {
145
+ if ((0, guards_1.isObjectLike)(value)) {
141
146
  return Object.fromEntries(Object.entries(value).map(([key, item]) => [
142
147
  key,
143
148
  substituteConfigVars(item, lookup),
@@ -186,15 +191,18 @@ function moduleFolder(projectDir, cacheFolder, source) {
186
191
  : [];
187
192
  return candidates.find((folder) => (0, node_fs_1.existsSync)((0, node_path_1.join)(folder, "package.json")));
188
193
  }
189
- function readShippingVersion(sourcePath) {
194
+ function readShippingPackage(sourcePath) {
190
195
  try {
191
196
  const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)((0, node_path_1.dirname)(sourcePath), "package.json"), "utf-8"));
192
- return (0, guards_1.isObjectLike)(pkg) && "version" in pkg && (0, guards_1.isText)(pkg.version)
193
- ? pkg.version
194
- : undefined;
197
+ if (!(0, guards_1.isObjectLike)(pkg))
198
+ return {};
199
+ return {
200
+ name: "name" in pkg && (0, guards_1.isText)(pkg.name) ? pkg.name : undefined,
201
+ version: "version" in pkg && (0, guards_1.isText)(pkg.version) ? pkg.version : undefined,
202
+ };
195
203
  }
196
204
  catch {
197
- return undefined;
205
+ return {};
198
206
  }
199
207
  }
200
208
  function toLayer(registration) {
@@ -269,6 +277,6 @@ async function readProjectFrontendModules(options) {
269
277
  .sort((left, right) => (right.priority ?? 0) - (left.priority ?? 0))
270
278
  .map((registration) => ({
271
279
  layer: toLayer(registration),
272
- version: readShippingVersion(registration.sourcePath),
280
+ version: readShippingPackage(registration.sourcePath).version,
273
281
  }));
274
282
  }
@@ -11,7 +11,8 @@ const semver_1 = __importDefault(require("semver"));
11
11
  const layers_1 = require("./layers");
12
12
  const output_1 = require("./output");
13
13
  const guards_1 = require("./internal/guards");
14
- const OWN_RELEASE = require("../package.json");
14
+ const plain_object_1 = require("./internal/plain-object");
15
+ const own_release_1 = require("./internal/own-release");
15
16
  const noticedModules = new Set();
16
17
  const NOTICED_MODULES_FILE = ".renderer-range-noticed";
17
18
  function readNoticedModules(workspaceDir) {
@@ -35,10 +36,11 @@ function shownModule(layer) {
35
36
  return layer.packageName ? `${layer.packageName} (${where})` : where;
36
37
  }
37
38
  function declaredRange(layer, rendererName) {
39
+ const engines = (0, layers_1.readLayerPackage)(layer.path)?.engines;
38
40
  return {
39
41
  module: moduleLabel(layer),
40
42
  shown: shownModule(layer),
41
- range: (0, layers_1.readLayerPackage)(layer.path)?.engines?.[rendererName],
43
+ range: (0, plain_object_1.isPlainObject)(engines) ? engines[rendererName] : undefined,
42
44
  };
43
45
  }
44
46
  function releaseLine(version) {
@@ -73,7 +75,7 @@ function noticeUndeclared(declarations, renderer, warn, workspaceDir) {
73
75
  });
74
76
  }
75
77
  function assertLayersSupportRenderer(layers, options = {}) {
76
- const renderer = options.renderer ?? OWN_RELEASE;
78
+ const renderer = options.renderer ?? own_release_1.ownRelease;
77
79
  const declarations = layers.map((layer) => declaredRange(layer, renderer.name));
78
80
  noticeUndeclared(declarations, renderer, options.warn ??
79
81
  ((text, messageOptions) => (0, cli_1.getProcessUi)().message("warn", text, messageOptions)), options.workspaceDir);
@@ -73,7 +73,7 @@ function readListenError(message) {
73
73
  function readStartError(message) {
74
74
  if (!isServerMessage(message) || message.type !== START_ERROR_MESSAGE)
75
75
  return undefined;
76
- const { location } = message;
76
+ const location = message.location;
77
77
  const isLocated = hasFile(location);
78
78
  return {
79
79
  message: String(message.message),
@@ -8,6 +8,8 @@ const cli_1 = require("@antelopejs/core/cli");
8
8
  const child_output_1 = require("./child-output");
9
9
  const build_action_1 = require("./commands/build-action");
10
10
  const common_1 = require("./common");
11
+ const text_list_1 = require("./internal/text-list");
12
+ const plain_object_1 = require("./internal/plain-object");
11
13
  const typecheck_output_1 = require("./typecheck-output");
12
14
  const verify_source_result_1 = require("./verify-source-result");
13
15
  const vite_output_1 = require("./vite-output");
@@ -39,8 +41,14 @@ const TYPECHECK_CONFIG = "tsconfig.verify.json";
39
41
  function snapshotTypeDeclarations(workspace) {
40
42
  (0, node_fs_1.cpSync)((0, node_path_1.join)(workspace, AUTO_IMPORTS_DECLARATIONS), (0, node_path_1.join)(workspace, AUTO_IMPORTS_SNAPSHOT));
41
43
  const config = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(workspace, "tsconfig.json"), "utf8"));
42
- config.files = (config.files ?? []).map((file) => file === AUTO_IMPORTS_DECLARATIONS ? AUTO_IMPORTS_SNAPSHOT : file);
43
- if (!config.files.includes(AUTO_IMPORTS_SNAPSHOT))
44
+ const listed = (0, plain_object_1.isPlainObject)(config) ? (config.files ?? []) : undefined;
45
+ if (!(0, plain_object_1.isPlainObject)(config) || !(0, text_list_1.isTextList)(listed))
46
+ throw new cli_1.CliError({
47
+ title: "The workspace tsconfig.json does not list its files as paths",
48
+ });
49
+ const files = listed.map((file) => file === AUTO_IMPORTS_DECLARATIONS ? AUTO_IMPORTS_SNAPSHOT : file);
50
+ config.files = files;
51
+ if (!files.includes(AUTO_IMPORTS_SNAPSHOT))
44
52
  throw new cli_1.CliError({
45
53
  title: `The workspace tsconfig.json does not list ${AUTO_IMPORTS_DECLARATIONS}`,
46
54
  });
@@ -0,0 +1 @@
1
+ export declare function checkClientBundle(workspace: string): void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkClientBundle = checkClientBundle;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const ensure_1 = require("./internal/ensure");
7
+ const vite_manifest_1 = require("./internal/vite-manifest");
8
+ const LAZY_LIBRARIES = [
9
+ { name: "ApexCharts", pattern: /ApexCharts/ },
10
+ { name: "Tiptap", pattern: /tiptap/i },
11
+ ];
12
+ const RUNTIME_MARKERS = ["auth/login", "DefaultLayout", "error.500.title"];
13
+ function checkClientBundle(workspace) {
14
+ const clientRoot = (0, node_path_1.join)(workspace, "dist", "client");
15
+ const manifest = (0, vite_manifest_1.parseViteManifest)((0, node_fs_1.readFileSync)((0, node_path_1.join)(clientRoot, ".vite", "manifest.json"), "utf8"), "client build manifest");
16
+ const mainEntry = manifest.find((entry) => entry.isEntry);
17
+ (0, ensure_1.ensure)(mainEntry !== undefined, "The Vite manifest names no entry chunk");
18
+ const mainJavascript = (0, node_fs_1.readFileSync)((0, node_path_1.join)(clientRoot, mainEntry.file), "utf8");
19
+ const javascript = (0, node_fs_1.readdirSync)((0, node_path_1.join)(clientRoot, "assets"))
20
+ .filter((file) => file.endsWith(".js"))
21
+ .map((file) => (0, node_fs_1.readFileSync)((0, node_path_1.join)(clientRoot, "assets", file), "utf8"))
22
+ .join("\n");
23
+ for (const { name, pattern } of LAZY_LIBRARIES) {
24
+ (0, ensure_1.ensure)(!pattern.test(mainJavascript), `The main chunk bundles ${name}`, "It must stay in a lazily loaded chunk.");
25
+ (0, ensure_1.ensure)(pattern.test(javascript), `No client chunk bundles ${name}`);
26
+ }
27
+ (0, ensure_1.ensure)(manifest.some((chunk) => chunk.src?.endsWith("/kpi/KpiCard.vue")), "DmsKpiCard is not reachable at runtime");
28
+ for (const marker of RUNTIME_MARKERS)
29
+ (0, ensure_1.ensure)(javascript.includes(marker), `${marker} is not reachable at runtime`);
30
+ }