@oasiz/sdk 1.5.5 → 1.6.0

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,35 +20,38 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- addScore: () => addScore,
24
- enableLogOverlay: () => enableLogOverlay,
23
+ consume: () => consume,
24
+ emitScoreConfig: () => emitScoreConfig,
25
25
  flushGameState: () => flushGameState,
26
+ getEntitlements: () => getEntitlements,
26
27
  getGameId: () => getGameId,
28
+ getJemBalance: () => getJemBalance,
27
29
  getPlayerAvatar: () => getPlayerAvatar,
28
- getPlayerCharacter: () => getPlayerCharacter,
29
- getPlayerId: () => getPlayerId,
30
30
  getPlayerName: () => getPlayerName,
31
+ getProducts: () => getProducts,
32
+ getQuantity: () => getQuantity,
31
33
  getRoomCode: () => getRoomCode,
32
- getSafeAreaTop: () => getSafeAreaTop,
34
+ hasEntitlement: () => hasEntitlement,
33
35
  leaveGame: () => leaveGame,
34
36
  loadGameState: () => loadGameState,
35
37
  oasiz: () => oasiz,
36
38
  onBackButton: () => onBackButton,
39
+ onEntitlementsChanged: () => onEntitlementsChanged,
40
+ onJemBalanceChanged: () => onJemBalanceChanged,
37
41
  onLeaveGame: () => onLeaveGame,
38
42
  onPause: () => onPause,
39
43
  onResume: () => onResume,
40
- openInviteModal: () => openInviteModal,
44
+ purchase: () => purchase,
41
45
  saveGameState: () => saveGameState,
42
- setLeaderboardVisible: () => setLeaderboardVisible,
43
- setScore: () => setScore,
44
46
  share: () => share,
45
47
  shareRoomCode: () => shareRoomCode,
46
48
  submitScore: () => submitScore,
49
+ syncProducts: () => syncProducts,
47
50
  triggerHaptic: () => triggerHaptic
48
51
  });
49
52
  module.exports = __toCommonJS(index_exports);
50
53
 
51
- // src/character.ts
54
+ // src/haptics.ts
52
55
  function isDevelopment() {
53
56
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
54
57
  return nodeEnv !== "production";
@@ -59,1014 +62,72 @@ function getBridgeWindow() {
59
62
  }
60
63
  return window;
61
64
  }
62
- function warnMissingBridge(methodName) {
63
- if (isDevelopment()) {
64
- console.warn(
65
- "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
66
- );
67
- }
68
- }
69
- async function getPlayerCharacter() {
70
- const bridge = getBridgeWindow();
71
- if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
72
- warnMissingBridge("getPlayerCharacter");
73
- return null;
74
- }
75
- try {
76
- const result = await bridge.__oasizGetPlayerCharacter();
77
- return result ?? null;
78
- } catch (error) {
79
- if (isDevelopment()) {
80
- console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
81
- }
82
- return null;
83
- }
84
- }
85
-
86
- // src/haptics.ts
87
- function isDevelopment2() {
88
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
89
- return nodeEnv !== "production";
90
- }
91
- function getBridgeWindow2() {
92
- if (typeof window === "undefined") {
93
- return void 0;
94
- }
95
- return window;
96
- }
97
65
  function triggerHaptic(type) {
98
- const bridge = getBridgeWindow2();
66
+ const bridge = getBridgeWindow();
99
67
  if (typeof bridge?.triggerHaptic === "function") {
100
68
  bridge.triggerHaptic(type);
101
69
  return;
102
70
  }
103
- if (isDevelopment2()) {
71
+ if (isDevelopment()) {
104
72
  console.warn(
105
73
  "[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
106
74
  );
107
75
  }
108
76
  }
109
77
 
110
- // src/log-overlay.ts
111
- var CONSOLE_METHODS = [
112
- "debug",
113
- "log",
114
- "info",
115
- "warn",
116
- "error"
117
- ];
118
- var DEFAULT_MAX_ENTRIES = 200;
119
- var DEFAULT_TITLE = "SDK Logs";
120
- var OVERLAY_MARGIN = 12;
121
- var DEFAULT_COLLAPSED_WIDTH = 156;
122
- var DEFAULT_COLLAPSED_HEIGHT = 52;
123
- var DEFAULT_EXPANDED_WIDTH = 565;
124
- var DEFAULT_EXPANDED_HEIGHT = 372;
125
- var DRAG_THRESHOLD_PX = 6;
126
- var MIN_EXPANDED_WIDTH = 160;
127
- var MIN_EXPANDED_HEIGHT = 110;
128
- var RESIZE_HOTSPOT_PX = 28;
129
- var TOP_DRAG_ZONE_PX = 44;
130
- var NOOP_HANDLE = {
131
- clear() {
132
- },
133
- destroy() {
134
- },
135
- hide() {
136
- },
137
- isVisible() {
138
- return false;
139
- },
140
- show() {
141
- }
142
- };
143
- function getBrowserWindow() {
144
- if (typeof window === "undefined") {
145
- return void 0;
146
- }
147
- return window;
148
- }
149
- function getDocument() {
150
- if (typeof document === "undefined") {
151
- return void 0;
152
- }
153
- return document;
154
- }
155
- function clampMaxEntries(value) {
156
- if (!Number.isFinite(value)) {
157
- return DEFAULT_MAX_ENTRIES;
158
- }
159
- return Math.max(10, Math.floor(value));
160
- }
161
- function createConsoleSnapshot() {
162
- const fallback = console.log.bind(console);
163
- return {
164
- debug: typeof console.debug === "function" ? console.debug.bind(console) : fallback,
165
- log: fallback,
166
- info: typeof console.info === "function" ? console.info.bind(console) : fallback,
167
- warn: typeof console.warn === "function" ? console.warn.bind(console) : fallback,
168
- error: typeof console.error === "function" ? console.error.bind(console) : fallback
169
- };
170
- }
171
- function formatTimestamp(timestamp) {
172
- const date = new Date(timestamp);
173
- const hours = String(date.getHours()).padStart(2, "0");
174
- const minutes = String(date.getMinutes()).padStart(2, "0");
175
- const seconds = String(date.getSeconds()).padStart(2, "0");
176
- const milliseconds = String(date.getMilliseconds()).padStart(3, "0");
177
- return "[" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + "]";
178
- }
179
- function safeStringify(value) {
180
- const seen = /* @__PURE__ */ new WeakSet();
181
- try {
182
- return JSON.stringify(
183
- value,
184
- (_key, candidate) => {
185
- if (typeof candidate === "bigint") {
186
- return candidate.toString() + "n";
187
- }
188
- if (typeof candidate === "object" && candidate !== null) {
189
- if (seen.has(candidate)) {
190
- return "[Circular]";
191
- }
192
- seen.add(candidate);
193
- }
194
- return candidate;
195
- },
196
- 2
197
- ) ?? String(value);
198
- } catch {
199
- return String(value);
200
- }
201
- }
202
- function formatArg(value) {
203
- if (typeof value === "string") {
204
- return value;
205
- }
206
- if (value instanceof Error) {
207
- if (value.stack) {
208
- return value.stack;
209
- }
210
- return value.name + ": " + value.message;
211
- }
212
- if (typeof value === "undefined") {
213
- return "undefined";
214
- }
215
- if (typeof value === "function") {
216
- return "[Function " + (value.name || "anonymous") + "]";
217
- }
218
- return safeStringify(value);
219
- }
220
- function formatEntryMessage(args) {
221
- const message = args.map(formatArg).join(" ");
222
- if (message.length <= 4e3) {
223
- return message;
224
- }
225
- return message.slice(0, 3997) + "...";
226
- }
227
- function createEntry(level, args, id) {
228
- return {
229
- id,
230
- level,
231
- message: formatEntryMessage(args),
232
- timestamp: Date.now()
233
- };
234
- }
235
- function createButton(label) {
236
- const button = document.createElement("button");
237
- button.type = "button";
238
- button.textContent = label;
239
- button.style.cssText = [
240
- "appearance:none",
241
- "border:1px solid rgba(255,255,255,0.18)",
242
- "background:rgba(255,255,255,0.06)",
243
- "color:#f8fafc",
244
- "border-radius:999px",
245
- "padding:6px 10px",
246
- "font:600 12px/1.1 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
247
- "cursor:pointer"
248
- ].join(";");
249
- return button;
250
- }
251
- function getLevelAccent(level) {
252
- if (level === "error") {
253
- return {
254
- lineBackground: "rgba(255, 109, 122, 0.08)"
255
- };
256
- }
257
- if (level === "warn") {
258
- return {
259
- lineBackground: "rgba(255, 196, 94, 0.07)"
260
- };
261
- }
262
- if (level === "info") {
263
- return {
264
- lineBackground: "rgba(82, 187, 255, 0.07)"
265
- };
266
- }
267
- if (level === "debug") {
268
- return {
269
- lineBackground: "rgba(166, 137, 255, 0.07)"
270
- };
271
- }
272
- return {
273
- lineBackground: "rgba(117, 235, 191, 0.06)"
274
- };
275
- }
276
- function getViewportSize() {
277
- const browserWindow = getBrowserWindow();
278
- return {
279
- width: Math.max(320, browserWindow?.innerWidth ?? 1280),
280
- height: Math.max(240, browserWindow?.innerHeight ?? 720)
281
- };
282
- }
283
- function clampPanelSize(size) {
284
- const viewport = getViewportSize();
285
- const maxWidth = Math.max(MIN_EXPANDED_WIDTH, viewport.width - OVERLAY_MARGIN * 2);
286
- const maxHeight = Math.max(
287
- MIN_EXPANDED_HEIGHT,
288
- viewport.height - OVERLAY_MARGIN * 2
289
- );
290
- return {
291
- width: Math.min(maxWidth, Math.max(MIN_EXPANDED_WIDTH, size.width)),
292
- height: Math.min(maxHeight, Math.max(MIN_EXPANDED_HEIGHT, size.height))
293
- };
294
- }
295
- function getOverlaySize(state) {
296
- if (state.expanded && state.panelSize) {
297
- return state.panelSize;
298
- }
299
- const rect = state.ui?.root && typeof state.ui.root.getBoundingClientRect === "function" ? state.ui.root.getBoundingClientRect() : null;
300
- if (rect && Number.isFinite(rect.width) && Number.isFinite(rect.height)) {
301
- return {
302
- width: Math.max(1, rect.width),
303
- height: Math.max(1, rect.height)
304
- };
305
- }
306
- return state.expanded ? clampPanelSize({
307
- width: DEFAULT_EXPANDED_WIDTH,
308
- height: DEFAULT_EXPANDED_HEIGHT
309
- }) : { width: DEFAULT_COLLAPSED_WIDTH, height: DEFAULT_COLLAPSED_HEIGHT };
310
- }
311
- function applyPanelSize(state) {
312
- if (!state.ui) {
313
- return;
314
- }
315
- if (!state.expanded) {
316
- state.ui.root.style.width = "auto";
317
- state.ui.panel.style.width = "min(565px, calc(100vw - 24px))";
318
- state.ui.panel.style.height = "auto";
319
- state.ui.entries.style.maxHeight = "min(36vh, 280px)";
320
- return;
321
- }
322
- if (!state.panelSize) {
323
- state.ui.root.style.width = "min(565px, calc(100vw - 24px))";
324
- state.ui.panel.style.width = "min(565px, calc(100vw - 24px))";
325
- state.ui.panel.style.height = "auto";
326
- state.ui.entries.style.maxHeight = "min(36vh, 280px)";
327
- return;
328
- }
329
- const nextSize = clampPanelSize(
330
- state.panelSize
331
- );
332
- state.panelSize = nextSize;
333
- state.ui.root.style.width = nextSize.width + "px";
334
- state.ui.panel.style.width = "100%";
335
- state.ui.panel.style.height = nextSize.height + "px";
336
- state.ui.entries.style.maxHeight = Math.max(72, nextSize.height - 88) + "px";
337
- }
338
- function clampPosition(point, state) {
339
- const viewport = getViewportSize();
340
- const size = getOverlaySize(state);
341
- const maxX = Math.max(OVERLAY_MARGIN, viewport.width - size.width - OVERLAY_MARGIN);
342
- const maxY = Math.max(
343
- OVERLAY_MARGIN,
344
- viewport.height - size.height - OVERLAY_MARGIN
345
- );
346
- return {
347
- x: Math.min(maxX, Math.max(OVERLAY_MARGIN, point.x)),
348
- y: Math.min(maxY, Math.max(OVERLAY_MARGIN, point.y))
349
- };
350
- }
351
- function applyOverlayPosition(state) {
352
- if (!state.ui) {
353
- return;
354
- }
355
- if (!state.position) {
356
- const viewport = getViewportSize();
357
- const size = getOverlaySize(state);
358
- state.position = clampPosition(
359
- {
360
- x: viewport.width - size.width - OVERLAY_MARGIN,
361
- y: viewport.height - size.height - OVERLAY_MARGIN
362
- },
363
- state
364
- );
365
- } else {
366
- state.position = clampPosition(state.position, state);
367
- }
368
- state.ui.root.style.left = state.position.x + "px";
369
- state.ui.root.style.top = state.position.y + "px";
370
- }
371
- function getPointFromMouseEvent(event) {
372
- return { x: event.clientX, y: event.clientY };
373
- }
374
- function getPointFromTouchEvent(event) {
375
- const touch = event.touches[0] ?? event.changedTouches[0];
376
- if (!touch) {
377
- return null;
378
- }
379
- return { x: touch.clientX, y: touch.clientY };
380
- }
381
- function stopDragging(state) {
382
- if (state.isDragging || state.isResizing) {
383
- state.suppressToggleClickUntil = Date.now() + 180;
384
- }
385
- state.isDragging = false;
386
- state.dragStartPoint = null;
387
- state.lastDragPoint = null;
388
- state.removeDragListeners?.();
389
- state.removeDragListeners = null;
390
- if (state.ui) {
391
- state.ui.panel.style.cursor = "default";
392
- state.ui.dragZone.style.cursor = "grab";
393
- state.ui.toggleButton.style.cursor = "grab";
394
- }
395
- }
396
- function stopResizing(state) {
397
- if (state.isResizing) {
398
- state.suppressToggleClickUntil = Date.now() + 180;
399
- }
400
- state.isResizing = false;
401
- state.resizeStartPoint = null;
402
- state.resizeStartSize = null;
403
- state.removeResizeListeners?.();
404
- state.removeResizeListeners = null;
405
- }
406
- function beginDragTracking(state, startPoint) {
407
- const doc = getDocument();
408
- if (!doc) {
409
- return;
410
- }
411
- stopResizing(state);
412
- stopDragging(state);
413
- state.dragMoved = false;
414
- state.dragStartPoint = startPoint;
415
- state.lastDragPoint = startPoint;
416
- const handlePointerMove = (nextPoint) => {
417
- if (!state.dragStartPoint || !state.lastDragPoint || !nextPoint) {
418
- return;
419
- }
420
- if (!state.isDragging) {
421
- const deltaFromStartX = nextPoint.x - state.dragStartPoint.x;
422
- const deltaFromStartY = nextPoint.y - state.dragStartPoint.y;
423
- const distance = Math.sqrt(
424
- deltaFromStartX * deltaFromStartX + deltaFromStartY * deltaFromStartY
425
- );
426
- if (distance < DRAG_THRESHOLD_PX) {
427
- return;
428
- }
429
- state.isDragging = true;
430
- state.dragMoved = true;
431
- if (state.ui) {
432
- state.ui.panel.style.cursor = "grabbing";
433
- state.ui.dragZone.style.cursor = "grabbing";
434
- state.ui.toggleButton.style.cursor = "grabbing";
435
- }
436
- }
437
- const currentPosition = state.position ?? { x: OVERLAY_MARGIN, y: OVERLAY_MARGIN };
438
- state.position = clampPosition(
439
- {
440
- x: currentPosition.x + (nextPoint.x - state.lastDragPoint.x),
441
- y: currentPosition.y + (nextPoint.y - state.lastDragPoint.y)
442
- },
443
- state
444
- );
445
- state.lastDragPoint = nextPoint;
446
- applyOverlayPosition(state);
447
- };
448
- const handleMouseMove = (event) => {
449
- handlePointerMove(getPointFromMouseEvent(event));
450
- };
451
- const handleTouchMove = (event) => {
452
- handlePointerMove(getPointFromTouchEvent(event));
453
- };
454
- const handleMouseUp = () => {
455
- stopDragging(state);
456
- };
457
- const handleTouchEnd = () => {
458
- stopDragging(state);
459
- };
460
- doc.addEventListener("mousemove", handleMouseMove);
461
- doc.addEventListener("mouseup", handleMouseUp);
462
- doc.addEventListener("touchmove", handleTouchMove, { passive: true });
463
- doc.addEventListener("touchend", handleTouchEnd);
464
- doc.addEventListener("touchcancel", handleTouchEnd);
465
- state.removeDragListeners = () => {
466
- doc.removeEventListener("mousemove", handleMouseMove);
467
- doc.removeEventListener("mouseup", handleMouseUp);
468
- doc.removeEventListener("touchmove", handleTouchMove);
469
- doc.removeEventListener("touchend", handleTouchEnd);
470
- doc.removeEventListener("touchcancel", handleTouchEnd);
471
- };
472
- }
473
- function startResizing(state, startPoint) {
474
- const doc = getDocument();
475
- if (!doc) {
476
- return;
477
- }
478
- stopDragging(state);
479
- stopResizing(state);
480
- state.isResizing = true;
481
- state.resizeStartPoint = startPoint;
482
- state.resizeStartSize = state.panelSize ?? clampPanelSize({ width: DEFAULT_EXPANDED_WIDTH, height: DEFAULT_EXPANDED_HEIGHT });
483
- const handleResizeMove = (nextPoint) => {
484
- if (!state.isResizing || !state.resizeStartPoint || !state.resizeStartSize || !nextPoint) {
485
- return;
486
- }
487
- state.panelSize = clampPanelSize({
488
- width: state.resizeStartSize.width + (nextPoint.x - state.resizeStartPoint.x),
489
- height: state.resizeStartSize.height + (nextPoint.y - state.resizeStartPoint.y)
490
- });
491
- applyPanelSize(state);
492
- applyOverlayPosition(state);
493
- };
494
- const handleMouseMove = (event) => {
495
- handleResizeMove(getPointFromMouseEvent(event));
496
- };
497
- const handleTouchMove = (event) => {
498
- handleResizeMove(getPointFromTouchEvent(event));
499
- };
500
- const handleFinish = () => {
501
- stopResizing(state);
502
- };
503
- doc.addEventListener("mousemove", handleMouseMove);
504
- doc.addEventListener("mouseup", handleFinish);
505
- doc.addEventListener("touchmove", handleTouchMove, { passive: true });
506
- doc.addEventListener("touchend", handleFinish);
507
- doc.addEventListener("touchcancel", handleFinish);
508
- state.removeResizeListeners = () => {
509
- doc.removeEventListener("mousemove", handleMouseMove);
510
- doc.removeEventListener("mouseup", handleFinish);
511
- doc.removeEventListener("touchmove", handleTouchMove);
512
- doc.removeEventListener("touchend", handleFinish);
513
- doc.removeEventListener("touchcancel", handleFinish);
514
- };
515
- }
516
- function isInBottomRightResizeZone(element, point) {
517
- const rect = element.getBoundingClientRect();
518
- return point.x >= rect.right - RESIZE_HOTSPOT_PX && point.x <= rect.right && point.y >= rect.bottom - RESIZE_HOTSPOT_PX && point.y <= rect.bottom;
519
- }
520
- function canStartDragFromTarget(target) {
521
- if (!(target instanceof Element)) {
522
- return true;
523
- }
524
- if (target.closest("button") || target.closest("a") || target.closest("input") || target.closest("textarea") || target.closest("select")) {
525
- return false;
526
- }
527
- return true;
528
- }
529
- function isInTopDragZone(element, point, zoneHeight) {
530
- const rect = element.getBoundingClientRect();
531
- return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.top + zoneHeight;
532
- }
533
- function attachDragStartListeners(element, state, options = {}) {
534
- element.addEventListener("mousedown", (event) => {
535
- if (!options.allowInteractiveTarget && !canStartDragFromTarget(event.target)) {
536
- return;
537
- }
538
- const point = getPointFromMouseEvent(event);
539
- if (typeof options.topZoneHeight === "number" && !isInTopDragZone(element, point, options.topZoneHeight)) {
540
- return;
541
- }
542
- beginDragTracking(state, point);
543
- });
544
- element.addEventListener("touchstart", (event) => {
545
- if (!options.allowInteractiveTarget && !canStartDragFromTarget(event.target)) {
546
- return;
547
- }
548
- const point = getPointFromTouchEvent(event);
549
- if (!point) {
550
- return;
551
- }
552
- if (typeof options.topZoneHeight === "number" && !isInTopDragZone(element, point, options.topZoneHeight)) {
553
- return;
554
- }
555
- beginDragTracking(state, point);
556
- });
557
- }
558
- function attachCollapsedToggleListeners(element, state) {
559
- const startToggleInteraction = (startPoint) => {
560
- const doc = getDocument();
561
- if (!doc) {
562
- return;
563
- }
564
- beginDragTracking(state, startPoint);
565
- const finishInteraction = () => {
566
- releaseListeners();
567
- if (state.dragMoved || Date.now() < state.suppressToggleClickUntil) {
568
- return;
569
- }
570
- state.expanded = true;
571
- state.unreadCount = 0;
572
- renderOverlay(state);
573
- };
574
- const releaseListeners = () => {
575
- doc.removeEventListener("mouseup", finishInteraction);
576
- doc.removeEventListener("touchend", finishInteraction);
577
- doc.removeEventListener("touchcancel", finishInteraction);
578
- };
579
- doc.addEventListener("mouseup", finishInteraction);
580
- doc.addEventListener("touchend", finishInteraction);
581
- doc.addEventListener("touchcancel", finishInteraction);
582
- };
583
- element.addEventListener("mousedown", (event) => {
584
- event.preventDefault();
585
- startToggleInteraction(getPointFromMouseEvent(event));
586
- });
587
- element.addEventListener("touchstart", (event) => {
588
- const point = getPointFromTouchEvent(event);
589
- if (!point) {
590
- return;
591
- }
592
- event.preventDefault();
593
- startToggleInteraction(point);
594
- });
595
- }
596
- function attachPanelResizeListeners(element, state) {
597
- element.addEventListener("mousedown", (event) => {
598
- if (!state.expanded || !canStartDragFromTarget(event.target)) {
599
- return;
600
- }
601
- const point = getPointFromMouseEvent(event);
602
- if (!isInBottomRightResizeZone(element, point)) {
603
- return;
604
- }
605
- event.preventDefault();
606
- event.stopPropagation();
607
- startResizing(state, point);
608
- });
609
- element.addEventListener("touchstart", (event) => {
610
- if (!state.expanded || !canStartDragFromTarget(event.target)) {
611
- return;
612
- }
613
- const point = getPointFromTouchEvent(event);
614
- if (!point || !isInBottomRightResizeZone(element, point)) {
615
- return;
616
- }
617
- event.preventDefault();
618
- event.stopPropagation();
619
- startResizing(state, point);
620
- });
621
- }
622
- function createOverlayUi(state) {
623
- const root = document.createElement("div");
624
- root.style.cssText = [
625
- "position:fixed",
626
- "left:12px",
627
- "top:12px",
628
- "z-index:2147483647",
629
- "display:flex",
630
- "flex-direction:column",
631
- "align-items:stretch",
632
- "gap:8px",
633
- "width:min(565px, calc(100vw - 24px))",
634
- "pointer-events:none"
635
- ].join(";");
636
- const toggleButton = createButton("Logs");
637
- toggleButton.style.pointerEvents = "auto";
638
- toggleButton.style.alignSelf = "flex-end";
639
- toggleButton.style.display = "inline-flex";
640
- toggleButton.style.alignItems = "center";
641
- toggleButton.style.justifyContent = "center";
642
- toggleButton.style.minHeight = "40px";
643
- toggleButton.style.minWidth = "76px";
644
- toggleButton.style.padding = "8px 14px";
645
- toggleButton.style.textAlign = "center";
646
- toggleButton.style.border = "1px solid rgba(122, 212, 255, 0.22)";
647
- toggleButton.style.background = "linear-gradient(180deg, rgba(13,31,54,0.98), rgba(8,19,37,0.98))";
648
- toggleButton.style.boxShadow = "0 18px 40px rgba(4,12,24,0.34)";
649
- toggleButton.style.cursor = "grab";
650
- toggleButton.style.touchAction = "none";
651
- const panel = document.createElement("div");
652
- panel.style.cssText = [
653
- "position:relative",
654
- "display:flex",
655
- "flex-direction:column",
656
- "width:min(565px, calc(100vw - 24px))",
657
- "max-height:min(48vh, 372px)",
658
- "border-radius:18px",
659
- "border:1px solid rgba(116,167,255,0.16)",
660
- "background:linear-gradient(180deg, rgba(9,19,37,0.98), rgba(5,12,24,0.98))",
661
- "box-shadow:0 28px 64px rgba(2,8,18,0.46)",
662
- "backdrop-filter:blur(16px)",
663
- "overflow:hidden",
664
- "cursor:default",
665
- "pointer-events:auto"
666
- ].join(";");
667
- const dragZone = document.createElement("div");
668
- dragZone.style.cssText = [
669
- "position:absolute",
670
- "top:0",
671
- "left:0",
672
- "right:0",
673
- "height:" + String(TOP_DRAG_ZONE_PX) + "px",
674
- "z-index:1",
675
- "cursor:grab",
676
- "background:transparent",
677
- "pointer-events:auto"
678
- ].join(";");
679
- const controls = document.createElement("div");
680
- controls.style.cssText = [
681
- "position:absolute",
682
- "top:22px",
683
- "right:22px",
684
- "z-index:2",
685
- "display:flex",
686
- "align-items:center",
687
- "gap:8px",
688
- "pointer-events:auto"
689
- ].join(";");
690
- const clearButton = createButton("Clear");
691
- clearButton.style.background = "rgba(255,255,255,0.1)";
692
- clearButton.style.border = "1px solid rgba(255,255,255,0.16)";
693
- clearButton.style.color = "#eef6ff";
694
- clearButton.style.minHeight = "30px";
695
- clearButton.style.padding = "4px 9px";
696
- clearButton.style.fontSize = "11px";
697
- clearButton.style.backdropFilter = "blur(8px)";
698
- const collapseButton = createButton("Hide");
699
- collapseButton.style.background = "rgba(113, 171, 255, 0.12)";
700
- collapseButton.style.border = "1px solid rgba(113, 171, 255, 0.2)";
701
- collapseButton.style.color = "#d9ebff";
702
- collapseButton.style.minHeight = "30px";
703
- collapseButton.style.padding = "4px 9px";
704
- collapseButton.style.fontSize = "11px";
705
- collapseButton.style.backdropFilter = "blur(8px)";
706
- const body = document.createElement("div");
707
- body.style.cssText = [
708
- "position:relative",
709
- "display:flex",
710
- "flex-direction:column",
711
- "padding:12px",
712
- "background:linear-gradient(180deg, rgba(4,10,20,0.88), rgba(3,8,18,0.98))",
713
- "flex:1 1 auto",
714
- "min-height:0"
715
- ].join(";");
716
- const entries = document.createElement("div");
717
- entries.style.cssText = [
718
- "display:flex",
719
- "flex-direction:column",
720
- "gap:0",
721
- "overflow:auto",
722
- "flex:1 1 auto",
723
- "min-height:96px",
724
- "max-height:min(36vh, 280px)",
725
- "padding:0",
726
- "border:1px solid rgba(115,153,212,0.14)",
727
- "border-radius:12px",
728
- "background:rgba(4,10,20,0.82)"
729
- ].join(";");
730
- const emptyState = document.createElement("div");
731
- emptyState.style.cssText = [
732
- "display:flex",
733
- "align-items:center",
734
- "justify-content:center",
735
- "flex:1 1 auto",
736
- "min-height:96px",
737
- "color:rgba(204,222,250,0.6)",
738
- "font:500 12px/1.5 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
739
- "text-align:center",
740
- "padding:18px"
741
- ].join(";");
742
- emptyState.textContent = "Console output will appear here.";
743
- collapseButton.addEventListener("click", (event) => {
744
- event.stopPropagation();
745
- state.expanded = false;
746
- renderOverlay(state);
747
- });
748
- clearButton.addEventListener("click", (event) => {
749
- event.stopPropagation();
750
- state.entries = [];
751
- state.unreadCount = 0;
752
- renderOverlay(state);
753
- });
754
- controls.appendChild(clearButton);
755
- controls.appendChild(collapseButton);
756
- entries.appendChild(emptyState);
757
- body.appendChild(entries);
758
- body.appendChild(controls);
759
- panel.appendChild(dragZone);
760
- panel.appendChild(body);
761
- attachDragStartListeners(dragZone, state);
762
- attachPanelResizeListeners(panel, state);
763
- attachCollapsedToggleListeners(toggleButton, state);
764
- root.appendChild(panel);
765
- root.appendChild(toggleButton);
766
- return {
767
- body,
768
- clearButton,
769
- collapseButton,
770
- controls,
771
- dragZone,
772
- emptyState,
773
- entries,
774
- panel,
775
- root,
776
- toggleButton
777
- };
778
- }
779
- function renderOverlay(state) {
780
- if (!state.ui) {
781
- return;
782
- }
783
- state.ui.panel.style.display = state.expanded ? "flex" : "none";
784
- state.ui.toggleButton.style.display = state.expanded ? "none" : "inline-flex";
785
- state.ui.toggleButton.textContent = "Logs";
786
- if (state.entries.length === 0) {
787
- state.ui.entries.style.display = "flex";
788
- state.ui.emptyState.style.display = "flex";
789
- state.ui.entries.replaceChildren(state.ui.emptyState);
790
- applyPanelSize(state);
791
- applyOverlayPosition(state);
792
- return;
793
- }
794
- state.ui.entries.style.display = "flex";
795
- state.ui.emptyState.style.display = "none";
796
- const nextChildren = state.entries.map((entry) => {
797
- const accent = getLevelAccent(entry.level);
798
- const row = document.createElement("div");
799
- row.style.cssText = [
800
- "display:flex",
801
- "align-items:flex-start",
802
- "gap:0",
803
- "padding:4px 12px",
804
- "background:" + accent.lineBackground
805
- ].join(";");
806
- const line = document.createElement("div");
807
- line.textContent = formatTimestamp(entry.timestamp) + " " + entry.level.toUpperCase() + " " + entry.message;
808
- line.style.cssText = [
809
- "color:#ecf4ff",
810
- "font:500 12px/1.5 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
811
- "white-space:pre-wrap",
812
- "word-break:break-word",
813
- "flex:1 1 auto"
814
- ].join(";");
815
- row.appendChild(line);
816
- return row;
817
- });
818
- state.ui.entries.replaceChildren(...nextChildren);
819
- state.ui.entries.scrollTop = state.ui.entries.scrollHeight;
820
- applyPanelSize(state);
821
- applyOverlayPosition(state);
822
- }
823
- function mountOverlay(state) {
824
- const doc = getDocument();
825
- if (!doc?.body || state.ui) {
826
- return;
827
- }
828
- state.ui = createOverlayUi(state);
829
- doc.body.appendChild(state.ui.root);
830
- applyPanelSize(state);
831
- applyOverlayPosition(state);
832
- renderOverlay(state);
833
- }
834
- function enqueueEntry(state, level, args) {
835
- state.entries.push(createEntry(level, args, state.nextEntryId));
836
- state.nextEntryId += 1;
837
- if (state.entries.length > state.maxEntries) {
838
- state.entries.splice(0, state.entries.length - state.maxEntries);
839
- }
840
- if (!state.expanded) {
841
- state.unreadCount += 1;
842
- }
843
- renderOverlay(state);
844
- }
845
- function restoreConsole(snapshot) {
846
- for (const method of CONSOLE_METHODS) {
847
- console[method] = snapshot[method];
848
- }
849
- }
850
- function patchConsole(state) {
851
- for (const method of CONSOLE_METHODS) {
852
- const original = state.originalConsole[method];
853
- console[method] = (...args) => {
854
- enqueueEntry(state, method, args);
855
- original(...args);
856
- };
857
- }
858
- }
859
- function cleanupOverlay(browserWindow, state) {
860
- restoreConsole(state.originalConsole);
861
- stopResizing(state);
862
- stopDragging(state);
863
- if (state.domReadyHandler) {
864
- getDocument()?.removeEventListener("DOMContentLoaded", state.domReadyHandler);
865
- state.domReadyHandler = void 0;
866
- }
867
- if (state.resizeHandler && typeof browserWindow.removeEventListener === "function") {
868
- browserWindow.removeEventListener("resize", state.resizeHandler);
869
- state.resizeHandler = void 0;
870
- }
871
- state.ui?.root.remove();
872
- state.ui = null;
873
- delete browserWindow.__oasizLogOverlayController__;
874
- delete browserWindow.__oasizLogOverlayState__;
875
- }
876
- function createController(browserWindow, state) {
877
- return {
878
- retain() {
879
- state.refCount += 1;
880
- this.ensureMounted();
881
- },
882
- ensureMounted() {
883
- const doc = getDocument();
884
- if (!doc) {
885
- return;
886
- }
887
- if (doc.body) {
888
- mountOverlay(state);
889
- applyOverlayPosition(state);
890
- return;
891
- }
892
- if (!state.domReadyHandler) {
893
- state.domReadyHandler = () => {
894
- mountOverlay(state);
895
- state.domReadyHandler = void 0;
896
- };
897
- doc.addEventListener("DOMContentLoaded", state.domReadyHandler, {
898
- once: true
899
- });
900
- }
901
- },
902
- clear() {
903
- state.entries = [];
904
- state.unreadCount = 0;
905
- renderOverlay(state);
906
- },
907
- show() {
908
- state.expanded = true;
909
- state.unreadCount = 0;
910
- renderOverlay(state);
911
- },
912
- hide() {
913
- state.expanded = false;
914
- renderOverlay(state);
915
- },
916
- isVisible() {
917
- return state.expanded;
918
- },
919
- destroy() {
920
- state.refCount = Math.max(0, state.refCount - 1);
921
- if (state.refCount === 0) {
922
- cleanupOverlay(browserWindow, state);
923
- }
924
- }
925
- };
926
- }
927
- function enableLogOverlay(options = {}) {
928
- if (options.enabled === false) {
929
- return NOOP_HANDLE;
930
- }
931
- const browserWindow = getBrowserWindow();
932
- const doc = getDocument();
933
- if (!browserWindow || !doc) {
934
- return NOOP_HANDLE;
935
- }
936
- const existingController = browserWindow.__oasizLogOverlayController__;
937
- const existingState = browserWindow.__oasizLogOverlayState__;
938
- if (existingController && existingState) {
939
- existingController.retain();
940
- if (typeof options.maxEntries === "number") {
941
- existingState.maxEntries = clampMaxEntries(options.maxEntries);
942
- if (existingState.entries.length > existingState.maxEntries) {
943
- existingState.entries.splice(
944
- 0,
945
- existingState.entries.length - existingState.maxEntries
946
- );
947
- }
948
- }
949
- if (typeof options.collapsed === "boolean") {
950
- existingState.expanded = !options.collapsed;
951
- applyPanelSize(existingState);
952
- if (existingState.expanded) {
953
- existingState.unreadCount = 0;
954
- }
955
- }
956
- if (typeof options.title === "string" && options.title.trim().length > 0) {
957
- existingState.title = options.title.trim();
958
- }
959
- existingController.ensureMounted();
960
- renderOverlay(existingState);
961
- return existingController;
962
- }
963
- const state = {
964
- dragMoved: false,
965
- dragStartPoint: null,
966
- entries: [],
967
- expanded: options.collapsed !== true,
968
- isDragging: false,
969
- isResizing: false,
970
- lastDragPoint: null,
971
- maxEntries: clampMaxEntries(options.maxEntries),
972
- nextEntryId: 1,
973
- originalConsole: createConsoleSnapshot(),
974
- panelSize: null,
975
- position: null,
976
- refCount: 1,
977
- removeDragListeners: null,
978
- removeResizeListeners: null,
979
- resizeStartPoint: null,
980
- resizeStartSize: null,
981
- suppressToggleClickUntil: 0,
982
- title: typeof options.title === "string" && options.title.trim().length > 0 ? options.title.trim() : DEFAULT_TITLE,
983
- resizeHandler: void 0,
984
- ui: null,
985
- unreadCount: 0
986
- };
987
- const controller = createController(browserWindow, state);
988
- browserWindow.__oasizLogOverlayState__ = state;
989
- browserWindow.__oasizLogOverlayController__ = controller;
990
- patchConsole(state);
991
- if (typeof browserWindow.addEventListener === "function") {
992
- state.resizeHandler = () => {
993
- applyOverlayPosition(state);
994
- };
995
- browserWindow.addEventListener("resize", state.resizeHandler);
996
- }
997
- controller.ensureMounted();
998
- return controller;
999
- }
1000
-
1001
78
  // src/multiplayer.ts
1002
- function isDevelopment3() {
79
+ function isDevelopment2() {
1003
80
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1004
81
  return nodeEnv !== "production";
1005
82
  }
1006
- function getBridgeWindow3() {
83
+ function getBridgeWindow2() {
1007
84
  if (typeof window === "undefined") {
1008
85
  return void 0;
1009
86
  }
1010
87
  return window;
1011
88
  }
1012
- function shareRoomCode(roomCode, options) {
1013
- const bridge = getBridgeWindow3();
89
+ function shareRoomCode(roomCode) {
90
+ const bridge = getBridgeWindow2();
1014
91
  if (typeof bridge?.shareRoomCode === "function") {
1015
- bridge.shareRoomCode(roomCode, options);
92
+ bridge.shareRoomCode(roomCode);
1016
93
  return;
1017
94
  }
1018
- if (isDevelopment3()) {
95
+ if (isDevelopment2()) {
1019
96
  console.warn(
1020
97
  "[oasiz/sdk] shareRoomCode bridge is unavailable. This is expected in local development."
1021
98
  );
1022
99
  }
1023
100
  }
1024
- function openInviteModal() {
1025
- const bridge = getBridgeWindow3();
1026
- if (typeof bridge?.openInviteModal === "function") {
1027
- bridge.openInviteModal();
1028
- return;
1029
- }
1030
- if (isDevelopment3()) {
1031
- console.warn(
1032
- "[oasiz/sdk] openInviteModal bridge is unavailable. This is expected in local development."
1033
- );
1034
- }
1035
- }
1036
101
  function getGameId() {
1037
- const bridge = getBridgeWindow3();
102
+ const bridge = getBridgeWindow2();
1038
103
  return bridge?.__GAME_ID__;
1039
104
  }
1040
105
  function getRoomCode() {
1041
- const bridge = getBridgeWindow3();
106
+ const bridge = getBridgeWindow2();
1042
107
  return bridge?.__ROOM_CODE__;
1043
108
  }
1044
- function getPlayerId() {
1045
- const bridge = getBridgeWindow3();
1046
- return bridge?.__PLAYER_ID__;
1047
- }
1048
109
  function getPlayerName() {
1049
- const bridge = getBridgeWindow3();
110
+ const bridge = getBridgeWindow2();
1050
111
  return bridge?.__PLAYER_NAME__;
1051
112
  }
1052
113
  function getPlayerAvatar() {
1053
- const bridge = getBridgeWindow3();
114
+ const bridge = getBridgeWindow2();
1054
115
  return bridge?.__PLAYER_AVATAR__;
1055
116
  }
1056
117
 
1057
118
  // src/score.ts
1058
- function isDevelopment4() {
119
+ function isDevelopment3() {
1059
120
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1060
121
  return nodeEnv !== "production";
1061
122
  }
1062
- function warnMissingBridge2(methodName) {
1063
- if (isDevelopment4()) {
123
+ function warnMissingBridge(methodName) {
124
+ if (isDevelopment3()) {
1064
125
  console.warn(
1065
126
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1066
127
  );
1067
128
  }
1068
129
  }
1069
- function getBridgeWindow4() {
130
+ function getBridgeWindow3() {
1070
131
  if (typeof window === "undefined") {
1071
132
  return void 0;
1072
133
  }
@@ -1074,92 +135,41 @@ function getBridgeWindow4() {
1074
135
  }
1075
136
  function submitScore(score) {
1076
137
  if (!Number.isFinite(score)) {
1077
- if (isDevelopment4()) {
138
+ if (isDevelopment3()) {
1078
139
  console.warn("[oasiz/sdk] submitScore expected a finite number:", score);
1079
140
  }
1080
141
  return;
1081
142
  }
1082
- const bridge = getBridgeWindow4();
143
+ const bridge = getBridgeWindow3();
1083
144
  const normalizedScore = Math.max(0, Math.floor(score));
1084
145
  if (typeof bridge?.submitScore === "function") {
1085
146
  bridge.submitScore(normalizedScore);
1086
147
  return;
1087
148
  }
1088
- warnMissingBridge2("submitScore");
1089
- }
1090
-
1091
- // src/score-edit.ts
1092
- function isDevelopment5() {
1093
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
1094
- return nodeEnv !== "production";
1095
- }
1096
- function getBridgeWindow5() {
1097
- if (typeof window === "undefined") {
1098
- return void 0;
1099
- }
1100
- return window;
1101
- }
1102
- function warnMissingBridge3(methodName) {
1103
- if (isDevelopment5()) {
1104
- console.warn(
1105
- "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1106
- );
1107
- }
1108
- }
1109
- async function editScore(payload, methodName) {
1110
- const bridge = getBridgeWindow5();
1111
- if (typeof bridge?.__oasizEditScore !== "function") {
1112
- warnMissingBridge3(methodName);
1113
- return null;
1114
- }
1115
- try {
1116
- const result = await bridge.__oasizEditScore(payload);
1117
- return result ?? null;
1118
- } catch (error) {
1119
- if (isDevelopment5()) {
1120
- console.error("[oasiz/sdk] " + methodName + " failed:", error);
1121
- }
1122
- return null;
1123
- }
149
+ warnMissingBridge("submitScore");
1124
150
  }
1125
- async function addScore(delta) {
1126
- if (!Number.isInteger(delta)) {
1127
- if (isDevelopment5()) {
1128
- console.warn("[oasiz/sdk] addScore expected an integer:", delta);
1129
- }
1130
- return null;
1131
- }
1132
- if (delta === 0) {
1133
- return null;
1134
- }
1135
- return editScore({ delta }, "addScore");
1136
- }
1137
- async function setScore(score) {
1138
- if (!Number.isInteger(score) || score < 0) {
1139
- if (isDevelopment5()) {
1140
- console.warn(
1141
- "[oasiz/sdk] setScore expected a non-negative integer:",
1142
- score
1143
- );
1144
- }
1145
- return null;
151
+ function emitScoreConfig(config) {
152
+ const bridge = getBridgeWindow3();
153
+ if (typeof bridge?.emitScoreConfig === "function") {
154
+ bridge.emitScoreConfig(config);
155
+ return;
1146
156
  }
1147
- return editScore({ score }, "setScore");
157
+ warnMissingBridge("emitScoreConfig");
1148
158
  }
1149
159
 
1150
160
  // src/share.ts
1151
- function isDevelopment6() {
161
+ function isDevelopment4() {
1152
162
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1153
163
  return nodeEnv !== "production";
1154
164
  }
1155
- function getBridgeWindow6() {
165
+ function getBridgeWindow4() {
1156
166
  if (typeof window === "undefined") {
1157
167
  return void 0;
1158
168
  }
1159
169
  return window;
1160
170
  }
1161
- function warnMissingBridge4(methodName) {
1162
- if (isDevelopment6()) {
171
+ function warnMissingBridge2(methodName) {
172
+ if (isDevelopment4()) {
1163
173
  console.warn(
1164
174
  "[oasiz/sdk] " + methodName + " share bridge is unavailable. This is expected in local development."
1165
175
  );
@@ -1202,20 +212,20 @@ function validateRequest(options) {
1202
212
  }
1203
213
  async function share(options) {
1204
214
  const request = validateRequest(options);
1205
- const bridge = getBridgeWindow6();
215
+ const bridge = getBridgeWindow4();
1206
216
  if (typeof bridge?.__oasizShareRequest !== "function") {
1207
- warnMissingBridge4("__oasizShareRequest");
217
+ warnMissingBridge2("__oasizShareRequest");
1208
218
  throw new Error("Share bridge unavailable");
1209
219
  }
1210
220
  await bridge.__oasizShareRequest(request);
1211
221
  }
1212
222
 
1213
223
  // src/state.ts
1214
- function isDevelopment7() {
224
+ function isDevelopment5() {
1215
225
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1216
226
  return nodeEnv !== "production";
1217
227
  }
1218
- function getBridgeWindow7() {
228
+ function getBridgeWindow5() {
1219
229
  if (typeof window === "undefined") {
1220
230
  return void 0;
1221
231
  }
@@ -1228,22 +238,22 @@ function isPlainObject(value) {
1228
238
  const proto = Object.getPrototypeOf(value);
1229
239
  return proto === Object.prototype || proto === null;
1230
240
  }
1231
- function warnMissingBridge5(methodName) {
1232
- if (isDevelopment7()) {
241
+ function warnMissingBridge3(methodName) {
242
+ if (isDevelopment5()) {
1233
243
  console.warn(
1234
244
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1235
245
  );
1236
246
  }
1237
247
  }
1238
248
  function loadGameState() {
1239
- const bridge = getBridgeWindow7();
249
+ const bridge = getBridgeWindow5();
1240
250
  if (typeof bridge?.loadGameState !== "function") {
1241
- warnMissingBridge5("loadGameState");
251
+ warnMissingBridge3("loadGameState");
1242
252
  return {};
1243
253
  }
1244
254
  const state = bridge.loadGameState();
1245
255
  if (!isPlainObject(state)) {
1246
- if (isDevelopment7()) {
256
+ if (isDevelopment5()) {
1247
257
  console.warn(
1248
258
  "[oasiz/sdk] loadGameState returned invalid data. Falling back to empty object."
1249
259
  );
@@ -1254,35 +264,35 @@ function loadGameState() {
1254
264
  }
1255
265
  function saveGameState(state) {
1256
266
  if (!isPlainObject(state)) {
1257
- if (isDevelopment7()) {
267
+ if (isDevelopment5()) {
1258
268
  console.warn("[oasiz/sdk] saveGameState expected a plain object:", state);
1259
269
  }
1260
270
  return;
1261
271
  }
1262
- const bridge = getBridgeWindow7();
272
+ const bridge = getBridgeWindow5();
1263
273
  if (typeof bridge?.saveGameState === "function") {
1264
274
  bridge.saveGameState(state);
1265
275
  return;
1266
276
  }
1267
- warnMissingBridge5("saveGameState");
277
+ warnMissingBridge3("saveGameState");
1268
278
  }
1269
279
  function flushGameState() {
1270
- const bridge = getBridgeWindow7();
280
+ const bridge = getBridgeWindow5();
1271
281
  if (typeof bridge?.flushGameState === "function") {
1272
282
  bridge.flushGameState();
1273
283
  return;
1274
284
  }
1275
- warnMissingBridge5("flushGameState");
285
+ warnMissingBridge3("flushGameState");
1276
286
  }
1277
287
 
1278
288
  // src/lifecycle.ts
1279
- function isDevelopment8() {
289
+ function isDevelopment6() {
1280
290
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1281
291
  return nodeEnv !== "production";
1282
292
  }
1283
293
  function addLifecycleListener(eventName, callback) {
1284
294
  if (typeof window === "undefined") {
1285
- if (isDevelopment8()) {
295
+ if (isDevelopment6()) {
1286
296
  console.warn(
1287
297
  "[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
1288
298
  );
@@ -1301,217 +311,20 @@ function onResume(callback) {
1301
311
  return addLifecycleListener("oasiz:resume", callback);
1302
312
  }
1303
313
 
1304
- // src/layout.ts
1305
- function isDevelopment9() {
1306
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
1307
- return nodeEnv !== "production";
1308
- }
1309
- function getBridgeWindow8() {
1310
- if (typeof window === "undefined") {
1311
- return void 0;
1312
- }
1313
- return window;
1314
- }
1315
- function warnMissingBridge6(methodName) {
1316
- if (isDevelopment9()) {
1317
- console.warn(
1318
- "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1319
- );
1320
- }
1321
- }
1322
- function toFiniteNumber(value) {
1323
- if (typeof value !== "number" || !Number.isFinite(value)) {
1324
- if (typeof value !== "string") {
1325
- return void 0;
1326
- }
1327
- const parsed = Number.parseFloat(value.trim());
1328
- if (!Number.isFinite(parsed)) {
1329
- return void 0;
1330
- }
1331
- return parsed;
1332
- }
1333
- return value;
1334
- }
1335
- function clampSafeAreaTopPixels(value) {
1336
- const numeric = toFiniteNumber(value);
1337
- if (typeof numeric === "undefined") {
1338
- return 0;
1339
- }
1340
- return Math.max(0, numeric);
1341
- }
1342
- function normalizeSafeAreaTopPercent(value) {
1343
- const numeric = toFiniteNumber(value);
1344
- if (typeof numeric === "undefined") {
1345
- return void 0;
1346
- }
1347
- return Math.min(100, Math.max(0, numeric));
1348
- }
1349
- function getViewportHeight(bridge) {
1350
- const visualViewportHeight = bridge.visualViewport?.height;
1351
- if (typeof visualViewportHeight === "number" && Number.isFinite(visualViewportHeight) && visualViewportHeight > 0) {
1352
- return visualViewportHeight;
1353
- }
1354
- const innerHeight = bridge.innerHeight;
1355
- if (typeof innerHeight === "number" && Number.isFinite(innerHeight) && innerHeight > 0) {
1356
- return innerHeight;
1357
- }
1358
- const documentHeight = bridge.document?.documentElement?.clientHeight;
1359
- if (typeof documentHeight === "number" && Number.isFinite(documentHeight) && documentHeight > 0) {
1360
- return documentHeight;
1361
- }
1362
- const bodyHeight = bridge.document?.body?.clientHeight;
1363
- if (typeof bodyHeight === "number" && Number.isFinite(bodyHeight) && bodyHeight > 0) {
1364
- return bodyHeight;
1365
- }
1366
- return 0;
1367
- }
1368
- function readCssSafeAreaValue(bridge, cssValue) {
1369
- const doc = bridge.document;
1370
- const root = doc?.body ?? doc?.documentElement;
1371
- if (!doc || !root || typeof doc.createElement !== "function" || typeof root.appendChild !== "function" || typeof bridge.getComputedStyle !== "function") {
1372
- return 0;
1373
- }
1374
- const probe = doc.createElement("div");
1375
- probe.style.position = "fixed";
1376
- probe.style.top = "0";
1377
- probe.style.left = "0";
1378
- probe.style.width = "0";
1379
- probe.style.height = "0";
1380
- probe.style.visibility = "hidden";
1381
- probe.style.pointerEvents = "none";
1382
- probe.style.paddingTop = cssValue;
1383
- root.appendChild(probe);
1384
- try {
1385
- return clampSafeAreaTopPixels(bridge.getComputedStyle(probe).paddingTop);
1386
- } finally {
1387
- if (typeof probe.remove === "function") {
1388
- probe.remove();
1389
- } else {
1390
- probe.parentNode?.removeChild(probe);
1391
- }
1392
- }
1393
- }
1394
- function readCssSafeAreaTopPixels(bridge) {
1395
- const envPixels = readCssSafeAreaValue(bridge, "env(safe-area-inset-top)");
1396
- if (envPixels > 0) {
1397
- return envPixels;
1398
- }
1399
- return readCssSafeAreaValue(bridge, "constant(safe-area-inset-top)");
1400
- }
1401
- function getDevicePixelRatio(bridge) {
1402
- const dpr = bridge.devicePixelRatio;
1403
- if (typeof dpr !== "number" || !Number.isFinite(dpr) || dpr <= 0) {
1404
- return 1;
1405
- }
1406
- return dpr;
1407
- }
1408
- function roughlyEqualPixels(a, b) {
1409
- return Math.abs(a - b) <= 2;
1410
- }
1411
- function normalizeSafeAreaTopPixels(value, bridge) {
1412
- const pixels = clampSafeAreaTopPixels(value);
1413
- const cssEnvPixels = readCssSafeAreaTopPixels(bridge);
1414
- if (pixels <= 0) {
1415
- return cssEnvPixels;
1416
- }
1417
- const dpr = getDevicePixelRatio(bridge);
1418
- if (cssEnvPixels > 0 && dpr > 1 && roughlyEqualPixels(pixels / dpr, cssEnvPixels)) {
1419
- return cssEnvPixels;
1420
- }
1421
- return pixels;
1422
- }
1423
- function pixelsTopToPercentOfViewport(pixels, bridge) {
1424
- const h = getViewportHeight(bridge);
1425
- if (h <= 0) {
1426
- return 0;
1427
- }
1428
- return normalizeSafeAreaTopPercent(pixels / h * 100) ?? 0;
1429
- }
1430
- function cssSafeAreaTopPercent(bridge) {
1431
- return pixelsTopToPercentOfViewport(readCssSafeAreaTopPixels(bridge), bridge);
1432
- }
1433
- function resolvePercentValue(value, bridge) {
1434
- const percent = normalizeSafeAreaTopPercent(value);
1435
- if (typeof percent === "undefined") {
1436
- return void 0;
1437
- }
1438
- return percent > 0 ? percent : cssSafeAreaTopPercent(bridge);
1439
- }
1440
- function resolvePixelValue(value, bridge) {
1441
- const numeric = toFiniteNumber(value);
1442
- if (typeof numeric === "undefined") {
1443
- return void 0;
1444
- }
1445
- return pixelsTopToPercentOfViewport(normalizeSafeAreaTopPixels(numeric, bridge), bridge);
1446
- }
1447
- function getSafeAreaTop() {
1448
- const bridge = getBridgeWindow8();
1449
- if (!bridge) {
1450
- return 0;
1451
- }
1452
- if (typeof bridge.getSafeAreaTopPercent === "function") {
1453
- const percent = resolvePercentValue(bridge.getSafeAreaTopPercent(), bridge);
1454
- if (typeof percent !== "undefined") {
1455
- return percent;
1456
- }
1457
- }
1458
- if (typeof bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__ !== "undefined") {
1459
- const percent = resolvePercentValue(bridge.__OASIZ_SAFE_AREA_TOP_PERCENT__, bridge);
1460
- if (typeof percent !== "undefined") {
1461
- return percent;
1462
- }
1463
- }
1464
- if (typeof bridge.getSafeAreaTop === "function") {
1465
- const percent = resolvePixelValue(bridge.getSafeAreaTop(), bridge);
1466
- if (typeof percent !== "undefined") {
1467
- return percent;
1468
- }
1469
- }
1470
- if (typeof bridge.__OASIZ_SAFE_AREA_TOP__ !== "undefined") {
1471
- const percent = resolvePixelValue(bridge.__OASIZ_SAFE_AREA_TOP__, bridge);
1472
- if (typeof percent !== "undefined") {
1473
- return percent;
1474
- }
1475
- }
1476
- const cssPercent = cssSafeAreaTopPercent(bridge);
1477
- if (cssPercent > 0) {
1478
- return cssPercent;
1479
- }
1480
- warnMissingBridge6("getSafeAreaTop");
1481
- return 0;
1482
- }
1483
- function setLeaderboardVisible(visible) {
1484
- if (typeof visible !== "boolean") {
1485
- if (isDevelopment9()) {
1486
- console.warn(
1487
- "[oasiz/sdk] setLeaderboardVisible expected a boolean:",
1488
- visible
1489
- );
1490
- }
1491
- return;
1492
- }
1493
- const bridge = getBridgeWindow8();
1494
- if (typeof bridge?.__oasizSetLeaderboardVisible === "function") {
1495
- bridge.__oasizSetLeaderboardVisible(visible);
1496
- return;
1497
- }
1498
- warnMissingBridge6("__oasizSetLeaderboardVisible");
1499
- }
1500
-
1501
314
  // src/navigation.ts
1502
315
  var activeBackListeners = 0;
1503
- function isDevelopment10() {
316
+ function isDevelopment7() {
1504
317
  const nodeEnv = globalThis.process?.env?.NODE_ENV;
1505
318
  return nodeEnv !== "production";
1506
319
  }
1507
- function getBridgeWindow9() {
320
+ function getBridgeWindow6() {
1508
321
  if (typeof window === "undefined") {
1509
322
  return void 0;
1510
323
  }
1511
324
  return window;
1512
325
  }
1513
- function warnMissingBridge7(methodName) {
1514
- if (isDevelopment10()) {
326
+ function warnMissingBridge4(methodName) {
327
+ if (isDevelopment7()) {
1515
328
  console.warn(
1516
329
  "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1517
330
  );
@@ -1527,7 +340,7 @@ function normalizeNavigationError(error) {
1527
340
  }
1528
341
  function addNavigationListener(eventName, callback) {
1529
342
  if (typeof window === "undefined") {
1530
- if (isDevelopment10()) {
343
+ if (isDevelopment7()) {
1531
344
  console.warn(
1532
345
  "[oasiz/sdk] " + eventName + " listener registered without a browser window. This is expected in local development."
1533
346
  );
@@ -1548,24 +361,24 @@ function onBackButton(callback) {
1548
361
  throw normalizeNavigationError(error);
1549
362
  }
1550
363
  });
1551
- const bridge = getBridgeWindow9();
364
+ const bridge = getBridgeWindow6();
1552
365
  activeBackListeners += 1;
1553
366
  if (activeBackListeners === 1) {
1554
367
  if (typeof bridge?.__oasizSetBackOverride === "function") {
1555
368
  bridge.__oasizSetBackOverride(true);
1556
369
  } else {
1557
- warnMissingBridge7("__oasizSetBackOverride");
370
+ warnMissingBridge4("__oasizSetBackOverride");
1558
371
  }
1559
372
  }
1560
373
  return () => {
1561
374
  off();
1562
375
  activeBackListeners = Math.max(0, activeBackListeners - 1);
1563
376
  if (activeBackListeners === 0) {
1564
- const currentBridge = getBridgeWindow9();
377
+ const currentBridge = getBridgeWindow6();
1565
378
  if (typeof currentBridge?.__oasizSetBackOverride === "function") {
1566
379
  currentBridge.__oasizSetBackOverride(false);
1567
380
  } else {
1568
- warnMissingBridge7("__oasizSetBackOverride");
381
+ warnMissingBridge4("__oasizSetBackOverride");
1569
382
  }
1570
383
  }
1571
384
  };
@@ -1574,79 +387,177 @@ function onLeaveGame(callback) {
1574
387
  return addNavigationListener("oasiz:leave", callback);
1575
388
  }
1576
389
  function leaveGame() {
1577
- const bridge = getBridgeWindow9();
390
+ const bridge = getBridgeWindow6();
1578
391
  if (typeof bridge?.__oasizLeaveGame === "function") {
1579
392
  bridge.__oasizLeaveGame();
1580
393
  return;
1581
394
  }
1582
- warnMissingBridge7("__oasizLeaveGame");
395
+ warnMissingBridge4("__oasizLeaveGame");
396
+ }
397
+
398
+ // src/store.ts
399
+ function isDevelopment8() {
400
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
401
+ return nodeEnv !== "production";
402
+ }
403
+ function getBridgeWindow7() {
404
+ if (typeof window === "undefined") {
405
+ return void 0;
406
+ }
407
+ return window;
408
+ }
409
+ function warnMissingBridge5(methodName) {
410
+ if (isDevelopment8()) {
411
+ console.warn(
412
+ "[oasiz/sdk] " + methodName + " store bridge is unavailable. This is expected in local development."
413
+ );
414
+ }
415
+ }
416
+ async function requestStoreBridge(action, payload) {
417
+ const bridge = getBridgeWindow7();
418
+ if (typeof bridge?.__oasizStoreBridgeRequest !== "function") {
419
+ warnMissingBridge5(action);
420
+ throw new Error("Store bridge unavailable");
421
+ }
422
+ return await bridge.__oasizStoreBridgeRequest({
423
+ action,
424
+ payload
425
+ });
426
+ }
427
+ async function getFreshState() {
428
+ return await requestStoreBridge("getStoreState");
429
+ }
430
+ function subscribeToStoreEvent(eventName, callback) {
431
+ if (typeof window === "undefined") {
432
+ return () => {
433
+ };
434
+ }
435
+ const handler = (event) => {
436
+ const customEvent = event;
437
+ callback(customEvent.detail);
438
+ };
439
+ window.addEventListener(eventName, handler);
440
+ return () => {
441
+ window.removeEventListener(eventName, handler);
442
+ };
443
+ }
444
+ async function syncProducts(products, expectedVersion) {
445
+ return await requestStoreBridge("syncProducts", {
446
+ expectedVersion: expectedVersion ?? null,
447
+ products
448
+ });
449
+ }
450
+ async function getProducts() {
451
+ const state = await getFreshState();
452
+ return state.products;
453
+ }
454
+ async function getEntitlements() {
455
+ const state = await getFreshState();
456
+ return state.entitlements;
457
+ }
458
+ async function hasEntitlement(productId) {
459
+ const state = await getFreshState();
460
+ return state.entitlements.find((item) => item.productId === productId)?.owned === true;
461
+ }
462
+ async function getQuantity(productId) {
463
+ const state = await getFreshState();
464
+ return state.entitlements.find((item) => item.productId === productId)?.quantity ?? 0;
465
+ }
466
+ async function purchase(productId, quantity = 1) {
467
+ return await requestStoreBridge("purchaseProduct", {
468
+ productId,
469
+ quantity
470
+ });
471
+ }
472
+ async function consume(productId, quantity = 1) {
473
+ return await requestStoreBridge("consumeProduct", {
474
+ productId,
475
+ quantity
476
+ });
477
+ }
478
+ async function getJemBalance() {
479
+ const state = await getFreshState();
480
+ return state.jemBalance;
481
+ }
482
+ function onEntitlementsChanged(callback) {
483
+ return subscribeToStoreEvent("oasiz:entitlements-changed", (state) => {
484
+ callback(state.entitlements);
485
+ });
486
+ }
487
+ function onJemBalanceChanged(callback) {
488
+ return subscribeToStoreEvent("oasiz:jem-balance-changed", (state) => {
489
+ callback(state.jemBalance);
490
+ });
1583
491
  }
1584
492
 
1585
493
  // src/index.ts
1586
494
  var oasiz = {
1587
495
  submitScore,
1588
- addScore,
1589
- setScore,
1590
- getPlayerCharacter,
496
+ emitScoreConfig,
1591
497
  share,
1592
498
  triggerHaptic,
1593
- enableLogOverlay,
1594
499
  loadGameState,
1595
500
  saveGameState,
1596
501
  flushGameState,
1597
502
  shareRoomCode,
1598
- openInviteModal,
1599
503
  onPause,
1600
504
  onResume,
1601
- getSafeAreaTop,
1602
- setLeaderboardVisible,
1603
505
  onBackButton,
1604
506
  onLeaveGame,
1605
507
  leaveGame,
508
+ store: {
509
+ syncProducts,
510
+ getProducts,
511
+ getEntitlements,
512
+ hasEntitlement,
513
+ getQuantity,
514
+ purchase,
515
+ consume,
516
+ getJemBalance,
517
+ onEntitlementsChanged,
518
+ onJemBalanceChanged
519
+ },
1606
520
  get gameId() {
1607
521
  return getGameId();
1608
522
  },
1609
523
  get roomCode() {
1610
524
  return getRoomCode();
1611
525
  },
1612
- get playerId() {
1613
- return getPlayerId();
1614
- },
1615
526
  get playerName() {
1616
527
  return getPlayerName();
1617
528
  },
1618
529
  get playerAvatar() {
1619
530
  return getPlayerAvatar();
1620
- },
1621
- get safeAreaTop() {
1622
- return getSafeAreaTop();
1623
531
  }
1624
532
  };
1625
533
  // Annotate the CommonJS export names for ESM import in node:
1626
534
  0 && (module.exports = {
1627
- addScore,
1628
- enableLogOverlay,
535
+ consume,
536
+ emitScoreConfig,
1629
537
  flushGameState,
538
+ getEntitlements,
1630
539
  getGameId,
540
+ getJemBalance,
1631
541
  getPlayerAvatar,
1632
- getPlayerCharacter,
1633
- getPlayerId,
1634
542
  getPlayerName,
543
+ getProducts,
544
+ getQuantity,
1635
545
  getRoomCode,
1636
- getSafeAreaTop,
546
+ hasEntitlement,
1637
547
  leaveGame,
1638
548
  loadGameState,
1639
549
  oasiz,
1640
550
  onBackButton,
551
+ onEntitlementsChanged,
552
+ onJemBalanceChanged,
1641
553
  onLeaveGame,
1642
554
  onPause,
1643
555
  onResume,
1644
- openInviteModal,
556
+ purchase,
1645
557
  saveGameState,
1646
- setLeaderboardVisible,
1647
- setScore,
1648
558
  share,
1649
559
  shareRoomCode,
1650
560
  submitScore,
561
+ syncProducts,
1651
562
  triggerHaptic
1652
563
  });