@antelopejs/dms-frontend 0.9.1 → 0.9.3
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 +9 -1
- package/dist/cancellation.js +2 -1
- package/dist/config.js +11 -7
- package/dist/derived-outputs.js +6 -113
- package/dist/dev-modules.js +3 -2
- package/dist/discovery.js +19 -12
- package/dist/fs-sync.js +1 -2
- package/dist/internal/guards.d.ts +5 -0
- package/dist/internal/guards.js +22 -0
- package/dist/internal/locale-catalogs.d.ts +6 -0
- package/dist/internal/locale-catalogs.js +115 -0
- package/dist/layer-aliases.js +2 -1
- package/dist/layers.js +2 -1
- package/dist/locale-files.js +9 -4
- package/dist/manifest-secrets.js +11 -4
- package/dist/manifest.js +11 -5
- package/dist/materialize.js +6 -5
- package/dist/module-set.js +2 -4
- package/dist/ports.js +8 -1
- package/dist/private-values.js +26 -17
- package/dist/project-modules.js +17 -11
- package/dist/renderer-range.js +2 -1
- package/dist/server-process.js +17 -16
- package/dist/update-check.js +23 -16
- package/dist/verify-source-runner.js +2 -2
- package/dist/workspace-setup.js +1 -2
- package/dist/workspace.js +11 -10
- package/package.json +7 -4
- package/skills/dms-frontend/SKILL.md +1 -1
- package/skills/dms-frontend/cases.json +77 -0
- package/templates/vue/app-runtime.ts +88 -7
- package/templates/vue/client-chunking.mjs +0 -5
- package/templates/vue/client-server-guard.mjs +10 -13
- package/templates/vue/entry-weight.mjs +12 -14
- package/templates/vue/frontend-module.ts +159 -3563
- package/templates/vue/frontend-runtime/async-data-entry.ts +320 -0
- package/templates/vue/frontend-runtime/async-data.ts +404 -0
- package/templates/vue/frontend-runtime/components.ts +386 -0
- package/templates/vue/frontend-runtime/cookies.ts +125 -0
- package/templates/vue/frontend-runtime/data-access.ts +132 -0
- package/templates/vue/frontend-runtime/dms-error.ts +11 -0
- package/templates/vue/frontend-runtime/errors.ts +145 -0
- package/templates/vue/frontend-runtime/fetch.ts +306 -0
- package/templates/vue/frontend-runtime/module-registration.ts +247 -0
- package/templates/vue/frontend-runtime/paged-data.ts +191 -0
- package/templates/vue/frontend-runtime/payload.ts +172 -0
- package/templates/vue/frontend-runtime/route.ts +328 -0
- package/templates/vue/frontend-runtime/sdk.ts +300 -0
- package/templates/vue/frontend-runtime/state.ts +167 -0
- package/templates/vue/frontend-runtime/types.ts +361 -0
- package/templates/vue/frontend-runtime/ui.ts +247 -0
- package/templates/vue/globals.d.ts +5 -0
- package/templates/vue/head-order.mjs +11 -13
- package/templates/vue/icon-bundle.ts +31 -0
- package/templates/vue/message-subset.ts +65 -0
- package/templates/vue/network-error.ts +4 -0
- package/templates/vue/prepare-types.mjs +0 -8
- package/templates/vue/server/auth/backend.mjs +4 -2
- package/templates/vue/server/auth/establish-endpoints.mjs +14 -9
- package/templates/vue/server/auth/session.mjs +4 -3
- package/templates/vue/server/auth-hooks.mjs +6 -6
- package/templates/vue/server/backend-proxies.mjs +6 -6
- package/templates/vue/server/backend-response.mjs +15 -14
- package/templates/vue/server/built-files.mjs +10 -8
- package/templates/vue/server/cli-report.mjs +7 -5
- package/templates/vue/server/client-error.mjs +11 -8
- package/templates/vue/server/client-manifest.mjs +9 -8
- package/templates/vue/server/content.mjs +2 -1
- package/templates/vue/server/dev-private-files.mjs +20 -15
- package/templates/vue/server/dev-styles.mjs +22 -25
- package/templates/vue/server/email-bundle-watch.mjs +0 -12
- package/templates/vue/server/email.mjs +20 -15
- package/templates/vue/server/favicon.mjs +12 -11
- package/templates/vue/server/homepage.mjs +8 -10
- package/templates/vue/server/icons.mjs +18 -9
- package/templates/vue/server/in-place-render.mjs +6 -8
- package/templates/vue/server/listen-host.mjs +2 -2
- package/templates/vue/server/module-event.mjs +5 -5
- package/templates/vue/server/module-routes.mjs +11 -7
- package/templates/vue/server/module-server.mjs +8 -7
- package/templates/vue/server/module-testing.mjs +7 -7
- package/templates/vue/server/page-props.mjs +14 -14
- package/templates/vue/server/path-patterns.mjs +4 -4
- package/templates/vue/server/proxy-compression.mjs +21 -13
- package/templates/vue/server/proxy-headers.mjs +5 -3
- package/templates/vue/server/proxy-redirects.mjs +7 -6
- package/templates/vue/server/proxy-transfers.mjs +15 -11
- package/templates/vue/server/public-endpoints.mjs +27 -19
- package/templates/vue/server/public-options.mjs +9 -7
- package/templates/vue/server/request-failure.mjs +4 -6
- package/templates/vue/server/request-routing.mjs +8 -11
- package/templates/vue/server/request-target.mjs +6 -6
- package/templates/vue/server/route-rules.mjs +7 -5
- package/templates/vue/server/static-files.mjs +19 -10
- package/templates/vue/server/web-body.mjs +3 -4
- package/templates/vue/server.mjs +32 -19
- package/templates/vue/sfc-global-types.mjs +27 -24
- package/templates/vue/ssr-renderer.ts +10 -1
- package/templates/vue/ui-inertia-page.mjs +7 -7
- package/templates/vue/ui-kbd.mjs +10 -10
- package/templates/vue/ui-lazy-icons.mjs +44 -0
- package/templates/vue/ui-request-state.mjs +9 -9
- package/templates/vue/vite.config.ts +2 -0
package/dist/materialize.js
CHANGED
|
@@ -15,6 +15,7 @@ const derived_outputs_1 = require("./derived-outputs");
|
|
|
15
15
|
const layers_1 = require("./layers");
|
|
16
16
|
const manifest_secrets_1 = require("./manifest-secrets");
|
|
17
17
|
const fs_sync_1 = require("./fs-sync");
|
|
18
|
+
const guards_1 = require("./internal/guards");
|
|
18
19
|
function getPackageRoot() {
|
|
19
20
|
return (0, node_path_1.resolve)(__dirname, "..");
|
|
20
21
|
}
|
|
@@ -87,7 +88,7 @@ function collectAuthEstablishEndpoints(layers) {
|
|
|
87
88
|
const endpoints = new Set();
|
|
88
89
|
for (const layer of layers) {
|
|
89
90
|
for (const endpoint of layer.authEstablishEndpoints ?? []) {
|
|
90
|
-
if (
|
|
91
|
+
if ((0, guards_1.isText)(endpoint) && BACKEND_API_PATH.test(endpoint)) {
|
|
91
92
|
endpoints.add(endpoint);
|
|
92
93
|
continue;
|
|
93
94
|
}
|
|
@@ -103,11 +104,11 @@ function writeAuthEstablishEndpoints(workspaceDir, layers) {
|
|
|
103
104
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspaceDir, config_1.AUTH_ESTABLISH_FILE), `${JSON.stringify({ endpoints }, null, 2)}\n`);
|
|
104
105
|
}
|
|
105
106
|
function collectPublicEndpoints(layers) {
|
|
106
|
-
return layers.flatMap((layer) => (Array.isArray(layer.publicEndpoints) ? layer.publicEndpoints : []).filter(
|
|
107
|
+
return layers.flatMap((layer) => (Array.isArray(layer.publicEndpoints) ? layer.publicEndpoints : []).filter(guards_1.isObjectLike));
|
|
107
108
|
}
|
|
108
109
|
function collectBackendProxies(layers) {
|
|
109
110
|
return layers.flatMap((layer) => (Array.isArray(layer.backendProxies) ? layer.backendProxies : [])
|
|
110
|
-
.filter(
|
|
111
|
+
.filter(guards_1.isObjectLike)
|
|
111
112
|
.map((proxy) => ({
|
|
112
113
|
...proxy,
|
|
113
114
|
module: layer.name ?? layer.packageName ?? "unknown",
|
|
@@ -121,9 +122,9 @@ function writePublicEndpoints(workspaceDir, layers) {
|
|
|
121
122
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspaceDir, config_1.PUBLIC_ENDPOINTS_FILE), `${JSON.stringify(declared, null, 2)}\n`);
|
|
122
123
|
}
|
|
123
124
|
function holdsValue(value) {
|
|
124
|
-
if (
|
|
125
|
+
if ((0, guards_1.isText)(value))
|
|
125
126
|
return value !== "";
|
|
126
|
-
if (
|
|
127
|
+
if ((0, guards_1.isObjectLike)(value))
|
|
127
128
|
return Object.values(value).some(holdsValue);
|
|
128
129
|
return false;
|
|
129
130
|
}
|
package/dist/module-set.js
CHANGED
|
@@ -48,8 +48,7 @@ function followModuleSet(options) {
|
|
|
48
48
|
inspect(moduleSetFingerprint(manifest.modules));
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
catch {
|
|
52
|
-
}
|
|
51
|
+
catch { }
|
|
53
52
|
if (!isStopped)
|
|
54
53
|
schedule();
|
|
55
54
|
};
|
|
@@ -102,8 +101,7 @@ async function reportFrontendReadyOnceAnswered(backendUrl, modules, bootstrapSec
|
|
|
102
101
|
if (response.status < SERVER_ERROR)
|
|
103
102
|
return response.ok;
|
|
104
103
|
}
|
|
105
|
-
catch {
|
|
106
|
-
}
|
|
104
|
+
catch { }
|
|
107
105
|
await (0, promises_1.setTimeout)(delayMs, undefined, { ref: false });
|
|
108
106
|
delayMs = Math.min(retry.maxDelayMs, delayMs * 2);
|
|
109
107
|
}
|
package/dist/ports.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.reserveFreePort = reserveFreePort;
|
|
|
5
5
|
exports.reservePort = reservePort;
|
|
6
6
|
const node_net_1 = require("node:net");
|
|
7
7
|
const cli_1 = require("@antelopejs/core/cli");
|
|
8
|
+
const guards_1 = require("./internal/guards");
|
|
8
9
|
exports.PORT_FALLBACK_RANGE = 20;
|
|
9
10
|
exports.MAX_TCP_PORT = 65535;
|
|
10
11
|
function tryListen(port) {
|
|
@@ -27,12 +28,18 @@ async function reserveFreePort(preferred, range = exports.PORT_FALLBACK_RANGE) {
|
|
|
27
28
|
fixes: ["Free one of these ports, or pass another one: -p <port>"],
|
|
28
29
|
});
|
|
29
30
|
}
|
|
31
|
+
function listeningPort(server) {
|
|
32
|
+
const address = server.address();
|
|
33
|
+
if (!(0, guards_1.isObjectLike)(address))
|
|
34
|
+
throw new Error("The reserved server does not listen on a TCP port");
|
|
35
|
+
return address.port;
|
|
36
|
+
}
|
|
30
37
|
async function reservePort(port) {
|
|
31
38
|
const server = await tryListen(port);
|
|
32
39
|
if (!server)
|
|
33
40
|
return undefined;
|
|
34
41
|
return {
|
|
35
|
-
port: server
|
|
42
|
+
port: listeningPort(server),
|
|
36
43
|
release: () => new Promise((resolve) => {
|
|
37
44
|
server.close(() => resolve());
|
|
38
45
|
}),
|
package/dist/private-values.js
CHANGED
|
@@ -6,26 +6,33 @@ exports.filledOptions = filledOptions;
|
|
|
6
6
|
exports.parsePrivateOptions = parsePrivateOptions;
|
|
7
7
|
exports.unfilledPrivateValues = unfilledPrivateValues;
|
|
8
8
|
const config_1 = require("./config");
|
|
9
|
+
const guards_1 = require("./internal/guards");
|
|
10
|
+
function isOptions(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
function isContainer(value) {
|
|
14
|
+
return typeof value === "object" && value !== null;
|
|
15
|
+
}
|
|
9
16
|
function emptied(value) {
|
|
10
|
-
if (
|
|
17
|
+
if ((0, guards_1.isText)(value))
|
|
11
18
|
return "";
|
|
12
19
|
if (Array.isArray(value))
|
|
13
20
|
return value.map(emptied);
|
|
14
|
-
if (value
|
|
21
|
+
if (isOptions(value))
|
|
15
22
|
return emptiedOptions(value);
|
|
16
23
|
return value;
|
|
17
24
|
}
|
|
18
25
|
function emptiedOptions(options) {
|
|
19
26
|
return Object.fromEntries(Object.entries(options).map(([key, value]) => [key, emptied(value)]));
|
|
20
27
|
}
|
|
21
|
-
function filled(
|
|
22
|
-
if (
|
|
23
|
-
return
|
|
24
|
-
if (Array.isArray(
|
|
25
|
-
return
|
|
26
|
-
if (
|
|
27
|
-
return filledOptions(
|
|
28
|
-
return
|
|
28
|
+
function filled(declared, value) {
|
|
29
|
+
if ((0, guards_1.isText)(declared))
|
|
30
|
+
return (0, guards_1.isText)(value) ? value : "";
|
|
31
|
+
if (Array.isArray(declared))
|
|
32
|
+
return declared.map((item, index) => filled(item, Array.isArray(value) ? value[index] : undefined));
|
|
33
|
+
if (isOptions(declared))
|
|
34
|
+
return filledOptions(declared, isOptions(value) ? value : undefined);
|
|
35
|
+
return declared;
|
|
29
36
|
}
|
|
30
37
|
function filledOptions(shape, values) {
|
|
31
38
|
return Object.fromEntries(Object.entries(shape).map(([key, value]) => [
|
|
@@ -34,8 +41,10 @@ function filledOptions(shape, values) {
|
|
|
34
41
|
]));
|
|
35
42
|
}
|
|
36
43
|
exports.PRIVATE_OPTIONS_VARIABLE = "DMS_PRIVATE_OPTIONS";
|
|
37
|
-
function
|
|
38
|
-
return
|
|
44
|
+
function isOptionsById(value) {
|
|
45
|
+
return ((0, guards_1.isObjectLike)(value) &&
|
|
46
|
+
!Array.isArray(value) &&
|
|
47
|
+
Object.values(value).every(isOptions));
|
|
39
48
|
}
|
|
40
49
|
function parsePrivateOptions(raw) {
|
|
41
50
|
if (!raw?.trim())
|
|
@@ -47,7 +56,7 @@ function parsePrivateOptions(raw) {
|
|
|
47
56
|
catch {
|
|
48
57
|
given = undefined;
|
|
49
58
|
}
|
|
50
|
-
if (!
|
|
59
|
+
if (!isOptionsById(given)) {
|
|
51
60
|
throw new config_1.UsageError({
|
|
52
61
|
title: `${exports.PRIVATE_OPTIONS_VARIABLE} is not a JSON object of options by module id`,
|
|
53
62
|
fixes: [
|
|
@@ -60,18 +69,18 @@ function parsePrivateOptions(raw) {
|
|
|
60
69
|
function readPath(options, path) {
|
|
61
70
|
let value = options;
|
|
62
71
|
for (const key of path) {
|
|
63
|
-
if (
|
|
72
|
+
if (!isContainer(value))
|
|
64
73
|
return undefined;
|
|
65
74
|
if (!Object.prototype.hasOwnProperty.call(value, key))
|
|
66
75
|
return undefined;
|
|
67
|
-
value = value[key];
|
|
76
|
+
value = isOptions(value) ? value[key] : value[Number(key)];
|
|
68
77
|
}
|
|
69
78
|
return value;
|
|
70
79
|
}
|
|
71
80
|
function* emptyStrings(value, path = []) {
|
|
72
81
|
if (value === "")
|
|
73
82
|
yield path;
|
|
74
|
-
else if (
|
|
83
|
+
else if (isContainer(value))
|
|
75
84
|
for (const [key, child] of Object.entries(value))
|
|
76
85
|
yield* emptyStrings(child, [...path, key]);
|
|
77
86
|
}
|
|
@@ -82,7 +91,7 @@ function unfilledPrivateValues(modules, given, covered) {
|
|
|
82
91
|
.filter((path) => path.length > 0 && !isCovered(path))
|
|
83
92
|
.filter((path) => {
|
|
84
93
|
const value = readPath(given[module], path);
|
|
85
|
-
return
|
|
94
|
+
return !(0, guards_1.isText)(value) || value === "";
|
|
86
95
|
})
|
|
87
96
|
.map((path) => ({ module, path })));
|
|
88
97
|
}
|
package/dist/project-modules.js
CHANGED
|
@@ -41,6 +41,7 @@ const node_fs_1 = require("node:fs");
|
|
|
41
41
|
const fsPromises = __importStar(require("node:fs/promises"));
|
|
42
42
|
const node_path_1 = require("node:path");
|
|
43
43
|
const cli_1 = require("@antelopejs/core/cli");
|
|
44
|
+
const guards_1 = require("./internal/guards");
|
|
44
45
|
const layers_1 = require("./layers");
|
|
45
46
|
const private_values_1 = require("./private-values");
|
|
46
47
|
exports.FRONTEND_DECLARATION_FIELD = "dmsFrontend";
|
|
@@ -66,9 +67,12 @@ const NODE_FILE_SYSTEM = {
|
|
|
66
67
|
};
|
|
67
68
|
function readAntelopeManifest(folder) {
|
|
68
69
|
const dedicated = (0, node_path_1.join)(folder, MODULE_MANIFEST_FILE);
|
|
69
|
-
if ((0, node_fs_1.existsSync)(dedicated))
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
if ((0, node_fs_1.existsSync)(dedicated)) {
|
|
71
|
+
const manifest = JSON.parse((0, node_fs_1.readFileSync)(dedicated, "utf-8"));
|
|
72
|
+
return (0, guards_1.isObjectLike)(manifest) ? manifest : undefined;
|
|
73
|
+
}
|
|
74
|
+
const block = (0, layers_1.readLayerPackage)(folder)?.antelopeJs;
|
|
75
|
+
return (0, guards_1.isObjectLike)(block) ? block : undefined;
|
|
72
76
|
}
|
|
73
77
|
function warnUndeclaredConfigVars(id) {
|
|
74
78
|
(0, cli_1.getProcessUi)().message("warn", `${id} declares no antelopeJs.configVarsFile in its package.json: the \${@${id}.<VAR>} references are left unresolved`, { detail: `Upgrade ${id} to a version that declares it` });
|
|
@@ -76,19 +80,19 @@ function warnUndeclaredConfigVars(id) {
|
|
|
76
80
|
function configVarsProvider(id, folder) {
|
|
77
81
|
const manifest = readAntelopeManifest(folder);
|
|
78
82
|
const file = manifest?.configVarsFile;
|
|
79
|
-
if (
|
|
83
|
+
if (!(0, guards_1.isText)(file)) {
|
|
80
84
|
warnUndeclaredConfigVars(id);
|
|
81
85
|
return undefined;
|
|
82
86
|
}
|
|
83
87
|
const { configVars } = require((0, node_path_1.join)(folder, file));
|
|
84
|
-
if (
|
|
88
|
+
if (!(0, guards_1.isCallable)(configVars)) {
|
|
85
89
|
throw new cli_1.CliError({
|
|
86
90
|
title: `${id}: ${file} exports no configVars function`,
|
|
87
91
|
fixes: [`Export configVars(config) from ${file}`],
|
|
88
92
|
});
|
|
89
93
|
}
|
|
90
94
|
const declared = Array.isArray(manifest?.configVars)
|
|
91
|
-
? manifest.configVars.filter(
|
|
95
|
+
? manifest.configVars.filter(guards_1.isText)
|
|
92
96
|
: [];
|
|
93
97
|
return { declared, configVars };
|
|
94
98
|
}
|
|
@@ -146,7 +150,7 @@ async function loadProjectConfig(projectDir, environment) {
|
|
|
146
150
|
const loader = new ConfigLoader(NODE_FILE_SYSTEM);
|
|
147
151
|
let loaded;
|
|
148
152
|
try {
|
|
149
|
-
loaded =
|
|
153
|
+
loaded = await loader.load(projectDir, environment);
|
|
150
154
|
}
|
|
151
155
|
catch (error) {
|
|
152
156
|
throw new cli_1.CliError({
|
|
@@ -185,7 +189,9 @@ function moduleFolder(projectDir, cacheFolder, source) {
|
|
|
185
189
|
function readShippingVersion(sourcePath) {
|
|
186
190
|
try {
|
|
187
191
|
const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)((0, node_path_1.dirname)(sourcePath), "package.json"), "utf-8"));
|
|
188
|
-
return
|
|
192
|
+
return (0, guards_1.isObjectLike)(pkg) && "version" in pkg && (0, guards_1.isText)(pkg.version)
|
|
193
|
+
? pkg.version
|
|
194
|
+
: undefined;
|
|
189
195
|
}
|
|
190
196
|
catch {
|
|
191
197
|
return undefined;
|
|
@@ -197,7 +203,7 @@ function toLayer(registration) {
|
|
|
197
203
|
path: registration.sourcePath,
|
|
198
204
|
name: registration.name,
|
|
199
205
|
sourcePath: registration.sourcePath,
|
|
200
|
-
packageName:
|
|
206
|
+
packageName: (0, guards_1.isText)(name) ? name : undefined,
|
|
201
207
|
priority: registration.priority ?? 0,
|
|
202
208
|
configKey: registration.configKey,
|
|
203
209
|
options: registration.options ?? {},
|
|
@@ -218,12 +224,12 @@ function warnUndeclaredFrontend(id, folder) {
|
|
|
218
224
|
}
|
|
219
225
|
function registrationOf(id, folder, config, context) {
|
|
220
226
|
const declaration = (0, layers_1.readLayerPackage)(folder)?.[exports.FRONTEND_DECLARATION_FIELD];
|
|
221
|
-
if (
|
|
227
|
+
if (!(0, guards_1.isText)(declaration)) {
|
|
222
228
|
warnUndeclaredFrontend(id, folder);
|
|
223
229
|
return undefined;
|
|
224
230
|
}
|
|
225
231
|
const { frontendModule } = require((0, node_path_1.join)(folder, declaration));
|
|
226
|
-
if (
|
|
232
|
+
if (!(0, guards_1.isCallable)(frontendModule)) {
|
|
227
233
|
throw new cli_1.CliError({
|
|
228
234
|
title: `${id}: ${declaration} exports no frontendModule function`,
|
|
229
235
|
fixes: [`Export frontendModule(config, context) from ${declaration}`],
|
package/dist/renderer-range.js
CHANGED
|
@@ -10,6 +10,7 @@ const cli_1 = require("@antelopejs/core/cli");
|
|
|
10
10
|
const semver_1 = __importDefault(require("semver"));
|
|
11
11
|
const layers_1 = require("./layers");
|
|
12
12
|
const output_1 = require("./output");
|
|
13
|
+
const guards_1 = require("./internal/guards");
|
|
13
14
|
const OWN_RELEASE = require("../package.json");
|
|
14
15
|
const noticedModules = new Set();
|
|
15
16
|
const NOTICED_MODULES_FILE = ".renderer-range-noticed";
|
|
@@ -45,7 +46,7 @@ function releaseLine(version) {
|
|
|
45
46
|
}
|
|
46
47
|
function describeProblem(declaration, version) {
|
|
47
48
|
const { shown, range } = declaration;
|
|
48
|
-
if (
|
|
49
|
+
if (!(0, guards_1.isText)(range) || semver_1.default.validRange(range) === null)
|
|
49
50
|
return `${shown} declares an unreadable range: ${JSON.stringify(range)}`;
|
|
50
51
|
if (semver_1.default.satisfies(releaseLine(version), range))
|
|
51
52
|
return undefined;
|
package/dist/server-process.js
CHANGED
|
@@ -11,6 +11,7 @@ const node_path_1 = require("node:path");
|
|
|
11
11
|
const cli_1 = require("@antelopejs/core/cli");
|
|
12
12
|
const cancellation_1 = require("./cancellation");
|
|
13
13
|
const workspace_setup_1 = require("./workspace-setup");
|
|
14
|
+
const guards_1 = require("./internal/guards");
|
|
14
15
|
const READY_MESSAGE = "dms:ready";
|
|
15
16
|
const LISTEN_ERROR_MESSAGE = "dms:listen-error";
|
|
16
17
|
const START_ERROR_MESSAGE = "dms:start-error";
|
|
@@ -36,8 +37,7 @@ function stopOnAbort(child, signal) {
|
|
|
36
37
|
process.kill(-child.pid, "SIGTERM");
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
|
-
catch {
|
|
40
|
-
}
|
|
40
|
+
catch { }
|
|
41
41
|
};
|
|
42
42
|
if (signal.aborted) {
|
|
43
43
|
stop();
|
|
@@ -46,43 +46,44 @@ function stopOnAbort(child, signal) {
|
|
|
46
46
|
signal.addEventListener("abort", stop, { once: true });
|
|
47
47
|
child.once("exit", () => signal.removeEventListener("abort", stop));
|
|
48
48
|
}
|
|
49
|
-
function
|
|
50
|
-
return
|
|
49
|
+
function hasFile(value) {
|
|
50
|
+
return (0, guards_1.isObjectLike)(value) && "file" in value && (0, guards_1.isText)(value.file);
|
|
51
|
+
}
|
|
52
|
+
function isServerMessage(message) {
|
|
53
|
+
return (0, guards_1.isObjectLike)(message);
|
|
51
54
|
}
|
|
52
55
|
function readReady(message) {
|
|
53
|
-
if (!
|
|
56
|
+
if (!isServerMessage(message) || message.type !== READY_MESSAGE)
|
|
54
57
|
return undefined;
|
|
55
58
|
const { address, port } = message;
|
|
56
|
-
if (
|
|
59
|
+
if (!(0, guards_1.isText)(address) || !(0, guards_1.isNumber)(port))
|
|
57
60
|
return undefined;
|
|
58
61
|
return { address, port };
|
|
59
62
|
}
|
|
60
63
|
function readListenError(message) {
|
|
61
|
-
if (!
|
|
64
|
+
if (!isServerMessage(message) || message.type !== LISTEN_ERROR_MESSAGE)
|
|
62
65
|
return undefined;
|
|
63
66
|
return {
|
|
64
|
-
code:
|
|
67
|
+
code: (0, guards_1.isText)(message.code) ? message.code : undefined,
|
|
65
68
|
message: String(message.message),
|
|
66
69
|
host: String(message.host),
|
|
67
70
|
port: Number(message.port),
|
|
68
71
|
};
|
|
69
72
|
}
|
|
70
73
|
function readStartError(message) {
|
|
71
|
-
if (!
|
|
74
|
+
if (!isServerMessage(message) || message.type !== START_ERROR_MESSAGE)
|
|
72
75
|
return undefined;
|
|
73
76
|
const { location } = message;
|
|
74
|
-
const isLocated =
|
|
77
|
+
const isLocated = hasFile(location);
|
|
75
78
|
return {
|
|
76
79
|
message: String(message.message),
|
|
77
|
-
code:
|
|
80
|
+
code: (0, guards_1.isText)(message.code) ? message.code : undefined,
|
|
78
81
|
location: isLocated
|
|
79
82
|
? {
|
|
80
83
|
file: String(location.file),
|
|
81
|
-
line:
|
|
82
|
-
column:
|
|
83
|
-
lineText:
|
|
84
|
-
? location.lineText
|
|
85
|
-
: undefined,
|
|
84
|
+
line: (0, guards_1.isNumber)(location.line) ? location.line : undefined,
|
|
85
|
+
column: (0, guards_1.isNumber)(location.column) ? location.column : undefined,
|
|
86
|
+
lineText: (0, guards_1.isText)(location.lineText) ? location.lineText : undefined,
|
|
86
87
|
}
|
|
87
88
|
: undefined,
|
|
88
89
|
};
|
package/dist/update-check.js
CHANGED
|
@@ -48,6 +48,7 @@ const node_path_1 = require("node:path");
|
|
|
48
48
|
const cli_1 = require("@antelopejs/core/cli");
|
|
49
49
|
const config_1 = require("./config");
|
|
50
50
|
const output_1 = require("./output");
|
|
51
|
+
const guards_1 = require("./internal/guards");
|
|
51
52
|
exports.UPDATE_CHECK_PACKAGE = "@antelopejs/dms-frontend";
|
|
52
53
|
const DEFAULT_REGISTRY_URL = "https://registry.npmjs.org/";
|
|
53
54
|
const UPDATE_COMMAND = "ajs update dms";
|
|
@@ -104,20 +105,24 @@ function isUpdateCheckEnabled(argv, env) {
|
|
|
104
105
|
function updateCheckCacheFile() {
|
|
105
106
|
return (0, node_path_1.join)(config_1.DMS_FRONTEND_HOME, "update-check.json");
|
|
106
107
|
}
|
|
108
|
+
function isUpdateCheckCache(value) {
|
|
109
|
+
return ((0, guards_1.isObjectLike)(value) &&
|
|
110
|
+
"checkedAt" in value &&
|
|
111
|
+
(0, guards_1.isNumber)(value.checkedAt) &&
|
|
112
|
+
(!("latestVersion" in value) ||
|
|
113
|
+
value.latestVersion === undefined ||
|
|
114
|
+
(0, guards_1.isText)(value.latestVersion)) &&
|
|
115
|
+
(!("succeeded" in value) ||
|
|
116
|
+
value.succeeded === undefined ||
|
|
117
|
+
(0, guards_1.isFlag)(value.succeeded)));
|
|
118
|
+
}
|
|
107
119
|
function readCache(file) {
|
|
108
120
|
try {
|
|
109
121
|
const parsed = JSON.parse((0, node_fs_1.readFileSync)(file, "utf-8"));
|
|
110
|
-
if (
|
|
111
|
-
return undefined;
|
|
112
|
-
const latestVersion = parsed.latestVersion;
|
|
113
|
-
if (latestVersion !== undefined && typeof latestVersion !== "string") {
|
|
114
|
-
return undefined;
|
|
115
|
-
}
|
|
116
|
-
const succeeded = parsed.succeeded;
|
|
117
|
-
if (succeeded !== undefined && typeof succeeded !== "boolean") {
|
|
122
|
+
if (!isUpdateCheckCache(parsed))
|
|
118
123
|
return undefined;
|
|
119
|
-
}
|
|
120
|
-
return { checkedAt
|
|
124
|
+
const { checkedAt, latestVersion, succeeded } = parsed;
|
|
125
|
+
return { checkedAt, latestVersion, succeeded };
|
|
121
126
|
}
|
|
122
127
|
catch {
|
|
123
128
|
return undefined;
|
|
@@ -128,8 +133,7 @@ function writeCache(file, cache) {
|
|
|
128
133
|
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(file), { recursive: true });
|
|
129
134
|
(0, node_fs_1.writeFileSync)(file, `${JSON.stringify(cache)}\n`);
|
|
130
135
|
}
|
|
131
|
-
catch {
|
|
132
|
-
}
|
|
136
|
+
catch { }
|
|
133
137
|
}
|
|
134
138
|
function fetchLatestVersionFromRegistry(packageName, registryUrl = DEFAULT_REGISTRY_URL, timeoutMs = exports.UPDATE_CHECK_TIMEOUT_MS) {
|
|
135
139
|
return new Promise((resolve) => {
|
|
@@ -160,8 +164,12 @@ function fetchLatestVersionFromRegistry(packageName, registryUrl = DEFAULT_REGIS
|
|
|
160
164
|
});
|
|
161
165
|
response.on("end", () => {
|
|
162
166
|
try {
|
|
163
|
-
const
|
|
164
|
-
settle(
|
|
167
|
+
const parsed = JSON.parse(body);
|
|
168
|
+
settle((0, guards_1.isObjectLike)(parsed) &&
|
|
169
|
+
"version" in parsed &&
|
|
170
|
+
(0, guards_1.isText)(parsed.version)
|
|
171
|
+
? parsed.version
|
|
172
|
+
: undefined);
|
|
165
173
|
}
|
|
166
174
|
catch {
|
|
167
175
|
settle();
|
|
@@ -220,8 +228,7 @@ function startUpdateCheck(options) {
|
|
|
220
228
|
latestVersion,
|
|
221
229
|
succeeded: published !== undefined,
|
|
222
230
|
});
|
|
223
|
-
}, () => {
|
|
224
|
-
});
|
|
231
|
+
}, () => { });
|
|
225
232
|
let isReported = false;
|
|
226
233
|
const report = async (placement = {}) => {
|
|
227
234
|
if (isReported)
|
|
@@ -98,7 +98,7 @@ function checkClientBundle(workspace) {
|
|
|
98
98
|
const clientRoot = (0, node_path_1.join)(workspace, "dist", "client");
|
|
99
99
|
const manifest = readJson((0, node_path_1.join)(clientRoot, ".vite", "manifest.json"));
|
|
100
100
|
const mainEntry = Object.values(manifest).find((entry) => entry.isEntry);
|
|
101
|
-
ensure(mainEntry, "The Vite manifest names no entry chunk");
|
|
101
|
+
ensure(mainEntry !== undefined, "The Vite manifest names no entry chunk");
|
|
102
102
|
const mainJavascript = (0, node_fs_1.readFileSync)((0, node_path_1.join)(clientRoot, mainEntry.file), "utf8");
|
|
103
103
|
const javascript = (0, node_fs_1.readdirSync)((0, node_path_1.join)(clientRoot, "assets"))
|
|
104
104
|
.filter((file) => file.endsWith(".js"))
|
|
@@ -119,7 +119,7 @@ async function checkServerModulesBundle(workspace) {
|
|
|
119
119
|
.map((file) => (0, node_fs_1.readFileSync)((0, node_path_1.join)(root, file), "utf8"))
|
|
120
120
|
.join("\n");
|
|
121
121
|
ensure(!/\.vue["'?]|createApp\(|DefaultLayout/.test(javascript), "The server modules bundle loads application code", "A dms.server.ts imports server code only, never .vue files or dms.frontend.ts.");
|
|
122
|
-
const { serverModules } =
|
|
122
|
+
const { serverModules } = await Promise.resolve(`${(0, node_path_1.join)(root, "server-modules.generated.js")}`).then(s => __importStar(require(s)));
|
|
123
123
|
ensure(Array.isArray(serverModules), "The server modules bundle exports none");
|
|
124
124
|
return `${(0, cli_1.pluralize)(serverModules.length, "server module")}, ${(0, output_1.formatSize)(Buffer.byteLength(javascript))} JS`;
|
|
125
125
|
}
|
package/dist/workspace-setup.js
CHANGED
package/dist/workspace.js
CHANGED
|
@@ -15,6 +15,7 @@ exports.isUnauthorized = isUnauthorized;
|
|
|
15
15
|
const node_fs_1 = require("node:fs");
|
|
16
16
|
const node_path_1 = require("node:path");
|
|
17
17
|
const config_1 = require("./config");
|
|
18
|
+
const guards_1 = require("./internal/guards");
|
|
18
19
|
const WORKSPACE_META_FILE = ".ajs-dms-meta.json";
|
|
19
20
|
function getWorkspaceDirForKey(key) {
|
|
20
21
|
return (0, node_path_1.join)(config_1.DMS_FRONTEND_HOME, (0, config_1.sha256Hex)(key));
|
|
@@ -75,15 +76,16 @@ function readWorkspaceMeta(dir) {
|
|
|
75
76
|
catch {
|
|
76
77
|
return undefined;
|
|
77
78
|
}
|
|
78
|
-
const
|
|
79
|
+
const backendUrl = (0, guards_1.isObjectLike)(meta) && "backendUrl" in meta ? meta.backendUrl : undefined;
|
|
80
|
+
const workspaceKey = (0, guards_1.isObjectLike)(meta) && "workspaceKey" in meta
|
|
81
|
+
? meta.workspaceKey
|
|
82
|
+
: undefined;
|
|
83
|
+
const updatedAt = (0, guards_1.isObjectLike)(meta) && "updatedAt" in meta ? meta.updatedAt : undefined;
|
|
79
84
|
return {
|
|
80
|
-
backendUrl:
|
|
81
|
-
workspaceKey:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
updatedAt: typeof record?.updatedAt === "string" &&
|
|
85
|
-
!Number.isNaN(Date.parse(record.updatedAt))
|
|
86
|
-
? new Date(record.updatedAt).toISOString()
|
|
85
|
+
backendUrl: (0, guards_1.isText)(backendUrl) ? backendUrl : undefined,
|
|
86
|
+
workspaceKey: (0, guards_1.isText)(workspaceKey) ? workspaceKey : undefined,
|
|
87
|
+
updatedAt: (0, guards_1.isText)(updatedAt) && !Number.isNaN(Date.parse(updatedAt))
|
|
88
|
+
? new Date(updatedAt).toISOString()
|
|
87
89
|
: undefined,
|
|
88
90
|
};
|
|
89
91
|
}
|
|
@@ -116,8 +118,7 @@ function directorySize(dir) {
|
|
|
116
118
|
seen.add(inode);
|
|
117
119
|
total += stats.size;
|
|
118
120
|
}
|
|
119
|
-
catch {
|
|
120
|
-
}
|
|
121
|
+
catch { }
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
124
|
return total;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/dms-frontend",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Frontend-agnostic loader for AntelopeJS DMS, shipping the Vue 3 renderer (Vite, Inertia, SSR)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelope",
|
|
@@ -65,13 +65,14 @@
|
|
|
65
65
|
"test:cli": "pnpm run build && DMS_PREBUILT=1 node --import tsx --test tests/cli.test.ts 'tests/cli-*.test.{ts,mts}'",
|
|
66
66
|
"test:real-source": "pnpm run build && node dist/verify-source-runner.js",
|
|
67
67
|
"format": "oxfmt .",
|
|
68
|
-
"lint": "oxlint && antelopejs-check-interface-ranges && pnpm run docs:reference:check",
|
|
68
|
+
"lint": "oxlint && antelopejs-check-interface-ranges && pnpm run docs:reference:check && pnpm run source-checks",
|
|
69
69
|
"typecheck": "tsc --noEmit",
|
|
70
70
|
"lint:fix": "oxlint --fix --max-warnings=1000000 && oxfmt .",
|
|
71
71
|
"knip": "knip --dependencies",
|
|
72
72
|
"knip:all": "knip",
|
|
73
73
|
"docs:reference": "tsx scripts/docs-reference.ts",
|
|
74
74
|
"docs:reference:check": "tsx scripts/docs-reference.ts --check",
|
|
75
|
+
"source-checks": "tsx scripts/source-checks.ts",
|
|
75
76
|
"prepare": "if git rev-parse --is-inside-work-tree >/dev/null 2>&1 && command -v lefthook >/dev/null 2>&1; then lefthook install; fi",
|
|
76
77
|
"checks": "antelopejs-checks",
|
|
77
78
|
"size": "antelopejs-check-size",
|
|
@@ -79,7 +80,9 @@
|
|
|
79
80
|
"sync": "antelopejs-sync",
|
|
80
81
|
"ratchet:update": "antelopejs-ratchet --update",
|
|
81
82
|
"sync:check": "antelopejs-sync --check",
|
|
82
|
-
"format:check": "oxfmt --check ."
|
|
83
|
+
"format:check": "oxfmt --check .",
|
|
84
|
+
"suppressions": "antelopejs-suppressions",
|
|
85
|
+
"suppressions:update": "antelopejs-suppressions --update"
|
|
83
86
|
},
|
|
84
87
|
"dependencies": {
|
|
85
88
|
"@intlify/message-compiler": "^11.1.12",
|
|
@@ -90,7 +93,7 @@
|
|
|
90
93
|
},
|
|
91
94
|
"devDependencies": {
|
|
92
95
|
"@antelopejs/core": "^1.16.0",
|
|
93
|
-
"@antelopejs/tooling-configs": "^0.2.
|
|
96
|
+
"@antelopejs/tooling-configs": "^0.2.17",
|
|
94
97
|
"@iconify/utils": "^3.1.0",
|
|
95
98
|
"@iconify/vue": "^5.0.1",
|
|
96
99
|
"@inertiajs/vue3": "^3.7.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dms-frontend
|
|
3
|
-
description: Runs, builds, deploys and extends the AntelopeJS DMS frontend with @antelopejs/dms-frontend (the ajs dms CLI, the Vue renderer, the frontend-module SDK). Use when running ajs dms dev, build, start, prepare, workspaces, clean or verify-source; configuring DMS_* environment variables, the session or bootstrap secret; writing a frontend module's dms.frontend.ts, dms.server.ts (server routes, auth hooks, route rules, backend proxies) or dms.frontend.build.ts; declaring engines["@antelopejs/dms-frontend"]; deploying the frontend server behind a reverse proxy; or debugging a refused range, a missing secret, a 404 from the proxy or a stale workspace.
|
|
3
|
+
description: Runs, builds, deploys and extends the AntelopeJS DMS frontend with @antelopejs/dms-frontend (the ajs dms CLI, the Vue renderer, the frontend-module SDK). Use when running ajs dms dev, build, start, prepare, workspaces, clean or verify-source; configuring DMS_* environment variables, the session or bootstrap secret; writing a frontend module's dms.frontend.ts, dms.server.ts (server routes, auth hooks, route rules, backend proxies) or dms.frontend.build.ts; declaring engines["@antelopejs/dms-frontend"]; deploying the frontend server behind a reverse proxy; or debugging a refused range, a missing secret, a 404 from the proxy or a stale workspace. Not for restarting a DMS project's running backend and frontend dev servers or reading their logs (use dms-project).
|
|
4
4
|
icon: i-lucide-app-window
|
|
5
5
|
category: tooling
|
|
6
6
|
tags: [frontend, cli, renderer, vue, inertia, ssr, deployment, dms-module]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"cases": [
|
|
4
|
+
{
|
|
5
|
+
"id": "deploy-dashboard",
|
|
6
|
+
"area": "dms",
|
|
7
|
+
"style": "clean",
|
|
8
|
+
"prompt": "Deploy the dashboard to production behind an nginx reverse proxy.",
|
|
9
|
+
"expect": {
|
|
10
|
+
"skills": ["dms-frontend"],
|
|
11
|
+
"acceptable": ["dms-project", "dms"]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "dms-build-401-casual",
|
|
16
|
+
"area": "dms",
|
|
17
|
+
"style": "casual",
|
|
18
|
+
"prompt": "ajs dms build fails with a 401, wtf",
|
|
19
|
+
"expect": {
|
|
20
|
+
"skills": ["dms-frontend"],
|
|
21
|
+
"acceptable": ["dms-project", "ajs-cli"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "frontend-session-secret",
|
|
26
|
+
"area": "dms",
|
|
27
|
+
"style": "clean",
|
|
28
|
+
"prompt": "The frontend server refuses to start because of a missing session secret. How do I configure it?",
|
|
29
|
+
"expect": {
|
|
30
|
+
"skills": ["dms-frontend"],
|
|
31
|
+
"acceptable": ["dms-project"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "frontend-server-route",
|
|
36
|
+
"area": "dms",
|
|
37
|
+
"style": "clean",
|
|
38
|
+
"prompt": "Add a server route to my module's frontend (dms.server.ts) that proxies to an external API.",
|
|
39
|
+
"expect": {
|
|
40
|
+
"skills": ["dms-frontend"],
|
|
41
|
+
"acceptable": ["dms-module", "dms"]
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "dms-frontend-not-dev-servers",
|
|
46
|
+
"area": "dms",
|
|
47
|
+
"style": "clean",
|
|
48
|
+
"prompt": "My page change does not show live. How do I restart the backend and the frontend dev servers of my DMS project and read their logs?",
|
|
49
|
+
"expect": {
|
|
50
|
+
"skills": ["dms-project"],
|
|
51
|
+
"acceptable": ["dms"],
|
|
52
|
+
"avoid": ["dms-frontend"]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "dms-frontend-backend-proxy",
|
|
57
|
+
"area": "dms",
|
|
58
|
+
"style": "clean",
|
|
59
|
+
"prompt": "Browser requests to /reports/summary answer 404 although my backend serves that route. How do I let the frontend server reach it?",
|
|
60
|
+
"expect": {
|
|
61
|
+
"skills": ["dms-frontend"],
|
|
62
|
+
"acceptable": ["dms-project", "dms-module"]
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "dms-frontend-module-entry",
|
|
67
|
+
"area": "dms",
|
|
68
|
+
"style": "clean",
|
|
69
|
+
"prompt": "Write the dms.frontend.ts entry for my module so its components are namespaced under the Acme prefix.",
|
|
70
|
+
"expect": {
|
|
71
|
+
"skills": ["dms-frontend"],
|
|
72
|
+
"acceptable": ["dms-module", "dms"],
|
|
73
|
+
"mustMention": ["componentPrefix", "setup"]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|