@antelopejs/dms-frontend 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +131 -0
- package/dist/commands/build.js +66 -0
- package/dist/commands/clean.js +42 -0
- package/dist/commands/dev.js +116 -0
- package/dist/commands/prepare.js +60 -0
- package/dist/commands/start.js +49 -0
- package/dist/commands/verify-source.js +39 -0
- package/dist/common.js +24 -0
- package/dist/config.js +142 -0
- package/dist/discovery.js +123 -0
- package/dist/fs-sync.js +142 -0
- package/dist/index.js +44 -0
- package/dist/layer-watch.js +154 -0
- package/dist/layers.js +120 -0
- package/dist/manifest.js +109 -0
- package/dist/materialize.js +249 -0
- package/dist/ports.js +30 -0
- package/dist/update-check.js +173 -0
- package/dist/utils/cli-ui.js +178 -0
- package/dist/verify-source-runner.js +228 -0
- package/dist/workspace-setup.js +109 -0
- package/dist/workspace.js +76 -0
- package/package.json +97 -0
- package/templates/vue/DmsDynamicPage.vue +89 -0
- package/templates/vue/app-config-stub.mjs +1 -0
- package/templates/vue/app-runtime.ts +240 -0
- package/templates/vue/compress-assets.mjs +48 -0
- package/templates/vue/email-locales.ts +32 -0
- package/templates/vue/email-renderer.ts +159 -0
- package/templates/vue/email-runtime.ts +23 -0
- package/templates/vue/frontend-module.ts +1418 -0
- package/templates/vue/globals.d.ts +1 -0
- package/templates/vue/index.html +24 -0
- package/templates/vue/main.ts +33 -0
- package/templates/vue/npmrc +2 -0
- package/templates/vue/package.json +35 -0
- package/templates/vue/pnpm-workspace.yaml +4 -0
- package/templates/vue/server/auth/backend.mjs +83 -0
- package/templates/vue/server/auth/client-ip.mjs +52 -0
- package/templates/vue/server/auth/oauth.mjs +213 -0
- package/templates/vue/server/auth/routes.mjs +254 -0
- package/templates/vue/server/auth/session.mjs +180 -0
- package/templates/vue/server/client-manifest.mjs +116 -0
- package/templates/vue/server/email.mjs +36 -0
- package/templates/vue/server/inertia.mjs +79 -0
- package/templates/vue/server/render-token.mjs +81 -0
- package/templates/vue/server/tester.mjs +228 -0
- package/templates/vue/server.mjs +526 -0
- package/templates/vue/ssr-renderer.ts +146 -0
- package/templates/vue/tsconfig.json +31 -0
- package/templates/vue/typecheck-loader.mjs +13 -0
- package/templates/vue/vite.config.ts +161 -0
- package/templates/vue/vite.email.config.ts +77 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Spinner = void 0;
|
|
7
|
+
exports.displayBox = displayBox;
|
|
8
|
+
exports.displayBanner = displayBanner;
|
|
9
|
+
exports.success = success;
|
|
10
|
+
exports.error = error;
|
|
11
|
+
exports.warning = warning;
|
|
12
|
+
exports.info = info;
|
|
13
|
+
exports.header = header;
|
|
14
|
+
exports.keyValue = keyValue;
|
|
15
|
+
const boxen_1 = __importDefault(require("boxen"));
|
|
16
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
17
|
+
const figlet_1 = __importDefault(require("figlet"));
|
|
18
|
+
const clearLine = () => process.stdout.write("\r\x1b[K");
|
|
19
|
+
const spinnerChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
20
|
+
const SPINNER_INTERVAL_MS = 80;
|
|
21
|
+
function isTerminalOutput() {
|
|
22
|
+
return process.stdout.isTTY ?? false;
|
|
23
|
+
}
|
|
24
|
+
class Spinner {
|
|
25
|
+
constructor(text) {
|
|
26
|
+
this.isRunning = false;
|
|
27
|
+
this.currentCharIndex = 0;
|
|
28
|
+
this.isTerminal = isTerminalOutput();
|
|
29
|
+
this.text = text;
|
|
30
|
+
}
|
|
31
|
+
async start(text) {
|
|
32
|
+
if (text) {
|
|
33
|
+
this.text = text;
|
|
34
|
+
}
|
|
35
|
+
if (this.isRunning) {
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
this.isRunning = true;
|
|
39
|
+
this.currentCharIndex = 0;
|
|
40
|
+
if (!this.isTerminal) {
|
|
41
|
+
console.log(` ${this.text}`);
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
this.interval = setInterval(() => {
|
|
45
|
+
if (this.isRunning) {
|
|
46
|
+
const spinnerChar = spinnerChars[this.currentCharIndex];
|
|
47
|
+
process.stdout.write(`\r${chalk_1.default.cyan(spinnerChar)} ${this.text}`);
|
|
48
|
+
this.currentCharIndex =
|
|
49
|
+
(this.currentCharIndex + 1) % spinnerChars.length;
|
|
50
|
+
}
|
|
51
|
+
}, SPINNER_INTERVAL_MS);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
update(text) {
|
|
55
|
+
this.text = text;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
log(stream, message) {
|
|
59
|
+
if (this.isRunning && this.isTerminal) {
|
|
60
|
+
clearLine();
|
|
61
|
+
stream.write(`${message}\n`);
|
|
62
|
+
const spinnerChar = spinnerChars[this.currentCharIndex];
|
|
63
|
+
process.stdout.write(`${chalk_1.default.cyan(spinnerChar)} ${this.text}`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
stream.write(`${message}\n`);
|
|
67
|
+
}
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
async succeed(text) {
|
|
71
|
+
if (!this.isRunning)
|
|
72
|
+
return;
|
|
73
|
+
await this.stop();
|
|
74
|
+
const message = text || this.text;
|
|
75
|
+
if (this.isTerminal) {
|
|
76
|
+
process.stdout.write(`\r${chalk_1.default.bold.green("✓")} ${message}\n`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.log(`✓ ${message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async fail(text) {
|
|
83
|
+
if (!this.isRunning)
|
|
84
|
+
return;
|
|
85
|
+
await this.stop();
|
|
86
|
+
const message = text || this.text;
|
|
87
|
+
if (this.isTerminal) {
|
|
88
|
+
process.stdout.write(`\r${chalk_1.default.bold.red("✗")} ${chalk_1.default.red(message)}\n`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.log(`✗ ${message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async info(text) {
|
|
95
|
+
if (!this.isRunning)
|
|
96
|
+
return;
|
|
97
|
+
await this.stop();
|
|
98
|
+
const message = text || this.text;
|
|
99
|
+
if (this.isTerminal) {
|
|
100
|
+
process.stdout.write(`\r${chalk_1.default.bold.blue("ℹ")} ${message}\n`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log(`ℹ ${message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async warn(text) {
|
|
107
|
+
if (!this.isRunning)
|
|
108
|
+
return;
|
|
109
|
+
await this.stop();
|
|
110
|
+
const message = text || this.text;
|
|
111
|
+
if (this.isTerminal) {
|
|
112
|
+
process.stdout.write(`\r${chalk_1.default.bold.yellow("⚠")} ${message}\n`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(`⚠ ${message}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async pause() {
|
|
119
|
+
if (this.interval) {
|
|
120
|
+
clearInterval(this.interval);
|
|
121
|
+
this.interval = undefined;
|
|
122
|
+
}
|
|
123
|
+
if (this.isTerminal) {
|
|
124
|
+
clearLine();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async stop() {
|
|
128
|
+
if (this.interval) {
|
|
129
|
+
clearInterval(this.interval);
|
|
130
|
+
this.interval = undefined;
|
|
131
|
+
}
|
|
132
|
+
this.isRunning = false;
|
|
133
|
+
if (this.isTerminal) {
|
|
134
|
+
clearLine();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async clear() {
|
|
138
|
+
await this.stop();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.Spinner = Spinner;
|
|
142
|
+
function displayBox(message, title, options) {
|
|
143
|
+
const defaultOptions = {
|
|
144
|
+
padding: 1,
|
|
145
|
+
margin: 1,
|
|
146
|
+
borderStyle: "round",
|
|
147
|
+
borderColor: "blue",
|
|
148
|
+
title: title,
|
|
149
|
+
titleAlignment: "center",
|
|
150
|
+
};
|
|
151
|
+
console.log((0, boxen_1.default)(message, { ...defaultOptions, ...options }));
|
|
152
|
+
}
|
|
153
|
+
function displayBanner(text, font) {
|
|
154
|
+
const figletText = figlet_1.default.textSync(text, {
|
|
155
|
+
font: (font || "Standard"),
|
|
156
|
+
});
|
|
157
|
+
console.log(chalk_1.default.blue(figletText));
|
|
158
|
+
}
|
|
159
|
+
function success(message) {
|
|
160
|
+
console.log(`${chalk_1.default.green.bold("✓")} ${message}`);
|
|
161
|
+
}
|
|
162
|
+
function error(message) {
|
|
163
|
+
console.log(`${chalk_1.default.red.bold("✗")} ${chalk_1.default.red(message)}`);
|
|
164
|
+
}
|
|
165
|
+
function warning(message) {
|
|
166
|
+
console.log(`${chalk_1.default.yellow.bold("⚠")} ${chalk_1.default.yellow(message)}`);
|
|
167
|
+
}
|
|
168
|
+
function info(message) {
|
|
169
|
+
console.log(`${chalk_1.default.blue.bold("ℹ")} ${message}`);
|
|
170
|
+
}
|
|
171
|
+
function header(text) {
|
|
172
|
+
console.log("");
|
|
173
|
+
console.log(chalk_1.default.bold.blue(text));
|
|
174
|
+
console.log(chalk_1.default.blue("─".repeat(text.length)));
|
|
175
|
+
}
|
|
176
|
+
function keyValue(key, value) {
|
|
177
|
+
return `${chalk_1.default.cyan(key)}: ${value}`;
|
|
178
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
40
|
+
const node_child_process_1 = require("node:child_process");
|
|
41
|
+
const node_fs_1 = require("node:fs");
|
|
42
|
+
const node_os_1 = require("node:os");
|
|
43
|
+
const node_path_1 = require("node:path");
|
|
44
|
+
const common_1 = require("./common");
|
|
45
|
+
function removeDevelopmentDependencies(root) {
|
|
46
|
+
const packagePath = (0, node_path_1.join)(root, "package.json");
|
|
47
|
+
if (!(0, node_fs_1.existsSync)(packagePath))
|
|
48
|
+
return;
|
|
49
|
+
const packageData = JSON.parse((0, node_fs_1.readFileSync)(packagePath, "utf8"));
|
|
50
|
+
delete packageData.devDependencies;
|
|
51
|
+
(0, node_fs_1.writeFileSync)(packagePath, `${JSON.stringify(packageData, null, 2)}\n`);
|
|
52
|
+
}
|
|
53
|
+
if (!process.env.DMS_LAYER_SOURCE)
|
|
54
|
+
throw new Error("DMS_LAYER_SOURCE must identify a frontend package");
|
|
55
|
+
const sourceRoot = (0, node_path_1.resolve)(process.env.DMS_LAYER_SOURCE);
|
|
56
|
+
const workspace = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "dms-inertia-real-source-"));
|
|
57
|
+
const templateRoot = (0, node_path_1.join)((0, common_1.getPackageRoot)(), "templates", "vue");
|
|
58
|
+
const commandEnvironment = { ...process.env };
|
|
59
|
+
const EMAIL_BUILD_SIZE_CEILING_BYTES = 256 * 1024;
|
|
60
|
+
const NON_EMAIL_RUNTIME_PATTERN = /DisplayRichText|ApexCharts|Tiptap|FlowCanvas|app\/.*table|components\/table/i;
|
|
61
|
+
delete commandEnvironment.NODE_OPTIONS;
|
|
62
|
+
const templateFiles = (0, node_fs_1.readdirSync)(templateRoot).filter((file) => !file.startsWith("npmrc"));
|
|
63
|
+
for (const file of templateFiles)
|
|
64
|
+
(0, node_fs_1.cpSync)((0, node_path_1.join)(templateRoot, file), (0, node_path_1.join)(workspace, file), { recursive: true });
|
|
65
|
+
const extraSources = JSON.parse(process.env.DMS_MODULE_SOURCES ?? "[]");
|
|
66
|
+
const roots = [
|
|
67
|
+
...((0, node_fs_1.existsSync)((0, node_path_1.join)(sourceRoot, "dms.frontend.ts"))
|
|
68
|
+
? [sourceRoot]
|
|
69
|
+
: (0, node_fs_1.readdirSync)(sourceRoot).map((directory) => (0, node_path_1.join)(sourceRoot, directory))),
|
|
70
|
+
...extraSources.map((root) => (0, node_path_1.resolve)(root)),
|
|
71
|
+
];
|
|
72
|
+
const layers = roots.map((root) => ({
|
|
73
|
+
path: root,
|
|
74
|
+
packageName: JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(root, "package.json"), "utf8"))
|
|
75
|
+
.name,
|
|
76
|
+
}));
|
|
77
|
+
(0, common_1.materializeLayers)(workspace, layers);
|
|
78
|
+
const registry = (0, common_1.createFrontendModuleRegistry)(workspace, layers);
|
|
79
|
+
registry.modules.forEach((module) => {
|
|
80
|
+
removeDevelopmentDependencies(module.root);
|
|
81
|
+
});
|
|
82
|
+
(0, common_1.writeFrontendModuleRegistry)(workspace, layers);
|
|
83
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspace, "dms-main.css"), '@import "tailwindcss";\n@import "@nuxt/ui";\n');
|
|
84
|
+
(0, common_1.writeWorkspacePackageJson)(workspace, layers);
|
|
85
|
+
const packagePath = (0, node_path_1.join)(workspace, "package.json");
|
|
86
|
+
const workspacePackage = JSON.parse((0, node_fs_1.readFileSync)(packagePath, "utf8"));
|
|
87
|
+
const localPackages = JSON.parse(process.env.DMS_LOCAL_PACKAGES ?? "{}");
|
|
88
|
+
workspacePackage.pnpm = {
|
|
89
|
+
overrides: {
|
|
90
|
+
...Object.fromEntries(layers.map((layer) => [layer.packageName, "workspace:*"])),
|
|
91
|
+
...Object.fromEntries(Object.entries(localPackages).map(([name, path]) => [
|
|
92
|
+
name,
|
|
93
|
+
`link:${(0, node_path_1.resolve)(path)}`,
|
|
94
|
+
])),
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
(0, node_fs_1.writeFileSync)(packagePath, `${JSON.stringify(workspacePackage, null, 2)}\n`);
|
|
98
|
+
process.stdout.write(`Generated workspace: ${workspace}\n`);
|
|
99
|
+
(0, node_child_process_1.execFileSync)("pnpm", ["install", "--ignore-scripts"], {
|
|
100
|
+
cwd: workspace,
|
|
101
|
+
env: commandEnvironment,
|
|
102
|
+
stdio: "inherit",
|
|
103
|
+
});
|
|
104
|
+
(0, node_child_process_1.execFileSync)("pnpm", ["run", "build"], {
|
|
105
|
+
cwd: workspace,
|
|
106
|
+
env: commandEnvironment,
|
|
107
|
+
stdio: "inherit",
|
|
108
|
+
});
|
|
109
|
+
const typecheckArguments = [
|
|
110
|
+
"--import",
|
|
111
|
+
"./typecheck-loader.mjs",
|
|
112
|
+
"./node_modules/vue-tsc/bin/vue-tsc.js",
|
|
113
|
+
"--noEmit",
|
|
114
|
+
];
|
|
115
|
+
const typecheckCommand = process.platform === "win32" ? process.execPath : "env";
|
|
116
|
+
const typecheckCommandArguments = process.platform === "win32"
|
|
117
|
+
? typecheckArguments
|
|
118
|
+
: ["-u", "NODE_OPTIONS", process.execPath, ...typecheckArguments];
|
|
119
|
+
(0, node_child_process_1.execFileSync)(typecheckCommand, typecheckCommandArguments, {
|
|
120
|
+
cwd: workspace,
|
|
121
|
+
env: commandEnvironment,
|
|
122
|
+
stdio: "inherit",
|
|
123
|
+
});
|
|
124
|
+
const clientRoot = (0, node_path_1.join)(workspace, "dist", "client");
|
|
125
|
+
const manifest = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(clientRoot, ".vite", "manifest.json"), "utf8"));
|
|
126
|
+
const mainEntry = Object.values(manifest).find((entry) => entry.isEntry);
|
|
127
|
+
strict_1.default.ok(mainEntry, "Vite manifest must identify the main entry");
|
|
128
|
+
const mainJavascript = (0, node_fs_1.readFileSync)((0, node_path_1.join)(clientRoot, mainEntry.file), "utf8");
|
|
129
|
+
const javascript = (0, node_fs_1.readdirSync)((0, node_path_1.join)(clientRoot, "assets"))
|
|
130
|
+
.filter((file) => file.endsWith(".js"))
|
|
131
|
+
.map((file) => (0, node_fs_1.readFileSync)((0, node_path_1.join)(clientRoot, "assets", file), "utf8"))
|
|
132
|
+
.join("\n");
|
|
133
|
+
strict_1.default.ok(Object.keys(manifest).length > 0, "Vite manifest must contain reachable entries");
|
|
134
|
+
strict_1.default.doesNotMatch(mainJavascript, /ApexCharts|tiptap/i);
|
|
135
|
+
strict_1.default.match(javascript, /ApexCharts/);
|
|
136
|
+
strict_1.default.match(javascript, /tiptap/i);
|
|
137
|
+
strict_1.default.ok(Object.keys(manifest).some((source) => source.endsWith("/kpi/KpiCard.vue")), "DmsKpiCard must be reachable at runtime");
|
|
138
|
+
const emailRoot = (0, node_path_1.join)(workspace, "dist", "server");
|
|
139
|
+
const emailManifestContent = (0, node_fs_1.readFileSync)((0, node_path_1.join)(emailRoot, ".vite", "manifest.json"), "utf8");
|
|
140
|
+
strict_1.default.doesNotMatch(emailManifestContent, NON_EMAIL_RUNTIME_PATTERN);
|
|
141
|
+
const emailManifest = JSON.parse(emailManifestContent);
|
|
142
|
+
const emailJavascriptFiles = [
|
|
143
|
+
...new Set([
|
|
144
|
+
"email-renderer.js",
|
|
145
|
+
...Object.values(emailManifest)
|
|
146
|
+
.map((entry) => entry.file)
|
|
147
|
+
.filter((file) => file.endsWith(".js")),
|
|
148
|
+
]),
|
|
149
|
+
];
|
|
150
|
+
const emailJavascript = emailJavascriptFiles
|
|
151
|
+
.map((file) => (0, node_fs_1.readFileSync)((0, node_path_1.join)(emailRoot, file), "utf8"))
|
|
152
|
+
.join("\n");
|
|
153
|
+
strict_1.default.doesNotMatch(emailJavascript, NON_EMAIL_RUNTIME_PATTERN);
|
|
154
|
+
const emailBuildSize = Buffer.byteLength(emailJavascript);
|
|
155
|
+
const emailLocaleBytes = (0, node_fs_1.readdirSync)((0, node_path_1.join)(emailRoot, "locales")).reduce((total, file) => total + (0, node_fs_1.readFileSync)((0, node_path_1.join)(emailRoot, "locales", file)).byteLength, 0);
|
|
156
|
+
process.stdout.write(`Email JavaScript: ${emailBuildSize} bytes; locale data: ${emailLocaleBytes} bytes\n`);
|
|
157
|
+
strict_1.default.ok(emailBuildSize <= EMAIL_BUILD_SIZE_CEILING_BYTES, `Email build is ${emailBuildSize} bytes; ceiling is ${EMAIL_BUILD_SIZE_CEILING_BYTES}`);
|
|
158
|
+
const emailCases = [
|
|
159
|
+
{
|
|
160
|
+
name: "EmailAdminInvite",
|
|
161
|
+
props: {
|
|
162
|
+
userName: "Ada",
|
|
163
|
+
signupLink: "https://example.test/join",
|
|
164
|
+
expiresIn: "1 hour",
|
|
165
|
+
},
|
|
166
|
+
marker: "Ada",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "EmailExportReady",
|
|
170
|
+
props: {
|
|
171
|
+
userName: "Ada",
|
|
172
|
+
downloadLink: "https://example.test/export",
|
|
173
|
+
fileName: "users.csv",
|
|
174
|
+
fileSize: "1 KB",
|
|
175
|
+
expiresIn: "1 hour",
|
|
176
|
+
},
|
|
177
|
+
marker: "users.csv",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: "EmailResetPassword",
|
|
181
|
+
props: { userName: "Ada", resetCode: "123456", expiresIn: "1 hour" },
|
|
182
|
+
marker: "123456",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "EmailTwoFactor",
|
|
186
|
+
props: { userName: "Ada", verificationCode: "654321" },
|
|
187
|
+
marker: "654321",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: "EmailUserValidation",
|
|
191
|
+
props: { userName: "Ada", validationCode: "112233", expiresIn: "1 hour" },
|
|
192
|
+
marker: "112233",
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: "EmailButton",
|
|
196
|
+
props: { href: "https://example.test", expiresIn: "1 hour" },
|
|
197
|
+
marker: "https://example.test",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: "EmailLayout",
|
|
201
|
+
props: { title: "Contract title" },
|
|
202
|
+
marker: "Contract title",
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: "EmailOTP",
|
|
206
|
+
props: { code: "445566", expiresIn: "1 hour" },
|
|
207
|
+
marker: "445566",
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
async function verifyEmailContracts() {
|
|
211
|
+
const { renderEmail } = await Promise.resolve(`${(0, node_path_1.join)(workspace, "dist/server/email-renderer.js")}`).then(s => __importStar(require(s)));
|
|
212
|
+
for (const emailCase of emailCases) {
|
|
213
|
+
const html = await renderEmail(emailCase.name, emailCase.props);
|
|
214
|
+
strict_1.default.match(html, /^<!doctype html>/);
|
|
215
|
+
if (emailCase.name === "EmailLayout") {
|
|
216
|
+
strict_1.default.match(html, /<meta charset="utf-8"/);
|
|
217
|
+
strict_1.default.match(html, /images\/antelope-logo\/light\.svg/);
|
|
218
|
+
strict_1.default.doesNotMatch(html, /<h1[^>]*\bas=/);
|
|
219
|
+
}
|
|
220
|
+
strict_1.default.match(html, new RegExp(emailCase.marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
for (const marker of ["auth/login", "DefaultLayout", "error.500.title"]) {
|
|
224
|
+
strict_1.default.match(javascript, new RegExp(marker), `${marker} must be reachable at runtime`);
|
|
225
|
+
}
|
|
226
|
+
void verifyEmailContracts().then(() => {
|
|
227
|
+
process.stdout.write(`Real DMS source compiled in ${(0, node_path_1.basename)(workspace)}\n`);
|
|
228
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeDepsHash = computeDepsHash;
|
|
4
|
+
exports.needsInstall = needsInstall;
|
|
5
|
+
exports.saveDepsHash = saveDepsHash;
|
|
6
|
+
exports.installDeps = installDeps;
|
|
7
|
+
exports.runCommand = runCommand;
|
|
8
|
+
exports.setupWorkspace = setupWorkspace;
|
|
9
|
+
const node_child_process_1 = require("node:child_process");
|
|
10
|
+
const node_crypto_1 = require("node:crypto");
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const node_path_1 = require("node:path");
|
|
13
|
+
const layers_1 = require("./layers");
|
|
14
|
+
const manifest_1 = require("./manifest");
|
|
15
|
+
const materialize_1 = require("./materialize");
|
|
16
|
+
const workspace_1 = require("./workspace");
|
|
17
|
+
const config_1 = require("./config");
|
|
18
|
+
function computeDepsHash(layerPaths, workspacePackage) {
|
|
19
|
+
const hash = (0, node_crypto_1.createHash)("sha256");
|
|
20
|
+
if (workspacePackage && (0, node_fs_1.existsSync)(workspacePackage))
|
|
21
|
+
hash.update((0, node_fs_1.readFileSync)(workspacePackage));
|
|
22
|
+
for (const layerPath of [...layerPaths].sort()) {
|
|
23
|
+
const pkgPath = (0, node_path_1.join)(layerPath, "package.json");
|
|
24
|
+
if ((0, node_fs_1.existsSync)(pkgPath)) {
|
|
25
|
+
hash.update((0, node_fs_1.readFileSync)(pkgPath, "utf-8"));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return hash.digest("hex");
|
|
29
|
+
}
|
|
30
|
+
function needsInstall(workspaceDir, layerPaths, force) {
|
|
31
|
+
if (force)
|
|
32
|
+
return true;
|
|
33
|
+
const hashFile = (0, node_path_1.join)(workspaceDir, config_1.DEPS_HASH_FILE);
|
|
34
|
+
if (!(0, node_fs_1.existsSync)(hashFile))
|
|
35
|
+
return true;
|
|
36
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.join)(workspaceDir, "node_modules")))
|
|
37
|
+
return true;
|
|
38
|
+
const currentHash = computeDepsHash(layerPaths, (0, node_path_1.join)(workspaceDir, "package.json"));
|
|
39
|
+
const savedHash = (0, node_fs_1.readFileSync)(hashFile, "utf-8").trim();
|
|
40
|
+
return currentHash !== savedHash;
|
|
41
|
+
}
|
|
42
|
+
function saveDepsHash(workspaceDir, layerPaths) {
|
|
43
|
+
const hash = computeDepsHash(layerPaths, (0, node_path_1.join)(workspaceDir, "package.json"));
|
|
44
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspaceDir, config_1.DEPS_HASH_FILE), hash);
|
|
45
|
+
}
|
|
46
|
+
function installDeps(workspaceDir) {
|
|
47
|
+
const { execSync } = require("node:child_process");
|
|
48
|
+
execSync("pnpm install", {
|
|
49
|
+
cwd: workspaceDir,
|
|
50
|
+
stdio: "inherit",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function runCommand(command, args, options) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
const child = (0, node_child_process_1.spawn)(command, args, {
|
|
56
|
+
stdio: "inherit",
|
|
57
|
+
shell: true,
|
|
58
|
+
...options,
|
|
59
|
+
});
|
|
60
|
+
child.on("error", (error) => reject(error));
|
|
61
|
+
child.on("exit", (code) => resolve(code || 0));
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async function setupWorkspace(opts) {
|
|
65
|
+
const { backendUrl, force, mode, offline, clientUrl, bootstrapSecret } = opts;
|
|
66
|
+
const workspaceKey = opts.workspaceKey ?? (0, config_1.canonicalizeBackendUrl)(backendUrl);
|
|
67
|
+
const workspaceDir = (0, workspace_1.ensureWorkspace)(workspaceKey);
|
|
68
|
+
(0, workspace_1.writeWorkspaceMeta)(workspaceDir, backendUrl, workspaceKey);
|
|
69
|
+
const resolved = await (0, manifest_1.resolveManifest)(workspaceDir, backendUrl, !!offline, clientUrl, bootstrapSecret);
|
|
70
|
+
const { manifest, fromCache, fetchedAt } = resolved;
|
|
71
|
+
let layers;
|
|
72
|
+
if (mode === "dev") {
|
|
73
|
+
(0, layers_1.assertLayerPathsServed)(manifest.modules);
|
|
74
|
+
if (fromCache) {
|
|
75
|
+
(0, manifest_1.assertCachedLayerPathsExist)(manifest.modules, fetchedAt);
|
|
76
|
+
}
|
|
77
|
+
layers = (0, layers_1.buildLayersFromPaths)(manifest.modules);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const cacheDir = (0, node_path_1.join)(workspaceDir, ".layers-cache");
|
|
81
|
+
if (fromCache) {
|
|
82
|
+
if (!(0, node_fs_1.existsSync)(cacheDir)) {
|
|
83
|
+
throw new Error("Backend unreachable and no previously downloaded layers archive — run once with the backend reachable first.");
|
|
84
|
+
}
|
|
85
|
+
(0, layers_1.assertCachedArchivesExist)(manifest.modules, cacheDir, fetchedAt);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
await (0, layers_1.downloadAndExtractLayers)(backendUrl, manifest.pack, cacheDir, force, bootstrapSecret);
|
|
89
|
+
}
|
|
90
|
+
layers = await (0, layers_1.buildLayersFromCache)(manifest.modules, cacheDir);
|
|
91
|
+
}
|
|
92
|
+
(0, materialize_1.copyStaticTemplates)(workspaceDir);
|
|
93
|
+
(0, materialize_1.writeWorkspacePackageJson)(workspaceDir, layers);
|
|
94
|
+
(0, materialize_1.materializeLayers)(workspaceDir, layers);
|
|
95
|
+
(0, materialize_1.writeFrontendModuleRegistry)(workspaceDir, layers);
|
|
96
|
+
(0, materialize_1.writeDmsMainCss)(workspaceDir, layers);
|
|
97
|
+
const layerPaths = layers.map((layer) => layer.path);
|
|
98
|
+
const shouldInstall = needsInstall(workspaceDir, layerPaths, force);
|
|
99
|
+
if (shouldInstall) {
|
|
100
|
+
installDeps(workspaceDir);
|
|
101
|
+
saveDepsHash(workspaceDir, layerPaths);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
workspaceDir,
|
|
105
|
+
layers,
|
|
106
|
+
manifestFromCache: fromCache,
|
|
107
|
+
manifestFetchedAt: fetchedAt,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FRONTEND_MANIFEST_VERSION = void 0;
|
|
4
|
+
exports.getWorkspaceDirForKey = getWorkspaceDirForKey;
|
|
5
|
+
exports.projectWorkspaceKey = projectWorkspaceKey;
|
|
6
|
+
exports.getWorkspaceDir = getWorkspaceDir;
|
|
7
|
+
exports.ensureWorkspace = ensureWorkspace;
|
|
8
|
+
exports.listWorkspaces = listWorkspaces;
|
|
9
|
+
exports.writeWorkspaceMeta = writeWorkspaceMeta;
|
|
10
|
+
exports.bootstrapHeaders = bootstrapHeaders;
|
|
11
|
+
exports.isUnauthorized = isUnauthorized;
|
|
12
|
+
const node_fs_1 = require("node:fs");
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const config_1 = require("./config");
|
|
15
|
+
const WORKSPACE_META_FILE = ".ajs-dms-meta.json";
|
|
16
|
+
function getWorkspaceDirForKey(key) {
|
|
17
|
+
return (0, node_path_1.join)(config_1.DMS_FRONTEND_HOME, (0, config_1.sha256Hex)(key));
|
|
18
|
+
}
|
|
19
|
+
function projectWorkspaceKey(projectDir) {
|
|
20
|
+
return `project:${(0, node_path_1.resolve)(projectDir)}`;
|
|
21
|
+
}
|
|
22
|
+
function getWorkspaceDir(backendUrl) {
|
|
23
|
+
return getWorkspaceDirForKey((0, config_1.canonicalizeBackendUrl)(backendUrl));
|
|
24
|
+
}
|
|
25
|
+
function ensureWorkspace(workspaceKey) {
|
|
26
|
+
const dir = getWorkspaceDirForKey(workspaceKey);
|
|
27
|
+
if (!(0, node_fs_1.existsSync)(dir)) {
|
|
28
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true, mode: config_1.WORKSPACE_DIR_MODE });
|
|
29
|
+
}
|
|
30
|
+
(0, node_fs_1.chmodSync)(dir, config_1.WORKSPACE_DIR_MODE);
|
|
31
|
+
return dir;
|
|
32
|
+
}
|
|
33
|
+
function listWorkspaces() {
|
|
34
|
+
if (!(0, node_fs_1.existsSync)(config_1.DMS_FRONTEND_HOME))
|
|
35
|
+
return [];
|
|
36
|
+
const workspaces = [];
|
|
37
|
+
for (const entry of (0, node_fs_1.readdirSync)(config_1.DMS_FRONTEND_HOME, { withFileTypes: true })) {
|
|
38
|
+
if (!entry.isDirectory())
|
|
39
|
+
continue;
|
|
40
|
+
const dir = (0, node_path_1.join)(config_1.DMS_FRONTEND_HOME, entry.name);
|
|
41
|
+
const backendUrl = readWorkspaceBackendUrl(dir);
|
|
42
|
+
if (backendUrl === undefined) {
|
|
43
|
+
console.warn(`⚠ Skipping ${dir}: no readable ${WORKSPACE_META_FILE}.`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
workspaces.push({ dir, backendUrl });
|
|
47
|
+
}
|
|
48
|
+
return workspaces;
|
|
49
|
+
}
|
|
50
|
+
function readWorkspaceBackendUrl(dir) {
|
|
51
|
+
let meta;
|
|
52
|
+
try {
|
|
53
|
+
meta = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(dir, WORKSPACE_META_FILE), "utf-8"));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
const backendUrl = meta?.backendUrl;
|
|
59
|
+
return typeof backendUrl === "string" ? backendUrl : undefined;
|
|
60
|
+
}
|
|
61
|
+
function writeWorkspaceMeta(workspaceDir, backendUrl, workspaceKey) {
|
|
62
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(workspaceDir, WORKSPACE_META_FILE), JSON.stringify({
|
|
63
|
+
backendUrl: (0, config_1.canonicalizeBackendUrl)(backendUrl),
|
|
64
|
+
workspaceKey,
|
|
65
|
+
updatedAt: new Date().toISOString(),
|
|
66
|
+
}, null, 2));
|
|
67
|
+
}
|
|
68
|
+
const BOOTSTRAP_HEADER = "x-dms-bootstrap";
|
|
69
|
+
const UNAUTHORIZED_STATUSES = [401, 403];
|
|
70
|
+
exports.FRONTEND_MANIFEST_VERSION = 1;
|
|
71
|
+
function bootstrapHeaders(secret) {
|
|
72
|
+
return secret ? { [BOOTSTRAP_HEADER]: secret } : {};
|
|
73
|
+
}
|
|
74
|
+
function isUnauthorized(status) {
|
|
75
|
+
return UNAUTHORIZED_STATUSES.includes(status);
|
|
76
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@antelopejs/dms-frontend",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Vue 3, Vite, and Inertia frontend loader for AntelopeJS DMS",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"antelope",
|
|
7
|
+
"antelopejs",
|
|
8
|
+
"dms",
|
|
9
|
+
"frontend",
|
|
10
|
+
"frontend-modules",
|
|
11
|
+
"inertia",
|
|
12
|
+
"loader",
|
|
13
|
+
"ui",
|
|
14
|
+
"vite",
|
|
15
|
+
"vue"
|
|
16
|
+
],
|
|
17
|
+
"license": "Apache-2.0",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/AntelopeJS/dms-frontend.git"
|
|
21
|
+
},
|
|
22
|
+
"bin": {
|
|
23
|
+
"ajs-dms": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/",
|
|
27
|
+
"templates/"
|
|
28
|
+
],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public",
|
|
31
|
+
"provenance": true,
|
|
32
|
+
"registry": "https://registry.npmjs.org/"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"boxen": "^5.1.2",
|
|
36
|
+
"chalk": "^4.1.2",
|
|
37
|
+
"chokidar": "^4.0.3",
|
|
38
|
+
"commander": "^13.1.0",
|
|
39
|
+
"figlet": "^1.8.0",
|
|
40
|
+
"ignore": "^7.0.5",
|
|
41
|
+
"semver": "^7.7.0",
|
|
42
|
+
"unzipper": "^0.12.3"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@antelopejs/tooling-configs": "^0.0.4",
|
|
46
|
+
"@inertiajs/vue3": "^3.7.0",
|
|
47
|
+
"@types/figlet": "^1.7.0",
|
|
48
|
+
"@types/node": "^24.0.0",
|
|
49
|
+
"@types/semver": "^7.7.0",
|
|
50
|
+
"@types/unzipper": "^0.10.11",
|
|
51
|
+
"@unhead/vue": "^2.0.14",
|
|
52
|
+
"@vitejs/plugin-vue": "^6.0.0",
|
|
53
|
+
"@vue/server-renderer": "^3.5.0",
|
|
54
|
+
"defu": "^6.1.4",
|
|
55
|
+
"knip": "^6.34.0",
|
|
56
|
+
"ofetch": "^1.4.1",
|
|
57
|
+
"oxfmt": "^0.66.0",
|
|
58
|
+
"oxlint": "1.81.0",
|
|
59
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
60
|
+
"release-it": "^19.2.4",
|
|
61
|
+
"release-it-changelogen": "^0.1.0",
|
|
62
|
+
"rimraf": "^6.0.1",
|
|
63
|
+
"tsx": "^4.20.6",
|
|
64
|
+
"typescript": "^5.8.2",
|
|
65
|
+
"unplugin-auto-import": "^20.2.0",
|
|
66
|
+
"vite": "^7.0.0",
|
|
67
|
+
"vue": "^3.5.0",
|
|
68
|
+
"vue-i18n": "^11.1.12"
|
|
69
|
+
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"@antelopejs/core": ">=1.5.0 <2"
|
|
72
|
+
},
|
|
73
|
+
"peerDependenciesMeta": {
|
|
74
|
+
"@antelopejs/core": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"optionalDependencies": {
|
|
79
|
+
"@oxc-parser/binding-darwin-arm64": "^0.95.0",
|
|
80
|
+
"@oxc-parser/binding-darwin-x64": "^0.95.0",
|
|
81
|
+
"@oxc-parser/binding-linux-arm64-gnu": "^0.95.0",
|
|
82
|
+
"@oxc-parser/binding-linux-x64-gnu": "^0.95.0",
|
|
83
|
+
"@oxc-parser/binding-win32-x64-msvc": "^0.95.0"
|
|
84
|
+
},
|
|
85
|
+
"scripts": {
|
|
86
|
+
"build": "rimraf dist && tsc -p tsconfig.build.json",
|
|
87
|
+
"release": "pnpm run lint && pnpm run test && pnpm run prepack && release-it",
|
|
88
|
+
"test": "node --import tsx --test tests/*.test.ts tests/*.test.mts",
|
|
89
|
+
"test:real-source": "pnpm run build && node dist/verify-source-runner.js",
|
|
90
|
+
"format": "oxfmt .",
|
|
91
|
+
"lint": "oxlint && oxfmt --check .",
|
|
92
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
93
|
+
"lint:fix": "oxlint --fix --max-warnings=1000000 && oxfmt .",
|
|
94
|
+
"knip": "knip --dependencies",
|
|
95
|
+
"knip:all": "knip"
|
|
96
|
+
}
|
|
97
|
+
}
|