games-development-ai/contracts/sdk-interface.d.ts
zizi 28a57b8e00 feat(contracts): T1b-β P2 三契约冻结(grounded 据真签名+插件真调用面)——待对抗复审
①受控面引擎能力透传通道 PluginContext.getEngine()→EngineCapabilities(api.d.ts):白名单3项particles.spawnEmitter/audio.synth/math.lerp+smoothStep(YAGNI核6件impl真调用点);铁律=封装禁裸Vector2/引擎import只活集成段host背书engineFactory不散进插件impl(保引擎可换+满足门1真接线);random/time集成段换引擎RandomGenerator/timeReal背书(契约形状不变)
②GamePackage manifest加packageUrl+immutable(additive,复用后端packageUrl镜像走DB-manifest降级,checksum复用旧字段供门4防demo假阳性)
③SDK StoragePlugin根契约上提(sdk-interface.d.ts):前端contract.ts定稿对象形态上提+含R4-P1 array排除契约语义声明

grounded工位核impl逮关键澄清:hitStop/屏震非通道项(impl.js:582-615=受控面输出+游戏层render.js:915应用闭环,插件不调引擎;屏震引擎化=render.js切相机属agent生成域)→通道收敛6件→3项,§7/§6 A2同步澄清;audio.synth留契约A2据SIZES定用否
JSON校验过+.d.ts括号平衡

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 05:12:35 +00:00

138 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 契约 #3 | WanxiangGameSDK 公共 API 类型 + SDK↔宿主 postMessage 协议
* ownerWS3 SDK 负责人 | 消费方game-studio 宿主 / 游戏侧
*
* 硬约束(来自 engineering-conventions §3
* - 零第三方依赖Core(Lifecycle+EventBus+Telemetry+ErrorTrack) 压缩后 < 8KB每 Plugin < 5KB
* - 所有对外 API 不返回 Promisefire-and-forget不占游戏主线程异常绝不向游戏抛
* - 新版本只增字段/方法、不删不改已有签名semver
*/
/** SDK 初始化参数(宿主注入) */
export interface WanxiangGameSDKInitOptions {
gameId: string;
versionId: string;
/** 贯穿 生成→编译→加载→运行→上报 的 trace_id */
traceId: string;
/** 是否开发模式(加载 Plugin.Debug仅 dev */
debug?: boolean;
}
/** 游戏生命周期事件名 */
export type LifecycleEvent =
| 'sdk_ready' // SDK 初始化完成
| 'game_loaded' // 游戏资源加载完成
| 'game_start' // 开始游玩
| 'game_end' // 本局结束
| 'game_error'; // 运行错误
/** SDK 根对象(挂在游戏侧 window.WanxiangGameSDK */
export interface WanxiangGameSDK {
/** 初始化(宿主调用一次) */
init(options: WanxiangGameSDKInitOptions): void;
/** 生命周期事件订阅EventBus */
on(event: LifecycleEvent, handler: (payload?: Record<string, unknown>) => void): void;
off(event: LifecycleEvent, handler: (payload?: Record<string, unknown>) => void): void;
/** 遥测上报fire-and-forget内部 10条/5s 批量 flush + sendBeacon 兜底) */
track(event: string, props?: Record<string, unknown>): void;
/** 错误上报(去重,不中断游戏) */
reportError(error: { message: string; stack?: string }): void;
/** 插件(首次调用懒加载) */
ad: AdPlugin;
pay: PayPlugin;
/** 存储插件首次调用懒加载idle 离线存档T1b-β 由前端 host/contract.ts 定稿形态上提至根契约) */
storage: StoragePlugin;
}
/** 广告插件MVP 桩 → 真实穿山甲/优量汇切换;每调用 5s 超时降级) */
export interface AdPlugin {
/** 激励视频;完成回调 rewarded=true */
showRewarded(slotId: string, cb: (result: { rewarded: boolean }) => void): void;
/** 插屏广告 */
showInterstitial(slotId: string, cb?: (result: { shown: boolean }) => void): void;
}
/** 支付插件MVP 桩 → 真实微信支付切换) */
export interface PayPlugin {
/** 发起积分充值;宿主侧拉起支付 */
pay(order: { orderId: string; amount: number }, cb: (result: { paid: boolean }) => void): void;
}
/** 存储插件idle 离线产出存档HJ-MC-TPL-EXEC-002 §6.1.1 定稿对象形态T1b-β 上提至根契约semver 只增不改) */
export interface StoragePlugin {
/**
* 写入存档fire-and-forget不返回 Promise。宿主侧白名单前缀校验 + 大小上限校验后落 localStorage。
* @param key 存档键runtime 侧按 'idle:'+gameId+':'+versionId 约定)。
* @param value 存档值JSON 字符串;宿主侧落库前校验大小)。
*/
save(key: string, value: string): void;
/**
* 读取存档宿主受信边界已解析为对象后回调runtime 侧零 JSON.parse守 runtime §5.5 零解析红线)。
* @param key 存档键。
* @param cb 回调;命中=已解析对象,未命中/校验失败/**非纯对象(含数组)**=null见 StorageResultPayload.value 的 array 排除)。
*/
load(key: string, cb: (value: Record<string, unknown> | null) => void): void;
}
/* ============================================================================
* SDK ↔ 宿主 postMessage 协议
* 游戏在 iframe 沙箱内,通过 postMessage 与 game-studio 宿主通信。
* 宿主侧校验 origin 白名单 + 消息 schema双校验见 security-and-reliability §1.1)。
* ========================================================================== */
/** 消息方向 */
export type MessageDirection = 'game_to_host' | 'host_to_game';
/** 消息类型全集 */
export type PostMessageType =
| 'init' // 宿主→游戏:初始化参数
| 'lifecycle' // 游戏→宿主:生命周期事件
| 'telemetry' // 游戏→宿主:遥测事件转发
| 'error' // 游戏→宿主:错误上报
| 'ad' // 双向:广告请求/结果(广告在 iframe 外宿主侧渲染)
| 'pay' // 双向:支付请求/结果
| 'social' // 双向:分享等
| 'storage'; // 双向:键值存储
/** postMessage 信封 */
export interface PostMessageEnvelope<T = unknown> {
/** 固定标识,宿主据此过滤非本协议消息 */
channel: 'wanxiang-game-sdk';
type: PostMessageType;
direction: MessageDirection;
/** 请求/响应配对 IDad/pay 等需回调的消息) */
requestId?: string;
traceId: string;
payload: T;
}
/* ----- storage 消息 payloadidle 离线产出存档HJ-MC-TPL-EXEC-002 §6.1.1T1b-β 上提semver 只增不改) ----- */
/** storage 写入请求 payload游戏→宿主保存键值 */
export interface StorageSetPayload {
/** 存档键runtime 侧按 'idle:'+gameId+':'+versionId 约定,宿主侧白名单前缀校验) */
key: string;
/** 存档值JSON 字符串,宿主侧落 localStorage 前校验大小上限) */
value: string;
}
/** storage 读取请求 payload游戏→宿主按 key 取值;带 requestId宿主读分支按同 requestId 回包) */
export interface StorageGetPayload {
key: string;
}
/** storage 读取结果 payload宿主→游戏回包 value无则 null */
export interface StorageResultPayload {
key: string;
/**
* 命中的存档值 = 宿主受信边界已解析好的对象(非原始 JSON 字符串);未命中/校验失败为 null。
* 解析在宿主侧做runtime 侧零 JSON.parse守 runtime §5.5「runtime 内不引可抛解析路径」),
* loadState resolve 出对象后 runtime 直接读字段。写入 payloadStorageSetPayload.value仍是 JSON 字符串。
* **对象语义不含数组T1b-β R4-P1**宿主回包端game-studio inject.ts 已落 !Array.isArray 运行时排除)
* 与本类型层须一致——value 虽 TS 标注 Record<string,unknown>|nullarray 在 TS 是 object 子型不被拒),
* 但**契约语义明令排除数组**:数组/字符串/标量一律按未命中处理resolve null
* storage 三套形状(本根契约 / game-studio host/contract.ts / inject.ts 应答端收敛校验须覆盖此「array→null」运行时语义不止类型签名对齐。
*/
value: Record<string, unknown> | null;
}