API reference
This page lists every module, signature and key type in SDK 1.2.0. Behavior details (runtime modes, offline reconciliation, email binding) live in the Integration guide.
Include and initialize
Platform-hosted games use the CDN bundle with the global Instfun:
<script src="/sdk/v1/instfun.js"></script>const sdk = await Instfun.init({
gameId: "my-game",
gameVersion: "0.1.0",
mode: "auto"
});| Method / property | Signature | Description |
|---|---|---|
Instfun.init | (config: InstfunConfig, deps?) => Promise<InstfunSdk> | Creates and replaces the singleton instance |
Instfun.getInstance | () => InstfunSdk / null | Returns null before initialization |
Instfun.version | string | SDK version (currently 1.2.0) |
InstfunConfig:
| Field | Type | Required | Description |
|---|---|---|---|
gameId | string | Yes | Matches ^[a-z0-9][a-z0-9_-]{0,63}$; must match the published package. The upload/submit API additionally requires no underscores, 2–64 characters, and consistency with game-info.json |
gameVersion | string | No | Defaults to "0.0.0" |
debug | boolean | No | Enable debug logging |
mode | "local" / "remote" / "auto" | No | Defaults to auto |
apiBaseUrl | string | No | Remote API prefix; remote defaults to /api/v1 |
initialBalance | Partial<Record<"coins" / "gems", number>> | No | Initial balance in local mode |
limits | { saveThrottleMs?: number; sessionEvents?: number } | No | Override save throttling and the per-process event cap |
InstfunSdk root object:
| Member | Type | Description |
|---|---|---|
sdkVersion | string | SDK version |
gameId | string | Current game identifier |
mode | "local" / "remote" | Resolved runtime mode |
host | { kind: "android" / "web" / "browser" } | Current host |
supports | (capability: "ads" / "login" / "payments" / "tracking") => Promise<boolean> | Host capability probe |
sync | () => Promise<{ flushed: number; pending: number }> | Flush analytics and replay the offline queue |
account / wallet / game / leaderboard / analytics / ads / storage | Modules | See below |
account
| Method | Signature | Description |
|---|---|---|
getCurrentUser | () => Promise<UserProfile> | Current guest profile (shared same-origin) |
updateProfile | (patch: Partial<Pick<UserProfile, "nickname" / "avatarUrl" / "bio">>) => Promise<UserProfile> | Update profile fields |
hasEmail | () => Promise<boolean> | Whether an email is bound; always false in local mode |
openEmailBindDialog | (options?: EmailBindDialogOptions) => Promise<EmailBindResult> | Email binding / rebinding dialog |
type EmailBindResult =
| { status: "bound"; email: string; profile: UserProfile }
| { status: "cancelled" }
| { status: "unavailable"; reason: "offline" | "already-bound" };Key UserProfile fields:
| Field | Type | Description |
|---|---|---|
userId / nickname / avatarUrl / bio | string | Basic profile |
isGuest | boolean | Always true for guest accounts |
accountCode | string | 8-character account code for support |
email | string / null | Masked email; null when unbound |
accountBound | boolean | Whether an email is bound |
createdAt | number | Creation time (millisecond timestamp) |
recentGameIds | string[] | Recently played games |
wallet
| Method | Signature | Description |
|---|---|---|
get | () => Promise<WalletBalance> | Balance snapshot { coins, gems, updatedAt } |
getBalance | (currency?: "coins" / "gems") => Promise<number> | Balance for one currency, default coins |
reward | (input: WalletRewardInput) => Promise<WalletTransaction> | Credit and return the transaction |
spend | (input: WalletSpendInput) => Promise<WalletTransaction> | Debit; throws INSUFFICIENT_FUNDS when short |
transactions | (options?: { limit?: number; currency?: "coins" / "gems" }) => Promise<WalletTransaction[]> | Recent transactions, newest first |
interface WalletRewardInput {
amount: number;
reason: string;
currency?: "coins" | "gems";
type?: WalletTransactionType;
idempotencyKey?: string;
}
interface WalletSpendInput {
amount: number;
reason: string;
currency?: "coins" | "gems";
idempotencyKey?: string;
}
interface WalletTransaction {
id: string;
userId: string;
currency: "coins" | "gems";
amount: number; // signed: positive is a credit, negative a debit
balanceAfter: number;
type: WalletTransactionType;
reason: string;
gameId: string;
idempotencyKey?: string;
createdAt: number;
}WalletTransactionType: "REWARD" | "SPEND" | "PURCHASE" | "AD_REWARD" | "MISSION_REWARD" | "ACHIEVEMENT_REWARD" | "ADMIN_ADJUST".
Amounts must be integers in [1, 10000] or the call throws INVALID_AMOUNT. Local mode uses a local ledger; remote mode is server-authoritative and supports idempotencyKey.
game
| Method | Signature | Description |
|---|---|---|
getInfo | () => Promise<GameInfo> | First/recent play times and open count |
start | (meta?: { level?: number; mode?: string }) => Promise<GameSession> | Open a session; returns { sessionId, startedAt } |
finish | (input: GameFinishInput) => Promise<GameFinishResult> | Settle: record + stats + optional save/leaderboard |
record | (input: GameRecordInput) => Promise<GameRecord> | Write a record without a session |
saveProgress | <T>(data: T, options?: { merge?: boolean }) => Promise<GameProgress<T>> | Write a save; merge is shallow |
loadProgress | <T>() => Promise<GameProgress<T> / null> | Read the save |
getStats | () => Promise<GameStats> | { playCount, bestScore, totalDurationMs, lastPlayedAt } |
getRecords | (options?: { limit?: number }) => Promise<GameRecord[]> | Recent records, newest first |
interface GameFinishInput {
result: "complete" | "fail" | "quit";
score?: number;
level?: number;
progress?: Record<string, unknown>;
mergeProgress?: boolean; // defaults to true
submitScore?: boolean; // defaults to false
boardId?: string; // defaults to "global"
}
interface GameFinishResult {
record: GameRecord;
stats: GameStats;
leaderboard: LeaderboardSnapshot | null;
}
interface GameProgress<T = Record<string, unknown>> {
gameId: string;
data: T;
revision: number;
gameVersion: string;
sdkVersion: string;
updatedAt: number;
pendingSync?: boolean; // set in remote mode only
}The leaderboard is submitted only when submitScore: true and score is a non-negative integer. A save over 256KB throws PAYLOAD_TOO_LARGE.
leaderboard
| Method | Signature | Description |
|---|---|---|
submitScore | (input: { boardId?: string; score: number; higherIsBetter?: boolean }) => Promise<LeaderboardEntry> | Keeps only the better score |
get | (options?: { boardId?: string; limit?: number }) => Promise<LeaderboardSnapshot> | Local or global board |
interface LeaderboardSnapshot {
boardId: string;
scope: "local" | "global";
localOnly: boolean;
window: "all" | "weekly";
entries: LeaderboardEntry[];
self: LeaderboardEntry | null;
total: number;
updatedAt: number;
}
interface LeaderboardEntry {
userId: string;
nickname: string;
score: number;
rank: number;
updatedAt: number;
}boardId defaults to "global". Scores must be non-negative integers or the call throws INVALID_SCORE. The SDK currently always requests window: "all".
analytics
| Method | Signature | Description |
|---|---|---|
track | (name: string, properties?: Record<string, unknown>) => Promise<AnalyticsEvent> | Queue an event; never throws |
getQueue | () => Promise<AnalyticsEvent[]> | Current queue snapshot |
flush | () => Promise<{ sent: number; pending: number }> | Batched upload in remote mode; local reports pending only |
clear | () => Promise<void> | Clear the queue |
Event names are 1–64 characters; properties over 8KB serialized are dropped; the queue keeps at most 500 events.
ads
| Method | Signature | Description |
|---|---|---|
showRewarded | (options: { placement: string; currency?: "coins" / "gems"; amount?: number; reason?: string }) => Promise<RewardedAdResult> | Grants the reward idempotently after a full view |
showInterstitial | (options?: { placement: string }) => Promise<InterstitialAdResult> | Interstitial; browser host returns shown: false |
interface RewardedAdResult {
completed: boolean;
simulated: boolean;
rewardGranted: boolean;
reward?: { currency: "coins" | "gems"; amount: number };
transactionId?: string;
}placement defaults to "GAME_OVER" for interstitials. The default reward is 100 coins; never grant currency yourself.
storage (game-level KV)
| Method | Signature | Description |
|---|---|---|
get | <T>(key: string) => Promise<T / null> | Read |
set | <T>(key: string, value: T) => Promise<void> | Write a JSON-serializable value |
remove | (key: string) => Promise<void> | Delete |
keys | () => Promise<string[]> | Keys for the current game |
persistent | boolean | Whether storage is durable (false after memory fallback) |
Keys are namespaced per gameId; identical keys in different games do not collide.
Module cheat sheet
| Module | Methods | Description |
|---|---|---|
| account | getCurrentUser() / updateProfile(patch) | Guest profile (with accountCode / email / accountBound); shared same-origin |
| account | hasEmail() | Whether an email is bound; always false locally |
| account | openEmailBindDialog(options?) | Email binding/rebinding dialog (bilingual, 60s resend countdown by default) |
| wallet | get() / getBalance(currency?) | Balance snapshot; coins by default |
| wallet | reward({ amount, reason, currency?, type?, idempotencyKey? }) | Credit and return the transaction |
| wallet | spend({ amount, reason, currency?, idempotencyKey? }) | Debit; throws INSUFFICIENT_FUNDS when short |
| wallet | transactions({ limit?, currency? }) | Recent transactions, newest first |
| game | getInfo() | First/recent play times and open count |
| game | start(meta?) / finish(input) | Session start and settlement (record + stats + optional save/leaderboard) |
| game | record(input) | Write a record without a session |
| game | saveProgress(data, { merge? }) / loadProgress() | Save read/write; merge is shallow |
| game | getStats() / getRecords({ limit? }) | Stats and recent records |
| leaderboard | submitScore({ boardId?, score, higherIsBetter? }) / get(...) | Keeps only the better score; local or global board |
| analytics | track(name, properties?) | Queue an event; never throws |
| analytics | getQueue() / flush() / clear() | Remote flush() uploads in batches; local reports pending |
| ads | showRewarded({ placement, currency?, amount?, reason? }) | Grants the reward idempotently after a full view |
| ads | showInterstitial({ placement }) | Interstitial; browser host returns shown: false |
| storage | get/set/remove/keys + persistent | Game-level KV |
| root | sdkVersion / gameId / mode / host / supports(capability) / sync() | Version, mode and host capability probing |
Type index
| Group | Key types |
|---|---|
| Host and basics | HostKind, HostCapability, Currency |
| Config | InstfunConfig, InstfunMode |
| Account | UserProfile, AccountModule, EmailBindDialogOptions, EmailBindResult |
| Wallet | WalletTransactionType, WalletTransaction, WalletRewardInput, WalletSpendInput, WalletBalance, WalletModule |
| Game | GameProgress, GameSession, GameResult, GameRecord, GameStats, GameInfo, GameFinishInput, GameFinishResult, GameModule, SyncResult |
| Leaderboard | LeaderboardEntry, LeaderboardSnapshot, LeaderboardModule |
| Analytics | AnalyticsEvent, AnalyticsModule |
| Ads | ShowRewardedOptions, RewardedAdResult, ShowInterstitialOptions, InterstitialAdResult, AdsModule |
| Storage | GameStorageModule |
| Aggregate | InstfunSdk |
The complete TypeScript definitions live in the SDK package's types module.
本页汇总 SDK 1.2.0 的全部模块、方法签名与关键类型。行为细节(运行模式、离线补偿、邮箱绑定流程等)见「接入指南」。
引入与初始化
平台托管游戏使用 CDN 单文件,全局对象为 Instfun:
<script src="/sdk/v1/instfun.js"></script>const sdk = await Instfun.init({
gameId: "my-game",
gameVersion: "0.1.0",
mode: "auto"
});| 方法 / 属性 | 签名 | 说明 |
|---|---|---|
Instfun.init | (config: InstfunConfig, deps?) => Promise<InstfunSdk> | 创建并覆盖单例实例 |
Instfun.getInstance | () => InstfunSdk / null | 未初始化时返回 null |
Instfun.version | string | SDK 版本(当前 1.2.0) |
InstfunConfig:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
gameId | string | 是 | 匹配 ^[a-z0-9][a-z0-9_-]{0,63}$,须与上架包一致;上传/上架接口额外要求不含下划线、2–64 位,且须与 game-info.json 一致 |
gameVersion | string | 否 | 缺省 "0.0.0" |
debug | boolean | 否 | 输出调试日志 |
mode | "local" / "remote" / "auto" | 否 | 缺省 auto |
apiBaseUrl | string | 否 | 远端 API 前缀;remote 缺省 /api/v1 |
initialBalance | Partial<Record<"coins" / "gems", number>> | 否 | 本地模式初始余额 |
limits | { saveThrottleMs?: number; sessionEvents?: number } | 否 | 覆盖存档节流与单次进程埋点上限 |
InstfunSdk 根对象:
| 成员 | 类型 | 说明 |
|---|---|---|
sdkVersion | string | SDK 版本 |
gameId | string | 当前游戏标识 |
mode | "local" / "remote" | 初始化后解析出的实际模式 |
host | { kind: "android" / "web" / "browser" } | 当前宿主 |
supports | (capability: "ads" / "login" / "payments" / "tracking") => Promise<boolean> | 宿主能力探测 |
sync | () => Promise<{ flushed: number; pending: number }> | 上报埋点并重放离线队列 |
account / wallet / game / leaderboard / analytics / ads / storage | 模块 | 见下 |
account
| 方法 | 签名 | 说明 |
|---|---|---|
getCurrentUser | () => Promise<UserProfile> | 当前游客资料(同源共享) |
updateProfile | (patch: Partial<Pick<UserProfile, "nickname" / "avatarUrl" / "bio">>) => Promise<UserProfile> | 更新资料 |
hasEmail | () => Promise<boolean> | 是否已绑定邮箱;本地模式恒为 false |
openEmailBindDialog | (options?: EmailBindDialogOptions) => Promise<EmailBindResult> | 邮箱绑定 / 换绑弹窗 |
type EmailBindResult =
| { status: "bound"; email: string; profile: UserProfile }
| { status: "cancelled" }
| { status: "unavailable"; reason: "offline" | "already-bound" };UserProfile 关键字段:
| 字段 | 类型 | 说明 |
|---|---|---|
userId / nickname / avatarUrl / bio | string | 基础资料 |
isGuest | boolean | 游客账号恒为 true |
accountCode | string | 8 位账号码,客服识别用 |
email | string / null | 脱敏邮箱;未绑定为 null |
accountBound | boolean | 是否已绑定邮箱 |
createdAt | number | 创建时间(毫秒时间戳) |
recentGameIds | string[] | 最近玩过的游戏 |
wallet
| 方法 | 签名 | 说明 |
|---|---|---|
get | () => Promise<WalletBalance> | 余额快照 { coins, gems, updatedAt } |
getBalance | (currency?: "coins" / "gems") => Promise<number> | 指定币种余额,缺省 coins |
reward | (input: WalletRewardInput) => Promise<WalletTransaction> | 入账,返回流水 |
spend | (input: WalletSpendInput) => Promise<WalletTransaction> | 扣款;余额不足抛 INSUFFICIENT_FUNDS |
transactions | (options?: { limit?: number; currency?: "coins" / "gems" }) => Promise<WalletTransaction[]> | 最近流水,倒序 |
interface WalletRewardInput {
amount: number;
reason: string;
currency?: "coins" | "gems";
type?: WalletTransactionType;
idempotencyKey?: string;
}
interface WalletSpendInput {
amount: number;
reason: string;
currency?: "coins" | "gems";
idempotencyKey?: string;
}
interface WalletTransaction {
id: string;
userId: string;
currency: "coins" | "gems";
amount: number; // 有符号:入账为正、支出为负
balanceAfter: number;
type: WalletTransactionType;
reason: string;
gameId: string;
idempotencyKey?: string;
createdAt: number;
}WalletTransactionType:"REWARD" | "SPEND" | "PURCHASE" | "AD_REWARD" | "MISSION_REWARD" | "ACHIEVEMENT_REWARD" | "ADMIN_ADJUST"。
单笔金额必须为 [1, 10000] 内的整数,否则抛 INVALID_AMOUNT。本地模式为本地账本;远端模式为服务端权威账本,支持 idempotencyKey 幂等。
game
| 方法 | 签名 | 说明 |
|---|---|---|
getInfo | () => Promise<GameInfo> | 首次/最近游玩与打开次数 |
start | (meta?: { level?: number; mode?: string }) => Promise<GameSession> | 开局,返回 { sessionId, startedAt } |
finish | (input: GameFinishInput) => Promise<GameFinishResult> | 结算:记录 + 统计 + 可选存档/榜单 |
record | (input: GameRecordInput) => Promise<GameRecord> | 不依赖会话直接落一条记录 |
saveProgress | <T>(data: T, options?: { merge?: boolean }) => Promise<GameProgress<T>> | 写存档,merge 为浅合并 |
loadProgress | <T>() => Promise<GameProgress<T> / null> | 读存档 |
getStats | () => Promise<GameStats> | { playCount, bestScore, totalDurationMs, lastPlayedAt } |
getRecords | (options?: { limit?: number }) => Promise<GameRecord[]> | 最近记录,倒序 |
interface GameFinishInput {
result: "complete" | "fail" | "quit";
score?: number;
level?: number;
progress?: Record<string, unknown>;
mergeProgress?: boolean; // 缺省 true
submitScore?: boolean; // 缺省 false
boardId?: string; // 缺省 "global"
}
interface GameFinishResult {
record: GameRecord;
stats: GameStats;
leaderboard: LeaderboardSnapshot | null;
}
interface GameProgress<T = Record<string, unknown>> {
gameId: string;
data: T;
revision: number;
gameVersion: string;
sdkVersion: string;
updatedAt: number;
pendingSync?: boolean; // 仅远端模式置位
}只有 submitScore: true 且 score 为非负整数时才提交榜单。存档超过 256KB 抛 PAYLOAD_TOO_LARGE。
leaderboard
| 方法 | 签名 | 说明 |
|---|---|---|
submitScore | (input: { boardId?: string; score: number; higherIsBetter?: boolean }) => Promise<LeaderboardEntry> | 只保留更优成绩 |
get | (options?: { boardId?: string; limit?: number }) => Promise<LeaderboardSnapshot> | 本机榜或全球榜 |
interface LeaderboardSnapshot {
boardId: string;
scope: "local" | "global";
localOnly: boolean;
window: "all" | "weekly";
entries: LeaderboardEntry[];
self: LeaderboardEntry | null;
total: number;
updatedAt: number;
}
interface LeaderboardEntry {
userId: string;
nickname: string;
score: number;
rank: number;
updatedAt: number;
}boardId 缺省 "global"。分数必须为非负整数,否则抛 INVALID_SCORE。SDK 当前固定请求 window: "all"。
analytics
| 方法 | 签名 | 说明 |
|---|---|---|
track | (name: string, properties?: Record<string, unknown>) => Promise<AnalyticsEvent> | 写入队列,永不抛错 |
getQueue | () => Promise<AnalyticsEvent[]> | 当前队列快照 |
flush | () => Promise<{ sent: number; pending: number }> | 远端分批上报;本地只报告 pending |
clear | () => Promise<void> | 清空队列 |
事件名长度 1~64;properties 序列化后不超过 8KB,超出被丢弃;队列上限 500 条。
ads
| 方法 | 签名 | 说明 |
|---|---|---|
showRewarded | (options: { placement: string; currency?: "coins" / "gems"; amount?: number; reason?: string }) => Promise<RewardedAdResult> | 看完后 SDK 幂等发奖 |
showInterstitial | (options?: { placement: string }) => Promise<InterstitialAdResult> | 插屏;浏览器宿主返回 shown: false |
interface RewardedAdResult {
completed: boolean;
simulated: boolean;
rewardGranted: boolean;
reward?: { currency: "coins" | "gems"; amount: number };
transactionId?: string;
}placement 缺省 "GAME_OVER"(插屏)。奖励默认 100 coins;游戏不要自行加币。
storage(游戏级 KV)
| 方法 | 签名 | 说明 |
|---|---|---|
get | <T>(key: string) => Promise<T / null> | 读取 |
set | <T>(key: string, value: T) => Promise<void> | 写入(可 JSON 化的值) |
remove | (key: string) => Promise<void> | 删除 |
keys | () => Promise<string[]> | 当前游戏的 key 列表 |
persistent | boolean | 存储是否持久(内存降级时为 false) |
key 按 gameId 隔离,不同游戏同名 key 互不影响。
模块速查
| 模块 | 方法 | 说明 |
|---|---|---|
| account | getCurrentUser() / updateProfile(patch) | 游客资料(含 accountCode / email / accountBound);同源共享 |
| account | hasEmail() | 是否已绑定邮箱;本地恒为 false |
| account | openEmailBindDialog(options?) | 邮箱绑定/换绑弹窗(中英双语,默认 60s 重发倒计时) |
| wallet | get() / getBalance(currency?) | 余额快照;默认 coins |
| wallet | reward({ amount, reason, currency?, type?, idempotencyKey? }) | 入账,返回流水 |
| wallet | spend({ amount, reason, currency?, idempotencyKey? }) | 扣款;余额不足抛 INSUFFICIENT_FUNDS |
| wallet | transactions({ limit?, currency? }) | 最近流水,倒序 |
| game | getInfo() | 游戏首次/最近游玩与打开次数 |
| game | start(meta?) / finish(input) | 会话开局与结算(记录 + 统计 + 可选存档/榜单) |
| game | record(input) | 不依赖会话直接落一条记录 |
| game | saveProgress(data, { merge? }) / loadProgress() | 存档读写,merge 为浅合并 |
| game | getStats() / getRecords({ limit? }) | 统计与最近记录 |
| leaderboard | submitScore({ boardId?, score, higherIsBetter? }) / get(...) | 只保留更优成绩;本机榜或全球榜 |
| analytics | track(name, properties?) | 写入队列,永不抛错 |
| analytics | getQueue() / flush() / clear() | 远端 flush() 批量上报,本地只报告 pending |
| ads | showRewarded({ placement, currency?, amount?, reason? }) | 完成后 SDK 幂等发奖 |
| ads | showInterstitial({ placement }) | 插屏;浏览器宿主返回 shown: false |
| storage | get/set/remove/keys + persistent | 游戏级 KV |
| 根对象 | sdkVersion / gameId / mode / host / supports(capability) / sync() | 版本、模式与宿主能力探测 |
类型索引
| 分组 | 关键类型 |
|---|---|
| 宿主与基础 | HostKind、HostCapability、Currency |
| 配置 | InstfunConfig、InstfunMode |
| 账号 | UserProfile、AccountModule、EmailBindDialogOptions、EmailBindResult |
| 钱包 | WalletTransactionType、WalletTransaction、WalletRewardInput、WalletSpendInput、WalletBalance、WalletModule |
| 游戏 | GameProgress、GameSession、GameResult、GameRecord、GameStats、GameInfo、GameFinishInput、GameFinishResult、GameModule、SyncResult |
| 榜单 | LeaderboardEntry、LeaderboardSnapshot、LeaderboardModule |
| 埋点 | AnalyticsEvent、AnalyticsModule |
| 广告 | ShowRewardedOptions、RewardedAdResult、ShowInterstitialOptions、InterstitialAdResult、AdsModule |
| 存储 | GameStorageModule |
| 聚合 | InstfunSdk |
完整 TypeScript 类型以 SDK 包内的 types 模块定义为准。