@antelopejs/dms-frontend 0.3.7 → 0.3.9

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 (81) hide show
  1. package/README.md +82 -23
  2. package/dist/cancellation.d.ts +8 -0
  3. package/dist/cancellation.js +23 -0
  4. package/dist/child-output.d.ts +45 -0
  5. package/dist/child-output.js +183 -0
  6. package/dist/commands/build-action.d.ts +21 -0
  7. package/dist/commands/build-action.js +144 -0
  8. package/dist/commands/build.js +54 -62
  9. package/dist/commands/clean-action.d.ts +8 -0
  10. package/dist/commands/clean-action.js +97 -0
  11. package/dist/commands/clean.js +52 -39
  12. package/dist/commands/dev-action.d.ts +8 -0
  13. package/dist/commands/dev-action.js +120 -0
  14. package/dist/commands/dev.js +55 -115
  15. package/dist/commands/prepare-action.d.ts +8 -0
  16. package/dist/commands/prepare-action.js +73 -0
  17. package/dist/commands/prepare.js +55 -54
  18. package/dist/commands/start-action.d.ts +5 -0
  19. package/dist/commands/start-action.js +77 -0
  20. package/dist/commands/start.js +48 -48
  21. package/dist/commands/verify-source-action.d.ts +10 -0
  22. package/dist/commands/verify-source-action.js +104 -0
  23. package/dist/commands/verify-source.d.ts +0 -1
  24. package/dist/commands/verify-source.js +53 -31
  25. package/dist/commands/workspace-task.d.ts +2 -0
  26. package/dist/commands/workspace-task.js +26 -0
  27. package/dist/commands/workspaces-action.d.ts +25 -0
  28. package/dist/commands/workspaces-action.js +71 -0
  29. package/dist/commands/workspaces.d.ts +2 -0
  30. package/dist/commands/workspaces.js +60 -0
  31. package/dist/common.d.ts +1 -0
  32. package/dist/common.js +1 -0
  33. package/dist/config.d.ts +13 -4
  34. package/dist/config.js +115 -18
  35. package/dist/derived-outputs.d.ts +6 -1
  36. package/dist/derived-outputs.js +12 -3
  37. package/dist/discovery.d.ts +2 -1
  38. package/dist/discovery.js +28 -11
  39. package/dist/env-file.js +5 -2
  40. package/dist/help.d.ts +5 -0
  41. package/dist/help.js +70 -0
  42. package/dist/index.js +98 -38
  43. package/dist/layer-watch.d.ts +2 -1
  44. package/dist/layer-watch.js +129 -26
  45. package/dist/layers.d.ts +2 -2
  46. package/dist/layers.js +71 -23
  47. package/dist/manifest-secrets.d.ts +3 -2
  48. package/dist/manifest-secrets.js +25 -21
  49. package/dist/manifest.d.ts +22 -5
  50. package/dist/manifest.js +184 -28
  51. package/dist/materialize.js +2 -1
  52. package/dist/output.d.ts +41 -0
  53. package/dist/output.js +197 -0
  54. package/dist/ports.d.ts +2 -0
  55. package/dist/ports.js +23 -13
  56. package/dist/renderer-range.d.ts +3 -1
  57. package/dist/renderer-range.js +49 -17
  58. package/dist/server-process.d.ts +39 -0
  59. package/dist/server-process.js +221 -0
  60. package/dist/typecheck-output.d.ts +13 -0
  61. package/dist/typecheck-output.js +87 -0
  62. package/dist/update-check.d.ts +14 -2
  63. package/dist/update-check.js +95 -29
  64. package/dist/verify-source-result.d.ts +11 -0
  65. package/dist/verify-source-result.js +17 -0
  66. package/dist/verify-source-runner.js +266 -131
  67. package/dist/vite-output.d.ts +14 -0
  68. package/dist/vite-output.js +99 -0
  69. package/dist/workspace-setup.d.ts +17 -3
  70. package/dist/workspace-setup.js +119 -35
  71. package/dist/workspace.d.ts +8 -2
  72. package/dist/workspace.js +47 -12
  73. package/package.json +4 -12
  74. package/templates/vue/frontend-module.ts +32 -10
  75. package/templates/vue/package.json +4 -0
  76. package/templates/vue/server/cli-report.mjs +91 -0
  77. package/templates/vue/server.mjs +45 -21
  78. package/templates/vue/vite.config.ts +8 -1
  79. package/templates/vue/vite.email.config.ts +5 -1
  80. package/dist/utils/cli-ui.d.ts +0 -27
  81. package/dist/utils/cli-ui.js +0 -178
package/dist/index.js CHANGED
@@ -1,63 +1,123 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
3
  Object.defineProperty(exports, "__esModule", { value: true });
7
- const chalk_1 = __importDefault(require("chalk"));
4
+ const cli_1 = require("@antelopejs/core/cli");
8
5
  const commander_1 = require("commander");
6
+ const cancellation_1 = require("./cancellation");
9
7
  const build_1 = require("./commands/build");
10
8
  const clean_1 = require("./commands/clean");
11
9
  const dev_1 = require("./commands/dev");
12
10
  const prepare_1 = require("./commands/prepare");
13
11
  const start_1 = require("./commands/start");
14
12
  const verify_source_1 = require("./commands/verify-source");
13
+ const workspaces_1 = require("./commands/workspaces");
15
14
  const env_file_1 = require("./env-file");
15
+ const help_1 = require("./help");
16
+ const output_1 = require("./output");
16
17
  const update_check_1 = require("./update-check");
17
- const cli_ui_1 = require("./utils/cli-ui");
18
18
  const { version } = require("../package.json");
19
+ const GLOBAL_FLAGS = ["--no-color", "--verbose"];
20
+ const ROOT_EXAMPLES = [
21
+ {
22
+ description: "Inside a project started with ajs project dev",
23
+ command: "ajs dms dev",
24
+ },
25
+ {
26
+ description: "Build for production, then serve the build",
27
+ command: "ajs dms build -b https://dms.example.com",
28
+ },
29
+ {
30
+ description: "Serve it on another port",
31
+ command: "ajs dms start -b https://dms.example.com -p 3001",
32
+ },
33
+ ];
34
+ function describeVersion(version, width) {
35
+ const name = `ajs dms ${version}`;
36
+ const line = [
37
+ (0, cli_1.unbreakable)(name),
38
+ "DMS frontend for AntelopeJS (Vue 3, Vite, Inertia)",
39
+ ].join((0, cli_1.getProcessUi)().symbols.separator);
40
+ const [first, ...rest] = (0, cli_1.wrapText)(line, width);
41
+ const title = first.replace(name, (0, cli_1.getProcessPalette)("result").bold(name));
42
+ return `${[title, ...rest].join("\n")}\n`;
43
+ }
44
+ function describeHelpFooter(width) {
45
+ const pointer = `Run ${(0, cli_1.unbreakable)("ajs dms <command> --help")} for its options and examples, and ` +
46
+ `${(0, cli_1.unbreakable)(`ajs dms help ${help_1.ENVIRONMENT_TOPIC}`)} for the variables read from the environment.`;
47
+ return [
48
+ "",
49
+ (0, cli_1.formatExamples)(ROOT_EXAMPLES, width),
50
+ "",
51
+ ...(0, cli_1.wrapText)(pointer, width),
52
+ ].join("\n");
53
+ }
54
+ function ownArguments(args) {
55
+ return args.filter((arg) => !GLOBAL_FLAGS.includes(arg));
56
+ }
57
+ function isInvocation(args, rest) {
58
+ const own = ownArguments(args);
59
+ return own.length === rest.length && own.every((arg, i) => arg === rest[i]);
60
+ }
61
+ function unknownHelpSubject(program, args) {
62
+ const [first, subject, ...rest] = ownArguments(args);
63
+ if (first !== "help" || subject === undefined || rest.length > 0) {
64
+ return undefined;
65
+ }
66
+ const known = [
67
+ ...program.commands.map((command) => command.name()),
68
+ "help",
69
+ help_1.ENVIRONMENT_TOPIC,
70
+ ];
71
+ return known.includes(subject) ? undefined : subject;
72
+ }
19
73
  const runCLI = async () => {
74
+ (0, output_1.exitOnBrokenPipe)();
20
75
  (0, env_file_1.loadProjectEnv)();
21
76
  const argv = process.argv.slice(2);
22
- void (0, update_check_1.checkForUpdate)({ currentVersion: version, argv });
23
- if (process.argv.length <= 2) {
24
- (0, cli_ui_1.displayBanner)("Antelope DMS");
25
- console.log(chalk_1.default.dim(` Frontend Loader for AntelopeJS DMS - v${version}\n`));
26
- }
77
+ (0, update_check_1.startProcessUpdateCheck)({ currentVersion: version, argv });
27
78
  const program = new commander_1.Command()
28
79
  .name("ajs dms")
29
- .description(`Antelope DMS - Frontend Loader v${version}\n\n` +
30
- `Materializes frontend modules from an AntelopeJS backend and starts a Vue or React Vite and Inertia application.`)
31
- .version(version, "-v, --version", "Display version number")
32
- .option("--no-update-check", "Skip the daily check for a newer DMS frontend release")
33
- .helpCommand("help [command]", "Display help for a specific command")
34
- .addHelpText("after", `
35
- Environment:
36
- Every command reads ${env_file_1.ENV_FILE_NAMES.join(" then ")} from the current directory before parsing
37
- its options, so DMS_API_BASE_URL, DMS_BOOTSTRAP_SECRET, DMS_SESSION_SECRET and
38
- the other variables below can live in the project's .env. A variable already
39
- set in the environment always wins over a file, and .env.local wins over .env.
40
- The generated workspace never loads a .env of its own.
41
- 'dev' generates an ephemeral 32-byte DMS_SESSION_SECRET when it is absent;
42
- restarting dev invalidates its sessions. 'build' and 'start' require a
43
- configured secret of at least 32 characters.
44
-
45
- Workspaces:
46
- Each canonical backend URL gets its own workspace under
47
- ~/.antelopejs/dms-frontend. 'dev' without -b is the exception: it keys the
48
- workspace on the antelope project directory instead, so a backend that lands
49
- on a different port between runs keeps its node_modules and manifest cache.
50
- Pass -b to 'dev' to share one workspace with 'build' and 'start'.`);
80
+ .version(version, "-v, --version", "Print the version")
81
+ .option("--no-color", "Disable colors (also NO_COLOR=1)")
82
+ .option("--verbose", "Show full output and stack traces (also ANTELOPEJS_VERBOSE)")
83
+ .option("--no-update-check", "Skip the daily update check (also NO_UPDATE_NOTIFIER=1)")
84
+ .addHelpText("before", (context) => describeVersion(version, (0, cli_1.helpTextWidth)(context)))
85
+ .addHelpText("after", (context) => describeHelpFooter((0, cli_1.helpTextWidth)(context)));
51
86
  program.addCommand((0, dev_1.cmdDev)());
52
87
  program.addCommand((0, build_1.cmdBuild)());
53
88
  program.addCommand((0, start_1.cmdStart)());
54
89
  program.addCommand((0, prepare_1.cmdPrepare)());
90
+ program.addCommand((0, workspaces_1.cmdWorkspaces)());
55
91
  program.addCommand((0, clean_1.cmdClean)());
56
92
  program.addCommand((0, verify_source_1.cmdVerifySource)());
57
- await program.parseAsync((0, update_check_1.stripUpdateCheckFlag)(argv), { from: "user" });
93
+ (0, help_1.applyDmsHelp)(program);
94
+ (0, cli_1.formatUsageErrors)(program);
95
+ const args = (0, update_check_1.stripUpdateCheckFlag)(argv);
96
+ if (isInvocation(args, [])) {
97
+ program.outputHelp();
98
+ return;
99
+ }
100
+ if (isInvocation(args, ["help", help_1.ENVIRONMENT_TOPIC])) {
101
+ (0, cli_1.getProcessUi)().value((0, help_1.formatEnvironmentHelp)());
102
+ return;
103
+ }
104
+ const helpSubject = unknownHelpSubject(program, args);
105
+ if (helpSubject !== undefined) {
106
+ program.error(`error: unknown command '${helpSubject}'`, {
107
+ code: "commander.unknownCommand",
108
+ });
109
+ }
110
+ try {
111
+ await program.parseAsync(args, { from: "user" });
112
+ }
113
+ catch (err) {
114
+ if (!(err instanceof cancellation_1.CancelledError))
115
+ throw err;
116
+ (0, output_1.reportStopped)(err);
117
+ process.exitCode = err.exitCode;
118
+ return;
119
+ }
120
+ if (!process.exitCode)
121
+ await (0, update_check_1.reportAvailableUpdate)();
58
122
  };
59
- process.on("SIGINT", () => process.exit(0));
60
- runCLI().catch((err) => {
61
- console.error(chalk_1.default.red("Error:"), err.message || err);
62
- process.exit(1);
63
- });
123
+ void (0, cli_1.runWithErrorBoundary)(runCLI, { verbose: (0, cli_1.isVerboseRun)() }).then(() => process.exit());
@@ -1,2 +1,3 @@
1
+ import { type Ui } from "@antelopejs/core/cli";
1
2
  import { ResolvedLayer } from "./workspace";
2
- export declare function startLayerWatchers(workspaceDir: string, layers: ResolvedLayer[]): () => Promise<void>;
3
+ export declare function startLayerWatchers(workspaceDir: string, layers: ResolvedLayer[], ui?: Ui, write?: (text: string) => void): () => Promise<void>;
@@ -6,25 +6,48 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.startLayerWatchers = startLayerWatchers;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = require("node:path");
9
+ const cli_1 = require("@antelopejs/core/cli");
9
10
  const chokidar_1 = __importDefault(require("chokidar"));
11
+ const child_output_1 = require("./child-output");
10
12
  const layers_1 = require("./layers");
11
13
  const derived_outputs_1 = require("./derived-outputs");
14
+ const output_1 = require("./output");
12
15
  const fs_sync_1 = require("./fs-sync");
13
16
  const WATCH_DEBOUNCE_MS = 80;
14
17
  const DERIVED_REFRESH_DEBOUNCE_MS = 100;
15
- function createLayerSync(src, dest, onFlushed) {
18
+ function capitalize(text) {
19
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
20
+ }
21
+ function createSyncFailures(src, reporter) {
22
+ const failed = new Set();
23
+ const show = (rel) => reporter.show((0, node_path_1.join)(src, rel));
24
+ return {
25
+ fail(rel, err) {
26
+ failed.add(rel);
27
+ reporter.warn(`${show(rel)} not copied to the workspace`, {
28
+ details: [
29
+ ...reporter.describe(err),
30
+ "The dev server keeps its previous version until the next save.",
31
+ ],
32
+ });
33
+ },
34
+ applied(rel) {
35
+ if (failed.delete(rel))
36
+ reporter.succeed(`${show(rel)} copied to the workspace`);
37
+ },
38
+ };
39
+ }
40
+ function createLayerSync(src, dest, onFlushed, reporter) {
16
41
  const fileUpserts = new Set();
17
42
  const fileDeletes = new Set();
18
43
  const dirCreates = new Set();
19
44
  const dirDeletes = new Set();
45
+ const failures = createSyncFailures(src, reporter);
20
46
  let timer = null;
21
47
  const toRel = (p) => {
22
48
  const r = (0, node_path_1.relative)(src, p);
23
49
  return r ? r : null;
24
50
  };
25
- const warnFailure = (rel, err) => {
26
- console.warn(`[ajs-dms] layer sync skipped ${rel}:`, err);
27
- };
28
51
  const flush = () => {
29
52
  timer = null;
30
53
  const touched = [
@@ -36,9 +59,10 @@ function createLayerSync(src, dest, onFlushed) {
36
59
  for (const rel of [...dirCreates].sort((a, b) => a.length - b.length)) {
37
60
  try {
38
61
  (0, node_fs_1.mkdirSync)((0, node_path_1.join)(dest, rel), { recursive: true });
62
+ failures.applied(rel);
39
63
  }
40
64
  catch (err) {
41
- warnFailure(rel, err);
65
+ failures.fail(rel, err);
42
66
  }
43
67
  }
44
68
  dirCreates.clear();
@@ -54,9 +78,10 @@ function createLayerSync(src, dest, onFlushed) {
54
78
  else {
55
79
  (0, fs_sync_1.applyFile)(srcPath, destPath);
56
80
  }
81
+ failures.applied(rel);
57
82
  }
58
83
  catch (err) {
59
- warnFailure(rel, err);
84
+ failures.fail(rel, err);
60
85
  }
61
86
  }
62
87
  fileUpserts.clear();
@@ -67,9 +92,10 @@ function createLayerSync(src, dest, onFlushed) {
67
92
  const destPath = (0, node_path_1.join)(dest, rel);
68
93
  if ((0, node_fs_1.existsSync)(destPath))
69
94
  (0, node_fs_1.rmSync)(destPath, { force: true });
95
+ failures.applied(rel);
70
96
  }
71
97
  catch (err) {
72
- warnFailure(rel, err);
98
+ failures.fail(rel, err);
73
99
  }
74
100
  }
75
101
  fileDeletes.clear();
@@ -80,9 +106,10 @@ function createLayerSync(src, dest, onFlushed) {
80
106
  const destPath = (0, node_path_1.join)(dest, rel);
81
107
  if ((0, node_fs_1.existsSync)(destPath))
82
108
  (0, node_fs_1.rmSync)(destPath, { recursive: true, force: true });
109
+ failures.applied(rel);
83
110
  }
84
111
  catch (err) {
85
- warnFailure(rel, err);
112
+ failures.fail(rel, err);
86
113
  }
87
114
  }
88
115
  dirDeletes.clear();
@@ -133,40 +160,106 @@ function createLayerSync(src, dest, onFlushed) {
133
160
  },
134
161
  };
135
162
  }
136
- function createDerivedOutputRefresher(workspaceDir, layers) {
137
- const pending = new Set();
163
+ function describeOutputFailure(output, err, reporter) {
164
+ const kept = `The dev server keeps the previous ${output.name} until the file is fixed.`;
165
+ if (err instanceof derived_outputs_1.InvalidLocaleFileError) {
166
+ const file = reporter.show(err.path);
167
+ return {
168
+ text: `${file} is not a valid locale file`,
169
+ options: { details: [err.reason, kept] },
170
+ fixed: [`${file} fixed`, `${output.name} regenerated`].join((0, cli_1.getProcessUi)().symbols.separator),
171
+ };
172
+ }
173
+ return {
174
+ text: `${capitalize(output.name)} not regenerated`,
175
+ options: { details: [...reporter.describe(err), kept] },
176
+ fixed: `${capitalize(output.name)} regenerated`,
177
+ };
178
+ }
179
+ function describeLayerDirectories(paths, reporter) {
180
+ const layers = [...new Set(paths)].filter((path) => !paths.some((other) => other.startsWith(`${path}${node_path_1.sep}`)));
181
+ const shown = layers.map((path) => reporter.show(path));
182
+ if (shown.length !== 1)
183
+ return `Layer directories added or removed: ${shown.join(", ")}`;
184
+ return (0, node_fs_1.existsSync)(layers[0])
185
+ ? `New layer directory ${shown[0]}`
186
+ : `Layer directory ${shown[0]} removed`;
187
+ }
188
+ function createDerivedOutputRefresher(workspaceDir, layers, reporter) {
189
+ const pending = new Map();
190
+ const failures = new Map();
191
+ let hasRestartNotice = false;
138
192
  let timer = null;
139
- const regenerate = (output, registry) => {
193
+ const fail = (key, failure) => {
194
+ failures.set(key, failure);
195
+ reporter.warn(failure.text, failure.options);
196
+ };
197
+ const recover = (key) => {
198
+ const failure = failures.get(key);
199
+ if (!failure)
200
+ return;
201
+ failures.delete(key);
202
+ reporter.succeed(failure.fixed);
203
+ };
204
+ const noticeRestart = (output, paths) => {
205
+ if (!output.restartHint || hasRestartNotice)
206
+ return;
207
+ hasRestartNotice = true;
208
+ reporter.warn(describeLayerDirectories(paths, reporter), {
209
+ fixes: [output.restartHint],
210
+ });
211
+ };
212
+ const regenerate = (output, paths, registry) => {
140
213
  try {
141
- if (output.write(workspaceDir, registry) && output.restartNotice)
142
- console.warn(`[ajs-dms] ${output.restartNotice}`);
214
+ const isChanged = output.write(workspaceDir, registry);
215
+ recover(output);
216
+ if (isChanged)
217
+ noticeRestart(output, paths);
143
218
  }
144
219
  catch (err) {
145
- console.warn(`[ajs-dms] ${output.name} not regenerated:`, err);
220
+ fail(output, describeOutputFailure(output, err, reporter));
146
221
  }
147
222
  };
148
223
  const refresh = () => {
149
224
  timer = null;
150
- const outputs = derived_outputs_1.DERIVED_OUTPUTS.filter((output) => pending.has(output));
225
+ const outputs = derived_outputs_1.DERIVED_OUTPUTS.filter((output) => pending.has(output)).map((output) => [output, pending.get(output) ?? []]);
151
226
  pending.clear();
152
227
  let registry;
153
228
  try {
154
229
  registry = (0, derived_outputs_1.createFrontendModuleRegistry)(workspaceDir, layers);
230
+ recover("registry");
155
231
  }
156
232
  catch (err) {
157
- console.warn("[ajs-dms] derived files not regenerated:", err);
233
+ fail("registry", {
234
+ text: "Derived files not regenerated",
235
+ options: {
236
+ details: [
237
+ ...reporter.describe(err),
238
+ "The dev server keeps the previous ones until the module is fixed.",
239
+ ],
240
+ },
241
+ fixed: "Derived files regenerated",
242
+ });
158
243
  return;
159
244
  }
160
- for (const output of outputs)
161
- regenerate(output, registry);
245
+ for (const [output, paths] of outputs)
246
+ regenerate(output, paths, registry);
162
247
  };
163
248
  return {
164
- schedule(paths) {
165
- const affected = derived_outputs_1.DERIVED_OUTPUTS.filter((output) => paths.some((path) => output.affects(path)));
166
- if (affected.length === 0)
249
+ schedule(src, paths) {
250
+ let isAffected = false;
251
+ for (const output of derived_outputs_1.DERIVED_OUTPUTS) {
252
+ const affected = paths.filter((path) => output.affects(path));
253
+ if (affected.length === 0)
254
+ continue;
255
+ isAffected = true;
256
+ pending.set(output, [
257
+ ...(pending.get(output) ?? []),
258
+ ...affected.map((path) => (0, node_path_1.join)(src, path)),
259
+ ]);
260
+ }
261
+ if (!isAffected)
167
262
  return;
168
- for (const output of affected)
169
- pending.add(output);
170
263
  if (timer)
171
264
  clearTimeout(timer);
172
265
  timer = setTimeout(refresh, DERIVED_REFRESH_DEBOUNCE_MS);
@@ -179,16 +272,26 @@ function createDerivedOutputRefresher(workspaceDir, layers) {
179
272
  },
180
273
  };
181
274
  }
182
- function startLayerWatchers(workspaceDir, layers) {
275
+ function startLayerWatchers(workspaceDir, layers, ui = (0, cli_1.getProcessUi)(), write = output_1.writeFeedback) {
276
+ const mapPath = (0, child_output_1.createPathMapper)(workspaceDir, layers.map((layer) => ({ ...layer, sourcePath: layer.path })));
277
+ const reporter = {
278
+ warn: (text, options) => write((0, output_1.formatTimedMessage)("warn", text, options, ui)),
279
+ succeed: (text) => write((0, output_1.formatTimedMessage)("success", text, {}, ui)),
280
+ describe: (error) => (0, output_1.failureDetails)(error, ui).map((line) => mapPath(line)),
281
+ show: (path) => {
282
+ const mapped = mapPath(path);
283
+ return mapped === path ? (0, output_1.showPath)(path) : mapped;
284
+ },
285
+ };
183
286
  const watchers = [];
184
287
  const syncs = [];
185
- const refresher = createDerivedOutputRefresher(workspaceDir, layers);
288
+ const refresher = createDerivedOutputRefresher(workspaceDir, layers, reporter);
186
289
  for (const layer of layers) {
187
290
  if (!layer.packageName)
188
291
  continue;
189
292
  const dest = (0, layers_1.getLayerWorkspacePath)(workspaceDir, layer);
190
293
  const src = layer.path;
191
- const sync = createLayerSync(src, dest, (paths) => refresher.schedule(paths));
294
+ const sync = createLayerSync(src, dest, (paths) => refresher.schedule(src, paths), reporter);
192
295
  syncs.push(sync);
193
296
  const watcher = chokidar_1.default.watch(src, {
194
297
  ignoreInitial: true,
package/dist/layers.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { ServedWithPath } from "./manifest";
2
2
  import { ManifestModule, ResolvedLayer } from "./workspace";
3
- export declare function assertLayerPathsServed(modules: ManifestModule[]): asserts modules is ServedWithPath[];
3
+ export declare function assertLayerPathsServed(modules: ManifestModule[], backendUrl: string, bootstrapSecret?: string): asserts modules is ServedWithPath[];
4
4
  export declare function assertCachedArchivesExist(modules: ManifestModule[], cacheDir: string, fetchedAt?: string): void;
5
5
  export interface LayerPackage {
6
6
  name?: unknown;
7
7
  engines?: Record<string, unknown>;
8
8
  }
9
9
  export declare function readLayerPackage(layerPath: string): LayerPackage | undefined;
10
- export declare function buildLayersFromPaths(modules: ManifestModule[]): ResolvedLayer[];
10
+ export declare function buildLayersFromPaths(modules: ServedWithPath[]): ResolvedLayer[];
11
11
  export declare function downloadAndExtractLayers(backendUrl: string, packUrl: string, cacheDir: string, force: boolean, bootstrapSecret?: string): Promise<void>;
12
12
  export declare function buildLayersFromCache(modules: ManifestModule[], cacheDir: string): Promise<ResolvedLayer[]>;
13
13
  export declare function getLayerSafeName(layer: ResolvedLayer): string;
package/dist/layers.js CHANGED
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.assertLayerPathsServed = assertLayerPathsServed;
4
37
  exports.assertCachedArchivesExist = assertCachedArchivesExist;
@@ -13,30 +46,46 @@ const promises_1 = require("node:fs/promises");
13
46
  const node_path_1 = require("node:path");
14
47
  const node_stream_1 = require("node:stream");
15
48
  const consumers_1 = require("node:stream/consumers");
16
- const unzipper_1 = require("unzipper");
49
+ const cli_1 = require("@antelopejs/core/cli");
17
50
  const manifest_1 = require("./manifest");
18
- const workspace_1 = require("./workspace");
19
51
  const fs_sync_1 = require("./fs-sync");
20
52
  const config_1 = require("./config");
21
- function assertLayerPathsServed(modules) {
53
+ const output_1 = require("./output");
54
+ function assertLayerPathsServed(modules, backendUrl, bootstrapSecret) {
22
55
  const pathless = modules.filter((mod) => !mod.path);
23
56
  if (pathless.length === 0)
24
57
  return;
25
- throw new Error("The backend served a manifest without layer source paths:\n" +
26
- pathless.map((mod) => ` - ${mod.name}`).join("\n") +
27
- "\n`ajs dms dev` needs a development backend running on this machine (started with " +
28
- "`ajs project dev`); use `ajs dms build` against a remote or production one.\n" +
29
- "If the backend is local and in development mode, it did not recognize the bootstrap " +
30
- "credential — see DMS_BOOTSTRAP_SECRET.");
58
+ const count = `${pathless.length} of ${modules.length} module${modules.length === 1 ? "" : "s"}`;
59
+ const { reason, fix } = bootstrapSecret
60
+ ? {
61
+ reason: "It sends them only to callers presenting its development credential, and did not accept the one this run sent.",
62
+ fix: "Run the command from the antelope project started with `ajs project dev`, without DMS_BOOTSTRAP_SECRET or --bootstrap-secret, so the credential is read from .antelope/dms-dev.json",
63
+ }
64
+ : {
65
+ reason: "It sends them only to callers presenting its development credential, and this run sent none: " +
66
+ "no DMS_BOOTSTRAP_SECRET or --bootstrap-secret, and no project started with `ajs project dev` " +
67
+ "serving this backend was found from the current directory, so no .antelope/dms-dev.json was read.",
68
+ fix: "Run the command from that project, or set DMS_BOOTSTRAP_SECRET to the backend's credential",
69
+ };
70
+ throw new cli_1.CliError({
71
+ title: `The backend at ${(0, manifest_1.displayUrl)(backendUrl)} did not send layer source paths (${count})`,
72
+ reason,
73
+ fixes: [
74
+ fix,
75
+ "A remote or production backend never sends them: use `ajs dms build` against it",
76
+ ],
77
+ });
31
78
  }
32
79
  function assertCachedArchivesExist(modules, cacheDir, fetchedAt) {
33
80
  const present = new Set((0, node_fs_1.readdirSync)(cacheDir));
34
81
  const missing = modules.filter((mod) => !present.has(mod.archiveName));
35
82
  if (missing.length === 0)
36
83
  return;
37
- throw new Error(`Cached layers archive is missing entries listed in the manifest${fetchedAt ? ` (fetched ${fetchedAt})` : ""}:\n` +
38
- missing.map((mod) => ` - ${mod.name}: ${mod.archiveName}`).join("\n") +
39
- "\nRun once with the backend reachable to re-download the layers.");
84
+ throw new cli_1.CliError({
85
+ title: `The cached layers archive is missing entries listed in the manifest${fetchedAt ? ` (fetched ${(0, output_1.formatAge)(fetchedAt)})` : ""}`,
86
+ fixes: ["Run once with the backend reachable to download the layers again"],
87
+ details: missing.map((mod) => `${mod.name}: ${mod.archiveName}`),
88
+ });
40
89
  }
41
90
  function sortModulesByPriority(modules) {
42
91
  return [...modules].sort((a, b) => b.priority - a.priority);
@@ -59,6 +108,7 @@ function readLayerPackageName(layerPath) {
59
108
  function resolveLayer(layerPath, mod) {
60
109
  return {
61
110
  path: layerPath,
111
+ sourcePath: mod.path,
62
112
  packageName: readLayerPackageName(layerPath),
63
113
  priority: mod.priority,
64
114
  configKey: mod.configKey,
@@ -67,34 +117,32 @@ function resolveLayer(layerPath, mod) {
67
117
  };
68
118
  }
69
119
  function buildLayersFromPaths(modules) {
70
- assertLayerPathsServed(modules);
71
120
  return sortModulesByPriority(modules).map((mod) => resolveLayer(mod.path, mod));
72
121
  }
73
122
  async function downloadAndExtractLayers(backendUrl, packUrl, cacheDir, force, bootstrapSecret) {
74
- const url = `${backendUrl}${packUrl}`;
75
- const response = await fetch(url, {
76
- headers: (0, workspace_1.bootstrapHeaders)(bootstrapSecret),
77
- });
78
- if ((0, workspace_1.isUnauthorized)(response.status)) {
79
- throw new manifest_1.ManifestUnauthorizedError(url, response.status);
123
+ const url = (0, manifest_1.backendEndpoint)(backendUrl, packUrl);
124
+ const response = await (0, manifest_1.fetchFromBackend)(backendUrl, url, bootstrapSecret);
125
+ if (!response.ok) {
126
+ throw new manifest_1.BackendResponseError("the layers archive", url, response);
80
127
  }
81
- if (!response.ok || !response.body) {
82
- throw new Error("Failed to download layers archive");
128
+ if (!response.body) {
129
+ throw new Error(`The layers archive from ${(0, manifest_1.displayUrl)(url)} came without a body`);
83
130
  }
84
131
  const modulesBlob = await (0, consumers_1.buffer)(node_stream_1.Readable.fromWeb(response.body));
132
+ const { Open } = await Promise.resolve().then(() => __importStar(require("unzipper")));
85
133
  const cacheExists = (0, node_fs_1.existsSync)(cacheDir);
86
134
  if (force || !cacheExists) {
87
135
  if (cacheExists) {
88
136
  (0, node_fs_1.rmSync)(cacheDir, { recursive: true, force: true });
89
137
  }
90
- await (await unzipper_1.Open.buffer(modulesBlob)).extract({ path: cacheDir });
138
+ await (await Open.buffer(modulesBlob)).extract({ path: cacheDir });
91
139
  return;
92
140
  }
93
141
  const tempDir = `${cacheDir}_temp`;
94
142
  if ((0, node_fs_1.existsSync)(tempDir)) {
95
143
  (0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true });
96
144
  }
97
- await (await unzipper_1.Open.buffer(modulesBlob)).extract({ path: tempDir });
145
+ await (await Open.buffer(modulesBlob)).extract({ path: tempDir });
98
146
  const tempEntries = (0, node_fs_1.readdirSync)(tempDir);
99
147
  for (const entry of tempEntries) {
100
148
  (0, fs_sync_1.syncDirectories)((0, node_path_1.join)(tempDir, entry), (0, node_path_1.join)(cacheDir, entry));
@@ -1,3 +1,4 @@
1
+ import { type Ui } from "@antelopejs/core/cli";
1
2
  import type { ManifestModule } from "./workspace";
2
3
  export declare const MANIFEST_SECRET_ENV: {
3
4
  readonly DMS_HTML_RENDER_SECRET: readonly ["htmlRender", "serviceSecret"];
@@ -26,6 +27,6 @@ export interface ResolvedManifestSecrets {
26
27
  export declare function collectManifestSecrets(modules: readonly ManifestModule[]): ManifestSecrets;
27
28
  export declare function resolveManifestSecrets(secrets: ManifestSecrets, env?: NodeJS.ProcessEnv): ResolvedManifestSecrets;
28
29
  export declare function formatSecretConflicts(conflicts: readonly ManifestSecretConflict[]): string[];
29
- export declare function formatSecretSources(sources: ResolvedManifestSecrets["sources"], manifestLabel?: string): string[];
30
- export declare function reportManifestSecrets(resolved: ResolvedManifestSecrets, manifestLabel?: string, log?: (line: string) => void): void;
30
+ export declare function describeSecretSources(sources: ResolvedManifestSecrets["sources"], manifestLabel?: string): string | undefined;
31
+ export declare function reportManifestSecrets(resolved: ResolvedManifestSecrets, fix: (count: number) => string, ui?: Ui): void;
31
32
  export {};