@oasiz/sdk 1.4.0 → 1.5.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.cjs CHANGED
@@ -20,32 +20,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- consume: () => consume,
24
- emitScoreConfig: () => emitScoreConfig,
23
+ enableLogOverlay: () => enableLogOverlay,
25
24
  flushGameState: () => flushGameState,
26
- getEntitlements: () => getEntitlements,
27
25
  getGameId: () => getGameId,
28
- getJemBalance: () => getJemBalance,
29
26
  getPlayerAvatar: () => getPlayerAvatar,
30
27
  getPlayerName: () => getPlayerName,
31
- getProducts: () => getProducts,
32
- getQuantity: () => getQuantity,
33
28
  getRoomCode: () => getRoomCode,
34
- hasEntitlement: () => hasEntitlement,
29
+ getSafeAreaTop: () => getSafeAreaTop,
35
30
  leaveGame: () => leaveGame,
36
31
  loadGameState: () => loadGameState,
37
32
  oasiz: () => oasiz,
38
33
  onBackButton: () => onBackButton,
39
- onEntitlementsChanged: () => onEntitlementsChanged,
40
- onJemBalanceChanged: () => onJemBalanceChanged,
41
34
  onLeaveGame: () => onLeaveGame,
42
35
  onPause: () => onPause,
43
36
  onResume: () => onResume,
44
- purchase: () => purchase,
37
+ openInviteModal: () => openInviteModal,
45
38
  saveGameState: () => saveGameState,
39
+ setLeaderboardVisible: () => setLeaderboardVisible,
46
40
  shareRoomCode: () => shareRoomCode,
47
41
  submitScore: () => submitScore,
48
- syncProducts: () => syncProducts,
49
42
  triggerHaptic: () => triggerHaptic
50
43
  });
51
44
  module.exports = __toCommonJS(index_exports);
@@ -74,6 +67,897 @@ function triggerHaptic(type) {
74
67
  }
75
68
  }
76
69
 
70
+ // src/log-overlay.ts
71
+ var CONSOLE_METHODS = [
72
+ "debug",
73
+ "log",
74
+ "info",
75
+ "warn",
76
+ "error"
77
+ ];
78
+ var DEFAULT_MAX_ENTRIES = 200;
79
+ var DEFAULT_TITLE = "SDK Logs";
80
+ var OVERLAY_MARGIN = 12;
81
+ var DEFAULT_COLLAPSED_WIDTH = 156;
82
+ var DEFAULT_COLLAPSED_HEIGHT = 52;
83
+ var DEFAULT_EXPANDED_WIDTH = 565;
84
+ var DEFAULT_EXPANDED_HEIGHT = 372;
85
+ var DRAG_THRESHOLD_PX = 6;
86
+ var MIN_EXPANDED_WIDTH = 160;
87
+ var MIN_EXPANDED_HEIGHT = 110;
88
+ var RESIZE_HOTSPOT_PX = 28;
89
+ var TOP_DRAG_ZONE_PX = 44;
90
+ var NOOP_HANDLE = {
91
+ clear() {
92
+ },
93
+ destroy() {
94
+ },
95
+ hide() {
96
+ },
97
+ isVisible() {
98
+ return false;
99
+ },
100
+ show() {
101
+ }
102
+ };
103
+ function getBrowserWindow() {
104
+ if (typeof window === "undefined") {
105
+ return void 0;
106
+ }
107
+ return window;
108
+ }
109
+ function getDocument() {
110
+ if (typeof document === "undefined") {
111
+ return void 0;
112
+ }
113
+ return document;
114
+ }
115
+ function clampMaxEntries(value) {
116
+ if (!Number.isFinite(value)) {
117
+ return DEFAULT_MAX_ENTRIES;
118
+ }
119
+ return Math.max(10, Math.floor(value));
120
+ }
121
+ function createConsoleSnapshot() {
122
+ const fallback = console.log.bind(console);
123
+ return {
124
+ debug: typeof console.debug === "function" ? console.debug.bind(console) : fallback,
125
+ log: fallback,
126
+ info: typeof console.info === "function" ? console.info.bind(console) : fallback,
127
+ warn: typeof console.warn === "function" ? console.warn.bind(console) : fallback,
128
+ error: typeof console.error === "function" ? console.error.bind(console) : fallback
129
+ };
130
+ }
131
+ function formatTimestamp(timestamp) {
132
+ const date = new Date(timestamp);
133
+ const hours = String(date.getHours()).padStart(2, "0");
134
+ const minutes = String(date.getMinutes()).padStart(2, "0");
135
+ const seconds = String(date.getSeconds()).padStart(2, "0");
136
+ const milliseconds = String(date.getMilliseconds()).padStart(3, "0");
137
+ return "[" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + "]";
138
+ }
139
+ function safeStringify(value) {
140
+ const seen = /* @__PURE__ */ new WeakSet();
141
+ try {
142
+ return JSON.stringify(
143
+ value,
144
+ (_key, candidate) => {
145
+ if (typeof candidate === "bigint") {
146
+ return candidate.toString() + "n";
147
+ }
148
+ if (typeof candidate === "object" && candidate !== null) {
149
+ if (seen.has(candidate)) {
150
+ return "[Circular]";
151
+ }
152
+ seen.add(candidate);
153
+ }
154
+ return candidate;
155
+ },
156
+ 2
157
+ ) ?? String(value);
158
+ } catch {
159
+ return String(value);
160
+ }
161
+ }
162
+ function formatArg(value) {
163
+ if (typeof value === "string") {
164
+ return value;
165
+ }
166
+ if (value instanceof Error) {
167
+ if (value.stack) {
168
+ return value.stack;
169
+ }
170
+ return value.name + ": " + value.message;
171
+ }
172
+ if (typeof value === "undefined") {
173
+ return "undefined";
174
+ }
175
+ if (typeof value === "function") {
176
+ return "[Function " + (value.name || "anonymous") + "]";
177
+ }
178
+ return safeStringify(value);
179
+ }
180
+ function formatEntryMessage(args) {
181
+ const message = args.map(formatArg).join(" ");
182
+ if (message.length <= 4e3) {
183
+ return message;
184
+ }
185
+ return message.slice(0, 3997) + "...";
186
+ }
187
+ function createEntry(level, args, id) {
188
+ return {
189
+ id,
190
+ level,
191
+ message: formatEntryMessage(args),
192
+ timestamp: Date.now()
193
+ };
194
+ }
195
+ function createButton(label) {
196
+ const button = document.createElement("button");
197
+ button.type = "button";
198
+ button.textContent = label;
199
+ button.style.cssText = [
200
+ "appearance:none",
201
+ "border:1px solid rgba(255,255,255,0.18)",
202
+ "background:rgba(255,255,255,0.06)",
203
+ "color:#f8fafc",
204
+ "border-radius:999px",
205
+ "padding:6px 10px",
206
+ "font:600 12px/1.1 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
207
+ "cursor:pointer"
208
+ ].join(";");
209
+ return button;
210
+ }
211
+ function getLevelAccent(level) {
212
+ if (level === "error") {
213
+ return {
214
+ lineBackground: "rgba(255, 109, 122, 0.08)"
215
+ };
216
+ }
217
+ if (level === "warn") {
218
+ return {
219
+ lineBackground: "rgba(255, 196, 94, 0.07)"
220
+ };
221
+ }
222
+ if (level === "info") {
223
+ return {
224
+ lineBackground: "rgba(82, 187, 255, 0.07)"
225
+ };
226
+ }
227
+ if (level === "debug") {
228
+ return {
229
+ lineBackground: "rgba(166, 137, 255, 0.07)"
230
+ };
231
+ }
232
+ return {
233
+ lineBackground: "rgba(117, 235, 191, 0.06)"
234
+ };
235
+ }
236
+ function getViewportSize() {
237
+ const browserWindow = getBrowserWindow();
238
+ return {
239
+ width: Math.max(320, browserWindow?.innerWidth ?? 1280),
240
+ height: Math.max(240, browserWindow?.innerHeight ?? 720)
241
+ };
242
+ }
243
+ function clampPanelSize(size) {
244
+ const viewport = getViewportSize();
245
+ const maxWidth = Math.max(MIN_EXPANDED_WIDTH, viewport.width - OVERLAY_MARGIN * 2);
246
+ const maxHeight = Math.max(
247
+ MIN_EXPANDED_HEIGHT,
248
+ viewport.height - OVERLAY_MARGIN * 2
249
+ );
250
+ return {
251
+ width: Math.min(maxWidth, Math.max(MIN_EXPANDED_WIDTH, size.width)),
252
+ height: Math.min(maxHeight, Math.max(MIN_EXPANDED_HEIGHT, size.height))
253
+ };
254
+ }
255
+ function getOverlaySize(state) {
256
+ if (state.expanded && state.panelSize) {
257
+ return state.panelSize;
258
+ }
259
+ const rect = state.ui?.root && typeof state.ui.root.getBoundingClientRect === "function" ? state.ui.root.getBoundingClientRect() : null;
260
+ if (rect && Number.isFinite(rect.width) && Number.isFinite(rect.height)) {
261
+ return {
262
+ width: Math.max(1, rect.width),
263
+ height: Math.max(1, rect.height)
264
+ };
265
+ }
266
+ return state.expanded ? clampPanelSize({
267
+ width: DEFAULT_EXPANDED_WIDTH,
268
+ height: DEFAULT_EXPANDED_HEIGHT
269
+ }) : { width: DEFAULT_COLLAPSED_WIDTH, height: DEFAULT_COLLAPSED_HEIGHT };
270
+ }
271
+ function applyPanelSize(state) {
272
+ if (!state.ui) {
273
+ return;
274
+ }
275
+ if (!state.expanded) {
276
+ state.ui.root.style.width = "auto";
277
+ state.ui.panel.style.width = "min(565px, calc(100vw - 24px))";
278
+ state.ui.panel.style.height = "auto";
279
+ state.ui.entries.style.maxHeight = "min(36vh, 280px)";
280
+ return;
281
+ }
282
+ if (!state.panelSize) {
283
+ state.ui.root.style.width = "min(565px, calc(100vw - 24px))";
284
+ state.ui.panel.style.width = "min(565px, calc(100vw - 24px))";
285
+ state.ui.panel.style.height = "auto";
286
+ state.ui.entries.style.maxHeight = "min(36vh, 280px)";
287
+ return;
288
+ }
289
+ const nextSize = clampPanelSize(
290
+ state.panelSize
291
+ );
292
+ state.panelSize = nextSize;
293
+ state.ui.root.style.width = nextSize.width + "px";
294
+ state.ui.panel.style.width = "100%";
295
+ state.ui.panel.style.height = nextSize.height + "px";
296
+ state.ui.entries.style.maxHeight = Math.max(72, nextSize.height - 88) + "px";
297
+ }
298
+ function clampPosition(point, state) {
299
+ const viewport = getViewportSize();
300
+ const size = getOverlaySize(state);
301
+ const maxX = Math.max(OVERLAY_MARGIN, viewport.width - size.width - OVERLAY_MARGIN);
302
+ const maxY = Math.max(
303
+ OVERLAY_MARGIN,
304
+ viewport.height - size.height - OVERLAY_MARGIN
305
+ );
306
+ return {
307
+ x: Math.min(maxX, Math.max(OVERLAY_MARGIN, point.x)),
308
+ y: Math.min(maxY, Math.max(OVERLAY_MARGIN, point.y))
309
+ };
310
+ }
311
+ function applyOverlayPosition(state) {
312
+ if (!state.ui) {
313
+ return;
314
+ }
315
+ if (!state.position) {
316
+ const viewport = getViewportSize();
317
+ const size = getOverlaySize(state);
318
+ state.position = clampPosition(
319
+ {
320
+ x: viewport.width - size.width - OVERLAY_MARGIN,
321
+ y: viewport.height - size.height - OVERLAY_MARGIN
322
+ },
323
+ state
324
+ );
325
+ } else {
326
+ state.position = clampPosition(state.position, state);
327
+ }
328
+ state.ui.root.style.left = state.position.x + "px";
329
+ state.ui.root.style.top = state.position.y + "px";
330
+ }
331
+ function getPointFromMouseEvent(event) {
332
+ return { x: event.clientX, y: event.clientY };
333
+ }
334
+ function getPointFromTouchEvent(event) {
335
+ const touch = event.touches[0] ?? event.changedTouches[0];
336
+ if (!touch) {
337
+ return null;
338
+ }
339
+ return { x: touch.clientX, y: touch.clientY };
340
+ }
341
+ function stopDragging(state) {
342
+ if (state.isDragging || state.isResizing) {
343
+ state.suppressToggleClickUntil = Date.now() + 180;
344
+ }
345
+ state.isDragging = false;
346
+ state.dragStartPoint = null;
347
+ state.lastDragPoint = null;
348
+ state.removeDragListeners?.();
349
+ state.removeDragListeners = null;
350
+ if (state.ui) {
351
+ state.ui.panel.style.cursor = "default";
352
+ state.ui.dragZone.style.cursor = "grab";
353
+ state.ui.toggleButton.style.cursor = "grab";
354
+ }
355
+ }
356
+ function stopResizing(state) {
357
+ if (state.isResizing) {
358
+ state.suppressToggleClickUntil = Date.now() + 180;
359
+ }
360
+ state.isResizing = false;
361
+ state.resizeStartPoint = null;
362
+ state.resizeStartSize = null;
363
+ state.removeResizeListeners?.();
364
+ state.removeResizeListeners = null;
365
+ }
366
+ function beginDragTracking(state, startPoint) {
367
+ const doc = getDocument();
368
+ if (!doc) {
369
+ return;
370
+ }
371
+ stopResizing(state);
372
+ stopDragging(state);
373
+ state.dragMoved = false;
374
+ state.dragStartPoint = startPoint;
375
+ state.lastDragPoint = startPoint;
376
+ const handlePointerMove = (nextPoint) => {
377
+ if (!state.dragStartPoint || !state.lastDragPoint || !nextPoint) {
378
+ return;
379
+ }
380
+ if (!state.isDragging) {
381
+ const deltaFromStartX = nextPoint.x - state.dragStartPoint.x;
382
+ const deltaFromStartY = nextPoint.y - state.dragStartPoint.y;
383
+ const distance = Math.sqrt(
384
+ deltaFromStartX * deltaFromStartX + deltaFromStartY * deltaFromStartY
385
+ );
386
+ if (distance < DRAG_THRESHOLD_PX) {
387
+ return;
388
+ }
389
+ state.isDragging = true;
390
+ state.dragMoved = true;
391
+ if (state.ui) {
392
+ state.ui.panel.style.cursor = "grabbing";
393
+ state.ui.dragZone.style.cursor = "grabbing";
394
+ state.ui.toggleButton.style.cursor = "grabbing";
395
+ }
396
+ }
397
+ const currentPosition = state.position ?? { x: OVERLAY_MARGIN, y: OVERLAY_MARGIN };
398
+ state.position = clampPosition(
399
+ {
400
+ x: currentPosition.x + (nextPoint.x - state.lastDragPoint.x),
401
+ y: currentPosition.y + (nextPoint.y - state.lastDragPoint.y)
402
+ },
403
+ state
404
+ );
405
+ state.lastDragPoint = nextPoint;
406
+ applyOverlayPosition(state);
407
+ };
408
+ const handleMouseMove = (event) => {
409
+ handlePointerMove(getPointFromMouseEvent(event));
410
+ };
411
+ const handleTouchMove = (event) => {
412
+ handlePointerMove(getPointFromTouchEvent(event));
413
+ };
414
+ const handleMouseUp = () => {
415
+ stopDragging(state);
416
+ };
417
+ const handleTouchEnd = () => {
418
+ stopDragging(state);
419
+ };
420
+ doc.addEventListener("mousemove", handleMouseMove);
421
+ doc.addEventListener("mouseup", handleMouseUp);
422
+ doc.addEventListener("touchmove", handleTouchMove, { passive: true });
423
+ doc.addEventListener("touchend", handleTouchEnd);
424
+ doc.addEventListener("touchcancel", handleTouchEnd);
425
+ state.removeDragListeners = () => {
426
+ doc.removeEventListener("mousemove", handleMouseMove);
427
+ doc.removeEventListener("mouseup", handleMouseUp);
428
+ doc.removeEventListener("touchmove", handleTouchMove);
429
+ doc.removeEventListener("touchend", handleTouchEnd);
430
+ doc.removeEventListener("touchcancel", handleTouchEnd);
431
+ };
432
+ }
433
+ function startResizing(state, startPoint) {
434
+ const doc = getDocument();
435
+ if (!doc) {
436
+ return;
437
+ }
438
+ stopDragging(state);
439
+ stopResizing(state);
440
+ state.isResizing = true;
441
+ state.resizeStartPoint = startPoint;
442
+ state.resizeStartSize = state.panelSize ?? clampPanelSize({ width: DEFAULT_EXPANDED_WIDTH, height: DEFAULT_EXPANDED_HEIGHT });
443
+ const handleResizeMove = (nextPoint) => {
444
+ if (!state.isResizing || !state.resizeStartPoint || !state.resizeStartSize || !nextPoint) {
445
+ return;
446
+ }
447
+ state.panelSize = clampPanelSize({
448
+ width: state.resizeStartSize.width + (nextPoint.x - state.resizeStartPoint.x),
449
+ height: state.resizeStartSize.height + (nextPoint.y - state.resizeStartPoint.y)
450
+ });
451
+ applyPanelSize(state);
452
+ applyOverlayPosition(state);
453
+ };
454
+ const handleMouseMove = (event) => {
455
+ handleResizeMove(getPointFromMouseEvent(event));
456
+ };
457
+ const handleTouchMove = (event) => {
458
+ handleResizeMove(getPointFromTouchEvent(event));
459
+ };
460
+ const handleFinish = () => {
461
+ stopResizing(state);
462
+ };
463
+ doc.addEventListener("mousemove", handleMouseMove);
464
+ doc.addEventListener("mouseup", handleFinish);
465
+ doc.addEventListener("touchmove", handleTouchMove, { passive: true });
466
+ doc.addEventListener("touchend", handleFinish);
467
+ doc.addEventListener("touchcancel", handleFinish);
468
+ state.removeResizeListeners = () => {
469
+ doc.removeEventListener("mousemove", handleMouseMove);
470
+ doc.removeEventListener("mouseup", handleFinish);
471
+ doc.removeEventListener("touchmove", handleTouchMove);
472
+ doc.removeEventListener("touchend", handleFinish);
473
+ doc.removeEventListener("touchcancel", handleFinish);
474
+ };
475
+ }
476
+ function isInBottomRightResizeZone(element, point) {
477
+ const rect = element.getBoundingClientRect();
478
+ return point.x >= rect.right - RESIZE_HOTSPOT_PX && point.x <= rect.right && point.y >= rect.bottom - RESIZE_HOTSPOT_PX && point.y <= rect.bottom;
479
+ }
480
+ function canStartDragFromTarget(target) {
481
+ if (!(target instanceof Element)) {
482
+ return true;
483
+ }
484
+ if (target.closest("button") || target.closest("a") || target.closest("input") || target.closest("textarea") || target.closest("select")) {
485
+ return false;
486
+ }
487
+ return true;
488
+ }
489
+ function isInTopDragZone(element, point, zoneHeight) {
490
+ const rect = element.getBoundingClientRect();
491
+ return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.top + zoneHeight;
492
+ }
493
+ function attachDragStartListeners(element, state, options = {}) {
494
+ element.addEventListener("mousedown", (event) => {
495
+ if (!options.allowInteractiveTarget && !canStartDragFromTarget(event.target)) {
496
+ return;
497
+ }
498
+ const point = getPointFromMouseEvent(event);
499
+ if (typeof options.topZoneHeight === "number" && !isInTopDragZone(element, point, options.topZoneHeight)) {
500
+ return;
501
+ }
502
+ beginDragTracking(state, point);
503
+ });
504
+ element.addEventListener("touchstart", (event) => {
505
+ if (!options.allowInteractiveTarget && !canStartDragFromTarget(event.target)) {
506
+ return;
507
+ }
508
+ const point = getPointFromTouchEvent(event);
509
+ if (!point) {
510
+ return;
511
+ }
512
+ if (typeof options.topZoneHeight === "number" && !isInTopDragZone(element, point, options.topZoneHeight)) {
513
+ return;
514
+ }
515
+ beginDragTracking(state, point);
516
+ });
517
+ }
518
+ function attachCollapsedToggleListeners(element, state) {
519
+ const startToggleInteraction = (startPoint) => {
520
+ const doc = getDocument();
521
+ if (!doc) {
522
+ return;
523
+ }
524
+ beginDragTracking(state, startPoint);
525
+ const finishInteraction = () => {
526
+ releaseListeners();
527
+ if (state.dragMoved || Date.now() < state.suppressToggleClickUntil) {
528
+ return;
529
+ }
530
+ state.expanded = true;
531
+ state.unreadCount = 0;
532
+ renderOverlay(state);
533
+ };
534
+ const releaseListeners = () => {
535
+ doc.removeEventListener("mouseup", finishInteraction);
536
+ doc.removeEventListener("touchend", finishInteraction);
537
+ doc.removeEventListener("touchcancel", finishInteraction);
538
+ };
539
+ doc.addEventListener("mouseup", finishInteraction);
540
+ doc.addEventListener("touchend", finishInteraction);
541
+ doc.addEventListener("touchcancel", finishInteraction);
542
+ };
543
+ element.addEventListener("mousedown", (event) => {
544
+ event.preventDefault();
545
+ startToggleInteraction(getPointFromMouseEvent(event));
546
+ });
547
+ element.addEventListener("touchstart", (event) => {
548
+ const point = getPointFromTouchEvent(event);
549
+ if (!point) {
550
+ return;
551
+ }
552
+ event.preventDefault();
553
+ startToggleInteraction(point);
554
+ });
555
+ }
556
+ function attachPanelResizeListeners(element, state) {
557
+ element.addEventListener("mousedown", (event) => {
558
+ if (!state.expanded || !canStartDragFromTarget(event.target)) {
559
+ return;
560
+ }
561
+ const point = getPointFromMouseEvent(event);
562
+ if (!isInBottomRightResizeZone(element, point)) {
563
+ return;
564
+ }
565
+ event.preventDefault();
566
+ event.stopPropagation();
567
+ startResizing(state, point);
568
+ });
569
+ element.addEventListener("touchstart", (event) => {
570
+ if (!state.expanded || !canStartDragFromTarget(event.target)) {
571
+ return;
572
+ }
573
+ const point = getPointFromTouchEvent(event);
574
+ if (!point || !isInBottomRightResizeZone(element, point)) {
575
+ return;
576
+ }
577
+ event.preventDefault();
578
+ event.stopPropagation();
579
+ startResizing(state, point);
580
+ });
581
+ }
582
+ function createOverlayUi(state) {
583
+ const root = document.createElement("div");
584
+ root.style.cssText = [
585
+ "position:fixed",
586
+ "left:12px",
587
+ "top:12px",
588
+ "z-index:2147483647",
589
+ "display:flex",
590
+ "flex-direction:column",
591
+ "align-items:stretch",
592
+ "gap:8px",
593
+ "width:min(565px, calc(100vw - 24px))",
594
+ "pointer-events:none"
595
+ ].join(";");
596
+ const toggleButton = createButton("Logs");
597
+ toggleButton.style.pointerEvents = "auto";
598
+ toggleButton.style.alignSelf = "flex-end";
599
+ toggleButton.style.display = "inline-flex";
600
+ toggleButton.style.alignItems = "center";
601
+ toggleButton.style.justifyContent = "center";
602
+ toggleButton.style.minHeight = "40px";
603
+ toggleButton.style.minWidth = "76px";
604
+ toggleButton.style.padding = "8px 14px";
605
+ toggleButton.style.textAlign = "center";
606
+ toggleButton.style.border = "1px solid rgba(122, 212, 255, 0.22)";
607
+ toggleButton.style.background = "linear-gradient(180deg, rgba(13,31,54,0.98), rgba(8,19,37,0.98))";
608
+ toggleButton.style.boxShadow = "0 18px 40px rgba(4,12,24,0.34)";
609
+ toggleButton.style.cursor = "grab";
610
+ toggleButton.style.touchAction = "none";
611
+ const panel = document.createElement("div");
612
+ panel.style.cssText = [
613
+ "position:relative",
614
+ "display:flex",
615
+ "flex-direction:column",
616
+ "width:min(565px, calc(100vw - 24px))",
617
+ "max-height:min(48vh, 372px)",
618
+ "border-radius:18px",
619
+ "border:1px solid rgba(116,167,255,0.16)",
620
+ "background:linear-gradient(180deg, rgba(9,19,37,0.98), rgba(5,12,24,0.98))",
621
+ "box-shadow:0 28px 64px rgba(2,8,18,0.46)",
622
+ "backdrop-filter:blur(16px)",
623
+ "overflow:hidden",
624
+ "cursor:default",
625
+ "pointer-events:auto"
626
+ ].join(";");
627
+ const dragZone = document.createElement("div");
628
+ dragZone.style.cssText = [
629
+ "position:absolute",
630
+ "top:0",
631
+ "left:0",
632
+ "right:0",
633
+ "height:" + String(TOP_DRAG_ZONE_PX) + "px",
634
+ "z-index:1",
635
+ "cursor:grab",
636
+ "background:transparent",
637
+ "pointer-events:auto"
638
+ ].join(";");
639
+ const controls = document.createElement("div");
640
+ controls.style.cssText = [
641
+ "position:absolute",
642
+ "top:22px",
643
+ "right:22px",
644
+ "z-index:2",
645
+ "display:flex",
646
+ "align-items:center",
647
+ "gap:8px",
648
+ "pointer-events:auto"
649
+ ].join(";");
650
+ const clearButton = createButton("Clear");
651
+ clearButton.style.background = "rgba(255,255,255,0.1)";
652
+ clearButton.style.border = "1px solid rgba(255,255,255,0.16)";
653
+ clearButton.style.color = "#eef6ff";
654
+ clearButton.style.minHeight = "30px";
655
+ clearButton.style.padding = "4px 9px";
656
+ clearButton.style.fontSize = "11px";
657
+ clearButton.style.backdropFilter = "blur(8px)";
658
+ const collapseButton = createButton("Hide");
659
+ collapseButton.style.background = "rgba(113, 171, 255, 0.12)";
660
+ collapseButton.style.border = "1px solid rgba(113, 171, 255, 0.2)";
661
+ collapseButton.style.color = "#d9ebff";
662
+ collapseButton.style.minHeight = "30px";
663
+ collapseButton.style.padding = "4px 9px";
664
+ collapseButton.style.fontSize = "11px";
665
+ collapseButton.style.backdropFilter = "blur(8px)";
666
+ const body = document.createElement("div");
667
+ body.style.cssText = [
668
+ "position:relative",
669
+ "display:flex",
670
+ "flex-direction:column",
671
+ "padding:12px",
672
+ "background:linear-gradient(180deg, rgba(4,10,20,0.88), rgba(3,8,18,0.98))",
673
+ "flex:1 1 auto",
674
+ "min-height:0"
675
+ ].join(";");
676
+ const entries = document.createElement("div");
677
+ entries.style.cssText = [
678
+ "display:flex",
679
+ "flex-direction:column",
680
+ "gap:0",
681
+ "overflow:auto",
682
+ "flex:1 1 auto",
683
+ "min-height:96px",
684
+ "max-height:min(36vh, 280px)",
685
+ "padding:0",
686
+ "border:1px solid rgba(115,153,212,0.14)",
687
+ "border-radius:12px",
688
+ "background:rgba(4,10,20,0.82)"
689
+ ].join(";");
690
+ const emptyState = document.createElement("div");
691
+ emptyState.style.cssText = [
692
+ "display:flex",
693
+ "align-items:center",
694
+ "justify-content:center",
695
+ "flex:1 1 auto",
696
+ "min-height:96px",
697
+ "color:rgba(204,222,250,0.6)",
698
+ "font:500 12px/1.5 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
699
+ "text-align:center",
700
+ "padding:18px"
701
+ ].join(";");
702
+ emptyState.textContent = "Console output will appear here.";
703
+ collapseButton.addEventListener("click", (event) => {
704
+ event.stopPropagation();
705
+ state.expanded = false;
706
+ renderOverlay(state);
707
+ });
708
+ clearButton.addEventListener("click", (event) => {
709
+ event.stopPropagation();
710
+ state.entries = [];
711
+ state.unreadCount = 0;
712
+ renderOverlay(state);
713
+ });
714
+ controls.appendChild(clearButton);
715
+ controls.appendChild(collapseButton);
716
+ entries.appendChild(emptyState);
717
+ body.appendChild(entries);
718
+ body.appendChild(controls);
719
+ panel.appendChild(dragZone);
720
+ panel.appendChild(body);
721
+ attachDragStartListeners(dragZone, state);
722
+ attachPanelResizeListeners(panel, state);
723
+ attachCollapsedToggleListeners(toggleButton, state);
724
+ root.appendChild(panel);
725
+ root.appendChild(toggleButton);
726
+ return {
727
+ body,
728
+ clearButton,
729
+ collapseButton,
730
+ controls,
731
+ dragZone,
732
+ emptyState,
733
+ entries,
734
+ panel,
735
+ root,
736
+ toggleButton
737
+ };
738
+ }
739
+ function renderOverlay(state) {
740
+ if (!state.ui) {
741
+ return;
742
+ }
743
+ state.ui.panel.style.display = state.expanded ? "flex" : "none";
744
+ state.ui.toggleButton.style.display = state.expanded ? "none" : "inline-flex";
745
+ state.ui.toggleButton.textContent = "Logs";
746
+ if (state.entries.length === 0) {
747
+ state.ui.entries.style.display = "flex";
748
+ state.ui.emptyState.style.display = "flex";
749
+ state.ui.entries.replaceChildren(state.ui.emptyState);
750
+ applyPanelSize(state);
751
+ applyOverlayPosition(state);
752
+ return;
753
+ }
754
+ state.ui.entries.style.display = "flex";
755
+ state.ui.emptyState.style.display = "none";
756
+ const nextChildren = state.entries.map((entry) => {
757
+ const accent = getLevelAccent(entry.level);
758
+ const row = document.createElement("div");
759
+ row.style.cssText = [
760
+ "display:flex",
761
+ "align-items:flex-start",
762
+ "gap:0",
763
+ "padding:4px 12px",
764
+ "background:" + accent.lineBackground
765
+ ].join(";");
766
+ const line = document.createElement("div");
767
+ line.textContent = formatTimestamp(entry.timestamp) + " " + entry.level.toUpperCase() + " " + entry.message;
768
+ line.style.cssText = [
769
+ "color:#ecf4ff",
770
+ "font:500 12px/1.5 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
771
+ "white-space:pre-wrap",
772
+ "word-break:break-word",
773
+ "flex:1 1 auto"
774
+ ].join(";");
775
+ row.appendChild(line);
776
+ return row;
777
+ });
778
+ state.ui.entries.replaceChildren(...nextChildren);
779
+ state.ui.entries.scrollTop = state.ui.entries.scrollHeight;
780
+ applyPanelSize(state);
781
+ applyOverlayPosition(state);
782
+ }
783
+ function mountOverlay(state) {
784
+ const doc = getDocument();
785
+ if (!doc?.body || state.ui) {
786
+ return;
787
+ }
788
+ state.ui = createOverlayUi(state);
789
+ doc.body.appendChild(state.ui.root);
790
+ applyPanelSize(state);
791
+ applyOverlayPosition(state);
792
+ renderOverlay(state);
793
+ }
794
+ function enqueueEntry(state, level, args) {
795
+ state.entries.push(createEntry(level, args, state.nextEntryId));
796
+ state.nextEntryId += 1;
797
+ if (state.entries.length > state.maxEntries) {
798
+ state.entries.splice(0, state.entries.length - state.maxEntries);
799
+ }
800
+ if (!state.expanded) {
801
+ state.unreadCount += 1;
802
+ }
803
+ renderOverlay(state);
804
+ }
805
+ function restoreConsole(snapshot) {
806
+ for (const method of CONSOLE_METHODS) {
807
+ console[method] = snapshot[method];
808
+ }
809
+ }
810
+ function patchConsole(state) {
811
+ for (const method of CONSOLE_METHODS) {
812
+ const original = state.originalConsole[method];
813
+ console[method] = (...args) => {
814
+ enqueueEntry(state, method, args);
815
+ original(...args);
816
+ };
817
+ }
818
+ }
819
+ function cleanupOverlay(browserWindow, state) {
820
+ restoreConsole(state.originalConsole);
821
+ stopResizing(state);
822
+ stopDragging(state);
823
+ if (state.domReadyHandler) {
824
+ getDocument()?.removeEventListener("DOMContentLoaded", state.domReadyHandler);
825
+ state.domReadyHandler = void 0;
826
+ }
827
+ if (state.resizeHandler && typeof browserWindow.removeEventListener === "function") {
828
+ browserWindow.removeEventListener("resize", state.resizeHandler);
829
+ state.resizeHandler = void 0;
830
+ }
831
+ state.ui?.root.remove();
832
+ state.ui = null;
833
+ delete browserWindow.__oasizLogOverlayController__;
834
+ delete browserWindow.__oasizLogOverlayState__;
835
+ }
836
+ function createController(browserWindow, state) {
837
+ return {
838
+ retain() {
839
+ state.refCount += 1;
840
+ this.ensureMounted();
841
+ },
842
+ ensureMounted() {
843
+ const doc = getDocument();
844
+ if (!doc) {
845
+ return;
846
+ }
847
+ if (doc.body) {
848
+ mountOverlay(state);
849
+ applyOverlayPosition(state);
850
+ return;
851
+ }
852
+ if (!state.domReadyHandler) {
853
+ state.domReadyHandler = () => {
854
+ mountOverlay(state);
855
+ state.domReadyHandler = void 0;
856
+ };
857
+ doc.addEventListener("DOMContentLoaded", state.domReadyHandler, {
858
+ once: true
859
+ });
860
+ }
861
+ },
862
+ clear() {
863
+ state.entries = [];
864
+ state.unreadCount = 0;
865
+ renderOverlay(state);
866
+ },
867
+ show() {
868
+ state.expanded = true;
869
+ state.unreadCount = 0;
870
+ renderOverlay(state);
871
+ },
872
+ hide() {
873
+ state.expanded = false;
874
+ renderOverlay(state);
875
+ },
876
+ isVisible() {
877
+ return state.expanded;
878
+ },
879
+ destroy() {
880
+ state.refCount = Math.max(0, state.refCount - 1);
881
+ if (state.refCount === 0) {
882
+ cleanupOverlay(browserWindow, state);
883
+ }
884
+ }
885
+ };
886
+ }
887
+ function enableLogOverlay(options = {}) {
888
+ if (options.enabled === false) {
889
+ return NOOP_HANDLE;
890
+ }
891
+ const browserWindow = getBrowserWindow();
892
+ const doc = getDocument();
893
+ if (!browserWindow || !doc) {
894
+ return NOOP_HANDLE;
895
+ }
896
+ const existingController = browserWindow.__oasizLogOverlayController__;
897
+ const existingState = browserWindow.__oasizLogOverlayState__;
898
+ if (existingController && existingState) {
899
+ existingController.retain();
900
+ if (typeof options.maxEntries === "number") {
901
+ existingState.maxEntries = clampMaxEntries(options.maxEntries);
902
+ if (existingState.entries.length > existingState.maxEntries) {
903
+ existingState.entries.splice(
904
+ 0,
905
+ existingState.entries.length - existingState.maxEntries
906
+ );
907
+ }
908
+ }
909
+ if (typeof options.collapsed === "boolean") {
910
+ existingState.expanded = !options.collapsed;
911
+ applyPanelSize(existingState);
912
+ if (existingState.expanded) {
913
+ existingState.unreadCount = 0;
914
+ }
915
+ }
916
+ if (typeof options.title === "string" && options.title.trim().length > 0) {
917
+ existingState.title = options.title.trim();
918
+ }
919
+ existingController.ensureMounted();
920
+ renderOverlay(existingState);
921
+ return existingController;
922
+ }
923
+ const state = {
924
+ dragMoved: false,
925
+ dragStartPoint: null,
926
+ entries: [],
927
+ expanded: options.collapsed !== true,
928
+ isDragging: false,
929
+ isResizing: false,
930
+ lastDragPoint: null,
931
+ maxEntries: clampMaxEntries(options.maxEntries),
932
+ nextEntryId: 1,
933
+ originalConsole: createConsoleSnapshot(),
934
+ panelSize: null,
935
+ position: null,
936
+ refCount: 1,
937
+ removeDragListeners: null,
938
+ removeResizeListeners: null,
939
+ resizeStartPoint: null,
940
+ resizeStartSize: null,
941
+ suppressToggleClickUntil: 0,
942
+ title: typeof options.title === "string" && options.title.trim().length > 0 ? options.title.trim() : DEFAULT_TITLE,
943
+ resizeHandler: void 0,
944
+ ui: null,
945
+ unreadCount: 0
946
+ };
947
+ const controller = createController(browserWindow, state);
948
+ browserWindow.__oasizLogOverlayState__ = state;
949
+ browserWindow.__oasizLogOverlayController__ = controller;
950
+ patchConsole(state);
951
+ if (typeof browserWindow.addEventListener === "function") {
952
+ state.resizeHandler = () => {
953
+ applyOverlayPosition(state);
954
+ };
955
+ browserWindow.addEventListener("resize", state.resizeHandler);
956
+ }
957
+ controller.ensureMounted();
958
+ return controller;
959
+ }
960
+
77
961
  // src/multiplayer.ts
78
962
  function isDevelopment2() {
79
963
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
@@ -85,10 +969,10 @@ function getBridgeWindow2() {
85
969
  }
86
970
  return window;
87
971
  }
88
- function shareRoomCode(roomCode) {
972
+ function shareRoomCode(roomCode, options) {
89
973
  const bridge = getBridgeWindow2();
90
974
  if (typeof bridge?.shareRoomCode === "function") {
91
- bridge.shareRoomCode(roomCode);
975
+ bridge.shareRoomCode(roomCode, options);
92
976
  return;
93
977
  }
94
978
  if (isDevelopment2()) {
@@ -97,6 +981,18 @@ function shareRoomCode(roomCode) {
97
981
  );
98
982
  }
99
983
  }
984
+ function openInviteModal() {
985
+ const bridge = getBridgeWindow2();
986
+ if (typeof bridge?.openInviteModal === "function") {
987
+ bridge.openInviteModal();
988
+ return;
989
+ }
990
+ if (isDevelopment2()) {
991
+ console.warn(
992
+ "[oasiz/sdk] openInviteModal bridge is unavailable. This is expected in local development."
993
+ );
994
+ }
995
+ }
100
996
  function getGameId() {
101
997
  const bridge = getBridgeWindow2();
102
998
  return bridge?.__GAME_ID__;
@@ -147,14 +1043,6 @@ function submitScore(score) {
147
1043
  }
148
1044
  warnMissingBridge("submitScore");
149
1045
  }
150
- function emitScoreConfig(config) {
151
- const bridge = getBridgeWindow3();
152
- if (typeof bridge?.emitScoreConfig === "function") {
153
- bridge.emitScoreConfig(config);
154
- return;
155
- }
156
- warnMissingBridge("emitScoreConfig");
157
- }
158
1046
 
159
1047
  // src/state.ts
160
1048
  function isDevelopment4() {
@@ -247,8 +1135,7 @@ function onResume(callback) {
247
1135
  return addLifecycleListener("oasiz:resume", callback);
248
1136
  }
249
1137
 
250
- // src/navigation.ts
251
- var activeBackListeners = 0;
1138
+ // src/layout.ts
252
1139
  function isDevelopment6() {
253
1140
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
254
1141
  return nodeEnv !== "production";
@@ -266,9 +1153,74 @@ function warnMissingBridge3(methodName) {
266
1153
  );
267
1154
  }
268
1155
  }
1156
+ function normalizeSafeAreaTop(value) {
1157
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1158
+ return 0;
1159
+ }
1160
+ return Math.max(0, value);
1161
+ }
1162
+ function getSafeAreaTop() {
1163
+ const bridge = getBridgeWindow5();
1164
+ if (!bridge) {
1165
+ return 0;
1166
+ }
1167
+ if (typeof bridge.getSafeAreaTop === "function") {
1168
+ return normalizeSafeAreaTop(bridge.getSafeAreaTop());
1169
+ }
1170
+ if (typeof bridge.__OASIZ_SAFE_AREA_TOP__ !== "undefined") {
1171
+ return normalizeSafeAreaTop(bridge.__OASIZ_SAFE_AREA_TOP__);
1172
+ }
1173
+ warnMissingBridge3("getSafeAreaTop");
1174
+ return 0;
1175
+ }
1176
+ function setLeaderboardVisible(visible) {
1177
+ if (typeof visible !== "boolean") {
1178
+ if (isDevelopment6()) {
1179
+ console.warn(
1180
+ "[oasiz/sdk] setLeaderboardVisible expected a boolean:",
1181
+ visible
1182
+ );
1183
+ }
1184
+ return;
1185
+ }
1186
+ const bridge = getBridgeWindow5();
1187
+ if (typeof bridge?.__oasizSetLeaderboardVisible === "function") {
1188
+ bridge.__oasizSetLeaderboardVisible(visible);
1189
+ return;
1190
+ }
1191
+ warnMissingBridge3("__oasizSetLeaderboardVisible");
1192
+ }
1193
+
1194
+ // src/navigation.ts
1195
+ var activeBackListeners = 0;
1196
+ function isDevelopment7() {
1197
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1198
+ return nodeEnv !== "production";
1199
+ }
1200
+ function getBridgeWindow6() {
1201
+ if (typeof window === "undefined") {
1202
+ return void 0;
1203
+ }
1204
+ return window;
1205
+ }
1206
+ function warnMissingBridge4(methodName) {
1207
+ if (isDevelopment7()) {
1208
+ console.warn(
1209
+ "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1210
+ );
1211
+ }
1212
+ }
1213
+ function normalizeNavigationError(error) {
1214
+ if (error instanceof Error) {
1215
+ return error;
1216
+ }
1217
+ return new Error(
1218
+ typeof error === "string" ? error : "Back button callback failed."
1219
+ );
1220
+ }
269
1221
  function addNavigationListener(eventName, callback) {
270
1222
  if (typeof window === "undefined") {
271
- if (isDevelopment6()) {
1223
+ if (isDevelopment7()) {
272
1224
  console.warn(
273
1225
  "[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
274
1226
  );
@@ -281,25 +1233,32 @@ function addNavigationListener(eventName, callback) {
281
1233
  return () => window.removeEventListener(eventName, handler);
282
1234
  }
283
1235
  function onBackButton(callback) {
284
- const off = addNavigationListener("oasiz:back", callback);
285
- const bridge = getBridgeWindow5();
1236
+ const off = addNavigationListener("oasiz:back", () => {
1237
+ try {
1238
+ callback();
1239
+ } catch (error) {
1240
+ leaveGame();
1241
+ throw normalizeNavigationError(error);
1242
+ }
1243
+ });
1244
+ const bridge = getBridgeWindow6();
286
1245
  activeBackListeners += 1;
287
1246
  if (activeBackListeners === 1) {
288
1247
  if (typeof bridge?.__oasizSetBackOverride === "function") {
289
1248
  bridge.__oasizSetBackOverride(true);
290
1249
  } else {
291
- warnMissingBridge3("__oasizSetBackOverride");
1250
+ warnMissingBridge4("__oasizSetBackOverride");
292
1251
  }
293
1252
  }
294
1253
  return () => {
295
1254
  off();
296
1255
  activeBackListeners = Math.max(0, activeBackListeners - 1);
297
1256
  if (activeBackListeners === 0) {
298
- const currentBridge = getBridgeWindow5();
1257
+ const currentBridge = getBridgeWindow6();
299
1258
  if (typeof currentBridge?.__oasizSetBackOverride === "function") {
300
1259
  currentBridge.__oasizSetBackOverride(false);
301
1260
  } else {
302
- warnMissingBridge3("__oasizSetBackOverride");
1261
+ warnMissingBridge4("__oasizSetBackOverride");
303
1262
  }
304
1263
  }
305
1264
  };
@@ -308,135 +1267,31 @@ function onLeaveGame(callback) {
308
1267
  return addNavigationListener("oasiz:leave", callback);
309
1268
  }
310
1269
  function leaveGame() {
311
- const bridge = getBridgeWindow5();
1270
+ const bridge = getBridgeWindow6();
312
1271
  if (typeof bridge?.__oasizLeaveGame === "function") {
313
1272
  bridge.__oasizLeaveGame();
314
1273
  return;
315
1274
  }
316
- warnMissingBridge3("__oasizLeaveGame");
317
- }
318
-
319
- // src/store.ts
320
- function isDevelopment7() {
321
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
322
- return nodeEnv !== "production";
323
- }
324
- function getBridgeWindow6() {
325
- if (typeof window === "undefined") {
326
- return void 0;
327
- }
328
- return window;
329
- }
330
- function warnMissingBridge4(methodName) {
331
- if (isDevelopment7()) {
332
- console.warn(
333
- "[oasiz/sdk] " + methodName + " store bridge is unavailable. This is expected in local development."
334
- );
335
- }
336
- }
337
- async function requestStoreBridge(action, payload) {
338
- const bridge = getBridgeWindow6();
339
- if (typeof bridge?.__oasizStoreBridgeRequest !== "function") {
340
- warnMissingBridge4(action);
341
- throw new Error("Store bridge unavailable");
342
- }
343
- return await bridge.__oasizStoreBridgeRequest({
344
- action,
345
- payload
346
- });
347
- }
348
- async function getFreshState() {
349
- return await requestStoreBridge("getStoreState");
350
- }
351
- function subscribeToStoreEvent(eventName, callback) {
352
- if (typeof window === "undefined") {
353
- return () => {
354
- };
355
- }
356
- const handler = (event) => {
357
- const customEvent = event;
358
- callback(customEvent.detail);
359
- };
360
- window.addEventListener(eventName, handler);
361
- return () => {
362
- window.removeEventListener(eventName, handler);
363
- };
364
- }
365
- async function syncProducts(products, expectedVersion) {
366
- return await requestStoreBridge("syncProducts", {
367
- expectedVersion: expectedVersion ?? null,
368
- products
369
- });
370
- }
371
- async function getProducts() {
372
- const state = await getFreshState();
373
- return state.products;
374
- }
375
- async function getEntitlements() {
376
- const state = await getFreshState();
377
- return state.entitlements;
378
- }
379
- async function hasEntitlement(productId) {
380
- const state = await getFreshState();
381
- return state.entitlements.find((item) => item.productId === productId)?.owned === true;
382
- }
383
- async function getQuantity(productId) {
384
- const state = await getFreshState();
385
- return state.entitlements.find((item) => item.productId === productId)?.quantity ?? 0;
386
- }
387
- async function purchase(productId, quantity = 1) {
388
- return await requestStoreBridge("purchaseProduct", {
389
- productId,
390
- quantity
391
- });
392
- }
393
- async function consume(productId, quantity = 1) {
394
- return await requestStoreBridge("consumeProduct", {
395
- productId,
396
- quantity
397
- });
398
- }
399
- async function getJemBalance() {
400
- const state = await getFreshState();
401
- return state.jemBalance;
402
- }
403
- function onEntitlementsChanged(callback) {
404
- return subscribeToStoreEvent("oasiz:entitlements-changed", (state) => {
405
- callback(state.entitlements);
406
- });
407
- }
408
- function onJemBalanceChanged(callback) {
409
- return subscribeToStoreEvent("oasiz:jem-balance-changed", (state) => {
410
- callback(state.jemBalance);
411
- });
1275
+ warnMissingBridge4("__oasizLeaveGame");
412
1276
  }
413
1277
 
414
1278
  // src/index.ts
415
1279
  var oasiz = {
416
1280
  submitScore,
417
- emitScoreConfig,
418
1281
  triggerHaptic,
1282
+ enableLogOverlay,
419
1283
  loadGameState,
420
1284
  saveGameState,
421
1285
  flushGameState,
422
1286
  shareRoomCode,
1287
+ openInviteModal,
423
1288
  onPause,
424
1289
  onResume,
1290
+ getSafeAreaTop,
1291
+ setLeaderboardVisible,
425
1292
  onBackButton,
426
1293
  onLeaveGame,
427
1294
  leaveGame,
428
- store: {
429
- syncProducts,
430
- getProducts,
431
- getEntitlements,
432
- hasEntitlement,
433
- getQuantity,
434
- purchase,
435
- consume,
436
- getJemBalance,
437
- onEntitlementsChanged,
438
- onJemBalanceChanged
439
- },
440
1295
  get gameId() {
441
1296
  return getGameId();
442
1297
  },
@@ -448,35 +1303,31 @@ var oasiz = {
448
1303
  },
449
1304
  get playerAvatar() {
450
1305
  return getPlayerAvatar();
1306
+ },
1307
+ get safeAreaTop() {
1308
+ return getSafeAreaTop();
451
1309
  }
452
1310
  };
453
1311
  // Annotate the CommonJS export names for ESM import in node:
454
1312
  0 && (module.exports = {
455
- consume,
456
- emitScoreConfig,
1313
+ enableLogOverlay,
457
1314
  flushGameState,
458
- getEntitlements,
459
1315
  getGameId,
460
- getJemBalance,
461
1316
  getPlayerAvatar,
462
1317
  getPlayerName,
463
- getProducts,
464
- getQuantity,
465
1318
  getRoomCode,
466
- hasEntitlement,
1319
+ getSafeAreaTop,
467
1320
  leaveGame,
468
1321
  loadGameState,
469
1322
  oasiz,
470
1323
  onBackButton,
471
- onEntitlementsChanged,
472
- onJemBalanceChanged,
473
1324
  onLeaveGame,
474
1325
  onPause,
475
1326
  onResume,
476
- purchase,
1327
+ openInviteModal,
477
1328
  saveGameState,
1329
+ setLeaderboardVisible,
478
1330
  shareRoomCode,
479
1331
  submitScore,
480
- syncProducts,
481
1332
  triggerHaptic
482
1333
  });