@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.
- 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/frontend-module.ts +32 -10
- package/templates/vue/package.json +4 -0
- package/templates/vue/server/cli-report.mjs +91 -0
- package/templates/vue/server.mjs +45 -21
- 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
package/dist/manifest-secrets.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.MANIFEST_SECRET_ENV = void 0;
|
|
7
4
|
exports.collectManifestSecrets = collectManifestSecrets;
|
|
8
5
|
exports.resolveManifestSecrets = resolveManifestSecrets;
|
|
9
6
|
exports.formatSecretConflicts = formatSecretConflicts;
|
|
10
|
-
exports.
|
|
7
|
+
exports.describeSecretSources = describeSecretSources;
|
|
11
8
|
exports.reportManifestSecrets = reportManifestSecrets;
|
|
12
|
-
const
|
|
9
|
+
const cli_1 = require("@antelopejs/core/cli");
|
|
13
10
|
exports.MANIFEST_SECRET_ENV = {
|
|
14
11
|
DMS_HTML_RENDER_SECRET: ["htmlRender", "serviceSecret"],
|
|
15
12
|
DMS_OAUTH_RELAY_SECRET: ["oauth", "relaySecret"],
|
|
@@ -80,22 +77,29 @@ function resolveManifestSecrets(secrets, env = process.env) {
|
|
|
80
77
|
function formatSecretConflicts(conflicts) {
|
|
81
78
|
return conflicts.map(({ name, used, ignored }) => `${name}: ${ignored.join(", ")} publish${ignored.length === 1 ? "es" : ""} a different value than ${used}; using ${used}'s`);
|
|
82
79
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
})
|
|
80
|
+
const SOURCE_LABELS = {
|
|
81
|
+
env: "the environment",
|
|
82
|
+
manifest: "the manifest",
|
|
83
|
+
};
|
|
84
|
+
function describeSecretSources(sources, manifestLabel = SOURCE_LABELS.manifest) {
|
|
85
|
+
const labels = { ...SOURCE_LABELS, manifest: manifestLabel };
|
|
86
|
+
const groups = ["env", "manifest"]
|
|
87
|
+
.map((source) => ({
|
|
88
|
+
names: SECRET_NAMES.filter((name) => sources[name] === source),
|
|
89
|
+
label: labels[source],
|
|
90
|
+
}))
|
|
91
|
+
.filter(({ names }) => names.length > 0)
|
|
92
|
+
.map(({ names, label }) => `${names.join(", ")} from ${label}`);
|
|
93
|
+
return groups.length > 0 ? groups.join("; ") : undefined;
|
|
94
94
|
}
|
|
95
|
-
function reportManifestSecrets(resolved,
|
|
95
|
+
function reportManifestSecrets(resolved, fix, ui = (0, cli_1.getProcessUi)()) {
|
|
96
96
|
for (const line of formatSecretConflicts(resolved.conflicts))
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
ui.message("warn", line);
|
|
98
|
+
const unset = SECRET_NAMES.filter((name) => resolved.sources[name] === "not set");
|
|
99
|
+
unset.forEach((name, index) => {
|
|
100
|
+
const isLast = index === unset.length - 1;
|
|
101
|
+
ui.message("warn", `${name} is not set: ${UNSET_CONSEQUENCE[name]}`, {
|
|
102
|
+
details: isLast ? [`${ui.symbols.levels.hint} ${fix(unset.length)}`] : [],
|
|
103
|
+
});
|
|
104
|
+
});
|
|
101
105
|
}
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
|
+
import { CliError, type CliProblem } from "@antelopejs/core/cli";
|
|
1
2
|
import { Manifest, ManifestModule } from "./workspace";
|
|
2
|
-
export declare class ManifestUnauthorizedError extends
|
|
3
|
+
export declare class ManifestUnauthorizedError extends CliError {
|
|
3
4
|
readonly url: string;
|
|
4
5
|
readonly status: number;
|
|
5
|
-
constructor(url: string, status: number);
|
|
6
|
+
constructor(url: string, status: number, credentialSent: boolean);
|
|
6
7
|
}
|
|
7
|
-
export declare class
|
|
8
|
-
|
|
8
|
+
export declare class BackendUnreachableError extends CliError {
|
|
9
|
+
readonly url: string;
|
|
10
|
+
readonly code?: string;
|
|
11
|
+
constructor(url: string, failure: unknown);
|
|
12
|
+
}
|
|
13
|
+
export declare function displayUrl(url: string | URL): string;
|
|
14
|
+
export declare function backendEndpoint(backendUrl: string, path: string): URL;
|
|
15
|
+
export declare function fetchFromBackend(backendUrl: string, url: URL, bootstrapSecret?: string): Promise<Response>;
|
|
16
|
+
export declare class ManifestRefusedError extends CliError {
|
|
17
|
+
constructor(problem: string | CliProblem);
|
|
18
|
+
}
|
|
19
|
+
export declare function describeManifestVersion(version: unknown): CliProblem;
|
|
20
|
+
export declare class BackendResponseError extends CliError {
|
|
21
|
+
constructor(subject: string, url: string | URL, response: Pick<Response, "status" | "statusText">);
|
|
22
|
+
}
|
|
23
|
+
export declare class NoCachedManifestError extends CliError {
|
|
24
|
+
constructor();
|
|
9
25
|
}
|
|
10
26
|
export declare function fetchManifest(backendUrl: string, clientUrl?: string, bootstrapSecret?: string): Promise<Manifest>;
|
|
11
27
|
export interface ManifestCacheEntry {
|
|
@@ -13,12 +29,13 @@ export interface ManifestCacheEntry {
|
|
|
13
29
|
fetchedAt: string;
|
|
14
30
|
}
|
|
15
31
|
export declare function readCachedManifest(workspaceDir: string): ManifestCacheEntry | undefined;
|
|
32
|
+
export type ManifestCacheUse = "fallback" | "offline" | "never";
|
|
16
33
|
export interface ResolvedManifest {
|
|
17
34
|
manifest: Manifest;
|
|
18
35
|
fromCache: boolean;
|
|
19
36
|
fetchedAt?: string;
|
|
20
37
|
}
|
|
21
|
-
export declare function resolveManifest(workspaceDir: string, backendUrl: string,
|
|
38
|
+
export declare function resolveManifest(workspaceDir: string, backendUrl: string, cacheUse: ManifestCacheUse, clientUrl?: string, bootstrapSecret?: string): Promise<ResolvedManifest>;
|
|
22
39
|
export declare function assertCachedLayerPathsExist(modules: ServedWithPath[], fetchedAt?: string): void;
|
|
23
40
|
export type ServedWithPath = ManifestModule & {
|
|
24
41
|
path: string;
|
package/dist/manifest.js
CHANGED
|
@@ -1,53 +1,192 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ManifestRefusedError = exports.ManifestUnauthorizedError = void 0;
|
|
3
|
+
exports.NoCachedManifestError = exports.BackendResponseError = exports.ManifestRefusedError = exports.BackendUnreachableError = exports.ManifestUnauthorizedError = void 0;
|
|
4
|
+
exports.displayUrl = displayUrl;
|
|
5
|
+
exports.backendEndpoint = backendEndpoint;
|
|
6
|
+
exports.fetchFromBackend = fetchFromBackend;
|
|
7
|
+
exports.describeManifestVersion = describeManifestVersion;
|
|
4
8
|
exports.fetchManifest = fetchManifest;
|
|
5
9
|
exports.readCachedManifest = readCachedManifest;
|
|
6
10
|
exports.resolveManifest = resolveManifest;
|
|
7
11
|
exports.assertCachedLayerPathsExist = assertCachedLayerPathsExist;
|
|
8
12
|
const node_fs_1 = require("node:fs");
|
|
9
13
|
const node_path_1 = require("node:path");
|
|
14
|
+
const cli_1 = require("@antelopejs/core/cli");
|
|
10
15
|
const config_1 = require("./config");
|
|
16
|
+
const output_1 = require("./output");
|
|
11
17
|
const workspace_1 = require("./workspace");
|
|
12
|
-
class ManifestUnauthorizedError extends
|
|
13
|
-
constructor(url, status) {
|
|
14
|
-
super(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
class ManifestUnauthorizedError extends cli_1.CliError {
|
|
19
|
+
constructor(url, status, credentialSent) {
|
|
20
|
+
super({
|
|
21
|
+
title: credentialSent
|
|
22
|
+
? `The backend refused the bootstrap credential (${status}) at ${url}`
|
|
23
|
+
: `The backend requires a bootstrap credential (${status}) at ${url}, and none was sent`,
|
|
24
|
+
fixes: [
|
|
25
|
+
"Production/CI: set DMS_BOOTSTRAP_SECRET to the backend's frontend.bootstrapSecret",
|
|
26
|
+
"Local dev: run inside the antelope project started with `ajs project dev`; the credential is read from .antelope/dms-dev.json automatically",
|
|
27
|
+
],
|
|
28
|
+
});
|
|
19
29
|
this.url = url;
|
|
20
30
|
this.status = status;
|
|
21
31
|
this.name = "ManifestUnauthorizedError";
|
|
22
32
|
}
|
|
23
33
|
}
|
|
24
34
|
exports.ManifestUnauthorizedError = ManifestUnauthorizedError;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
const UNREACHABLE_REASONS = {
|
|
36
|
+
ECONNREFUSED: "Connection refused",
|
|
37
|
+
ECONNRESET: "Connection reset",
|
|
38
|
+
ENOTFOUND: "Unknown host",
|
|
39
|
+
EAI_AGAIN: "Host name lookup failed",
|
|
40
|
+
ETIMEDOUT: "Connection timed out",
|
|
41
|
+
UND_ERR_CONNECT_TIMEOUT: "Connection timed out",
|
|
42
|
+
};
|
|
43
|
+
const UNKNOWN_HOST_CODES = ["ENOTFOUND", "EAI_AGAIN"];
|
|
44
|
+
class BackendUnreachableError extends cli_1.CliError {
|
|
45
|
+
constructor(url, failure) {
|
|
46
|
+
const cause = failure?.cause ?? failure;
|
|
47
|
+
const code = errorCode(cause);
|
|
48
|
+
const detail = code
|
|
49
|
+
? (UNREACHABLE_REASONS[code] ?? errorMessage(cause))
|
|
50
|
+
: `The request failed: ${errorMessage(cause)}`;
|
|
51
|
+
const fix = code && UNKNOWN_HOST_CODES.includes(code)
|
|
52
|
+
? `Check the host name '${new URL(url).hostname}' in -b <url> or DMS_API_BASE_URL`
|
|
53
|
+
: "Start the backend (`ajs project dev` for a local one), or pass its URL with -b <url>";
|
|
54
|
+
super({
|
|
55
|
+
title: `Cannot reach the DMS backend at ${url}`,
|
|
56
|
+
reason: `${code ? `${detail} (${code})` : detail}.`,
|
|
57
|
+
fixes: [fix],
|
|
58
|
+
}, { cause: failure });
|
|
59
|
+
this.url = url;
|
|
60
|
+
this.name = "BackendUnreachableError";
|
|
61
|
+
this.code = code;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.BackendUnreachableError = BackendUnreachableError;
|
|
65
|
+
function errorCode(err) {
|
|
66
|
+
const { code, errors } = (err ?? {});
|
|
67
|
+
if (typeof code === "string")
|
|
68
|
+
return code;
|
|
69
|
+
return Array.isArray(errors) ? errorCode(errors[0]) : undefined;
|
|
70
|
+
}
|
|
71
|
+
function errorMessage(err) {
|
|
72
|
+
return err instanceof Error ? err.message : String(err);
|
|
73
|
+
}
|
|
74
|
+
function displayUrl(url) {
|
|
75
|
+
const { origin, pathname } = new URL(url);
|
|
76
|
+
return `${origin}${pathname.replace(/\/$/, "")}`;
|
|
77
|
+
}
|
|
78
|
+
function backendEndpoint(backendUrl, path) {
|
|
79
|
+
try {
|
|
80
|
+
return new URL(`${(0, config_1.parseBackendUrl)(backendUrl)}${path}`);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
if (!(err instanceof config_1.UsageError))
|
|
84
|
+
throw err;
|
|
85
|
+
throw new cli_1.CliError({ ...err.problem, exitCode: cli_1.FAILURE_EXIT_CODE }, { cause: err });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function fetchFromBackend(backendUrl, url, bootstrapSecret) {
|
|
89
|
+
let response;
|
|
90
|
+
try {
|
|
91
|
+
response = await fetch(url, { headers: (0, workspace_1.bootstrapHeaders)(bootstrapSecret) });
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
throw new BackendUnreachableError(displayUrl(backendUrl), err);
|
|
95
|
+
}
|
|
96
|
+
if ((0, workspace_1.isUnauthorized)(response.status)) {
|
|
97
|
+
throw new ManifestUnauthorizedError(displayUrl(url), response.status, !!bootstrapSecret);
|
|
98
|
+
}
|
|
99
|
+
return response;
|
|
100
|
+
}
|
|
101
|
+
class ManifestRefusedError extends cli_1.CliError {
|
|
102
|
+
constructor(problem) {
|
|
103
|
+
super(typeof problem === "string" ? { title: problem } : problem);
|
|
28
104
|
this.name = "ManifestRefusedError";
|
|
29
105
|
}
|
|
30
106
|
}
|
|
31
107
|
exports.ManifestRefusedError = ManifestRefusedError;
|
|
108
|
+
const OWN_RELEASE = require("../package.json");
|
|
109
|
+
const BACKEND_PACKAGE = "@antelopejs/dms";
|
|
110
|
+
const LOADER_UPDATE_COMMAND = "ajs update dms";
|
|
111
|
+
function describeManifestVersion(version) {
|
|
112
|
+
const loader = `${OWN_RELEASE.name} ${OWN_RELEASE.version}`;
|
|
113
|
+
const supported = `This loader reads version ${workspace_1.FRONTEND_MANIFEST_VERSION}`;
|
|
114
|
+
if (typeof version !== "number") {
|
|
115
|
+
return {
|
|
116
|
+
title: "The backend served a frontend manifest without a protocol version",
|
|
117
|
+
reason: `${supported}; the answer does not look like one from ${BACKEND_PACKAGE}.`,
|
|
118
|
+
fixes: [
|
|
119
|
+
`Check that -b <url> points at a DMS backend running ${BACKEND_PACKAGE}`,
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const title = `The backend serves frontend manifest version ${version}, which ${loader} cannot read`;
|
|
124
|
+
if (version > workspace_1.FRONTEND_MANIFEST_VERSION) {
|
|
125
|
+
return {
|
|
126
|
+
title,
|
|
127
|
+
reason: `${supported}; the backend's ${BACKEND_PACKAGE} is newer than this loader.`,
|
|
128
|
+
fixes: [
|
|
129
|
+
`Upgrade the loader (${LOADER_UPDATE_COMMAND}) to a release that reads version ${version}`,
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
title,
|
|
135
|
+
reason: `${supported}; the backend's ${BACKEND_PACKAGE} is older than this loader.`,
|
|
136
|
+
fixes: [
|
|
137
|
+
`Upgrade ${BACKEND_PACKAGE} on the backend, or use a ${OWN_RELEASE.name} release that reads version ${version}`,
|
|
138
|
+
],
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
class BackendResponseError extends cli_1.CliError {
|
|
142
|
+
constructor(subject, url, response) {
|
|
143
|
+
const { status, statusText } = response;
|
|
144
|
+
const answer = `HTTP ${status}${statusText ? ` ${statusText}` : ""}`;
|
|
145
|
+
const shown = displayUrl(url);
|
|
146
|
+
const problem = status >= 500
|
|
147
|
+
? {
|
|
148
|
+
title: `The DMS backend failed to serve ${subject} (${answer})`,
|
|
149
|
+
reason: `${shown} answered ${status}: the backend failed on the request.`,
|
|
150
|
+
fixes: [
|
|
151
|
+
"Check the backend logs (the `ajs project dev` output for a local backend), then run again",
|
|
152
|
+
],
|
|
153
|
+
}
|
|
154
|
+
: {
|
|
155
|
+
title: `The DMS backend did not serve ${subject} (${answer})`,
|
|
156
|
+
reason: `${shown} answered ${status}.`,
|
|
157
|
+
fixes: [
|
|
158
|
+
`Check that -b <url> points at a DMS backend running ${BACKEND_PACKAGE}`,
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
super(problem);
|
|
162
|
+
this.name = "BackendResponseError";
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.BackendResponseError = BackendResponseError;
|
|
166
|
+
class NoCachedManifestError extends cli_1.CliError {
|
|
167
|
+
constructor() {
|
|
168
|
+
super({
|
|
169
|
+
title: "No cached manifest for this workspace",
|
|
170
|
+
fixes: ["Run once with the backend reachable before using --offline"],
|
|
171
|
+
});
|
|
172
|
+
this.name = "NoCachedManifestError";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.NoCachedManifestError = NoCachedManifestError;
|
|
32
176
|
async function fetchManifest(backendUrl, clientUrl, bootstrapSecret) {
|
|
33
|
-
const frontendUrl =
|
|
177
|
+
const frontendUrl = backendEndpoint(backendUrl, "/dms/frontend");
|
|
34
178
|
frontendUrl.searchParams.set("renderer", "vue");
|
|
35
179
|
frontendUrl.searchParams.set("rendererVersion", "3");
|
|
36
180
|
if (clientUrl) {
|
|
37
181
|
frontendUrl.searchParams.set("clientUrl", clientUrl);
|
|
38
182
|
}
|
|
39
|
-
const response = await
|
|
40
|
-
headers: (0, workspace_1.bootstrapHeaders)(bootstrapSecret),
|
|
41
|
-
});
|
|
42
|
-
if ((0, workspace_1.isUnauthorized)(response.status)) {
|
|
43
|
-
throw new ManifestUnauthorizedError(frontendUrl.href, response.status);
|
|
44
|
-
}
|
|
183
|
+
const response = await fetchFromBackend(backendUrl, frontendUrl, bootstrapSecret);
|
|
45
184
|
if (!response.ok) {
|
|
46
|
-
throw new
|
|
185
|
+
throw new BackendResponseError("the frontend manifest", frontendUrl, response);
|
|
47
186
|
}
|
|
48
187
|
const manifest = (await response.json());
|
|
49
188
|
if (manifest.version !== workspace_1.FRONTEND_MANIFEST_VERSION) {
|
|
50
|
-
throw new ManifestRefusedError(
|
|
189
|
+
throw new ManifestRefusedError(describeManifestVersion(manifest.version));
|
|
51
190
|
}
|
|
52
191
|
const incompatible = manifest.modules.filter((module) => module.renderer?.name !== "vue" || module.renderer?.version !== "3");
|
|
53
192
|
if (incompatible.length) {
|
|
@@ -77,8 +216,8 @@ function writeCachedManifest(workspaceDir, manifest) {
|
|
|
77
216
|
};
|
|
78
217
|
(0, config_1.writeSecretBearingFile)((0, node_path_1.join)(workspaceDir, MANIFEST_CACHE_FILE), `${JSON.stringify(entry, null, 2)}\n`);
|
|
79
218
|
}
|
|
80
|
-
async function resolveManifest(workspaceDir, backendUrl,
|
|
81
|
-
if (
|
|
219
|
+
async function resolveManifest(workspaceDir, backendUrl, cacheUse, clientUrl, bootstrapSecret) {
|
|
220
|
+
if (cacheUse !== "offline") {
|
|
82
221
|
try {
|
|
83
222
|
const manifest = await fetchManifest(backendUrl, clientUrl, bootstrapSecret);
|
|
84
223
|
writeCachedManifest(workspaceDir, manifest);
|
|
@@ -92,15 +231,30 @@ async function resolveManifest(workspaceDir, backendUrl, offline, clientUrl, boo
|
|
|
92
231
|
const cached = readCachedManifest(workspaceDir);
|
|
93
232
|
if (!cached)
|
|
94
233
|
throw err;
|
|
234
|
+
if (cacheUse === "never")
|
|
235
|
+
throw cacheNotUsed(err, backendUrl, cached);
|
|
95
236
|
return fromCachedEntry(cached);
|
|
96
237
|
}
|
|
97
238
|
}
|
|
98
239
|
const cached = readCachedManifest(workspaceDir);
|
|
99
|
-
if (!cached)
|
|
100
|
-
throw new
|
|
101
|
-
}
|
|
240
|
+
if (!cached)
|
|
241
|
+
throw new NoCachedManifestError();
|
|
102
242
|
return fromCachedEntry(cached);
|
|
103
243
|
}
|
|
244
|
+
function cacheNotUsed(failure, backendUrl, cached) {
|
|
245
|
+
const problem = failure instanceof cli_1.CliError
|
|
246
|
+
? failure.problem
|
|
247
|
+
: { title: errorMessage(failure) };
|
|
248
|
+
const cache = `A manifest${(0, output_1.cachedAge)(cached.fetchedAt)} exists; a build uses it only with --offline.`;
|
|
249
|
+
return new cli_1.CliError({
|
|
250
|
+
...problem,
|
|
251
|
+
reason: problem.reason ? `${problem.reason} ${cache}` : cache,
|
|
252
|
+
fixes: [
|
|
253
|
+
...(problem.fixes ?? []),
|
|
254
|
+
`Or build from the cache on purpose: ajs dms build -b ${displayUrl(backendUrl)} --offline`,
|
|
255
|
+
],
|
|
256
|
+
}, { cause: failure });
|
|
257
|
+
}
|
|
104
258
|
function fromCachedEntry(cached) {
|
|
105
259
|
return {
|
|
106
260
|
manifest: cached.manifest,
|
|
@@ -112,7 +266,9 @@ function assertCachedLayerPathsExist(modules, fetchedAt) {
|
|
|
112
266
|
const missing = modules.filter((mod) => !(0, node_fs_1.existsSync)(mod.path));
|
|
113
267
|
if (missing.length === 0)
|
|
114
268
|
return;
|
|
115
|
-
throw new
|
|
116
|
-
|
|
117
|
-
"
|
|
269
|
+
throw new cli_1.CliError({
|
|
270
|
+
title: `The cached manifest${fetchedAt ? ` (fetched ${(0, output_1.formatAge)(fetchedAt)})` : ""} references layer paths that no longer exist`,
|
|
271
|
+
fixes: ["Start the backend and run again to refresh the cache"],
|
|
272
|
+
details: missing.map((mod) => `${mod.name}: ${mod.path}`),
|
|
273
|
+
});
|
|
118
274
|
}
|
package/dist/materialize.js
CHANGED
|
@@ -9,6 +9,7 @@ exports.writeFrontendModuleRegistry = writeFrontendModuleRegistry;
|
|
|
9
9
|
exports.writeDmsMainCss = writeDmsMainCss;
|
|
10
10
|
const node_fs_1 = require("node:fs");
|
|
11
11
|
const node_path_1 = require("node:path");
|
|
12
|
+
const cli_1 = require("@antelopejs/core/cli");
|
|
12
13
|
const config_1 = require("./config");
|
|
13
14
|
const derived_outputs_1 = require("./derived-outputs");
|
|
14
15
|
const layers_1 = require("./layers");
|
|
@@ -83,7 +84,7 @@ function collectAuthEstablishEndpoints(layers) {
|
|
|
83
84
|
endpoints.add(endpoint);
|
|
84
85
|
continue;
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
+
(0, cli_1.getProcessUi)().message("warn", `Ignoring malformed authEstablishEndpoints entry ${JSON.stringify(endpoint)} ` +
|
|
87
88
|
`declared by ${layer.packageName ?? layer.path}: expected an absolute ` +
|
|
88
89
|
"backend API path under /api/ with no query string.");
|
|
89
90
|
}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type TaskHandle, type Ui } from "@antelopejs/core/cli";
|
|
2
|
+
import { CancelledError } from "./cancellation";
|
|
3
|
+
export declare function exitOnBrokenPipe(stream?: NodeJS.WriteStream): void;
|
|
4
|
+
export declare function isTerminalFeedback(): boolean;
|
|
5
|
+
export declare function isTerminalResult(): boolean;
|
|
6
|
+
export declare function writeFeedback(line: string): void;
|
|
7
|
+
export declare function writeHeader(command: string, context: string[], ui?: Ui): void;
|
|
8
|
+
export declare function writeBlankLine(): void;
|
|
9
|
+
export declare function showPath(target: string, home?: string): string;
|
|
10
|
+
export declare function showWorkspace(dir: string, isTerminal?: boolean, home?: string, ui?: Ui): string;
|
|
11
|
+
export declare function workspaceId(dir: string, isTerminal: boolean): string;
|
|
12
|
+
export declare function formatSize(bytes: number): string;
|
|
13
|
+
export declare function formatAge(iso: string, now?: number): string;
|
|
14
|
+
export declare function cachedAge(fetchedAt: string | undefined): string;
|
|
15
|
+
export declare function failureDetails(error: unknown, ui?: Ui): string[];
|
|
16
|
+
export declare function endInterruptedTask(task: TaskHandle, error: unknown, stopped: string): void;
|
|
17
|
+
export declare function reportStopped(stop: CancelledError, ui?: Ui): void;
|
|
18
|
+
export interface ReadyLine {
|
|
19
|
+
label: string;
|
|
20
|
+
value: string;
|
|
21
|
+
isLink?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface ReadyBlock {
|
|
24
|
+
title: string;
|
|
25
|
+
lines: ReadyLine[];
|
|
26
|
+
footer: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function formatReadyBlock(block: ReadyBlock, ui?: Ui): string[];
|
|
29
|
+
export declare function writeReadyBlock(block: ReadyBlock, ui?: Ui): void;
|
|
30
|
+
declare const TIMED_LEVEL_COLORS: {
|
|
31
|
+
readonly success: "green";
|
|
32
|
+
readonly info: "blue";
|
|
33
|
+
readonly warn: "yellow";
|
|
34
|
+
};
|
|
35
|
+
type TimedLevel = keyof typeof TIMED_LEVEL_COLORS;
|
|
36
|
+
export interface TimedMessageOptions {
|
|
37
|
+
details?: readonly string[];
|
|
38
|
+
fixes?: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
export declare function formatTimedMessage(level: TimedLevel, text: string, options?: TimedMessageOptions, ui?: Ui, now?: Date): string;
|
|
41
|
+
export {};
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exitOnBrokenPipe = exitOnBrokenPipe;
|
|
4
|
+
exports.isTerminalFeedback = isTerminalFeedback;
|
|
5
|
+
exports.isTerminalResult = isTerminalResult;
|
|
6
|
+
exports.writeFeedback = writeFeedback;
|
|
7
|
+
exports.writeHeader = writeHeader;
|
|
8
|
+
exports.writeBlankLine = writeBlankLine;
|
|
9
|
+
exports.showPath = showPath;
|
|
10
|
+
exports.showWorkspace = showWorkspace;
|
|
11
|
+
exports.workspaceId = workspaceId;
|
|
12
|
+
exports.formatSize = formatSize;
|
|
13
|
+
exports.formatAge = formatAge;
|
|
14
|
+
exports.cachedAge = cachedAge;
|
|
15
|
+
exports.failureDetails = failureDetails;
|
|
16
|
+
exports.endInterruptedTask = endInterruptedTask;
|
|
17
|
+
exports.reportStopped = reportStopped;
|
|
18
|
+
exports.formatReadyBlock = formatReadyBlock;
|
|
19
|
+
exports.writeReadyBlock = writeReadyBlock;
|
|
20
|
+
exports.formatTimedMessage = formatTimedMessage;
|
|
21
|
+
const node_os_1 = require("node:os");
|
|
22
|
+
const node_path_1 = require("node:path");
|
|
23
|
+
const cli_1 = require("@antelopejs/core/cli");
|
|
24
|
+
const cancellation_1 = require("./cancellation");
|
|
25
|
+
const HOME_PREFIX = "~";
|
|
26
|
+
const CURRENT_DIRECTORY = ".";
|
|
27
|
+
const WORKSPACE_ID_LENGTH = 8;
|
|
28
|
+
const LINE_BREAK = /\r?\n/;
|
|
29
|
+
const CARRIAGE_RETURN = "\r";
|
|
30
|
+
const STOPPED_SYMBOLS = { unicode: "■", ascii: "x" };
|
|
31
|
+
const LINK_SYMBOLS = { unicode: "➜", ascii: ">" };
|
|
32
|
+
const BLOCK_INDENT = " ";
|
|
33
|
+
const LINK_GAP = " ";
|
|
34
|
+
const LABEL_SUFFIX = ":";
|
|
35
|
+
const TIME_LENGTH = 8;
|
|
36
|
+
const BYTES_PER_UNIT = 1024;
|
|
37
|
+
const SIZE_UNITS = ["B", "KB", "MB", "GB", "TB"];
|
|
38
|
+
const DECIMAL_SIZE_LIMIT = 10;
|
|
39
|
+
const MS_PER_MINUTE = 60_000;
|
|
40
|
+
const MINUTES_PER_HOUR = 60;
|
|
41
|
+
const HOURS_PER_DAY = 24;
|
|
42
|
+
function isUnicode(ui) {
|
|
43
|
+
return ui.symbols === cli_1.SYMBOL_SETS.unicode;
|
|
44
|
+
}
|
|
45
|
+
function exitOnBrokenPipe(stream = process.stdout) {
|
|
46
|
+
stream.on("error", (error) => {
|
|
47
|
+
if (error.code !== "EPIPE")
|
|
48
|
+
throw error;
|
|
49
|
+
process.exit(cli_1.SUCCESS_EXIT_CODE);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function isTerminalFeedback() {
|
|
53
|
+
return (0, cli_1.detectCapabilities)((0, cli_1.processCapabilityContext)()).terminals.feedback;
|
|
54
|
+
}
|
|
55
|
+
function isTerminalResult() {
|
|
56
|
+
return (0, cli_1.detectCapabilities)((0, cli_1.processCapabilityContext)()).terminals.result;
|
|
57
|
+
}
|
|
58
|
+
function writeFeedback(line) {
|
|
59
|
+
(0, cli_1.getProcessTasks)().write(process.stderr, `${line}\n`);
|
|
60
|
+
}
|
|
61
|
+
function writeHeader(command, context, ui = (0, cli_1.getProcessUi)()) {
|
|
62
|
+
const title = ui.palette().bold(`ajs dms ${command}`);
|
|
63
|
+
writeFeedback(`${title} ${context.join(ui.symbols.separator)}`);
|
|
64
|
+
}
|
|
65
|
+
function writeBlankLine() {
|
|
66
|
+
writeFeedback("");
|
|
67
|
+
}
|
|
68
|
+
function showPath(target, home = (0, node_os_1.homedir)()) {
|
|
69
|
+
if ((0, node_path_1.resolve)(target) === process.cwd())
|
|
70
|
+
return CURRENT_DIRECTORY;
|
|
71
|
+
const shown = (0, cli_1.displayPath)(target);
|
|
72
|
+
if (shown !== target)
|
|
73
|
+
return shown;
|
|
74
|
+
const fromHome = (0, node_path_1.relative)(home, target);
|
|
75
|
+
const isInHome = fromHome !== "" && !(0, node_path_1.isAbsolute)(fromHome) && fromHome.split(node_path_1.sep)[0] !== "..";
|
|
76
|
+
return isInHome ? (0, node_path_1.join)(HOME_PREFIX, fromHome) : target;
|
|
77
|
+
}
|
|
78
|
+
function showWorkspace(dir, isTerminal = isTerminalFeedback(), home = (0, node_os_1.homedir)(), ui = (0, cli_1.getProcessUi)()) {
|
|
79
|
+
const shown = showPath(dir, home);
|
|
80
|
+
const id = (0, node_path_1.basename)(dir);
|
|
81
|
+
if (!isTerminal || id.length <= WORKSPACE_ID_LENGTH)
|
|
82
|
+
return shown;
|
|
83
|
+
return (0, node_path_1.join)((0, node_path_1.dirname)(shown), `${id.slice(0, WORKSPACE_ID_LENGTH)}${ui.symbols.ellipsis}`);
|
|
84
|
+
}
|
|
85
|
+
function workspaceId(dir, isTerminal) {
|
|
86
|
+
const id = (0, node_path_1.basename)(dir);
|
|
87
|
+
return isTerminal ? id.slice(0, WORKSPACE_ID_LENGTH) : id;
|
|
88
|
+
}
|
|
89
|
+
function formatSize(bytes) {
|
|
90
|
+
let value = bytes;
|
|
91
|
+
let unit = 0;
|
|
92
|
+
while (value >= BYTES_PER_UNIT && unit < SIZE_UNITS.length - 1) {
|
|
93
|
+
value /= BYTES_PER_UNIT;
|
|
94
|
+
unit += 1;
|
|
95
|
+
}
|
|
96
|
+
const shown = unit > 0 && value < DECIMAL_SIZE_LIMIT
|
|
97
|
+
? String(Math.round(value * 10) / 10)
|
|
98
|
+
: String(Math.round(value));
|
|
99
|
+
return `${shown} ${SIZE_UNITS[unit]}`;
|
|
100
|
+
}
|
|
101
|
+
function formatAge(iso, now = Date.now()) {
|
|
102
|
+
const time = Date.parse(iso);
|
|
103
|
+
if (Number.isNaN(time))
|
|
104
|
+
return iso;
|
|
105
|
+
const minutes = Math.floor(Math.max(0, now - time) / MS_PER_MINUTE);
|
|
106
|
+
if (minutes < 1)
|
|
107
|
+
return "just now";
|
|
108
|
+
if (minutes < MINUTES_PER_HOUR)
|
|
109
|
+
return `${minutes} min ago`;
|
|
110
|
+
const hours = Math.floor(minutes / MINUTES_PER_HOUR);
|
|
111
|
+
if (hours < HOURS_PER_DAY)
|
|
112
|
+
return `${hours} h ago`;
|
|
113
|
+
const days = Math.floor(hours / HOURS_PER_DAY);
|
|
114
|
+
return `${days} ${days === 1 ? "day" : "days"} ago`;
|
|
115
|
+
}
|
|
116
|
+
function cachedAge(fetchedAt) {
|
|
117
|
+
return fetchedAt ? ` cached ${formatAge(fetchedAt)}` : "";
|
|
118
|
+
}
|
|
119
|
+
function describeProblem(error) {
|
|
120
|
+
if (error instanceof cli_1.CliError)
|
|
121
|
+
return error.problem;
|
|
122
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
123
|
+
return { title: message.split(LINE_BREAK)[0] };
|
|
124
|
+
}
|
|
125
|
+
function failureDetails(error, ui = (0, cli_1.getProcessUi)()) {
|
|
126
|
+
const { title, reason, fixes = [], details = [] } = describeProblem(error);
|
|
127
|
+
const hint = ui.symbols.levels.hint;
|
|
128
|
+
const stack = (0, cli_1.isVerboseRun)() && error instanceof Error && !(error instanceof cli_1.CliError)
|
|
129
|
+
? (error.stack ?? "").split(LINE_BREAK).slice(1)
|
|
130
|
+
: [];
|
|
131
|
+
return [
|
|
132
|
+
title,
|
|
133
|
+
...(reason ? [reason] : []),
|
|
134
|
+
...details,
|
|
135
|
+
...stack.map((line) => line.trim()),
|
|
136
|
+
...fixes.map((fix) => `${hint} ${fix}`),
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
function lineStartAfter(signal) {
|
|
140
|
+
return signal === "SIGINT" && process.stderr.isTTY ? CARRIAGE_RETURN : "";
|
|
141
|
+
}
|
|
142
|
+
function endInterruptedTask(task, error, stopped) {
|
|
143
|
+
if (!(error instanceof cancellation_1.CancelledError))
|
|
144
|
+
return task.dismiss();
|
|
145
|
+
const lineStart = lineStartAfter(error.signal);
|
|
146
|
+
if (lineStart)
|
|
147
|
+
(0, cli_1.getProcessTasks)().write(process.stderr, lineStart);
|
|
148
|
+
task.skip(stopped);
|
|
149
|
+
}
|
|
150
|
+
function reportStopped(stop, ui = (0, cli_1.getProcessUi)()) {
|
|
151
|
+
const symbol = isUnicode(ui)
|
|
152
|
+
? STOPPED_SYMBOLS.unicode
|
|
153
|
+
: STOPPED_SYMBOLS.ascii;
|
|
154
|
+
const text = [stop.stopped, ...stop.context].join(ui.symbols.separator);
|
|
155
|
+
writeFeedback(`${lineStartAfter(stop.signal)}${ui.palette().red(symbol)} ${text}`);
|
|
156
|
+
}
|
|
157
|
+
function formatReadyBlock(block, ui = (0, cli_1.getProcessUi)()) {
|
|
158
|
+
const palette = ui.palette();
|
|
159
|
+
const arrow = isUnicode(ui) ? LINK_SYMBOLS.unicode : LINK_SYMBOLS.ascii;
|
|
160
|
+
const width = Math.max(...block.lines.map(({ label }) => label.length + LABEL_SUFFIX.length));
|
|
161
|
+
const lead = (isLink) => `${BLOCK_INDENT}${isLink ? palette.cyan(arrow) : " ".repeat(arrow.length)}${LINK_GAP}`;
|
|
162
|
+
const lines = block.lines.map(({ label, value, isLink }) => {
|
|
163
|
+
const shownLabel = `${label}${LABEL_SUFFIX}`.padEnd(width);
|
|
164
|
+
const shownValue = isLink ? palette.cyan(value) : value;
|
|
165
|
+
return `${lead(isLink)}${palette.dim(shownLabel)} ${shownValue}`;
|
|
166
|
+
});
|
|
167
|
+
return [
|
|
168
|
+
`${palette.green(ui.symbols.levels.success)} ${block.title}`,
|
|
169
|
+
"",
|
|
170
|
+
...lines,
|
|
171
|
+
`${lead()}${palette.dim(block.footer)}`,
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
function writeReadyBlock(block, ui = (0, cli_1.getProcessUi)()) {
|
|
175
|
+
for (const line of [...formatReadyBlock(block, ui), ""])
|
|
176
|
+
writeFeedback(line);
|
|
177
|
+
}
|
|
178
|
+
const TIMED_LEVEL_COLORS = {
|
|
179
|
+
success: "green",
|
|
180
|
+
info: "blue",
|
|
181
|
+
warn: "yellow",
|
|
182
|
+
};
|
|
183
|
+
function clockTime(date) {
|
|
184
|
+
return date.toTimeString().slice(0, TIME_LENGTH);
|
|
185
|
+
}
|
|
186
|
+
function formatTimedMessage(level, text, options = {}, ui = (0, cli_1.getProcessUi)(), now = new Date()) {
|
|
187
|
+
const { details = [], fixes = [] } = options;
|
|
188
|
+
const palette = ui.palette();
|
|
189
|
+
const paint = palette[TIMED_LEVEL_COLORS[level]];
|
|
190
|
+
const hint = palette.cyan(ui.symbols.levels.hint);
|
|
191
|
+
const indent = " ".repeat(TIME_LENGTH + 1) + BLOCK_INDENT;
|
|
192
|
+
return [
|
|
193
|
+
`${palette.dim(clockTime(now))} ${paint(ui.symbols.levels[level])} ${text}`,
|
|
194
|
+
...details.map((detail) => `${indent}${palette.dim(detail)}`),
|
|
195
|
+
...fixes.map((fix) => `${indent}${hint} ${fix}`),
|
|
196
|
+
].join("\n");
|
|
197
|
+
}
|
package/dist/ports.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const PORT_FALLBACK_RANGE = 20;
|
|
2
|
+
export declare const MAX_TCP_PORT = 65535;
|
|
2
3
|
export interface ReservedPort {
|
|
3
4
|
port: number;
|
|
4
5
|
release: () => Promise<void>;
|
|
5
6
|
}
|
|
6
7
|
export declare function reserveFreePort(preferred: number, range?: number): Promise<ReservedPort>;
|
|
8
|
+
export declare function reservePort(port: number): Promise<ReservedPort | undefined>;
|