@antelopejs/dms-frontend 0.3.8 → 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.
- package/README.md +82 -23
- package/dist/cancellation.d.ts +8 -0
- package/dist/cancellation.js +23 -0
- package/dist/child-output.d.ts +45 -0
- package/dist/child-output.js +183 -0
- package/dist/commands/build-action.d.ts +21 -0
- package/dist/commands/build-action.js +144 -0
- package/dist/commands/build.js +54 -62
- package/dist/commands/clean-action.d.ts +8 -0
- package/dist/commands/clean-action.js +97 -0
- package/dist/commands/clean.js +52 -39
- package/dist/commands/dev-action.d.ts +8 -0
- package/dist/commands/dev-action.js +120 -0
- package/dist/commands/dev.js +55 -115
- package/dist/commands/prepare-action.d.ts +8 -0
- package/dist/commands/prepare-action.js +73 -0
- package/dist/commands/prepare.js +55 -54
- package/dist/commands/start-action.d.ts +5 -0
- package/dist/commands/start-action.js +77 -0
- package/dist/commands/start.js +48 -48
- package/dist/commands/verify-source-action.d.ts +10 -0
- package/dist/commands/verify-source-action.js +104 -0
- package/dist/commands/verify-source.d.ts +0 -1
- package/dist/commands/verify-source.js +53 -31
- package/dist/commands/workspace-task.d.ts +2 -0
- package/dist/commands/workspace-task.js +26 -0
- package/dist/commands/workspaces-action.d.ts +25 -0
- package/dist/commands/workspaces-action.js +71 -0
- package/dist/commands/workspaces.d.ts +2 -0
- package/dist/commands/workspaces.js +60 -0
- package/dist/common.d.ts +1 -0
- package/dist/common.js +1 -0
- package/dist/config.d.ts +13 -4
- package/dist/config.js +115 -18
- package/dist/derived-outputs.d.ts +6 -1
- package/dist/derived-outputs.js +12 -3
- package/dist/discovery.d.ts +2 -1
- package/dist/discovery.js +28 -11
- package/dist/env-file.js +5 -2
- package/dist/help.d.ts +5 -0
- package/dist/help.js +70 -0
- package/dist/index.js +98 -38
- package/dist/layer-watch.d.ts +2 -1
- package/dist/layer-watch.js +129 -26
- package/dist/layers.d.ts +2 -2
- package/dist/layers.js +71 -23
- package/dist/manifest-secrets.d.ts +3 -2
- package/dist/manifest-secrets.js +25 -21
- package/dist/manifest.d.ts +22 -5
- package/dist/manifest.js +184 -28
- package/dist/materialize.js +2 -1
- package/dist/output.d.ts +41 -0
- package/dist/output.js +197 -0
- package/dist/ports.d.ts +2 -0
- package/dist/ports.js +23 -13
- package/dist/renderer-range.d.ts +3 -1
- package/dist/renderer-range.js +49 -17
- package/dist/server-process.d.ts +39 -0
- package/dist/server-process.js +221 -0
- package/dist/typecheck-output.d.ts +13 -0
- package/dist/typecheck-output.js +87 -0
- package/dist/update-check.d.ts +14 -2
- package/dist/update-check.js +95 -29
- package/dist/verify-source-result.d.ts +11 -0
- package/dist/verify-source-result.js +17 -0
- package/dist/verify-source-runner.js +266 -131
- package/dist/vite-output.d.ts +14 -0
- package/dist/vite-output.js +99 -0
- package/dist/workspace-setup.d.ts +17 -3
- package/dist/workspace-setup.js +119 -35
- package/dist/workspace.d.ts +8 -2
- package/dist/workspace.js +47 -12
- package/package.json +4 -12
- package/templates/vue/package.json +4 -0
- package/templates/vue/server/cli-report.mjs +91 -0
- package/templates/vue/server.mjs +18 -15
- package/templates/vue/vite.config.ts +8 -1
- package/templates/vue/vite.email.config.ts +5 -1
- package/dist/utils/cli-ui.d.ts +0 -27
- package/dist/utils/cli-ui.js +0 -178
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type CliProblem, type Ui } from "@antelopejs/core/cli";
|
|
2
|
+
export declare const VITE_LOG_LEVEL_VARIABLE = "DMS_VITE_LOG_LEVEL";
|
|
3
|
+
export declare function viteLogLevel(isVerbose: boolean): string;
|
|
4
|
+
export declare const VERBOSE_VITE_HINT = "Run with --verbose for the full Vite output.";
|
|
5
|
+
export declare class ViteWarnings {
|
|
6
|
+
private readonly kept;
|
|
7
|
+
private opened;
|
|
8
|
+
private isAfterPluginTag;
|
|
9
|
+
read(line: string): void;
|
|
10
|
+
get count(): number;
|
|
11
|
+
lines(): string[];
|
|
12
|
+
}
|
|
13
|
+
export declare function reportViteWarnings(warnings: ViteWarnings, isVerbose: boolean, ui: Ui): void;
|
|
14
|
+
export declare function describeViteFailure(lines: string[], subject: string, isVerbose: boolean, rerun?: string, nameFile?: (file: string) => string): CliProblem | undefined;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ViteWarnings = exports.VERBOSE_VITE_HINT = exports.VITE_LOG_LEVEL_VARIABLE = void 0;
|
|
4
|
+
exports.viteLogLevel = viteLogLevel;
|
|
5
|
+
exports.reportViteWarnings = reportViteWarnings;
|
|
6
|
+
exports.describeViteFailure = describeViteFailure;
|
|
7
|
+
const cli_1 = require("@antelopejs/core/cli");
|
|
8
|
+
const output_1 = require("./output");
|
|
9
|
+
exports.VITE_LOG_LEVEL_VARIABLE = "DMS_VITE_LOG_LEVEL";
|
|
10
|
+
function viteLogLevel(isVerbose) {
|
|
11
|
+
return isVerbose ? "info" : "warn";
|
|
12
|
+
}
|
|
13
|
+
exports.VERBOSE_VITE_HINT = "Run with --verbose for the full Vite output.";
|
|
14
|
+
const WARNING_START = /^(\(!\)|\[plugin[ :][^\]]*\]|\(node:\d+\))/;
|
|
15
|
+
const PLUGIN_TAG_LINE = /^\[plugin[ :][^\]]*\]$/;
|
|
16
|
+
class ViteWarnings {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.kept = [];
|
|
19
|
+
this.opened = 0;
|
|
20
|
+
this.isAfterPluginTag = false;
|
|
21
|
+
}
|
|
22
|
+
read(line) {
|
|
23
|
+
const text = line.trim();
|
|
24
|
+
if (text === "")
|
|
25
|
+
return;
|
|
26
|
+
this.kept.push(line.trimEnd());
|
|
27
|
+
const continuesTag = this.isAfterPluginTag && text.startsWith("(!)");
|
|
28
|
+
if (WARNING_START.test(text) && !continuesTag)
|
|
29
|
+
this.opened += 1;
|
|
30
|
+
this.isAfterPluginTag = PLUGIN_TAG_LINE.test(text);
|
|
31
|
+
}
|
|
32
|
+
get count() {
|
|
33
|
+
if (this.opened === 0 && this.kept.length > 0)
|
|
34
|
+
return 1;
|
|
35
|
+
return this.opened;
|
|
36
|
+
}
|
|
37
|
+
lines() {
|
|
38
|
+
return [...this.kept];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.ViteWarnings = ViteWarnings;
|
|
42
|
+
function reportViteWarnings(warnings, isVerbose, ui) {
|
|
43
|
+
if (isVerbose || warnings.count === 0)
|
|
44
|
+
return;
|
|
45
|
+
const title = (0, cli_1.pluralize)(warnings.count, "Vite warning");
|
|
46
|
+
const details = (0, output_1.isTerminalFeedback)()
|
|
47
|
+
? [`${ui.symbols.levels.hint} Run with --verbose to list them`]
|
|
48
|
+
: warnings.lines();
|
|
49
|
+
ui.message("warn", title, { details });
|
|
50
|
+
}
|
|
51
|
+
const ERROR_START = "error during build:";
|
|
52
|
+
const FILE_LINE = /^file:\s+(.+)$/;
|
|
53
|
+
const CODE_FRAME_LINE = /^\s*\d*\s*\|/;
|
|
54
|
+
const STACK_FRAME = /^\s+at\s/;
|
|
55
|
+
const LOCATION_SUFFIX = /\s*\(\d+:\d+\)$/;
|
|
56
|
+
const VITE_PLUGIN_TAG = /^\[vite:[^\]]+\]\s+(?=\S)/;
|
|
57
|
+
function errorBlock(lines) {
|
|
58
|
+
let start = -1;
|
|
59
|
+
lines.forEach((line, index) => {
|
|
60
|
+
if (line.trim() === ERROR_START)
|
|
61
|
+
start = index;
|
|
62
|
+
});
|
|
63
|
+
if (start < 0)
|
|
64
|
+
return undefined;
|
|
65
|
+
const block = [];
|
|
66
|
+
for (const line of lines.slice(start + 1)) {
|
|
67
|
+
if (STACK_FRAME.test(line))
|
|
68
|
+
break;
|
|
69
|
+
if (line.trim() !== "")
|
|
70
|
+
block.push(line.trimEnd());
|
|
71
|
+
}
|
|
72
|
+
return block;
|
|
73
|
+
}
|
|
74
|
+
function describeViteFailure(lines, subject, isVerbose, rerun = "ajs dms build", nameFile = (file) => file) {
|
|
75
|
+
const block = errorBlock(lines);
|
|
76
|
+
if (!block)
|
|
77
|
+
return undefined;
|
|
78
|
+
const [message = "", ...rest] = block;
|
|
79
|
+
const reason = message
|
|
80
|
+
.replace(LOCATION_SUFFIX, "")
|
|
81
|
+
.replace(VITE_PLUGIN_TAG, "");
|
|
82
|
+
const hint = isVerbose ? [] : [exports.VERBOSE_VITE_HINT];
|
|
83
|
+
const file = rest
|
|
84
|
+
.map((line) => FILE_LINE.exec(line.trim())?.[1])
|
|
85
|
+
.find((match) => match !== undefined);
|
|
86
|
+
if (file) {
|
|
87
|
+
return {
|
|
88
|
+
title: `Vite could not compile ${nameFile(file)}`,
|
|
89
|
+
reason,
|
|
90
|
+
fixes: [`Fix the file and run ${rerun} again`],
|
|
91
|
+
details: [...rest.filter((line) => CODE_FRAME_LINE.test(line)), ...hint],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
title: `Vite could not build the ${subject}`,
|
|
96
|
+
reason,
|
|
97
|
+
details: [...rest, ...hint],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import { type SpawnOptions } from "node:child_process";
|
|
1
|
+
import { type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
2
|
+
import { type PathMapper } from "./child-output";
|
|
2
3
|
import { type ManifestSecrets } from "./manifest-secrets";
|
|
3
4
|
import { ResolvedLayer } from "./workspace";
|
|
4
5
|
export declare function computeDepsHash(layerPaths: string[], workspacePackage?: string, installInputs?: readonly string[]): string;
|
|
5
6
|
export declare function needsInstall(workspaceDir: string, layerPaths: string[], force: boolean): boolean;
|
|
6
7
|
export declare function saveDepsHash(workspaceDir: string, layerPaths: string[]): void;
|
|
7
|
-
export declare function installDeps(workspaceDir: string): void
|
|
8
|
-
export declare function runCommand(command: string, args: string[], options?: SpawnOptions): Promise<number>;
|
|
8
|
+
export declare function installDeps(workspaceDir: string, mapLine?: PathMapper, extraArgs?: string[]): Promise<void>;
|
|
9
|
+
export declare function runCommand(command: string, args: string[], options?: SpawnOptions, onSpawn?: (child: ChildProcess) => void): Promise<number>;
|
|
10
|
+
export interface FramedCommandOptions {
|
|
11
|
+
name: string;
|
|
12
|
+
cwd: string;
|
|
13
|
+
env?: NodeJS.ProcessEnv;
|
|
14
|
+
mapLine?: PathMapper;
|
|
15
|
+
onLine?: (line: string) => void;
|
|
16
|
+
}
|
|
17
|
+
export interface FramedCommandResult {
|
|
18
|
+
code: number;
|
|
19
|
+
lines: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare function runFramedCommand(command: string, args: string[], options: FramedCommandOptions): Promise<FramedCommandResult>;
|
|
9
22
|
export interface SetupWorkspaceOptions {
|
|
10
23
|
backendUrl: string;
|
|
11
24
|
force: boolean;
|
|
@@ -14,6 +27,7 @@ export interface SetupWorkspaceOptions {
|
|
|
14
27
|
clientUrl?: string;
|
|
15
28
|
workspaceKey?: string;
|
|
16
29
|
bootstrapSecret?: string;
|
|
30
|
+
beforeInstall?: () => Promise<void>;
|
|
17
31
|
}
|
|
18
32
|
export interface SetupWorkspaceResult {
|
|
19
33
|
workspaceDir: string;
|
package/dist/workspace-setup.js
CHANGED
|
@@ -5,18 +5,22 @@ exports.needsInstall = needsInstall;
|
|
|
5
5
|
exports.saveDepsHash = saveDepsHash;
|
|
6
6
|
exports.installDeps = installDeps;
|
|
7
7
|
exports.runCommand = runCommand;
|
|
8
|
+
exports.runFramedCommand = runFramedCommand;
|
|
8
9
|
exports.setupWorkspace = setupWorkspace;
|
|
9
10
|
const node_child_process_1 = require("node:child_process");
|
|
10
11
|
const node_crypto_1 = require("node:crypto");
|
|
11
12
|
const node_fs_1 = require("node:fs");
|
|
12
|
-
const node_os_1 = require("node:os");
|
|
13
13
|
const node_path_1 = require("node:path");
|
|
14
|
+
const cli_1 = require("@antelopejs/core/cli");
|
|
15
|
+
const child_output_1 = require("./child-output");
|
|
14
16
|
const layers_1 = require("./layers");
|
|
15
17
|
const manifest_1 = require("./manifest");
|
|
16
18
|
const manifest_secrets_1 = require("./manifest-secrets");
|
|
17
19
|
const renderer_range_1 = require("./renderer-range");
|
|
18
20
|
const materialize_1 = require("./materialize");
|
|
19
21
|
const workspace_1 = require("./workspace");
|
|
22
|
+
const cancellation_1 = require("./cancellation");
|
|
23
|
+
const output_1 = require("./output");
|
|
20
24
|
const config_1 = require("./config");
|
|
21
25
|
const WORKSPACE_PNPM_CONFIG = "pnpm-workspace.yaml";
|
|
22
26
|
const WORKSPACE_PATCHES_DIR = "patches";
|
|
@@ -61,48 +65,77 @@ function saveDepsHash(workspaceDir, layerPaths) {
|
|
|
61
65
|
const hash = computeDepsHash(layerPaths, (0, node_path_1.join)(workspaceDir, "package.json"), workspaceInstallInputs(workspaceDir));
|
|
62
66
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspaceDir, config_1.DEPS_HASH_FILE), hash);
|
|
63
67
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
const PNPM_INSTALL_ARGS = ["install", "--reporter=append-only"];
|
|
69
|
+
async function installDeps(workspaceDir, mapLine, extraArgs = []) {
|
|
70
|
+
const progress = new child_output_1.InstallProgress();
|
|
71
|
+
const task = (0, cli_1.getProcessTasks)().start(progress.label);
|
|
72
|
+
try {
|
|
73
|
+
const { code, lines } = await runFramedCommand("pnpm", [...PNPM_INSTALL_ARGS, ...extraArgs], {
|
|
74
|
+
name: "pnpm",
|
|
75
|
+
cwd: workspaceDir,
|
|
76
|
+
env: { ...process.env, npm_config_update_notifier: "false" },
|
|
77
|
+
mapLine,
|
|
78
|
+
onLine: (line) => {
|
|
79
|
+
if (progress.read(line))
|
|
80
|
+
task.update(progress.label);
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
if (code !== 0) {
|
|
84
|
+
throw new cli_1.CliError((0, child_output_1.describeChildFailure)({
|
|
85
|
+
title: "Dependency install failed",
|
|
86
|
+
command: "pnpm install",
|
|
87
|
+
code,
|
|
88
|
+
lines,
|
|
89
|
+
isVerbose: (0, cli_1.isVerboseRun)(),
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
task.succeed(progress.doneLabel);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
(0, output_1.endInterruptedTask)(task, error, "Dependency install stopped");
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
70
98
|
}
|
|
71
99
|
const FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
72
100
|
const CHILD_SHUTDOWN_TIMEOUT_MS = 5000;
|
|
73
|
-
function
|
|
74
|
-
const number = node_os_1.constants.signals[signal];
|
|
75
|
-
return 128 + (typeof number === "number" ? number : 15);
|
|
76
|
-
}
|
|
77
|
-
function runCommand(command, args, options) {
|
|
101
|
+
function runCommand(command, args, options, onSpawn) {
|
|
78
102
|
const isWindows = process.platform === "win32";
|
|
79
103
|
return new Promise((resolve, reject) => {
|
|
80
104
|
const child = (0, node_child_process_1.spawn)(command, args, {
|
|
81
105
|
stdio: "inherit",
|
|
82
106
|
shell: isWindows,
|
|
83
107
|
...options,
|
|
108
|
+
detached: !isWindows,
|
|
84
109
|
});
|
|
110
|
+
onSpawn?.(child);
|
|
85
111
|
let escalation;
|
|
86
112
|
let forwarded;
|
|
87
113
|
const alive = () => child.exitCode === null && child.signalCode === null;
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
114
|
+
const signalTree = (signal) => {
|
|
115
|
+
if (child.pid === undefined)
|
|
90
116
|
return;
|
|
91
117
|
try {
|
|
92
|
-
|
|
118
|
+
if (isWindows) {
|
|
119
|
+
(0, node_child_process_1.spawnSync)("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
120
|
+
stdio: "ignore",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
process.kill(-child.pid, signal);
|
|
125
|
+
}
|
|
93
126
|
}
|
|
94
127
|
catch {
|
|
95
128
|
}
|
|
129
|
+
};
|
|
130
|
+
const stopChild = (signal) => {
|
|
131
|
+
if (!alive())
|
|
132
|
+
return;
|
|
133
|
+
signalTree(signal);
|
|
96
134
|
if (escalation || isWindows)
|
|
97
135
|
return;
|
|
98
136
|
escalation = setTimeout(() => {
|
|
99
|
-
if (alive())
|
|
100
|
-
|
|
101
|
-
child.kill("SIGKILL");
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
}
|
|
105
|
-
}
|
|
137
|
+
if (alive())
|
|
138
|
+
signalTree("SIGKILL");
|
|
106
139
|
}, CHILD_SHUTDOWN_TIMEOUT_MS);
|
|
107
140
|
escalation.unref();
|
|
108
141
|
};
|
|
@@ -111,13 +144,8 @@ function runCommand(command, args, options) {
|
|
|
111
144
|
stopChild(signal);
|
|
112
145
|
};
|
|
113
146
|
const onParentExit = () => {
|
|
114
|
-
if (alive())
|
|
115
|
-
|
|
116
|
-
child.kill("SIGKILL");
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
}
|
|
120
|
-
}
|
|
147
|
+
if (alive())
|
|
148
|
+
signalTree("SIGKILL");
|
|
121
149
|
};
|
|
122
150
|
for (const signal of FORWARDED_SIGNALS)
|
|
123
151
|
process.on(signal, onSignal);
|
|
@@ -135,22 +163,72 @@ function runCommand(command, args, options) {
|
|
|
135
163
|
});
|
|
136
164
|
child.on("exit", (code, signal) => {
|
|
137
165
|
cleanup();
|
|
166
|
+
if (forwarded) {
|
|
167
|
+
if (!isWindows)
|
|
168
|
+
signalTree("SIGKILL");
|
|
169
|
+
return reject(new cancellation_1.CancelledError(forwarded));
|
|
170
|
+
}
|
|
138
171
|
if (code !== null)
|
|
139
172
|
return resolve(code);
|
|
140
|
-
resolve(exitCodeForSignal(signal ??
|
|
173
|
+
resolve((0, cancellation_1.exitCodeForSignal)(signal ?? "SIGTERM"));
|
|
141
174
|
});
|
|
142
175
|
});
|
|
143
176
|
}
|
|
177
|
+
const OUTPUT_DRAIN_TIMEOUT_MS = 2000;
|
|
178
|
+
function drained(stream) {
|
|
179
|
+
if (!stream)
|
|
180
|
+
return Promise.resolve();
|
|
181
|
+
return new Promise((settle) => {
|
|
182
|
+
stream.once("end", settle);
|
|
183
|
+
stream.once("error", settle);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function drainTimeout() {
|
|
187
|
+
return new Promise((settle) => {
|
|
188
|
+
setTimeout(settle, OUTPUT_DRAIN_TIMEOUT_MS).unref();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
async function runFramedCommand(command, args, options) {
|
|
192
|
+
const { name, cwd, env, mapLine = (line) => line, onLine } = options;
|
|
193
|
+
const isVerbose = (0, cli_1.isVerboseRun)();
|
|
194
|
+
const tails = [new child_output_1.OutputTail(), new child_output_1.OutputTail()];
|
|
195
|
+
const readLine = (tail, line) => {
|
|
196
|
+
const mapped = mapLine(line);
|
|
197
|
+
if (isVerbose)
|
|
198
|
+
(0, child_output_1.writeChildLine)(name, mapped);
|
|
199
|
+
const plain = (0, child_output_1.stripAnsi)(mapped);
|
|
200
|
+
tail.push(plain);
|
|
201
|
+
onLine?.(plain);
|
|
202
|
+
};
|
|
203
|
+
let ended = Promise.resolve();
|
|
204
|
+
const code = await runCommand(command, args, { cwd, env, stdio: ["ignore", "pipe", "pipe"] }, (child) => {
|
|
205
|
+
const streams = [child.stdout, child.stderr];
|
|
206
|
+
for (const [index, stream] of streams.entries()) {
|
|
207
|
+
const splitter = new child_output_1.LineSplitter((line) => readLine(tails[index], line));
|
|
208
|
+
stream?.setEncoding("utf8");
|
|
209
|
+
stream?.on("data", (chunk) => splitter.push(chunk));
|
|
210
|
+
stream?.once("end", () => splitter.flush());
|
|
211
|
+
}
|
|
212
|
+
ended = Promise.all(streams.map((stream) => drained(stream)));
|
|
213
|
+
});
|
|
214
|
+
await Promise.race([ended, drainTimeout()]);
|
|
215
|
+
return { code, lines: tails.flatMap((tail) => tail.lines()) };
|
|
216
|
+
}
|
|
217
|
+
function manifestCacheUse(mode, offline) {
|
|
218
|
+
if (offline)
|
|
219
|
+
return "offline";
|
|
220
|
+
return mode === "build" ? "never" : "fallback";
|
|
221
|
+
}
|
|
144
222
|
async function setupWorkspace(opts) {
|
|
145
223
|
const { backendUrl, force, mode, offline, clientUrl, bootstrapSecret } = opts;
|
|
146
224
|
const workspaceKey = opts.workspaceKey ?? (0, config_1.canonicalizeBackendUrl)(backendUrl);
|
|
147
225
|
const workspaceDir = (0, workspace_1.ensureWorkspace)(workspaceKey);
|
|
148
226
|
(0, workspace_1.writeWorkspaceMeta)(workspaceDir, backendUrl, workspaceKey);
|
|
149
|
-
const resolved = await (0, manifest_1.resolveManifest)(workspaceDir, backendUrl,
|
|
227
|
+
const resolved = await (0, manifest_1.resolveManifest)(workspaceDir, backendUrl, manifestCacheUse(mode, offline), clientUrl, bootstrapSecret);
|
|
150
228
|
const { manifest, fromCache, fetchedAt } = resolved;
|
|
151
229
|
let layers;
|
|
152
230
|
if (mode === "dev") {
|
|
153
|
-
(0, layers_1.assertLayerPathsServed)(manifest.modules);
|
|
231
|
+
(0, layers_1.assertLayerPathsServed)(manifest.modules, backendUrl, bootstrapSecret);
|
|
154
232
|
if (fromCache) {
|
|
155
233
|
(0, manifest_1.assertCachedLayerPathsExist)(manifest.modules, fetchedAt);
|
|
156
234
|
}
|
|
@@ -160,7 +238,12 @@ async function setupWorkspace(opts) {
|
|
|
160
238
|
const cacheDir = (0, node_path_1.join)(workspaceDir, ".layers-cache");
|
|
161
239
|
if (fromCache) {
|
|
162
240
|
if (!(0, node_fs_1.existsSync)(cacheDir)) {
|
|
163
|
-
throw new
|
|
241
|
+
throw new cli_1.CliError({
|
|
242
|
+
title: "No layers archive was downloaded for this workspace",
|
|
243
|
+
fixes: [
|
|
244
|
+
"Run once without --offline, with the backend reachable, first",
|
|
245
|
+
],
|
|
246
|
+
});
|
|
164
247
|
}
|
|
165
248
|
(0, layers_1.assertCachedArchivesExist)(manifest.modules, cacheDir, fetchedAt);
|
|
166
249
|
}
|
|
@@ -169,7 +252,7 @@ async function setupWorkspace(opts) {
|
|
|
169
252
|
}
|
|
170
253
|
layers = await (0, layers_1.buildLayersFromCache)(manifest.modules, cacheDir);
|
|
171
254
|
}
|
|
172
|
-
(0, renderer_range_1.assertLayersSupportRenderer)(layers);
|
|
255
|
+
(0, renderer_range_1.assertLayersSupportRenderer)(layers, { workspaceDir });
|
|
173
256
|
(0, materialize_1.copyStaticTemplates)(workspaceDir);
|
|
174
257
|
(0, materialize_1.writeWorkspacePackageJson)(workspaceDir, layers);
|
|
175
258
|
(0, materialize_1.materializeLayers)(workspaceDir, layers);
|
|
@@ -178,7 +261,8 @@ async function setupWorkspace(opts) {
|
|
|
178
261
|
const layerPaths = layers.map((layer) => layer.path);
|
|
179
262
|
const shouldInstall = needsInstall(workspaceDir, layerPaths, force);
|
|
180
263
|
if (shouldInstall) {
|
|
181
|
-
|
|
264
|
+
await opts.beforeInstall?.();
|
|
265
|
+
await installDeps(workspaceDir, (0, child_output_1.createPathMapper)(workspaceDir, layers));
|
|
182
266
|
saveDepsHash(workspaceDir, layerPaths);
|
|
183
267
|
}
|
|
184
268
|
return {
|
package/dist/workspace.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export interface FrontendManifest {
|
|
|
27
27
|
}
|
|
28
28
|
export interface ResolvedLayer {
|
|
29
29
|
path: string;
|
|
30
|
+
sourcePath?: string;
|
|
30
31
|
packageName?: string;
|
|
31
32
|
priority?: number;
|
|
32
33
|
configKey?: string;
|
|
@@ -42,9 +43,14 @@ export interface WorkspaceEntry {
|
|
|
42
43
|
dir: string;
|
|
43
44
|
backendUrl: string;
|
|
44
45
|
workspaceKey?: string;
|
|
46
|
+
lastUsedAt: string;
|
|
45
47
|
}
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
+
export interface WorkspaceListing {
|
|
49
|
+
workspaces: WorkspaceEntry[];
|
|
50
|
+
skipped: string[];
|
|
51
|
+
}
|
|
52
|
+
export declare function listWorkspaces(): WorkspaceListing;
|
|
53
|
+
export declare function directorySize(dir: string): number;
|
|
48
54
|
export declare function writeWorkspaceMeta(workspaceDir: string, backendUrl: string, workspaceKey: string): void;
|
|
49
55
|
export declare const FRONTEND_MANIFEST_VERSION = 1;
|
|
50
56
|
export declare function bootstrapHeaders(secret?: string): Record<string, string>;
|
package/dist/workspace.js
CHANGED
|
@@ -6,8 +6,8 @@ exports.projectWorkspaceKey = projectWorkspaceKey;
|
|
|
6
6
|
exports.projectDirFromWorkspaceKey = projectDirFromWorkspaceKey;
|
|
7
7
|
exports.getWorkspaceDir = getWorkspaceDir;
|
|
8
8
|
exports.ensureWorkspace = ensureWorkspace;
|
|
9
|
-
exports.describeWorkspace = describeWorkspace;
|
|
10
9
|
exports.listWorkspaces = listWorkspaces;
|
|
10
|
+
exports.directorySize = directorySize;
|
|
11
11
|
exports.writeWorkspaceMeta = writeWorkspaceMeta;
|
|
12
12
|
exports.bootstrapHeaders = bootstrapHeaders;
|
|
13
13
|
exports.isUnauthorized = isUnauthorized;
|
|
@@ -38,32 +38,28 @@ function ensureWorkspace(workspaceKey) {
|
|
|
38
38
|
(0, node_fs_1.chmodSync)(dir, config_1.WORKSPACE_DIR_MODE);
|
|
39
39
|
return dir;
|
|
40
40
|
}
|
|
41
|
-
function describeWorkspace(entry) {
|
|
42
|
-
const projectDir = projectDirFromWorkspaceKey(entry.workspaceKey);
|
|
43
|
-
return projectDir
|
|
44
|
-
? `${entry.backendUrl}, keyed on project ${projectDir}`
|
|
45
|
-
: entry.backendUrl;
|
|
46
|
-
}
|
|
47
41
|
function listWorkspaces() {
|
|
42
|
+
const listing = { workspaces: [], skipped: [] };
|
|
48
43
|
if (!(0, node_fs_1.existsSync)(config_1.DMS_FRONTEND_HOME))
|
|
49
|
-
return
|
|
50
|
-
const workspaces = [];
|
|
44
|
+
return listing;
|
|
51
45
|
for (const entry of (0, node_fs_1.readdirSync)(config_1.DMS_FRONTEND_HOME, { withFileTypes: true })) {
|
|
52
46
|
if (!entry.isDirectory())
|
|
53
47
|
continue;
|
|
54
48
|
const dir = (0, node_path_1.join)(config_1.DMS_FRONTEND_HOME, entry.name);
|
|
55
49
|
const meta = readWorkspaceMeta(dir);
|
|
56
50
|
if (meta?.backendUrl === undefined) {
|
|
57
|
-
|
|
51
|
+
listing.skipped.push(dir);
|
|
58
52
|
continue;
|
|
59
53
|
}
|
|
60
|
-
workspaces.push({
|
|
54
|
+
listing.workspaces.push({
|
|
61
55
|
dir,
|
|
62
56
|
backendUrl: meta.backendUrl,
|
|
63
57
|
workspaceKey: meta.workspaceKey,
|
|
58
|
+
lastUsedAt: meta.updatedAt ?? metaModifiedAt(dir),
|
|
64
59
|
});
|
|
65
60
|
}
|
|
66
|
-
|
|
61
|
+
listing.workspaces.sort((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt));
|
|
62
|
+
return listing;
|
|
67
63
|
}
|
|
68
64
|
function readWorkspaceMeta(dir) {
|
|
69
65
|
let meta;
|
|
@@ -79,8 +75,47 @@ function readWorkspaceMeta(dir) {
|
|
|
79
75
|
workspaceKey: typeof record?.workspaceKey === "string"
|
|
80
76
|
? record.workspaceKey
|
|
81
77
|
: undefined,
|
|
78
|
+
updatedAt: typeof record?.updatedAt === "string" &&
|
|
79
|
+
!Number.isNaN(Date.parse(record.updatedAt))
|
|
80
|
+
? new Date(record.updatedAt).toISOString()
|
|
81
|
+
: undefined,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
+
function metaModifiedAt(dir) {
|
|
85
|
+
return (0, node_fs_1.statSync)((0, node_path_1.join)(dir, WORKSPACE_META_FILE)).mtime.toISOString();
|
|
86
|
+
}
|
|
87
|
+
function directorySize(dir) {
|
|
88
|
+
const seen = new Set();
|
|
89
|
+
const pending = [dir];
|
|
90
|
+
let total = 0;
|
|
91
|
+
for (let current = pending.pop(); current; current = pending.pop()) {
|
|
92
|
+
let entries;
|
|
93
|
+
try {
|
|
94
|
+
entries = (0, node_fs_1.readdirSync)(current, { withFileTypes: true });
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
for (const entry of entries) {
|
|
100
|
+
const path = (0, node_path_1.join)(current, entry.name);
|
|
101
|
+
if (entry.isDirectory()) {
|
|
102
|
+
pending.push(path);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const stats = (0, node_fs_1.lstatSync)(path);
|
|
107
|
+
const inode = `${stats.dev}:${stats.ino}`;
|
|
108
|
+
if (stats.nlink > 1 && seen.has(inode))
|
|
109
|
+
continue;
|
|
110
|
+
seen.add(inode);
|
|
111
|
+
total += stats.size;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return total;
|
|
118
|
+
}
|
|
84
119
|
function writeWorkspaceMeta(workspaceDir, backendUrl, workspaceKey) {
|
|
85
120
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspaceDir, WORKSPACE_META_FILE), JSON.stringify({
|
|
86
121
|
backendUrl: (0, config_1.canonicalizeBackendUrl)(backendUrl),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/dms-frontend",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Frontend-agnostic loader for AntelopeJS DMS, shipping the Vue 3 renderer (Vite, Inertia, SSR)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelope",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "rimraf dist && tsc",
|
|
57
57
|
"prepack": "pnpm run build",
|
|
58
|
-
"release": "pnpm run lint && pnpm run
|
|
58
|
+
"release": "pnpm run lint && pnpm run build && pnpm run test && release-it",
|
|
59
59
|
"test": "node --import tsx --test tests/*.test.ts tests/*.test.mts",
|
|
60
60
|
"test:real-source": "pnpm run build && node dist/verify-source-runner.js",
|
|
61
61
|
"format": "oxfmt .",
|
|
@@ -66,21 +66,18 @@
|
|
|
66
66
|
"knip:all": "knip"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"boxen": "^5.1.2",
|
|
70
|
-
"chalk": "^4.1.2",
|
|
71
69
|
"chokidar": "^4.0.3",
|
|
72
70
|
"commander": "^13.1.0",
|
|
73
|
-
"figlet": "^1.9.4",
|
|
74
71
|
"ignore": "^7.0.5",
|
|
75
72
|
"semver": "^7.7.4",
|
|
76
73
|
"unzipper": "^0.12.3"
|
|
77
74
|
},
|
|
78
75
|
"devDependencies": {
|
|
76
|
+
"@antelopejs/core": "^1.13.0",
|
|
79
77
|
"@antelopejs/tooling-configs": ">=0.0.7 <1.0.0",
|
|
80
78
|
"@iconify/utils": "^3.1.0",
|
|
81
79
|
"@iconify/vue": "^5.0.1",
|
|
82
80
|
"@inertiajs/vue3": "^3.7.1",
|
|
83
|
-
"@types/figlet": "^1.7.0",
|
|
84
81
|
"@types/node": "^24.8.1",
|
|
85
82
|
"@types/semver": "^7.7.1",
|
|
86
83
|
"@types/unzipper": "^0.10.11",
|
|
@@ -104,12 +101,7 @@
|
|
|
104
101
|
"vue-i18n": "^11.2.7"
|
|
105
102
|
},
|
|
106
103
|
"peerDependencies": {
|
|
107
|
-
"@antelopejs/core": ">=1.
|
|
108
|
-
},
|
|
109
|
-
"peerDependenciesMeta": {
|
|
110
|
-
"@antelopejs/core": {
|
|
111
|
-
"optional": true
|
|
112
|
-
}
|
|
104
|
+
"@antelopejs/core": ">=1.13.0 <2"
|
|
113
105
|
},
|
|
114
106
|
"optionalDependencies": {
|
|
115
107
|
"@oxc-parser/binding-darwin-arm64": "^0.95.0",
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite",
|
|
7
7
|
"build": "vite build && node compress-assets.mjs && vite build --ssr ssr-renderer.ts --outDir dist/ssr && vite build --config vite.email.config.ts",
|
|
8
|
+
"build:client": "vite build",
|
|
9
|
+
"build:compress": "node compress-assets.mjs",
|
|
10
|
+
"build:ssr": "vite build --ssr ssr-renderer.ts --outDir dist/ssr",
|
|
11
|
+
"build:email": "vite build --config vite.email.config.ts",
|
|
8
12
|
"typecheck": "node --import ./typecheck-loader.mjs ./node_modules/vue-tsc/bin/vue-tsc.js --noEmit",
|
|
9
13
|
"start": "node server.mjs"
|
|
10
14
|
},
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// What the server tells whoever started it. Started by `ajs dms dev` or
|
|
2
|
+
// `ajs dms start`, it reports over IPC and the CLI words what the user reads.
|
|
3
|
+
// Started on its own, it prints the line itself.
|
|
4
|
+
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
const WILDCARD_ADDRESSES = ["0.0.0.0", "::"];
|
|
8
|
+
|
|
9
|
+
async function report(message, line, write) {
|
|
10
|
+
if (!process.send) return write(line);
|
|
11
|
+
await new Promise((sent) => process.send(message, () => sent()));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** The server answers at `address`:`port`. */
|
|
15
|
+
export async function reportReady(address, port) {
|
|
16
|
+
const host = WILDCARD_ADDRESSES.includes(address)
|
|
17
|
+
? "localhost"
|
|
18
|
+
: address.includes(":")
|
|
19
|
+
? `[${address}]`
|
|
20
|
+
: address;
|
|
21
|
+
await report(
|
|
22
|
+
{ type: "dms:ready", address, port },
|
|
23
|
+
`✓ Server ready on http://${host}:${port}`,
|
|
24
|
+
console.log,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The server cannot listen: a port taken by another process, an address this
|
|
30
|
+
* host does not have. Reported instead of Node's unhandled-error dump, then
|
|
31
|
+
* the server exits.
|
|
32
|
+
*/
|
|
33
|
+
export async function reportListenError(error, host, port) {
|
|
34
|
+
await report(
|
|
35
|
+
{
|
|
36
|
+
type: "dms:listen-error",
|
|
37
|
+
code: error.code,
|
|
38
|
+
message: error.message,
|
|
39
|
+
host,
|
|
40
|
+
port,
|
|
41
|
+
},
|
|
42
|
+
`DMS server cannot listen on ${host}:${port}: ${error.message}`,
|
|
43
|
+
console.error,
|
|
44
|
+
);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Where a startup error points, when it says: esbuild's location for a config
|
|
50
|
+
* it could not bundle, Rollup's for a plugin that failed on a file.
|
|
51
|
+
*/
|
|
52
|
+
function errorLocation(error) {
|
|
53
|
+
const location = error?.errors?.[0]?.location;
|
|
54
|
+
if (location?.file) {
|
|
55
|
+
return {
|
|
56
|
+
file: resolve(location.file),
|
|
57
|
+
line: location.line,
|
|
58
|
+
column: location.column,
|
|
59
|
+
lineText: location.lineText,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const file = error?.loc?.file ?? error?.id;
|
|
63
|
+
if (typeof file !== "string") return undefined;
|
|
64
|
+
return { file, line: error.loc?.line, column: error.loc?.column };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** The first line of what went wrong, without esbuild's error count. */
|
|
68
|
+
function errorText(error) {
|
|
69
|
+
const text = error?.errors?.[0]?.text;
|
|
70
|
+
if (typeof text === "string") return text;
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
return message.split(/\r?\n/)[0];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Vite could not start, so no page can be served: the error and where it
|
|
77
|
+
* points instead of a stack trace, then the server exits.
|
|
78
|
+
*/
|
|
79
|
+
export async function reportStartError(error) {
|
|
80
|
+
const message = errorText(error);
|
|
81
|
+
const location = errorLocation(error);
|
|
82
|
+
const where = location
|
|
83
|
+
? `${location.file}${location.line ? `:${location.line}:${location.column ?? 0}` : ""}: `
|
|
84
|
+
: "";
|
|
85
|
+
await report(
|
|
86
|
+
{ type: "dms:start-error", message, code: error?.code, location },
|
|
87
|
+
`DMS development server failed to start: ${where}${message}`,
|
|
88
|
+
console.error,
|
|
89
|
+
);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|