@oasiz/sdk 1.6.0 → 1.6.1

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/dist/index.d.cts CHANGED
@@ -1,10 +1,66 @@
1
+ type GraphicsPerformanceTier = "minimal" | "low" | "medium" | "high";
2
+ interface GraphicsPerformanceMetric {
3
+ /** Recommended graphics/rendering frame-rate target for the current device. */
4
+ fps: number;
5
+ /** Suggested graphics/rendering tier for the current device. */
6
+ tier: GraphicsPerformanceTier;
7
+ }
8
+ /**
9
+ * Return the current device's recommended graphics performance profile.
10
+ *
11
+ * Hosts can provide an FPS/tier recommendation through
12
+ * `window.getGraphicsPerformance()` or `window.__OASIZ_GRAPHICS_PERFORMANCE__`.
13
+ * When no host value exists, the SDK estimates from browser/device/WebGL
14
+ * capability signals so games still get a usable recommendation in local
15
+ * development and unsupported hosts.
16
+ */
17
+ declare function getGraphicsPerformance(): GraphicsPerformanceMetric;
18
+
19
+ type ViewportInsetSide = "top" | "right" | "bottom" | "left";
20
+ interface ViewportInsetEdges {
21
+ top: number;
22
+ right: number;
23
+ bottom: number;
24
+ left: number;
25
+ }
26
+ interface ViewportInsets {
27
+ pixels: ViewportInsetEdges;
28
+ percent: ViewportInsetEdges;
29
+ }
30
+ /**
31
+ * Effective viewport insets that game UI should avoid.
32
+ *
33
+ * `top` preserves the existing Oasiz game-safe top behavior: host chrome and
34
+ * invite/leaderboard clearance can contribute to it. Other sides are device
35
+ * safe-area insets today, and can include future host UI obstructions.
36
+ */
37
+ declare function getViewportInsets(): ViewportInsets;
38
+ /**
39
+ * Legacy alias for the top entry of `getViewportInsets().percent`.
40
+ */
41
+ declare function getSafeAreaTop(): number;
42
+ declare function setLeaderboardVisible(visible: boolean): void;
43
+
1
44
  type HapticType = "light" | "medium" | "heavy" | "success" | "error";
2
- interface ScoreAnchor {
3
- raw: number;
4
- normalized: 100 | 300 | 600 | 950;
45
+ type LogOverlayLevel = "debug" | "log" | "info" | "warn" | "error";
46
+ interface LogOverlayEntry {
47
+ id: number;
48
+ level: LogOverlayLevel;
49
+ message: string;
50
+ timestamp: number;
5
51
  }
6
- interface ScoreConfig {
7
- anchors: [ScoreAnchor, ScoreAnchor, ScoreAnchor, ScoreAnchor];
52
+ interface LogOverlayOptions {
53
+ collapsed?: boolean;
54
+ enabled?: boolean;
55
+ maxEntries?: number;
56
+ title?: string;
57
+ }
58
+ interface LogOverlayHandle {
59
+ clear: () => void;
60
+ destroy: () => void;
61
+ hide: () => void;
62
+ isVisible: () => boolean;
63
+ show: () => void;
8
64
  }
9
65
  type GameState = Record<string, unknown>;
10
66
  interface ShareRequest {
@@ -12,88 +68,166 @@ interface ShareRequest {
12
68
  score?: number;
13
69
  text?: string;
14
70
  }
15
- type StoreProductType = "non-consumable" | "consumable";
16
- type StoreProductStatus = "active" | "disabled" | "archived";
17
- type StoreEntitlementStatus = "active" | "consumed" | "revoked" | "refunded";
18
- interface StoreManifestProduct {
19
- description?: string | null;
20
- jemPrice: number;
21
- metadata?: Record<string, unknown>;
22
- productId: string;
23
- title: string;
24
- type: StoreProductType;
25
- }
26
- interface StoreProduct {
27
- description: string | null;
28
- gameId: string;
29
- jemPrice: number;
30
- metadata: Record<string, unknown>;
31
- productId: string;
32
- status: StoreProductStatus;
33
- title: string;
34
- type: StoreProductType;
35
- version: number;
36
- }
37
- interface StoreEntitlement {
38
- gameId: string;
39
- grantedAt: string | null;
40
- lastEventId: string | null;
41
- owned: boolean;
42
- productId: string;
43
- quantity: number;
44
- status: StoreEntitlementStatus;
45
- updatedAt: string;
46
- }
47
- interface StoreStateSnapshot {
48
- catalogVersion: number;
49
- entitlements: StoreEntitlement[];
50
- gameId: string;
51
- jemBalance: number;
52
- products: StoreProduct[];
53
- }
54
- interface StorePurchaseSuccess {
55
- attemptId: string;
56
- entitlement: StoreEntitlement;
57
- jemBalance: number;
58
- ok: true;
59
- state: StoreStateSnapshot;
60
- transactionId: string;
61
- }
62
- interface StorePurchaseFailure {
63
- attemptId: string;
64
- code: "ALREADY_OWNED" | "INSUFFICIENT_JEMS" | "INVALID_PRODUCT" | "PRODUCT_DISABLED" | "INVALID_QUANTITY" | "ENTITLEMENT_EXHAUSTED" | "STALE_CATALOG_VERSION" | "UNAUTHORIZED";
65
- jemBalance: number;
66
- message: string;
67
- ok: false;
68
- state?: StoreStateSnapshot;
69
- topUpIntentId?: string;
70
- topUpRedirectUrl?: string;
71
- }
72
- type StorePurchaseResult = StorePurchaseSuccess | StorePurchaseFailure;
73
- interface StoreConsumeSuccess {
74
- entitlement: StoreEntitlement;
75
- ok: true;
76
- state: StoreStateSnapshot;
77
- }
78
- interface StoreConsumeFailure {
79
- code: "INVALID_PRODUCT" | "INVALID_QUANTITY" | "NOT_CONSUMABLE" | "ENTITLEMENT_EXHAUSTED";
80
- jemBalance: number;
81
- message: string;
82
- ok: false;
83
- state?: StoreStateSnapshot;
71
+ /**
72
+ * One frame in a texture atlas. Coordinates are in pixels, top-left origin
73
+ * (matches HTML canvas / WebGL texture coordinates after Y-flip).
74
+ */
75
+ interface TextureAtlasFrame {
76
+ name: string;
77
+ x: number;
78
+ y: number;
79
+ width: number;
80
+ height: number;
81
+ }
82
+ /**
83
+ * Per-direction frame indexes inside an animation. `left` is either an
84
+ * integer index or the literal string `"mirror"`, indicating the renderer
85
+ * should mirror the right-facing frame instead of using a dedicated one.
86
+ */
87
+ interface FacingFrameMap {
88
+ front: number;
89
+ back: number;
90
+ right: number;
91
+ left: number | "mirror";
92
+ }
93
+ /**
94
+ * One named animation in a texture atlas. `frames` is the playback-ordered
95
+ * list of frame names; resolve each name against the parent atlas's
96
+ * `frames` array to get pixel coordinates.
97
+ */
98
+ interface TextureAtlasAnimation {
99
+ animationId: string;
100
+ role: string | null;
101
+ group: string | null;
102
+ direction: string | null;
103
+ frameRate: number;
104
+ frames: string[];
105
+ facingFrameMap: FacingFrameMap | null;
106
+ }
107
+ /**
108
+ * TexturePacker / Phaser-style texture atlas describing a baked sprite
109
+ * image. Drop-in compatible with Phaser via `addAtlas(key, img, atlas)`
110
+ * after a tiny shape transform; usable directly in custom GL renderers.
111
+ */
112
+ interface TextureAtlas {
113
+ imageUrl: string;
114
+ imageWidth: number;
115
+ imageHeight: number;
116
+ frames: TextureAtlasFrame[];
117
+ animations: TextureAtlasAnimation[];
118
+ }
119
+ /**
120
+ * The authenticated player's character, returned by `getPlayerCharacter()`.
121
+ * `editorTextureAtlas` is the higher-detail variant intended for character
122
+ * previews / customizer UI and may be `null`.
123
+ */
124
+ interface PlayerCharacter {
125
+ characterName: string | null;
126
+ baseCharacterId: string;
127
+ compositionCode: string;
128
+ textureAtlas: TextureAtlas;
129
+ editorTextureAtlas: TextureAtlas | null;
130
+ }
131
+ /**
132
+ * Result of `addScore(delta)` / `setScore(score)`. Returns `null` when the
133
+ * host bridge is unavailable (e.g. local development) or when the backend
134
+ * refused the request; production code should treat `null` as "no change
135
+ * was persisted, do not update local UI".
136
+ */
137
+ interface ScoreEditResult {
138
+ playerId: string;
139
+ previousScore: number;
140
+ newScore: number;
141
+ previousWeeklyScore: number;
142
+ newWeeklyScore: number;
143
+ normalizedScore: number | null;
84
144
  }
85
- type StoreConsumeResult = StoreConsumeSuccess | StoreConsumeFailure;
145
+
146
+ /**
147
+ * Fetch the authenticated player's character, including a TexturePacker /
148
+ * Phaser-style texture atlas describing the baked sprite image.
149
+ *
150
+ * Returns:
151
+ * - `null` when the user has no character composition yet, OR
152
+ * - `null` when the host bridge is unavailable (local dev / unauthenticated)
153
+ *
154
+ * The host transparently caches and proxies to `GET /api/sdk/me/character`,
155
+ * so calling this multiple times in a session is cheap. The returned
156
+ * `imageUrl` is content-addressed (R2 key derives from the composition
157
+ * hash), so games can safely cache the downloaded texture by `compositionCode`.
158
+ *
159
+ * Example (Phaser):
160
+ *
161
+ * const character = await oasiz.getPlayerCharacter();
162
+ * if (!character) return;
163
+ * const atlas = character.textureAtlas;
164
+ * scene.load.image("player-tex", atlas.imageUrl);
165
+ * scene.load.atlas("player", atlas.imageUrl, {
166
+ * frames: Object.fromEntries(
167
+ * atlas.frames.map((f) => [f.name, { frame: { x: f.x, y: f.y, w: f.width, h: f.height } }]),
168
+ * ),
169
+ * });
170
+ */
171
+ declare function getPlayerCharacter(): Promise<PlayerCharacter | null>;
86
172
 
87
173
  declare function triggerHaptic(type: HapticType): void;
88
174
 
89
- declare function shareRoomCode(roomCode: string | null): void;
175
+ declare function enableLogOverlay(options?: LogOverlayOptions): LogOverlayHandle;
176
+
177
+ interface ShareRoomCodeOptions {
178
+ inviteOverride?: boolean;
179
+ }
180
+ /**
181
+ * Notify the platform of the active multiplayer room so friends can join.
182
+ * Pass `{ inviteOverride: true }` when the game wants to hide the platform
183
+ * invite pill and own the invite UI itself.
184
+ */
185
+ declare function shareRoomCode(roomCode: string | null, options?: ShareRoomCodeOptions): void;
186
+ /**
187
+ * Ask the platform to open the invite-friends modal for the current game room.
188
+ * Only has effect when the platform has a room code (game has called shareRoomCode).
189
+ * No-op when the bridge is unavailable (e.g. local development).
190
+ */
191
+ declare function openInviteModal(): void;
90
192
  declare function getGameId(): string | undefined;
91
193
  declare function getRoomCode(): string | undefined;
194
+ /**
195
+ * Stable, unique, opaque identifier for the authenticated player, injected
196
+ * by the platform. Safe to use as a primary key for save slots, matchmaking,
197
+ * per-player analytics, or anywhere you need a reliable per-user key —
198
+ * unlike `getPlayerName()` (mutable, not unique).
199
+ *
200
+ * Mirrors the backend's `playerId` field returned by `GET /api/sdk/me`
201
+ * (= the Better Auth `user.id`). Returns `undefined` when the platform
202
+ * has not injected an identity (e.g. unauthenticated preview).
203
+ */
204
+ declare function getPlayerId(): string | undefined;
92
205
  declare function getPlayerName(): string | undefined;
93
206
  declare function getPlayerAvatar(): string | undefined;
94
207
 
95
208
  declare function submitScore(score: number): void;
96
- declare function emitScoreConfig(config: ScoreConfig): void;
209
+
210
+ /**
211
+ * Add (or subtract) `delta` from the player's current score for this game.
212
+ * The new score is clamped to >= 0 server-side.
213
+ *
214
+ * Unlike `submitScore()` (which is high-water and only ever raises the
215
+ * score), this endpoint always overwrites the row. Use it for game models
216
+ * where the leaderboard tracks an accumulator, balance, or persistent state
217
+ * instead of a single best-run value.
218
+ *
219
+ * Returns the resulting score values, or `null` when the bridge is
220
+ * unavailable. The integer must be a non-zero integer (positive or negative).
221
+ */
222
+ declare function addScore(delta: number): Promise<ScoreEditResult | null>;
223
+ /**
224
+ * Force the player's score to an absolute value (clamped to >= 0).
225
+ *
226
+ * Same overwrite semantics as `addScore`. Use when the game has computed
227
+ * the authoritative score locally (e.g. after offline play) and wants to
228
+ * sync it back to the leaderboard.
229
+ */
230
+ declare function setScore(score: number): Promise<ScoreEditResult | null>;
97
231
 
98
232
  declare function share(options: ShareRequest): Promise<void>;
99
233
 
@@ -105,51 +239,63 @@ type Unsubscribe = () => void;
105
239
  declare function onPause(callback: () => void): Unsubscribe;
106
240
  declare function onResume(callback: () => void): Unsubscribe;
107
241
 
242
+ interface BackButtonTestingOptions {
243
+ /**
244
+ * When true, pressing Escape dispatches the same event the host app sends for
245
+ * back actions. Defaults to true.
246
+ */
247
+ keyboard?: boolean;
248
+ /**
249
+ * When true, the SDK traps one browser-history entry while back override is
250
+ * active, so the browser Back button can be used for local testing. Defaults
251
+ * to true.
252
+ */
253
+ browserHistory?: boolean;
254
+ /** Log setup details to the console. Defaults to false. */
255
+ log?: boolean;
256
+ }
257
+ interface BackButtonTestingHandle {
258
+ destroy: () => void;
259
+ isBackOverrideActive: () => boolean;
260
+ triggerBack: () => void;
261
+ triggerLeave: () => void;
262
+ }
263
+ declare function enableBackButtonTesting(options?: BackButtonTestingOptions): BackButtonTestingHandle;
108
264
  declare function onBackButton(callback: () => void): Unsubscribe;
109
265
  declare function onLeaveGame(callback: () => void): Unsubscribe;
110
266
  declare function leaveGame(): void;
111
267
 
112
- declare function syncProducts(products: StoreManifestProduct[], expectedVersion?: number | null): Promise<StoreStateSnapshot>;
113
- declare function getProducts(): Promise<StoreProduct[]>;
114
- declare function getEntitlements(): Promise<StoreEntitlement[]>;
115
- declare function hasEntitlement(productId: string): Promise<boolean>;
116
- declare function getQuantity(productId: string): Promise<number>;
117
- declare function purchase(productId: string, quantity?: number): Promise<StorePurchaseResult>;
118
- declare function consume(productId: string, quantity?: number): Promise<StoreConsumeResult>;
119
- declare function getJemBalance(): Promise<number>;
120
- declare function onEntitlementsChanged(callback: (entitlements: StoreEntitlement[]) => void): () => void;
121
- declare function onJemBalanceChanged(callback: (jemBalance: number) => void): () => void;
122
-
123
268
  declare const oasiz: {
124
269
  submitScore: typeof submitScore;
125
- emitScoreConfig: typeof emitScoreConfig;
270
+ addScore: typeof addScore;
271
+ setScore: typeof setScore;
272
+ getPlayerCharacter: typeof getPlayerCharacter;
126
273
  share: typeof share;
127
274
  triggerHaptic: typeof triggerHaptic;
275
+ enableLogOverlay: typeof enableLogOverlay;
128
276
  loadGameState: typeof loadGameState;
129
277
  saveGameState: typeof saveGameState;
130
278
  flushGameState: typeof flushGameState;
131
279
  shareRoomCode: typeof shareRoomCode;
280
+ openInviteModal: typeof openInviteModal;
132
281
  onPause: typeof onPause;
133
282
  onResume: typeof onResume;
283
+ getSafeAreaTop: typeof getSafeAreaTop;
284
+ getViewportInsets: typeof getViewportInsets;
285
+ setLeaderboardVisible: typeof setLeaderboardVisible;
286
+ getGraphicsPerformance: typeof getGraphicsPerformance;
287
+ enableBackButtonTesting: typeof enableBackButtonTesting;
134
288
  onBackButton: typeof onBackButton;
135
289
  onLeaveGame: typeof onLeaveGame;
136
290
  leaveGame: typeof leaveGame;
137
- store: {
138
- syncProducts: typeof syncProducts;
139
- getProducts: typeof getProducts;
140
- getEntitlements: typeof getEntitlements;
141
- hasEntitlement: typeof hasEntitlement;
142
- getQuantity: typeof getQuantity;
143
- purchase: typeof purchase;
144
- consume: typeof consume;
145
- getJemBalance: typeof getJemBalance;
146
- onEntitlementsChanged: typeof onEntitlementsChanged;
147
- onJemBalanceChanged: typeof onJemBalanceChanged;
148
- };
149
291
  readonly gameId: string | undefined;
150
292
  readonly roomCode: string | undefined;
293
+ readonly playerId: string | undefined;
151
294
  readonly playerName: string | undefined;
152
295
  readonly playerAvatar: string | undefined;
296
+ readonly safeAreaTop: number;
297
+ readonly viewportInsets: ViewportInsets;
298
+ readonly graphicsPerformance: GraphicsPerformanceMetric;
153
299
  };
154
300
 
155
- export { type GameState, type HapticType, type ScoreAnchor, type ScoreConfig, type ShareRequest, type StoreConsumeFailure, type StoreConsumeResult, type StoreConsumeSuccess, type StoreEntitlement, type StoreEntitlementStatus, type StoreManifestProduct, type StoreProduct, type StoreProductStatus, type StoreProductType, type StorePurchaseFailure, type StorePurchaseResult, type StorePurchaseSuccess, type StoreStateSnapshot, type Unsubscribe, consume, emitScoreConfig, flushGameState, getEntitlements, getGameId, getJemBalance, getPlayerAvatar, getPlayerName, getProducts, getQuantity, getRoomCode, hasEntitlement, leaveGame, loadGameState, oasiz, onBackButton, onEntitlementsChanged, onJemBalanceChanged, onLeaveGame, onPause, onResume, purchase, saveGameState, share, shareRoomCode, submitScore, syncProducts, triggerHaptic };
301
+ export { type BackButtonTestingHandle, type BackButtonTestingOptions, type FacingFrameMap, type GameState, type GraphicsPerformanceMetric, type GraphicsPerformanceTier, type HapticType, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type PlayerCharacter, type ScoreEditResult, type ShareRequest, type ShareRoomCodeOptions, type TextureAtlas, type TextureAtlasAnimation, type TextureAtlasFrame, type Unsubscribe, type ViewportInsetEdges, type ViewportInsetSide, type ViewportInsets, addScore, enableBackButtonTesting, enableLogOverlay, flushGameState, getGameId, getGraphicsPerformance, getPlayerAvatar, getPlayerCharacter, getPlayerId, getPlayerName, getRoomCode, getSafeAreaTop, getViewportInsets, leaveGame, loadGameState, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, setScore, share, shareRoomCode, submitScore, triggerHaptic };