feat(sdk): 版本注入与事件归属骨架(0.2.0/build_id/schema_version)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
+13
-2
@@ -1,6 +1,17 @@
|
|||||||
import { build } from "esbuild";
|
import { build } from "esbuild";
|
||||||
|
import { execSync } from "node:child_process";
|
||||||
|
|
||||||
|
let buildId;
|
||||||
|
try {
|
||||||
|
buildId = execSync("git log -1 --format=%h-%cd --date=format:%Y%m%d%H%M").toString().trim();
|
||||||
|
} catch {
|
||||||
|
buildId = "dev-" + Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
await build({
|
await build({
|
||||||
entryPoints: ["src/index.ts"],
|
entryPoints: ["src/index.ts"], bundle: true, minify: true, format: "iife",
|
||||||
bundle: true, minify: true, format: "iife",
|
|
||||||
outfile: "dist/v1.js", target: ["es2020"], // 代码依赖 globalThis(es2018 目标名不副实)
|
outfile: "dist/v1.js", target: ["es2020"], // 代码依赖 globalThis(es2018 目标名不副实)
|
||||||
|
// define 键必须用点链:esbuild 只做精确表达式匹配,裸键不会替换
|
||||||
|
// globalThis.__BUILD_ID__ 成员访问(实测 0.24.2),裸键将恒为 "unknown"
|
||||||
|
define: { "globalThis.__BUILD_ID__": JSON.stringify(buildId) },
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ctk-sdk",
|
"name": "ctk-sdk",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+2
-1
@@ -3,6 +3,7 @@ import { mergeConfig } from "./config";
|
|||||||
import { Transport } from "./transport";
|
import { Transport } from "./transport";
|
||||||
import { startPageTracking } from "./events";
|
import { startPageTracking } from "./events";
|
||||||
import { buildEnvContext, collectHighEntropyHints, pageContext } from "./context";
|
import { buildEnvContext, collectHighEntropyHints, pageContext } from "./context";
|
||||||
|
import { SDK_VERSION, BUILD_ID, SCHEMA_VERSION, CONFIG_VERSION } from "./types";
|
||||||
import type { CtkConfig } from "./config";
|
import type { CtkConfig } from "./config";
|
||||||
|
|
||||||
// IIFE 打包入口(build.mjs):模块加载即接管全局 ctk 命令队列并重放。
|
// IIFE 打包入口(build.mjs):模块加载即接管全局 ctk 命令队列并重放。
|
||||||
@@ -49,7 +50,7 @@ function dispatch(cmd: string, arg?: unknown) {
|
|||||||
occurred_at: new Date().toISOString(),
|
occurred_at: new Date().toISOString(),
|
||||||
path: pc.path,
|
path: pc.path,
|
||||||
title: pc.title,
|
title: pc.title,
|
||||||
properties: { sdk_version: "0.1.0" },
|
properties: { sdk_version: SDK_VERSION, build_id: BUILD_ID, schema_version: SCHEMA_VERSION, config_version: CONFIG_VERSION },
|
||||||
});
|
});
|
||||||
startPageTracking(transport);
|
startPageTracking(transport);
|
||||||
} else if (cmd === "track" && transport) {
|
} else if (cmd === "track" && transport) {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/** 事件归属四元组:入队时冻结,flush 不再重读(spec §1.1) */
|
||||||
|
export interface Attribution {
|
||||||
|
site_id: string;
|
||||||
|
visitor_id: string;
|
||||||
|
session_id: string;
|
||||||
|
page_id: string;
|
||||||
|
seq: number;
|
||||||
|
purpose?: null; // V1.1 预留
|
||||||
|
epoch?: null; // V1.1 预留
|
||||||
|
grant_ref?: null; // V1.1 预留
|
||||||
|
}
|
||||||
|
export const SDK_VERSION = "0.2.0"; // 与 package.json 同步手维护
|
||||||
|
export const SCHEMA_VERSION = 2;
|
||||||
|
export const CONFIG_VERSION = "1";
|
||||||
|
|
||||||
|
// build_id 由 esbuild/vitest define 注入的全局常量(ambient 声明,
|
||||||
|
// 不能用模块级 export declare——esbuild 打包时会被擦除导致引用悬空)
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
|
var __BUILD_ID__: string | undefined;
|
||||||
|
}
|
||||||
|
/** 运行时兜底读取(build 注入缺失时降级 "unknown",绝不抛) */
|
||||||
|
export const BUILD_ID: string = globalThis.__BUILD_ID__ ?? "unknown";
|
||||||
@@ -54,7 +54,7 @@ describe("index 入口", () => {
|
|||||||
delete (document as { referrer?: string }).referrer;
|
delete (document as { referrer?: string }).referrer;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("init 后 sdk_loaded 入队(含 sdk_version)", async () => {
|
it("init 后 sdk_loaded 入队(含版本组:sdk_version/build_id/schema_version/config_version)", async () => {
|
||||||
await loadSdk([["init", { siteId: "site-1", endpoint: "/e", flushMs: 60000 }]]);
|
await loadSdk([["init", { siteId: "site-1", endpoint: "/e", flushMs: 60000 }]]);
|
||||||
g.ctk!("flush");
|
g.ctk!("flush");
|
||||||
|
|
||||||
@@ -62,7 +62,11 @@ describe("index 入口", () => {
|
|||||||
expect(bodies).toHaveLength(1);
|
expect(bodies).toHaveLength(1);
|
||||||
const loaded = bodies[0].events.find((e: { event_name: string }) => e.event_name === "sdk_loaded");
|
const loaded = bodies[0].events.find((e: { event_name: string }) => e.event_name === "sdk_loaded");
|
||||||
expect(loaded).toBeTruthy();
|
expect(loaded).toBeTruthy();
|
||||||
expect(loaded.properties.sdk_version).toBe("0.1.0");
|
expect(loaded.properties.sdk_version).toBe("0.2.0");
|
||||||
|
// build_id 由 vitest.config define 注入 "vitest";无 define 环境兜底 "unknown"
|
||||||
|
expect(loaded.properties.build_id).toBe("vitest");
|
||||||
|
expect(loaded.properties.schema_version).toBe(2);
|
||||||
|
expect(loaded.properties.config_version).toBe("1");
|
||||||
expect(loaded.event_id).toMatch(UUID_RE);
|
expect(loaded.event_id).toMatch(UUID_RE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { defineConfig } from "vitest/config";
|
import { defineConfig } from "vitest/config";
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
test: { environment: "happy-dom", setupFiles: [] },
|
test: { environment: "happy-dom", setupFiles: [] },
|
||||||
|
// 与 build.mjs 同构的 define 注入(点链键):测试内 BUILD_ID 恒为 "vitest"
|
||||||
|
define: { "globalThis.__BUILD_ID__": JSON.stringify("vitest") },
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user