@ctc-front/build-meta 0.0.0-stage → 0.2.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - Vite 插件将构建元数据以内联 `<meta name="ctc-build-meta">` 注入构建 HTML,不再生成独立 `log.ico`。
6
+ - CLI 和 Node API 保留独立 `log.ico` 文件输出,避免影响非 Vite 构建流程。
7
+ - 补齐 Vite、Vue CLI/Webpack、CLI 和 Node API 的接入示例及迁移说明。
8
+
9
+ ## 0.1.1
10
+
11
+ - 修复 `remoteUrl` 暴露 Git 服务 IP、域名和端口的问题,现在仅保留仓库路径。
12
+
13
+ ## 0.1.0
14
+
15
+ - 提供与前端技术栈无关的构建元数据采集、编码、解码和文件生成能力。
16
+ - 提供可选 Vite 插件与命令行入口。
17
+ - 默认生成 `log.ico`,沿用 `c` → `ctcFront` 的可逆编码协议。
18
+ - 构建元数据不包含邮箱,并对 Git remote 中的协议、凭据、Token 和 `.git` 后缀做脱敏。
package/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ UNLICENSED
2
+
3
+ Copyright (c) CTC Front Team. All rights reserved.
4
+
5
+ This package is published on the public npm registry by CTC Front. Public
6
+ availability does not grant an open-source license or authorize modification,
7
+ redistribution, or use outside projects approved by CTC Front. All other rights
8
+ are reserved.
package/README.md CHANGED
@@ -1,3 +1,161 @@
1
- # Temporary Holding Version
1
+ # @ctc-front/build-meta
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 统一采集、编码并输出 CTC Front Web 项目的构建元数据。包本身不依赖 Vue、Vite 或 Webpack;Vite 项目通过 `@ctc-front/build-meta/vite` 使用可选适配层。
4
+
5
+ 本包配置为公开发布至 npmjs 的 `@ctc-front` scope。安装方式:`pnpm add -D @ctc-front/build-meta`。在仓库根目录运行 `pnpm pack:build-meta` 仍可生成用于本地验证的 `.tgz`。
6
+
7
+ ## 新项目:Vite(Vue 3)
8
+
9
+ Vite 项目使用包提供的插件,在 production build 时把元数据内联到 HTML。先安装开发依赖:
10
+
11
+ ```bash
12
+ pnpm add -D @ctc-front/build-meta
13
+ ```
14
+
15
+ 然后在 `vite.config.ts` 中配置:
16
+
17
+ ```ts
18
+ import { buildMetaPlugin } from '@ctc-front/build-meta/vite'
19
+ import { name, title, version } from './package.json'
20
+
21
+ export default {
22
+ plugins: [buildMetaPlugin({ name, title, version })],
23
+ }
24
+ ```
25
+
26
+ 入口 HTML 中不需要额外写模板代码;构建后可在部署页面的浏览器控制台读取 meta 标签。完整接入示例见仓库内 [`examples/build-meta`](../../examples/build-meta/README.md);项目级说明可查看 `ctc-fe-web-starter/docs/build-meta.md`。
27
+
28
+ 执行 Vite production build 后,插件会把编码后的元数据作为以下 `<meta>` 标签插入到每个 HTML 入口的 `<head>`,不会另外生成 `log.ico`:
29
+
30
+ ```html
31
+ <meta name="ctc-build-meta" content="编码后的版本信息" />
32
+ ```
33
+
34
+ 插件不要求入口文件必须叫 `index.html`。Vite 实际处理的每个 HTML 入口都会注入,例如 `admin.html` 或配置的自定义 HTML 入口也可以使用。若项目没有任何 HTML 入口(例如仅打包 JavaScript 的 library mode),`transformIndexHtml` 不会执行,插件不会注入标签,也不会因此让构建失败。
35
+
36
+ 这种情况下,如果仍需输出元数据,可使用 CLI 或 Node API 生成独立 `log.ico`;如果消费者必须从 HTML 读取,则需要提供一个 HTML 入口,或在业务构建中自行决定元数据的承载方式。
37
+
38
+ 在浏览器控制台读取并还原信息:
39
+
40
+ ```js
41
+ const encoded = document.querySelector('meta[name="ctc-build-meta"]')?.content
42
+ if (encoded) {
43
+ const normalized = encoded.replace(/ctcFront/g, 'c')
44
+ const meta = JSON.parse(decodeURIComponent(atob(normalized)))
45
+ console.table(meta)
46
+ }
47
+ ```
48
+
49
+ 此处采用 URI 编码后再 Base64 的内容格式;`ctcFront` 替换仅为可逆的兼容编码,不是加密或访问控制。内联只取消独立 `log.ico` 文件,不会隐藏 HTML 中的元数据。不得将密钥、Token 或其他不应公开的敏感信息放入这些字段。
50
+
51
+ ## 老项目:Vue CLI / Webpack(Vue 2)
52
+
53
+ 老项目不使用 Vite 插件。通过包根入口的 Node API 在 Webpack 构建配置阶段采集并编码元数据,再由 `HtmlWebpackPlugin` 模板写入 HTML。先安装开发依赖:
54
+
55
+ ```bash
56
+ npm install --save-dev @ctc-front/build-meta
57
+ ```
58
+
59
+ 然后在 `vue.config.js` 中配置:
60
+
61
+ ```js
62
+ const { collectBuildMeta, encodeBuildMeta } = require('@ctc-front/build-meta')
63
+ const { name, title, version } = require('./package.json')
64
+
65
+ // 放在现有的 chainWebpack(config) 配置中
66
+ if (process.env.NODE_ENV === 'production') {
67
+ config.plugin('html').tap((args) => {
68
+ args[0].ctcBuildMeta = encodeBuildMeta(
69
+ collectBuildMeta({ name, title, version, cwd: __dirname }),
70
+ ).version
71
+ return args
72
+ })
73
+ }
74
+ ```
75
+
76
+ 然后在 `public/index.html` 的 `<head>` 中加入 HtmlWebpackPlugin/EJS 模板片段:
77
+
78
+ ```html
79
+ <% if (htmlWebpackPlugin.options.ctcBuildMeta) { %>
80
+ <meta name="ctc-build-meta" content="<%= htmlWebpackPlugin.options.ctcBuildMeta %>" />
81
+ <% } %>
82
+ ```
83
+
84
+ 这段逻辑只在生产构建时写入标签;开发服务器不注入。构建后检查实际输出的 HTML(Vue CLI 项目的输出目录由 `outputDir` 决定),读取方式与上面的 Vite 项目相同。老项目不需要也不应安装 `vite` 或使用 `@ctc-front/build-meta/vite`。项目级迁移说明可查看 `ctc-startup-web/docs/build-meta.md`。
85
+
86
+ ## 元数据格式与隐私
87
+
88
+ 编码前的数据结构:
89
+
90
+ ```ts
91
+ interface BuildMeta {
92
+ schemaVersion: 1
93
+ name: string
94
+ projectName: string
95
+ version: string
96
+ remoteUrl: string
97
+ buildDate: string
98
+ user: string
99
+ lastCommitLog: string
100
+ lastCommitHash: string
101
+ lastCommitDate: string
102
+ }
103
+ ```
104
+
105
+ 元数据不包含构建者邮箱。`remoteUrl` 只保留仓库路径,例如 `project/front/demo`;协议、域名、IP、端口、用户名、密码、Token 和 `.git` 后缀都会被移除。构建目录不是 Git 仓库或 Git 信息缺失时,对应字段使用 `unknown` 或 `detached`,不会中断打包。
106
+
107
+ ## CLI 与 Node API:独立文件模式
108
+
109
+ Vite 插件改为 HTML 内联;CLI 和 Node API 为兼容现有自动化流程,仍可生成独立 `log.ico` 文件。
110
+
111
+ CLI:
112
+
113
+ ```bash
114
+ ctc-build-meta generate --out-dir dist
115
+ ctc-build-meta decode ./dist/log.ico
116
+ ```
117
+
118
+ `generate` 默认读取当前目录 `package.json` 中的 `name`、`title` 和 `version`。
119
+
120
+ Node API:
121
+
122
+ ```ts
123
+ import { decodeBuildMeta, generateBuildMeta } from '@ctc-front/build-meta'
124
+
125
+ const result = generateBuildMeta({
126
+ name: 'example-web',
127
+ title: '示例系统',
128
+ version: '1.0.0',
129
+ outDir: './dist',
130
+ })
131
+
132
+ console.log(decodeBuildMeta(result.artifact))
133
+ ```
134
+
135
+ ## 从旧 Vite 产物迁移
136
+
137
+ 旧版本的 Vite 插件在 `outDir` 生成 `log.ico`。新版本改为在 HTML 中输出 `meta[name="ctc-build-meta"]`,不再提供该文件。若应用代码或构建检查脚本仍在 `fetch('/log.ico')` 或检查 `dist/log.ico`,需要改为读取 HTML meta 标签。
138
+
139
+ ```js
140
+ const encoded = document.querySelector('meta[name="ctc-build-meta"]')?.content
141
+ if (!encoded) throw new Error('Build metadata is missing from this HTML entry')
142
+ const meta = JSON.parse(decodeURIComponent(atob(encoded.replace(/ctcFront/g, 'c'))))
143
+ ```
144
+
145
+ 这段代码应在承载应用的 HTML 页面中执行;不必假定页面文件名是 `index.html`。如果构建产物没有 HTML,页面端自然也没有可读取的 meta 标签。
146
+
147
+ ## 本地开发
148
+
149
+ 在仓库根目录运行:
150
+
151
+ ```bash
152
+ pnpm build:build-meta
153
+ pnpm --filter @ctc-front/build-meta test
154
+ pnpm --filter @ctc-front/build-meta pack:check
155
+ ```
156
+
157
+ 生产构建默认关闭 sourcemap。
158
+
159
+ ## 版本与发布
160
+
161
+ 包版本以 `packages/build-meta/package.json` 为准,当前为 `0.2.0`。本版本将 Vite 插件行为改为内联 HTML meta;CLI 与 Node API 仍生成独立 `log.ico`。npm 上是否已提供该版本,以 registry 查询结果为准;需要生成可安装 tarball 时,在仓库根目录执行 `pnpm pack:build-meta`,产物位于 `artifacts/`。
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /* global process */
3
+
4
+ void import('../dist/cli.js')
5
+ .then(({ runCli }) => runCli(process.argv.slice(2)))
6
+ .catch((error) => {
7
+ const message = error instanceof Error ? error.message : String(error)
8
+ process.stderr.write(`[build-meta] ${message}\n`)
9
+ process.exitCode = 1
10
+ })
package/dist/cli.cjs ADDED
@@ -0,0 +1,58 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_generate = require("./generate-CQvoIMfu.cjs");
3
+ let node_fs = require("node:fs");
4
+ node_fs = require_generate.__toESM(node_fs, 1);
5
+ let node_path = require("node:path");
6
+ node_path = require_generate.__toESM(node_path, 1);
7
+ //#region src/cli.ts
8
+ function readOption(args, name) {
9
+ const index = args.indexOf(name);
10
+ if (index < 0) return void 0;
11
+ const value = args[index + 1];
12
+ if (!value || value.startsWith("--")) throw new TypeError(`${name} requires a value.`);
13
+ return value;
14
+ }
15
+ function readPackageMetadata(cwd) {
16
+ const source = JSON.parse(node_fs.default.readFileSync(node_path.default.join(cwd, "package.json"), "utf8"));
17
+ if (!source || typeof source !== "object") throw new TypeError("Invalid package.json.");
18
+ const value = source;
19
+ if (typeof value.name !== "string" || typeof value.version !== "string") throw new TypeError("package.json must contain name and version.");
20
+ return {
21
+ name: value.name,
22
+ title: typeof value.title === "string" ? value.title : value.name,
23
+ version: value.version
24
+ };
25
+ }
26
+ function generate(args) {
27
+ var _readOption;
28
+ const cwd = node_path.default.resolve((_readOption = readOption(args, "--cwd")) !== null && _readOption !== void 0 ? _readOption : process.cwd());
29
+ const project = readPackageMetadata(cwd);
30
+ const outDir = readOption(args, "--out-dir");
31
+ if (!outDir) throw new TypeError("generate requires --out-dir <directory>.");
32
+ const title = readOption(args, "--title");
33
+ const result = require_generate.generateBuildMeta({
34
+ ...project,
35
+ cwd,
36
+ outDir,
37
+ ...title ? { title } : {}
38
+ });
39
+ process.stdout.write(`[build-meta] ${result.filePath}\n`);
40
+ }
41
+ function decode(args) {
42
+ const filePath = args[0];
43
+ if (!filePath) throw new TypeError("decode requires a log.ico path.");
44
+ const source = node_fs.default.readFileSync(node_path.default.resolve(filePath), "utf8");
45
+ process.stdout.write(`${JSON.stringify(require_generate.decodeBuildMeta(source), null, 2)}\n`);
46
+ }
47
+ function printHelp() {
48
+ process.stdout.write("Usage:\n ctc-build-meta generate --out-dir <directory> [--title <title>]\n ctc-build-meta decode <log.ico>\n");
49
+ }
50
+ function runCli(args) {
51
+ const [command, ...rest] = args;
52
+ if (command === "generate") return generate(rest);
53
+ if (command === "decode") return decode(rest);
54
+ if (command === void 0 || command === "--help" || command === "-h") return printHelp();
55
+ throw new TypeError(`Unknown command: ${command}`);
56
+ }
57
+ //#endregion
58
+ exports.runCli = runCli;
package/dist/cli.d.cts ADDED
@@ -0,0 +1,3 @@
1
+ //#region src/cli.d.ts
2
+ export declare function runCli(args: readonly string[]): void;
3
+ //#endregion
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ //#region src/cli.d.ts
2
+ export declare function runCli(args: readonly string[]): void;
3
+ //#endregion
package/dist/cli.js ADDED
@@ -0,0 +1,55 @@
1
+ import { i as decodeBuildMeta, n as generateBuildMeta } from "./generate-BlU9oOSR.js";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ //#region src/cli.ts
5
+ function readOption(args, name) {
6
+ const index = args.indexOf(name);
7
+ if (index < 0) return void 0;
8
+ const value = args[index + 1];
9
+ if (!value || value.startsWith("--")) throw new TypeError(`${name} requires a value.`);
10
+ return value;
11
+ }
12
+ function readPackageMetadata(cwd) {
13
+ const source = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8"));
14
+ if (!source || typeof source !== "object") throw new TypeError("Invalid package.json.");
15
+ const value = source;
16
+ if (typeof value.name !== "string" || typeof value.version !== "string") throw new TypeError("package.json must contain name and version.");
17
+ return {
18
+ name: value.name,
19
+ title: typeof value.title === "string" ? value.title : value.name,
20
+ version: value.version
21
+ };
22
+ }
23
+ function generate(args) {
24
+ var _readOption;
25
+ const cwd = path.resolve((_readOption = readOption(args, "--cwd")) !== null && _readOption !== void 0 ? _readOption : process.cwd());
26
+ const project = readPackageMetadata(cwd);
27
+ const outDir = readOption(args, "--out-dir");
28
+ if (!outDir) throw new TypeError("generate requires --out-dir <directory>.");
29
+ const title = readOption(args, "--title");
30
+ const result = generateBuildMeta({
31
+ ...project,
32
+ cwd,
33
+ outDir,
34
+ ...title ? { title } : {}
35
+ });
36
+ process.stdout.write(`[build-meta] ${result.filePath}\n`);
37
+ }
38
+ function decode(args) {
39
+ const filePath = args[0];
40
+ if (!filePath) throw new TypeError("decode requires a log.ico path.");
41
+ const source = fs.readFileSync(path.resolve(filePath), "utf8");
42
+ process.stdout.write(`${JSON.stringify(decodeBuildMeta(source), null, 2)}\n`);
43
+ }
44
+ function printHelp() {
45
+ process.stdout.write("Usage:\n ctc-build-meta generate --out-dir <directory> [--title <title>]\n ctc-build-meta decode <log.ico>\n");
46
+ }
47
+ function runCli(args) {
48
+ const [command, ...rest] = args;
49
+ if (command === "generate") return generate(rest);
50
+ if (command === "decode") return decode(rest);
51
+ if (command === void 0 || command === "--help" || command === "-h") return printHelp();
52
+ throw new TypeError(`Unknown command: ${command}`);
53
+ }
54
+ //#endregion
55
+ export { runCli };
@@ -0,0 +1,193 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { execFileSync } from "node:child_process";
4
+ //#region src/codec.ts
5
+ const OBFUSCATED_CHARACTER = "ctcFront";
6
+ const STRING_FIELDS = [
7
+ "name",
8
+ "projectName",
9
+ "version",
10
+ "remoteUrl",
11
+ "buildDate",
12
+ "user",
13
+ "lastCommitLog",
14
+ "lastCommitHash",
15
+ "lastCommitDate"
16
+ ];
17
+ function isRecord(value) {
18
+ return typeof value === "object" && value !== null;
19
+ }
20
+ function parseArtifact(value) {
21
+ const parsed = typeof value === "string" ? JSON.parse(value) : value;
22
+ if (!isRecord(parsed) || typeof parsed.version !== "string") throw new TypeError("Build meta artifact must contain a string version field.");
23
+ return { version: parsed.version };
24
+ }
25
+ function isBuildMeta(value) {
26
+ if (!isRecord(value) || value.schemaVersion !== 1) return false;
27
+ return STRING_FIELDS.every((field) => typeof value[field] === "string");
28
+ }
29
+ function encodeBuildMeta(meta) {
30
+ return { version: Buffer.from(encodeURIComponent(JSON.stringify(meta)), "utf8").toString("base64").replace(/c/gu, OBFUSCATED_CHARACTER) };
31
+ }
32
+ function decodeBuildMeta(value) {
33
+ const encoded = parseArtifact(value).version.replace(/ctcFront/gu, "c");
34
+ const decoded = JSON.parse(decodeURIComponent(Buffer.from(encoded, "base64").toString()));
35
+ if (!isBuildMeta(decoded)) throw new TypeError("Unsupported build meta schema.");
36
+ return decoded;
37
+ }
38
+ function serializeBuildMetaArtifact(artifact) {
39
+ return JSON.stringify(artifact, null, 2);
40
+ }
41
+ //#endregion
42
+ //#region src/date.ts
43
+ const UNKNOWN_VALUE$2 = "unknown";
44
+ function pad(value) {
45
+ return String(value).padStart(2, "0");
46
+ }
47
+ function formatBuildDate(value) {
48
+ const date = value instanceof Date ? value : new Date(value);
49
+ if (Number.isNaN(date.getTime())) return UNKNOWN_VALUE$2;
50
+ return `${`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`} ${`${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`}`;
51
+ }
52
+ //#endregion
53
+ //#region src/repository.ts
54
+ const UNKNOWN_VALUE$1 = "unknown";
55
+ const SUPPORTED_PROTOCOLS = /* @__PURE__ */ new Set([
56
+ "git:",
57
+ "http:",
58
+ "https:",
59
+ "ssh:"
60
+ ]);
61
+ function removeGitSuffix(value) {
62
+ return value.replace(/\/+$/u, "").replace(/\.git$/u, "");
63
+ }
64
+ function removeQueryAndFragment(value) {
65
+ var _value$split$;
66
+ return (_value$split$ = value.split(/[?#]/u, 1)[0]) !== null && _value$split$ !== void 0 ? _value$split$ : "";
67
+ }
68
+ function normalizeRepositoryPath(value) {
69
+ const normalized = removeGitSuffix(removeQueryAndFragment(value).replace(/^[\\/]+/u, ""));
70
+ return normalized.length > 0 ? normalized : void 0;
71
+ }
72
+ function sanitizeUrl(value) {
73
+ try {
74
+ var _normalizeRepositoryP;
75
+ const url = new URL(value);
76
+ if (!SUPPORTED_PROTOCOLS.has(url.protocol) || url.host.length === 0) return UNKNOWN_VALUE$1;
77
+ return (_normalizeRepositoryP = normalizeRepositoryPath(url.pathname)) !== null && _normalizeRepositoryP !== void 0 ? _normalizeRepositoryP : UNKNOWN_VALUE$1;
78
+ } catch (_unused) {
79
+ return;
80
+ }
81
+ }
82
+ function sanitizeScpLike(value) {
83
+ const match = /^(?:[^@\s]+@)?([^:\s]+):(.+)$/u.exec(value);
84
+ if (!(match === null || match === void 0 ? void 0 : match[1]) || !match[2] || match[2].includes("@")) return void 0;
85
+ return normalizeRepositoryPath(match[2]);
86
+ }
87
+ function sanitizeRepositoryUrl(value) {
88
+ var _ref, _sanitizeUrl;
89
+ const trimmed = value.trim();
90
+ if (trimmed.length === 0) return UNKNOWN_VALUE$1;
91
+ return (_ref = (_sanitizeUrl = sanitizeUrl(trimmed)) !== null && _sanitizeUrl !== void 0 ? _sanitizeUrl : sanitizeScpLike(trimmed)) !== null && _ref !== void 0 ? _ref : UNKNOWN_VALUE$1;
92
+ }
93
+ //#endregion
94
+ //#region src/git.ts
95
+ const UNKNOWN_VALUE = "unknown";
96
+ function execGit(args, cwd, fallback = UNKNOWN_VALUE) {
97
+ try {
98
+ const value = execFileSync("git", args, {
99
+ cwd,
100
+ encoding: "utf8",
101
+ stdio: [
102
+ "ignore",
103
+ "pipe",
104
+ "ignore"
105
+ ]
106
+ }).trim();
107
+ return value.length > 0 ? value : fallback;
108
+ } catch (_unused) {
109
+ return fallback;
110
+ }
111
+ }
112
+ function resolveBranch(cwd) {
113
+ var _ref, _process$env$CI_COMMI;
114
+ const gitBranch = execGit(["branch", "--show-current"], cwd, "");
115
+ return ((_ref = (_process$env$CI_COMMI = process.env.CI_COMMIT_REF_NAME) !== null && _process$env$CI_COMMI !== void 0 ? _process$env$CI_COMMI : process.env.GITHUB_REF_NAME) !== null && _ref !== void 0 ? _ref : gitBranch) || "detached";
116
+ }
117
+ function collectGitMetadata(cwd, remoteUrl) {
118
+ const resolvedRemote = remoteUrl !== null && remoteUrl !== void 0 ? remoteUrl : execGit([
119
+ "config",
120
+ "--get",
121
+ "remote.origin.url"
122
+ ], cwd);
123
+ return {
124
+ branch: resolveBranch(cwd),
125
+ commitDate: formatBuildDate(execGit([
126
+ "show",
127
+ "-s",
128
+ "--format=%cI"
129
+ ], cwd)),
130
+ commitHash: execGit([
131
+ "show",
132
+ "-s",
133
+ "--format=%H"
134
+ ], cwd),
135
+ commitLog: execGit([
136
+ "show",
137
+ "-s",
138
+ "--format=%s"
139
+ ], cwd),
140
+ remoteUrl: sanitizeRepositoryUrl(resolvedRemote),
141
+ user: execGit(["config", "user.name"], cwd)
142
+ };
143
+ }
144
+ //#endregion
145
+ //#region src/generate.ts
146
+ const DEFAULT_FILE_NAME = "log.ico";
147
+ function assertProjectConfig(options) {
148
+ if ([
149
+ options.name,
150
+ options.title,
151
+ options.version
152
+ ].some((value) => value.trim().length === 0)) throw new TypeError("Build meta name, title and version must be non-empty strings.");
153
+ }
154
+ function resolveOutputFile(options) {
155
+ var _options$cwd, _options$fileName;
156
+ const cwd = path.resolve((_options$cwd = options.cwd) !== null && _options$cwd !== void 0 ? _options$cwd : process.cwd());
157
+ const outDir = path.resolve(cwd, options.outDir);
158
+ const filePath = path.resolve(outDir, (_options$fileName = options.fileName) !== null && _options$fileName !== void 0 ? _options$fileName : DEFAULT_FILE_NAME);
159
+ const relativePath = path.relative(outDir, filePath);
160
+ if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) throw new TypeError("Build meta fileName must stay inside outDir.");
161
+ return filePath;
162
+ }
163
+ function collectBuildMeta(options) {
164
+ var _options$cwd2;
165
+ assertProjectConfig(options);
166
+ const git = collectGitMetadata(path.resolve((_options$cwd2 = options.cwd) !== null && _options$cwd2 !== void 0 ? _options$cwd2 : process.cwd()), options.remoteUrl);
167
+ return {
168
+ schemaVersion: 1,
169
+ name: options.name,
170
+ projectName: options.title,
171
+ version: options.version,
172
+ remoteUrl: git.remoteUrl,
173
+ buildDate: formatBuildDate(/* @__PURE__ */ new Date()),
174
+ user: git.user,
175
+ lastCommitLog: git.commitLog,
176
+ lastCommitHash: `${options.name}/${git.branch}/${git.commitHash}`,
177
+ lastCommitDate: git.commitDate
178
+ };
179
+ }
180
+ function generateBuildMeta(options) {
181
+ const meta = collectBuildMeta(options);
182
+ const artifact = encodeBuildMeta(meta);
183
+ const filePath = resolveOutputFile(options);
184
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
185
+ fs.writeFileSync(filePath, serializeBuildMetaArtifact(artifact));
186
+ return {
187
+ artifact,
188
+ filePath,
189
+ meta
190
+ };
191
+ }
192
+ //#endregion
193
+ export { encodeBuildMeta as a, decodeBuildMeta as i, generateBuildMeta as n, serializeBuildMetaArtifact as o, sanitizeRepositoryUrl as r, collectBuildMeta as t };
@@ -0,0 +1,258 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ let node_fs = require("node:fs");
24
+ node_fs = __toESM(node_fs, 1);
25
+ let node_path = require("node:path");
26
+ node_path = __toESM(node_path, 1);
27
+ let node_child_process = require("node:child_process");
28
+ //#region src/codec.ts
29
+ const OBFUSCATED_CHARACTER = "ctcFront";
30
+ const STRING_FIELDS = [
31
+ "name",
32
+ "projectName",
33
+ "version",
34
+ "remoteUrl",
35
+ "buildDate",
36
+ "user",
37
+ "lastCommitLog",
38
+ "lastCommitHash",
39
+ "lastCommitDate"
40
+ ];
41
+ function isRecord(value) {
42
+ return typeof value === "object" && value !== null;
43
+ }
44
+ function parseArtifact(value) {
45
+ const parsed = typeof value === "string" ? JSON.parse(value) : value;
46
+ if (!isRecord(parsed) || typeof parsed.version !== "string") throw new TypeError("Build meta artifact must contain a string version field.");
47
+ return { version: parsed.version };
48
+ }
49
+ function isBuildMeta(value) {
50
+ if (!isRecord(value) || value.schemaVersion !== 1) return false;
51
+ return STRING_FIELDS.every((field) => typeof value[field] === "string");
52
+ }
53
+ function encodeBuildMeta(meta) {
54
+ return { version: Buffer.from(encodeURIComponent(JSON.stringify(meta)), "utf8").toString("base64").replace(/c/gu, OBFUSCATED_CHARACTER) };
55
+ }
56
+ function decodeBuildMeta(value) {
57
+ const encoded = parseArtifact(value).version.replace(/ctcFront/gu, "c");
58
+ const decoded = JSON.parse(decodeURIComponent(Buffer.from(encoded, "base64").toString()));
59
+ if (!isBuildMeta(decoded)) throw new TypeError("Unsupported build meta schema.");
60
+ return decoded;
61
+ }
62
+ function serializeBuildMetaArtifact(artifact) {
63
+ return JSON.stringify(artifact, null, 2);
64
+ }
65
+ //#endregion
66
+ //#region src/date.ts
67
+ const UNKNOWN_VALUE$2 = "unknown";
68
+ function pad(value) {
69
+ return String(value).padStart(2, "0");
70
+ }
71
+ function formatBuildDate(value) {
72
+ const date = value instanceof Date ? value : new Date(value);
73
+ if (Number.isNaN(date.getTime())) return UNKNOWN_VALUE$2;
74
+ return `${`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`} ${`${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`}`;
75
+ }
76
+ //#endregion
77
+ //#region src/repository.ts
78
+ const UNKNOWN_VALUE$1 = "unknown";
79
+ const SUPPORTED_PROTOCOLS = /* @__PURE__ */ new Set([
80
+ "git:",
81
+ "http:",
82
+ "https:",
83
+ "ssh:"
84
+ ]);
85
+ function removeGitSuffix(value) {
86
+ return value.replace(/\/+$/u, "").replace(/\.git$/u, "");
87
+ }
88
+ function removeQueryAndFragment(value) {
89
+ var _value$split$;
90
+ return (_value$split$ = value.split(/[?#]/u, 1)[0]) !== null && _value$split$ !== void 0 ? _value$split$ : "";
91
+ }
92
+ function normalizeRepositoryPath(value) {
93
+ const normalized = removeGitSuffix(removeQueryAndFragment(value).replace(/^[\\/]+/u, ""));
94
+ return normalized.length > 0 ? normalized : void 0;
95
+ }
96
+ function sanitizeUrl(value) {
97
+ try {
98
+ var _normalizeRepositoryP;
99
+ const url = new URL(value);
100
+ if (!SUPPORTED_PROTOCOLS.has(url.protocol) || url.host.length === 0) return UNKNOWN_VALUE$1;
101
+ return (_normalizeRepositoryP = normalizeRepositoryPath(url.pathname)) !== null && _normalizeRepositoryP !== void 0 ? _normalizeRepositoryP : UNKNOWN_VALUE$1;
102
+ } catch (_unused) {
103
+ return;
104
+ }
105
+ }
106
+ function sanitizeScpLike(value) {
107
+ const match = /^(?:[^@\s]+@)?([^:\s]+):(.+)$/u.exec(value);
108
+ if (!(match === null || match === void 0 ? void 0 : match[1]) || !match[2] || match[2].includes("@")) return void 0;
109
+ return normalizeRepositoryPath(match[2]);
110
+ }
111
+ function sanitizeRepositoryUrl(value) {
112
+ var _ref, _sanitizeUrl;
113
+ const trimmed = value.trim();
114
+ if (trimmed.length === 0) return UNKNOWN_VALUE$1;
115
+ return (_ref = (_sanitizeUrl = sanitizeUrl(trimmed)) !== null && _sanitizeUrl !== void 0 ? _sanitizeUrl : sanitizeScpLike(trimmed)) !== null && _ref !== void 0 ? _ref : UNKNOWN_VALUE$1;
116
+ }
117
+ //#endregion
118
+ //#region src/git.ts
119
+ const UNKNOWN_VALUE = "unknown";
120
+ function execGit(args, cwd, fallback = UNKNOWN_VALUE) {
121
+ try {
122
+ const value = (0, node_child_process.execFileSync)("git", args, {
123
+ cwd,
124
+ encoding: "utf8",
125
+ stdio: [
126
+ "ignore",
127
+ "pipe",
128
+ "ignore"
129
+ ]
130
+ }).trim();
131
+ return value.length > 0 ? value : fallback;
132
+ } catch (_unused) {
133
+ return fallback;
134
+ }
135
+ }
136
+ function resolveBranch(cwd) {
137
+ var _ref, _process$env$CI_COMMI;
138
+ const gitBranch = execGit(["branch", "--show-current"], cwd, "");
139
+ return ((_ref = (_process$env$CI_COMMI = process.env.CI_COMMIT_REF_NAME) !== null && _process$env$CI_COMMI !== void 0 ? _process$env$CI_COMMI : process.env.GITHUB_REF_NAME) !== null && _ref !== void 0 ? _ref : gitBranch) || "detached";
140
+ }
141
+ function collectGitMetadata(cwd, remoteUrl) {
142
+ const resolvedRemote = remoteUrl !== null && remoteUrl !== void 0 ? remoteUrl : execGit([
143
+ "config",
144
+ "--get",
145
+ "remote.origin.url"
146
+ ], cwd);
147
+ return {
148
+ branch: resolveBranch(cwd),
149
+ commitDate: formatBuildDate(execGit([
150
+ "show",
151
+ "-s",
152
+ "--format=%cI"
153
+ ], cwd)),
154
+ commitHash: execGit([
155
+ "show",
156
+ "-s",
157
+ "--format=%H"
158
+ ], cwd),
159
+ commitLog: execGit([
160
+ "show",
161
+ "-s",
162
+ "--format=%s"
163
+ ], cwd),
164
+ remoteUrl: sanitizeRepositoryUrl(resolvedRemote),
165
+ user: execGit(["config", "user.name"], cwd)
166
+ };
167
+ }
168
+ //#endregion
169
+ //#region src/generate.ts
170
+ const DEFAULT_FILE_NAME = "log.ico";
171
+ function assertProjectConfig(options) {
172
+ if ([
173
+ options.name,
174
+ options.title,
175
+ options.version
176
+ ].some((value) => value.trim().length === 0)) throw new TypeError("Build meta name, title and version must be non-empty strings.");
177
+ }
178
+ function resolveOutputFile(options) {
179
+ var _options$cwd, _options$fileName;
180
+ const cwd = node_path.default.resolve((_options$cwd = options.cwd) !== null && _options$cwd !== void 0 ? _options$cwd : process.cwd());
181
+ const outDir = node_path.default.resolve(cwd, options.outDir);
182
+ const filePath = node_path.default.resolve(outDir, (_options$fileName = options.fileName) !== null && _options$fileName !== void 0 ? _options$fileName : DEFAULT_FILE_NAME);
183
+ const relativePath = node_path.default.relative(outDir, filePath);
184
+ if (relativePath.startsWith("..") || node_path.default.isAbsolute(relativePath)) throw new TypeError("Build meta fileName must stay inside outDir.");
185
+ return filePath;
186
+ }
187
+ function collectBuildMeta(options) {
188
+ var _options$cwd2;
189
+ assertProjectConfig(options);
190
+ const git = collectGitMetadata(node_path.default.resolve((_options$cwd2 = options.cwd) !== null && _options$cwd2 !== void 0 ? _options$cwd2 : process.cwd()), options.remoteUrl);
191
+ return {
192
+ schemaVersion: 1,
193
+ name: options.name,
194
+ projectName: options.title,
195
+ version: options.version,
196
+ remoteUrl: git.remoteUrl,
197
+ buildDate: formatBuildDate(/* @__PURE__ */ new Date()),
198
+ user: git.user,
199
+ lastCommitLog: git.commitLog,
200
+ lastCommitHash: `${options.name}/${git.branch}/${git.commitHash}`,
201
+ lastCommitDate: git.commitDate
202
+ };
203
+ }
204
+ function generateBuildMeta(options) {
205
+ const meta = collectBuildMeta(options);
206
+ const artifact = encodeBuildMeta(meta);
207
+ const filePath = resolveOutputFile(options);
208
+ node_fs.default.mkdirSync(node_path.default.dirname(filePath), { recursive: true });
209
+ node_fs.default.writeFileSync(filePath, serializeBuildMetaArtifact(artifact));
210
+ return {
211
+ artifact,
212
+ filePath,
213
+ meta
214
+ };
215
+ }
216
+ //#endregion
217
+ Object.defineProperty(exports, "__toESM", {
218
+ enumerable: true,
219
+ get: function() {
220
+ return __toESM;
221
+ }
222
+ });
223
+ Object.defineProperty(exports, "collectBuildMeta", {
224
+ enumerable: true,
225
+ get: function() {
226
+ return collectBuildMeta;
227
+ }
228
+ });
229
+ Object.defineProperty(exports, "decodeBuildMeta", {
230
+ enumerable: true,
231
+ get: function() {
232
+ return decodeBuildMeta;
233
+ }
234
+ });
235
+ Object.defineProperty(exports, "encodeBuildMeta", {
236
+ enumerable: true,
237
+ get: function() {
238
+ return encodeBuildMeta;
239
+ }
240
+ });
241
+ Object.defineProperty(exports, "generateBuildMeta", {
242
+ enumerable: true,
243
+ get: function() {
244
+ return generateBuildMeta;
245
+ }
246
+ });
247
+ Object.defineProperty(exports, "sanitizeRepositoryUrl", {
248
+ enumerable: true,
249
+ get: function() {
250
+ return sanitizeRepositoryUrl;
251
+ }
252
+ });
253
+ Object.defineProperty(exports, "serializeBuildMetaArtifact", {
254
+ enumerable: true,
255
+ get: function() {
256
+ return serializeBuildMetaArtifact;
257
+ }
258
+ });
package/dist/index.cjs ADDED
@@ -0,0 +1,8 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_generate = require("./generate-CQvoIMfu.cjs");
3
+ exports.collectBuildMeta = require_generate.collectBuildMeta;
4
+ exports.decodeBuildMeta = require_generate.decodeBuildMeta;
5
+ exports.encodeBuildMeta = require_generate.encodeBuildMeta;
6
+ exports.generateBuildMeta = require_generate.generateBuildMeta;
7
+ exports.sanitizeRepositoryUrl = require_generate.sanitizeRepositoryUrl;
8
+ exports.serializeBuildMetaArtifact = require_generate.serializeBuildMetaArtifact;
@@ -0,0 +1,14 @@
1
+ import { a as BuildMetaPluginOptions, i as BuildMetaOptions, n as BuildMetaArtifact, o as BuildMetaProject, r as BuildMetaCollectOptions, s as BuildMetaResult, t as BuildMeta } from "./types-DHl2uQY2.cjs";
2
+ //#region src/codec.d.ts
3
+ export declare function encodeBuildMeta(meta: BuildMeta): BuildMetaArtifact;
4
+ export declare function decodeBuildMeta(value: string | BuildMetaArtifact): BuildMeta;
5
+ export declare function serializeBuildMetaArtifact(artifact: BuildMetaArtifact): string;
6
+ //#endregion
7
+ //#region src/generate.d.ts
8
+ export declare function collectBuildMeta(options: BuildMetaCollectOptions): BuildMeta;
9
+ export declare function generateBuildMeta(options: BuildMetaOptions): BuildMetaResult;
10
+ //#endregion
11
+ //#region src/repository.d.ts
12
+ export declare function sanitizeRepositoryUrl(value: string): string;
13
+ //#endregion
14
+ export type { BuildMeta, BuildMetaArtifact, BuildMetaCollectOptions, BuildMetaOptions, BuildMetaPluginOptions, BuildMetaProject, BuildMetaResult };
@@ -0,0 +1,14 @@
1
+ import { a as BuildMetaPluginOptions, i as BuildMetaOptions, n as BuildMetaArtifact, o as BuildMetaProject, r as BuildMetaCollectOptions, s as BuildMetaResult, t as BuildMeta } from "./types-DHl2uQY2.js";
2
+ //#region src/codec.d.ts
3
+ export declare function encodeBuildMeta(meta: BuildMeta): BuildMetaArtifact;
4
+ export declare function decodeBuildMeta(value: string | BuildMetaArtifact): BuildMeta;
5
+ export declare function serializeBuildMetaArtifact(artifact: BuildMetaArtifact): string;
6
+ //#endregion
7
+ //#region src/generate.d.ts
8
+ export declare function collectBuildMeta(options: BuildMetaCollectOptions): BuildMeta;
9
+ export declare function generateBuildMeta(options: BuildMetaOptions): BuildMetaResult;
10
+ //#endregion
11
+ //#region src/repository.d.ts
12
+ export declare function sanitizeRepositoryUrl(value: string): string;
13
+ //#endregion
14
+ export type { BuildMeta, BuildMetaArtifact, BuildMetaCollectOptions, BuildMetaOptions, BuildMetaPluginOptions, BuildMetaProject, BuildMetaResult };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { a as encodeBuildMeta, i as decodeBuildMeta, n as generateBuildMeta, o as serializeBuildMetaArtifact, r as sanitizeRepositoryUrl, t as collectBuildMeta } from "./generate-BlU9oOSR.js";
2
+ export { collectBuildMeta, decodeBuildMeta, encodeBuildMeta, generateBuildMeta, sanitizeRepositoryUrl, serializeBuildMetaArtifact };
@@ -0,0 +1,41 @@
1
+ //#region src/types.d.ts
2
+ interface BuildMetaProject {
3
+ name: string;
4
+ title: string;
5
+ version: string;
6
+ }
7
+ interface BuildMeta {
8
+ schemaVersion: 1;
9
+ name: string;
10
+ projectName: string;
11
+ version: string;
12
+ remoteUrl: string;
13
+ buildDate: string;
14
+ user: string;
15
+ lastCommitLog: string;
16
+ lastCommitHash: string;
17
+ lastCommitDate: string;
18
+ }
19
+ interface BuildMetaArtifact {
20
+ version: string;
21
+ }
22
+ interface BuildMetaCollectOptions extends BuildMetaProject {
23
+ cwd?: string;
24
+ remoteUrl?: string;
25
+ }
26
+ interface BuildMetaOptions extends BuildMetaCollectOptions {
27
+ fileName?: string;
28
+ outDir: string;
29
+ }
30
+ interface BuildMetaResult {
31
+ artifact: BuildMetaArtifact;
32
+ filePath: string;
33
+ meta: BuildMeta;
34
+ }
35
+ interface BuildMetaPluginOptions extends BuildMetaProject {
36
+ cwd?: string;
37
+ fileName?: string;
38
+ remoteUrl?: string;
39
+ }
40
+ //#endregion
41
+ export { BuildMetaPluginOptions as a, BuildMetaOptions as i, BuildMetaArtifact as n, BuildMetaProject as o, BuildMetaCollectOptions as r, BuildMetaResult as s, BuildMeta as t };
@@ -0,0 +1,41 @@
1
+ //#region src/types.d.ts
2
+ interface BuildMetaProject {
3
+ name: string;
4
+ title: string;
5
+ version: string;
6
+ }
7
+ interface BuildMeta {
8
+ schemaVersion: 1;
9
+ name: string;
10
+ projectName: string;
11
+ version: string;
12
+ remoteUrl: string;
13
+ buildDate: string;
14
+ user: string;
15
+ lastCommitLog: string;
16
+ lastCommitHash: string;
17
+ lastCommitDate: string;
18
+ }
19
+ interface BuildMetaArtifact {
20
+ version: string;
21
+ }
22
+ interface BuildMetaCollectOptions extends BuildMetaProject {
23
+ cwd?: string;
24
+ remoteUrl?: string;
25
+ }
26
+ interface BuildMetaOptions extends BuildMetaCollectOptions {
27
+ fileName?: string;
28
+ outDir: string;
29
+ }
30
+ interface BuildMetaResult {
31
+ artifact: BuildMetaArtifact;
32
+ filePath: string;
33
+ meta: BuildMeta;
34
+ }
35
+ interface BuildMetaPluginOptions extends BuildMetaProject {
36
+ cwd?: string;
37
+ fileName?: string;
38
+ remoteUrl?: string;
39
+ }
40
+ //#endregion
41
+ export { BuildMetaPluginOptions as a, BuildMetaOptions as i, BuildMetaArtifact as n, BuildMetaProject as o, BuildMetaCollectOptions as r, BuildMetaResult as s, BuildMeta as t };
package/dist/vite.cjs ADDED
@@ -0,0 +1,43 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_generate = require("./generate-CQvoIMfu.cjs");
3
+ let node_path = require("node:path");
4
+ node_path = require_generate.__toESM(node_path, 1);
5
+ //#region src/vite.ts
6
+ function buildMetaPlugin(options) {
7
+ var _options$cwd;
8
+ let cwd = node_path.default.resolve((_options$cwd = options.cwd) !== null && _options$cwd !== void 0 ? _options$cwd : process.cwd());
9
+ let artifact;
10
+ let logged = false;
11
+ return {
12
+ name: "ctc-build-meta",
13
+ apply: "build",
14
+ configResolved(config) {
15
+ var _options$cwd2;
16
+ cwd = node_path.default.resolve((_options$cwd2 = options.cwd) !== null && _options$cwd2 !== void 0 ? _options$cwd2 : config.root);
17
+ },
18
+ transformIndexHtml: {
19
+ order: "post",
20
+ handler() {
21
+ var _artifact;
22
+ (_artifact = artifact) !== null && _artifact !== void 0 || (artifact = require_generate.encodeBuildMeta(require_generate.collectBuildMeta({
23
+ ...options,
24
+ cwd
25
+ })));
26
+ if (!logged) {
27
+ process.stdout.write("[build-meta] metadata injected into HTML\n");
28
+ logged = true;
29
+ }
30
+ return [{
31
+ tag: "meta",
32
+ attrs: {
33
+ name: "ctc-build-meta",
34
+ content: artifact.version
35
+ },
36
+ injectTo: "head-prepend"
37
+ }];
38
+ }
39
+ }
40
+ };
41
+ }
42
+ //#endregion
43
+ exports.buildMetaPlugin = buildMetaPlugin;
@@ -0,0 +1,26 @@
1
+ import { a as BuildMetaPluginOptions } from "./types-DHl2uQY2.cjs";
2
+ //#region src/vite.d.ts
3
+ interface ResolvedViteConfig {
4
+ build: {
5
+ outDir: string;
6
+ };
7
+ root: string;
8
+ }
9
+ export interface BuildMetaVitePlugin {
10
+ apply: "build";
11
+ transformIndexHtml: {
12
+ handler(): Array<{
13
+ attrs: {
14
+ content: string;
15
+ name: "ctc-build-meta";
16
+ };
17
+ injectTo: "head-prepend";
18
+ tag: "meta";
19
+ }>;
20
+ order: "post";
21
+ };
22
+ configResolved(config: ResolvedViteConfig): void;
23
+ name: "ctc-build-meta";
24
+ }
25
+ export declare function buildMetaPlugin(options: BuildMetaPluginOptions): BuildMetaVitePlugin;
26
+ //#endregion
package/dist/vite.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { a as BuildMetaPluginOptions } from "./types-DHl2uQY2.js";
2
+ //#region src/vite.d.ts
3
+ interface ResolvedViteConfig {
4
+ build: {
5
+ outDir: string;
6
+ };
7
+ root: string;
8
+ }
9
+ export interface BuildMetaVitePlugin {
10
+ apply: "build";
11
+ transformIndexHtml: {
12
+ handler(): Array<{
13
+ attrs: {
14
+ content: string;
15
+ name: "ctc-build-meta";
16
+ };
17
+ injectTo: "head-prepend";
18
+ tag: "meta";
19
+ }>;
20
+ order: "post";
21
+ };
22
+ configResolved(config: ResolvedViteConfig): void;
23
+ name: "ctc-build-meta";
24
+ }
25
+ export declare function buildMetaPlugin(options: BuildMetaPluginOptions): BuildMetaVitePlugin;
26
+ //#endregion
package/dist/vite.js ADDED
@@ -0,0 +1,41 @@
1
+ import { a as encodeBuildMeta, t as collectBuildMeta } from "./generate-BlU9oOSR.js";
2
+ import path from "node:path";
3
+ //#region src/vite.ts
4
+ function buildMetaPlugin(options) {
5
+ var _options$cwd;
6
+ let cwd = path.resolve((_options$cwd = options.cwd) !== null && _options$cwd !== void 0 ? _options$cwd : process.cwd());
7
+ let artifact;
8
+ let logged = false;
9
+ return {
10
+ name: "ctc-build-meta",
11
+ apply: "build",
12
+ configResolved(config) {
13
+ var _options$cwd2;
14
+ cwd = path.resolve((_options$cwd2 = options.cwd) !== null && _options$cwd2 !== void 0 ? _options$cwd2 : config.root);
15
+ },
16
+ transformIndexHtml: {
17
+ order: "post",
18
+ handler() {
19
+ var _artifact;
20
+ (_artifact = artifact) !== null && _artifact !== void 0 || (artifact = encodeBuildMeta(collectBuildMeta({
21
+ ...options,
22
+ cwd
23
+ })));
24
+ if (!logged) {
25
+ process.stdout.write("[build-meta] metadata injected into HTML\n");
26
+ logged = true;
27
+ }
28
+ return [{
29
+ tag: "meta",
30
+ attrs: {
31
+ name: "ctc-build-meta",
32
+ content: artifact.version
33
+ },
34
+ injectTo: "head-prepend"
35
+ }];
36
+ }
37
+ }
38
+ };
39
+ }
40
+ //#endregion
41
+ export { buildMetaPlugin };
package/package.json CHANGED
@@ -1,6 +1,69 @@
1
1
  {
2
2
  "name": "@ctc-front/build-meta",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "CTC Front 团队统一构建元数据生成工具",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
20
+ },
21
+ "./vite": {
22
+ "import": {
23
+ "types": "./dist/vite.d.ts",
24
+ "default": "./dist/vite.js"
25
+ },
26
+ "require": {
27
+ "types": "./dist/vite.d.cts",
28
+ "default": "./dist/vite.cjs"
29
+ }
30
+ }
31
+ },
32
+ "bin": {
33
+ "ctc-build-meta": "./bin/ctc-build-meta.cjs"
34
+ },
35
+ "files": [
36
+ "bin",
37
+ "dist",
38
+ "CHANGELOG.md",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "sideEffects": false,
43
+ "engines": {
44
+ "node": ">=14"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "registry": "https://registry.npmjs.org/"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "24.10.1",
52
+ "acorn": "6.4.2",
53
+ "publint": "0.3.24",
54
+ "tsdown": "0.23.0",
55
+ "typescript": "5.9.3",
56
+ "vitest": "5.0.2"
57
+ },
58
+ "scripts": {
59
+ "dev": "tsdown --watch",
60
+ "build": "tsdown",
61
+ "lint": "eslint .",
62
+ "typecheck": "tsc -p tsconfig.json --noEmit",
63
+ "test": "vitest run",
64
+ "test:watch": "vitest",
65
+ "compat:node14": "node ./scripts/check-node14-syntax.mjs",
66
+ "pack:check": "publint && pnpm compat:node14 && pnpm pack --dry-run",
67
+ "check": "pnpm lint && pnpm typecheck && pnpm test && pnpm build && pnpm pack:check"
68
+ }
6
69
  }