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