fix(sdk): flush前resume检查点预埋+onClose晚注册即触发+归属预留字段从快照展开
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
+15
-3
@@ -115,6 +115,16 @@ export class PageSession {
|
|||||||
|
|
||||||
onClose(fn: () => void): void {
|
onClose(fn: () => void): void {
|
||||||
this.closeListeners.push(fn);
|
this.closeListeners.push(fn);
|
||||||
|
// 注册晚于 close(T7 初始化与 pagehide/路由切换竞态):立即补触发一次。
|
||||||
|
// closeListeners 不因 revive 清空——bfcache 复活后的下一次 close 会再次触发
|
||||||
|
// 全部监听器(周期结算正确性)。
|
||||||
|
if (this._closed) {
|
||||||
|
try {
|
||||||
|
fn();
|
||||||
|
} catch {
|
||||||
|
/* 静默(spec §4.5) */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 本段 page_view(初始加载 / SPA 新段);bfcache 复活不调此方法(不产生新 PV)。 */
|
/** 本段 page_view(初始加载 / SPA 新段);bfcache 复活不调此方法(不产生新 PV)。 */
|
||||||
@@ -164,9 +174,11 @@ export class PageSession {
|
|||||||
session_id: a.session_id,
|
session_id: a.session_id,
|
||||||
page_id: a.page_id,
|
page_id: a.page_id,
|
||||||
seq: a.seq,
|
seq: a.seq,
|
||||||
purpose: null,
|
// V1.1 预留字段从快照展开(非字面量)——将来 attribution() 填真实值时
|
||||||
epoch: null,
|
// 事件自动携带,不会静默漏
|
||||||
grant_ref: null,
|
purpose: a.purpose,
|
||||||
|
epoch: a.epoch,
|
||||||
|
grant_ref: a.grant_ref,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { uuid } from "./util";
|
import { uuid } from "./util";
|
||||||
import { getVisitorId, getSessionId } from "./identity";
|
import { getVisitorId, getSessionId } from "./identity";
|
||||||
|
import { getPageSession } from "./page";
|
||||||
import type { CtkConfig } from "./config";
|
import type { CtkConfig } from "./config";
|
||||||
|
|
||||||
export type TransportConfig = Required<CtkConfig>;
|
export type TransportConfig = Required<CtkConfig>;
|
||||||
@@ -28,6 +29,15 @@ export class Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
flush(beacon = false) {
|
flush(beacon = false) {
|
||||||
|
// flush 前 resume 检查点(T8 预埋 + T8 前双路径保险):本批信封仍走
|
||||||
|
// getSessionId()(会 touchActivity 刷 ctk_act)——若不先检查,hidden 期间的
|
||||||
|
// 定时器 flush 会把空闲判定无限续期,用户回前台后永不 resume(OT01 违规)。
|
||||||
|
// PageSession 未启动时为 null → 安全跳过(v1 旧路径照旧)。
|
||||||
|
try {
|
||||||
|
getPageSession()?.maybeResume();
|
||||||
|
} catch {
|
||||||
|
/* 静默(spec §4.5:定时器回调内的异常不得冒泡) */
|
||||||
|
}
|
||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
clearTimeout(this.timer);
|
clearTimeout(this.timer);
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
|
|||||||
@@ -265,4 +265,33 @@ describe("PageSession / startPageSession", () => {
|
|||||||
t.flush();
|
t.flush();
|
||||||
expect(flushedEvents("site-close").some((e) => e.event_name === "session_resume")).toBe(false);
|
expect(flushedEvents("site-close").some((e) => e.event_name === "session_resume")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("onClose 晚注册于 close 之后立即补触发;revive 后再 close 再次触发(bfcache 周期结算)", () => {
|
||||||
|
const t = mkTransport("site-late-hook");
|
||||||
|
const ps = startPageSession(t);
|
||||||
|
ps.close(); // 先关闭(T7 初始化与 pagehide/路由切换竞态)
|
||||||
|
const hook = vi.fn();
|
||||||
|
ps.onClose(hook); // 晚注册:立即触发一次,不丢失本次结算时机
|
||||||
|
expect(hook).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
ps.revive(); // bfcache 复活:监听器不因 revive 清空
|
||||||
|
ps.close();
|
||||||
|
expect(hook).toHaveBeenCalledTimes(2); // 新周期的 close 再次触发
|
||||||
|
});
|
||||||
|
|
||||||
|
it("flush 前检查点(Transport.flush 预埋):hidden 期间 flush 刷活 ctk_act 后仍能恢复", () => {
|
||||||
|
const t = mkTransport("site-flushcp");
|
||||||
|
const ps = startPageSession(t);
|
||||||
|
const sid = ps.attribution().session_id;
|
||||||
|
Object.defineProperty(document, "hidden", { value: true, configurable: true });
|
||||||
|
vi.advanceTimersByTime(31 * 60_000);
|
||||||
|
|
||||||
|
t.flush(); // 信封 getSessionId() 会 touchActivity——若无 flush 前检查点,空闲被无限续期
|
||||||
|
delete (document as { hidden?: boolean }).hidden;
|
||||||
|
document.dispatchEvent(new Event("visibilitychange")); // 用户回前台
|
||||||
|
expect(ps.attribution().session_id).not.toBe(sid); // 恢复未被抑制(OT01)
|
||||||
|
|
||||||
|
const sr = flushedEvents("site-flushcp").find((e) => e.event_name === "session_resume")!;
|
||||||
|
expect(sr.properties.prev_session_id).toBe(sid);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user