@mentra/crust 0.1.0-beta.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.
Files changed (66) hide show
  1. package/README.md +41 -0
  2. package/android/build.gradle +146 -0
  3. package/android/src/internal/AndroidManifest.xml +9 -0
  4. package/android/src/internal/java/com/mentra/crust/receivers/CaptionsTesterIncidentReceiver.kt +46 -0
  5. package/android/src/main/AndroidManifest.xml +19 -0
  6. package/android/src/main/java/com/mentra/crust/CrustModule.kt +1042 -0
  7. package/android/src/main/java/com/mentra/crust/CrustView.kt +30 -0
  8. package/android/src/main/java/com/mentra/crust/heading/HeadingManager.kt +150 -0
  9. package/android/src/main/java/com/mentra/crust/jsc/JSCDispatcher.kt +189 -0
  10. package/android/src/main/java/com/mentra/crust/jsc/JSCPolyfillBridge.kt +287 -0
  11. package/android/src/main/java/com/mentra/crust/jsc/JSCRuntime.kt +593 -0
  12. package/android/src/main/java/com/mentra/crust/navigation/NavigationManager.kt +1445 -0
  13. package/android/src/main/java/com/mentra/crust/services/NotificationListener.kt +319 -0
  14. package/android/src/main/java/com/mentra/crust/utils/ImageProcessor.java +452 -0
  15. package/android/src/main/java/com/mentra/crust/utils/VideoStabilizer.kt +556 -0
  16. package/android/src/main/res/values/strings.xml +3 -0
  17. package/app.plugin.js +3 -0
  18. package/build/Crust.types.d.ts +148 -0
  19. package/build/Crust.types.d.ts.map +1 -0
  20. package/build/Crust.types.js +2 -0
  21. package/build/Crust.types.js.map +1 -0
  22. package/build/CrustModule.d.ts +182 -0
  23. package/build/CrustModule.d.ts.map +1 -0
  24. package/build/CrustModule.js +4 -0
  25. package/build/CrustModule.js.map +1 -0
  26. package/build/CrustModule.web.d.ts +34 -0
  27. package/build/CrustModule.web.d.ts.map +1 -0
  28. package/build/CrustModule.web.js +63 -0
  29. package/build/CrustModule.web.js.map +1 -0
  30. package/build/CrustView.d.ts +4 -0
  31. package/build/CrustView.d.ts.map +1 -0
  32. package/build/CrustView.js +7 -0
  33. package/build/CrustView.js.map +1 -0
  34. package/build/CrustView.web.d.ts +4 -0
  35. package/build/CrustView.web.d.ts.map +1 -0
  36. package/build/CrustView.web.js +7 -0
  37. package/build/CrustView.web.js.map +1 -0
  38. package/build/index.d.ts +4 -0
  39. package/build/index.d.ts.map +1 -0
  40. package/build/index.js +6 -0
  41. package/build/index.js.map +1 -0
  42. package/expo-module.config.json +9 -0
  43. package/ios/Crust.podspec +65 -0
  44. package/ios/CrustModule.swift +781 -0
  45. package/ios/CrustView.swift +38 -0
  46. package/ios/Resources/startup.js +814 -0
  47. package/ios/Source/JSCDispatcher.swift +226 -0
  48. package/ios/Source/JSCPolyfillBridge.swift +378 -0
  49. package/ios/Source/JSCRuntime.swift +673 -0
  50. package/ios/Source/utils/ImageProcessor.swift +392 -0
  51. package/ios/Source/utils/SystemGestures.swift +53 -0
  52. package/ios/Source/utils/VideoStabilizer.swift +374 -0
  53. package/ios/heading/HeadingManager.swift +74 -0
  54. package/ios/navigation/NavPayloads.swift +62 -0
  55. package/ios/navigation/NavigationManager.swift +720 -0
  56. package/package.json +69 -0
  57. package/plugin/build/index.d.ts +19 -0
  58. package/plugin/build/index.js +23 -0
  59. package/plugin/build/withAndroid.d.ts +2 -0
  60. package/plugin/build/withAndroid.js +78 -0
  61. package/src/Crust.types.ts +157 -0
  62. package/src/CrustModule.ts +191 -0
  63. package/src/CrustModule.web.ts +66 -0
  64. package/src/CrustView.tsx +10 -0
  65. package/src/CrustView.web.tsx +11 -0
  66. package/src/index.ts +5 -0
@@ -0,0 +1,814 @@
1
+ // @generated MentraJS polyfill bundle — see mobile/modules/jspolyfill
2
+ "use strict";
3
+ (() => {
4
+ // src/startup.ts
5
+ (function installMentraJSRuntime() {
6
+ const g = globalThis;
7
+ function installConsole() {
8
+ const safeStringify = (args) => {
9
+ try {
10
+ return JSON.stringify(
11
+ args.map((a) => {
12
+ if (a instanceof Error) {
13
+ return { __error: true, name: a.name, message: a.message, stack: a.stack };
14
+ }
15
+ return a;
16
+ })
17
+ );
18
+ } catch {
19
+ return JSON.stringify(args.map((a) => String(a)));
20
+ }
21
+ };
22
+ const make = (level, prev) => {
23
+ return (...args) => {
24
+ try {
25
+ __hostLog(level, safeStringify(args));
26
+ } catch {
27
+ }
28
+ if (prev) {
29
+ try {
30
+ prev(...args);
31
+ } catch {
32
+ }
33
+ }
34
+ };
35
+ };
36
+ const prevConsole = g.console;
37
+ const c = {
38
+ log: make("log", prevConsole?.log?.bind(prevConsole)),
39
+ info: make("info", prevConsole?.info?.bind(prevConsole)),
40
+ warn: make("warn", prevConsole?.warn?.bind(prevConsole)),
41
+ error: make("error", prevConsole?.error?.bind(prevConsole)),
42
+ debug: make("debug", prevConsole?.debug?.bind(prevConsole)),
43
+ trace: make("trace", prevConsole?.trace?.bind(prevConsole))
44
+ };
45
+ g.console = c;
46
+ }
47
+ installConsole();
48
+ g.onerror = (msg, src, line, col, err) => {
49
+ try {
50
+ __hostError(
51
+ JSON.stringify({
52
+ message: String(msg),
53
+ src: src ?? "",
54
+ line: line ?? 0,
55
+ col: col ?? 0,
56
+ stack: err && err.stack ? err.stack : ""
57
+ })
58
+ );
59
+ } catch {
60
+ }
61
+ return false;
62
+ };
63
+ try {
64
+ const origThen = g.Promise.prototype.then;
65
+ const seen = /* @__PURE__ */ new WeakSet();
66
+ g.Promise.prototype.then = function patchedThen(onFulfilled, onRejected) {
67
+ seen.add(this);
68
+ return origThen.call(this, onFulfilled, onRejected);
69
+ };
70
+ g.__reportUnhandledRejection = (reason) => {
71
+ try {
72
+ __hostUnhandledRejection(
73
+ JSON.stringify({
74
+ reason: reason instanceof Error ? { message: reason.message, stack: reason.stack } : reason
75
+ })
76
+ );
77
+ } catch {
78
+ }
79
+ };
80
+ } catch {
81
+ }
82
+ function installTimers() {
83
+ const callbacks = /* @__PURE__ */ new Map();
84
+ let nextToken = 1;
85
+ g.__deliverTimer = (token) => {
86
+ const entry = callbacks.get(token);
87
+ if (!entry) return;
88
+ try {
89
+ entry.fn();
90
+ } catch (e) {
91
+ try {
92
+ __hostError(
93
+ JSON.stringify({
94
+ message: e instanceof Error ? e.message : String(e),
95
+ stack: e instanceof Error ? e.stack : void 0,
96
+ source: "timer",
97
+ token
98
+ })
99
+ );
100
+ } catch {
101
+ }
102
+ }
103
+ if (entry.repeating) {
104
+ try {
105
+ __nativeSetTimeout(token, entry.interval);
106
+ } catch {
107
+ callbacks.delete(token);
108
+ }
109
+ } else {
110
+ callbacks.delete(token);
111
+ }
112
+ };
113
+ const installSetTimeout = g.setTimeout == null || g.__mentraOwnsSetTimeout;
114
+ if (installSetTimeout) {
115
+ g.setTimeout = (fn, delayMs, ...rest) => {
116
+ const token = nextToken++;
117
+ const ms = typeof delayMs === "number" ? Math.max(0, delayMs) : 0;
118
+ callbacks.set(token, {
119
+ fn: () => fn(...rest),
120
+ repeating: false,
121
+ interval: ms
122
+ });
123
+ try {
124
+ __nativeSetTimeout(token, ms);
125
+ } catch {
126
+ callbacks.delete(token);
127
+ return -1;
128
+ }
129
+ return token;
130
+ };
131
+ g.clearTimeout = (token) => {
132
+ if (typeof token !== "number") return;
133
+ callbacks.delete(token);
134
+ try {
135
+ __nativeClearTimer(token);
136
+ } catch {
137
+ }
138
+ };
139
+ g.__mentraOwnsSetTimeout = true;
140
+ }
141
+ g.setInterval = (fn, delayMs, ...rest) => {
142
+ const token = nextToken++;
143
+ const ms = typeof delayMs === "number" ? Math.max(0, delayMs) : 0;
144
+ callbacks.set(token, {
145
+ fn: () => fn(...rest),
146
+ repeating: true,
147
+ interval: ms
148
+ });
149
+ try {
150
+ __nativeSetTimeout(token, ms);
151
+ } catch {
152
+ callbacks.delete(token);
153
+ return -1;
154
+ }
155
+ return token;
156
+ };
157
+ g.clearInterval = (token) => {
158
+ if (typeof token !== "number") return;
159
+ callbacks.delete(token);
160
+ try {
161
+ __nativeClearTimer(token);
162
+ } catch {
163
+ }
164
+ };
165
+ if (typeof g.queueMicrotask !== "function") {
166
+ g.queueMicrotask = (cb) => {
167
+ g.Promise.resolve().then(() => {
168
+ try {
169
+ cb();
170
+ } catch (e) {
171
+ try {
172
+ __hostError(
173
+ JSON.stringify({
174
+ message: e instanceof Error ? e.message : String(e),
175
+ stack: e instanceof Error ? e.stack : void 0,
176
+ source: "queueMicrotask"
177
+ })
178
+ );
179
+ } catch {
180
+ }
181
+ }
182
+ });
183
+ };
184
+ }
185
+ }
186
+ installTimers();
187
+ function installAbortController() {
188
+ if (typeof g.AbortController === "function") return;
189
+ class MentraAbortSignal {
190
+ constructor() {
191
+ this.aborted = false;
192
+ this.reason = void 0;
193
+ this.listeners = /* @__PURE__ */ new Set();
194
+ }
195
+ addEventListener(type, cb) {
196
+ if (type !== "abort" || typeof cb !== "function") return;
197
+ if (this.aborted) {
198
+ try {
199
+ cb();
200
+ } catch {
201
+ }
202
+ return;
203
+ }
204
+ this.listeners.add(cb);
205
+ }
206
+ removeEventListener(type, cb) {
207
+ if (type !== "abort") return;
208
+ this.listeners.delete(cb);
209
+ }
210
+ /** @internal — only invoked by the owning AbortController.abort(). */
211
+ __fire(reason) {
212
+ if (this.aborted) return;
213
+ this.aborted = true;
214
+ this.reason = reason;
215
+ for (const cb of this.listeners) {
216
+ try {
217
+ cb();
218
+ } catch {
219
+ }
220
+ }
221
+ this.listeners.clear();
222
+ }
223
+ }
224
+ class MentraAbortController {
225
+ constructor() {
226
+ this.signal = new MentraAbortSignal();
227
+ }
228
+ abort(reason) {
229
+ this.signal.__fire(reason ?? new Error("aborted"));
230
+ }
231
+ }
232
+ ;
233
+ MentraAbortSignal.any = (signals) => {
234
+ const out = new MentraAbortSignal();
235
+ const onAbort = (s) => {
236
+ if (!out.aborted) out.__fire(s.reason);
237
+ };
238
+ for (const s of signals) {
239
+ if (s.aborted) {
240
+ onAbort(s);
241
+ break;
242
+ }
243
+ s.addEventListener("abort", () => onAbort(s));
244
+ }
245
+ return out;
246
+ };
247
+ g.AbortController = MentraAbortController;
248
+ g.AbortSignal = MentraAbortSignal;
249
+ }
250
+ installAbortController();
251
+ const pending = /* @__PURE__ */ new Map();
252
+ let nextReqId = 1;
253
+ g.__deliver = (envelopeJson) => {
254
+ let env;
255
+ try {
256
+ env = JSON.parse(envelopeJson);
257
+ } catch {
258
+ try {
259
+ __hostError(JSON.stringify({ message: "Bad __deliver envelope JSON", source: "__deliver" }));
260
+ } catch {
261
+ }
262
+ return;
263
+ }
264
+ if (env.kind === "response" && env.reqId) {
265
+ const handlers = pending.get(env.reqId);
266
+ if (handlers) {
267
+ pending.delete(env.reqId);
268
+ if (env.ok) {
269
+ handlers.resolve(env.result);
270
+ } else {
271
+ handlers.reject(env.error ?? { code: "NATIVE_THROW", message: "Unknown native error" });
272
+ }
273
+ }
274
+ return;
275
+ }
276
+ if (env.kind === "event" && typeof env.iface === "string") {
277
+ const listeners = g.__mentraEventListeners ?? /* @__PURE__ */ new Map();
278
+ const set = listeners.get(env.iface);
279
+ if (set) {
280
+ for (const l of set) {
281
+ try {
282
+ l(env.payload);
283
+ } catch (e) {
284
+ try {
285
+ __hostError(
286
+ JSON.stringify({
287
+ message: e instanceof Error ? e.message : String(e),
288
+ stack: e instanceof Error ? e.stack : void 0,
289
+ source: `event:${env.iface}`
290
+ })
291
+ );
292
+ } catch {
293
+ }
294
+ }
295
+ }
296
+ }
297
+ return;
298
+ }
299
+ if (env.kind === "ws-event") {
300
+ const wsHook = g.__mentraDeliverWebSocketEvent;
301
+ const sid = env.sid;
302
+ const wsType = env.wsType;
303
+ if (typeof wsHook === "function" && typeof sid === "string" && typeof wsType === "string") {
304
+ wsHook(sid, wsType, env.payload ?? {});
305
+ }
306
+ return;
307
+ }
308
+ if (env.kind === "bridge" && typeof env.raw === "string") {
309
+ const deliver = g.__mentraDeliverBridgeRaw;
310
+ if (typeof deliver === "function") {
311
+ deliver(env.raw);
312
+ }
313
+ return;
314
+ }
315
+ if (env.kind === "init" && typeof env.sessionId === "string") {
316
+ ;
317
+ g.__mentraSessionId = env.sessionId;
318
+ const initCb = g.__mentraInitCallback;
319
+ if (initCb) initCb(env.sessionId);
320
+ }
321
+ };
322
+ g.__mentraSendOneShot = (iface, method, args) => {
323
+ try {
324
+ __dispatch(iface, method, JSON.stringify(args ?? []));
325
+ } catch (e) {
326
+ try {
327
+ __hostError(
328
+ JSON.stringify({
329
+ message: e instanceof Error ? e.message : String(e),
330
+ source: `oneShot:${iface}.${method}`
331
+ })
332
+ );
333
+ } catch {
334
+ }
335
+ }
336
+ };
337
+ g.__mentraSendRequest = (iface, method, args) => {
338
+ return new g.Promise((resolve, reject) => {
339
+ const reqId = `${nextReqId++}`;
340
+ pending.set(reqId, { resolve, reject });
341
+ try {
342
+ __dispatch(iface, method, JSON.stringify({ args: args ?? [], reqId }));
343
+ } catch (e) {
344
+ pending.delete(reqId);
345
+ reject({ code: "NATIVE_THROW", message: e instanceof Error ? e.message : String(e) });
346
+ }
347
+ });
348
+ };
349
+ g.__mentraEventListeners = /* @__PURE__ */ new Map();
350
+ g.__mentraSubscribe = (iface, cb) => {
351
+ const map = g.__mentraEventListeners;
352
+ let set = map.get(iface);
353
+ if (!set) {
354
+ set = /* @__PURE__ */ new Set();
355
+ map.set(iface, set);
356
+ }
357
+ set.add(cb);
358
+ return () => {
359
+ set.delete(cb);
360
+ };
361
+ };
362
+ const dispatchSyncOrNull = (iface, method, args) => {
363
+ try {
364
+ const raw = __dispatch(iface, method, JSON.stringify(args ?? []));
365
+ if (raw == null) return null;
366
+ try {
367
+ return JSON.parse(raw);
368
+ } catch {
369
+ return raw;
370
+ }
371
+ } catch {
372
+ return null;
373
+ }
374
+ };
375
+ g.__mentraDispatchSync = dispatchSyncOrNull;
376
+ const localStorage = {
377
+ getItem(key) {
378
+ const v = dispatchSyncOrNull("localStorage", "getItem", [String(key)]);
379
+ return typeof v === "string" ? v : null;
380
+ },
381
+ setItem(key, value) {
382
+ dispatchSyncOrNull("localStorage", "setItem", [String(key), String(value)]);
383
+ },
384
+ removeItem(key) {
385
+ dispatchSyncOrNull("localStorage", "removeItem", [String(key)]);
386
+ },
387
+ clear() {
388
+ dispatchSyncOrNull("localStorage", "clear", []);
389
+ },
390
+ key(index) {
391
+ const v = dispatchSyncOrNull("localStorage", "key", [Number(index)]);
392
+ return typeof v === "string" ? v : null;
393
+ },
394
+ get length() {
395
+ const v = dispatchSyncOrNull("localStorage", "length", []);
396
+ return typeof v === "number" ? v : 0;
397
+ }
398
+ };
399
+ g.localStorage = localStorage;
400
+ const cryptoNs = g.crypto ?? {};
401
+ if (typeof cryptoNs.getRandomValues !== "function") {
402
+ cryptoNs.getRandomValues = (arr) => {
403
+ const bytes = dispatchSyncOrNull("crypto", "getRandomBytes", [arr.byteLength]);
404
+ if (!Array.isArray(bytes) || bytes.length !== arr.byteLength) {
405
+ const view = new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
406
+ for (let i = 0; i < view.length; i++) view[i] = Math.floor(Math.random() * 256);
407
+ } else {
408
+ const view = new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
409
+ for (let i = 0; i < bytes.length; i++) view[i] = bytes[i] & 255;
410
+ }
411
+ return arr;
412
+ };
413
+ }
414
+ if (typeof cryptoNs.randomUUID !== "function") {
415
+ cryptoNs.randomUUID = () => {
416
+ const buf = new Uint8Array(16);
417
+ cryptoNs.getRandomValues(buf);
418
+ buf[6] = buf[6] & 15 | 64;
419
+ buf[8] = buf[8] & 63 | 128;
420
+ const hex = Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join("");
421
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
422
+ };
423
+ }
424
+ if (!cryptoNs.subtle) {
425
+ const notImplemented = () => {
426
+ throw new Error(
427
+ "crypto.subtle is not yet implemented in MentraJS \u2014 see agents/mentrajs-two-layer-miniapp-architecture.md (Polyfill strategy section). Use a pure-JS hash/encrypt library for now."
428
+ );
429
+ };
430
+ cryptoNs.subtle = new Proxy(
431
+ {},
432
+ {
433
+ get: () => notImplemented
434
+ }
435
+ );
436
+ }
437
+ ;
438
+ g.crypto = cryptoNs;
439
+ if (typeof g.TextEncoder !== "function") {
440
+ class TextEncoderPolyfill {
441
+ constructor() {
442
+ this.encoding = "utf-8";
443
+ }
444
+ encode(input) {
445
+ const str = input ?? "";
446
+ const out = [];
447
+ for (let i = 0; i < str.length; i++) {
448
+ let code = str.charCodeAt(i);
449
+ if (code >= 55296 && code <= 56319 && i + 1 < str.length) {
450
+ const next = str.charCodeAt(i + 1);
451
+ if (next >= 56320 && next <= 57343) {
452
+ code = (code - 55296 << 10) + (next - 56320) + 65536;
453
+ i++;
454
+ }
455
+ }
456
+ if (code < 128) {
457
+ out.push(code);
458
+ } else if (code < 2048) {
459
+ out.push(192 | code >> 6, 128 | code & 63);
460
+ } else if (code < 65536) {
461
+ out.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
462
+ } else {
463
+ out.push(
464
+ 240 | code >> 18,
465
+ 128 | code >> 12 & 63,
466
+ 128 | code >> 6 & 63,
467
+ 128 | code & 63
468
+ );
469
+ }
470
+ }
471
+ return new Uint8Array(out);
472
+ }
473
+ }
474
+ ;
475
+ g.TextEncoder = TextEncoderPolyfill;
476
+ }
477
+ if (typeof g.TextDecoder !== "function") {
478
+ class TextDecoderPolyfill {
479
+ constructor(encoding = "utf-8") {
480
+ this.encoding = encoding;
481
+ }
482
+ decode(buffer) {
483
+ if (!buffer) return "";
484
+ const bytes = buffer instanceof Uint8Array ? buffer : buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
485
+ let out = "";
486
+ let i = 0;
487
+ while (i < bytes.length) {
488
+ const b1 = bytes[i++];
489
+ let code;
490
+ if (b1 < 128) {
491
+ code = b1;
492
+ } else if (b1 < 192) {
493
+ code = 65533;
494
+ } else if (b1 < 224) {
495
+ code = (b1 & 31) << 6 | bytes[i++] & 63;
496
+ } else if (b1 < 240) {
497
+ code = (b1 & 15) << 12 | (bytes[i++] & 63) << 6 | bytes[i++] & 63;
498
+ } else {
499
+ code = (b1 & 7) << 18 | (bytes[i++] & 63) << 12 | (bytes[i++] & 63) << 6 | bytes[i++] & 63;
500
+ }
501
+ if (code > 65535) {
502
+ code -= 65536;
503
+ out += String.fromCharCode(55296 + (code >> 10), 56320 + (code & 1023));
504
+ } else {
505
+ out += String.fromCharCode(code);
506
+ }
507
+ }
508
+ return out;
509
+ }
510
+ }
511
+ ;
512
+ g.TextDecoder = TextDecoderPolyfill;
513
+ }
514
+ if (typeof g.btoa !== "function") {
515
+ const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
516
+ g.btoa = (input) => {
517
+ let out = "";
518
+ let i = 0;
519
+ while (i < input.length) {
520
+ const c1 = input.charCodeAt(i++);
521
+ const c2 = i < input.length ? input.charCodeAt(i++) : NaN;
522
+ const c3 = i < input.length ? input.charCodeAt(i++) : NaN;
523
+ const e1 = c1 >> 2;
524
+ const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
525
+ const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
526
+ const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
527
+ out += b64[e1] + b64[e2] + (e3 === 64 ? "=" : b64[e3]) + (e4 === 64 ? "=" : b64[e4]);
528
+ }
529
+ return out;
530
+ };
531
+ g.atob = (input) => {
532
+ const clean = input.replace(/=+$/, "");
533
+ let out = "";
534
+ let buf = 0;
535
+ let bits = 0;
536
+ for (let i = 0; i < clean.length; i++) {
537
+ const idx = b64.indexOf(clean[i]);
538
+ if (idx < 0) continue;
539
+ buf = buf << 6 | idx;
540
+ bits += 6;
541
+ if (bits >= 8) {
542
+ bits -= 8;
543
+ out += String.fromCharCode(buf >> bits & 255);
544
+ }
545
+ }
546
+ return out;
547
+ };
548
+ }
549
+ if (typeof g.fetch !== "function") {
550
+ ;
551
+ g.fetch = async (input, init) => {
552
+ const url = typeof input === "string" ? input : input.toString();
553
+ const method = (init?.method ?? "GET").toUpperCase();
554
+ let bodyString = null;
555
+ const reqBody = init?.body;
556
+ if (typeof reqBody === "string") {
557
+ bodyString = reqBody;
558
+ } else if (reqBody && typeof reqBody.toString === "function") {
559
+ bodyString = reqBody.toString();
560
+ }
561
+ const headers = {};
562
+ const rawHeaders = init?.headers;
563
+ if (rawHeaders) {
564
+ if (Array.isArray(rawHeaders)) {
565
+ for (const [k, v] of rawHeaders) {
566
+ if (k != null) headers[String(k)] = String(v);
567
+ }
568
+ } else if (typeof rawHeaders.forEach === "function") {
569
+ ;
570
+ rawHeaders.forEach((v, k) => {
571
+ headers[k] = v;
572
+ });
573
+ } else {
574
+ for (const [k, v] of Object.entries(rawHeaders)) {
575
+ headers[String(k)] = String(v);
576
+ }
577
+ }
578
+ }
579
+ const sendRequest = g.__mentraSendRequest;
580
+ const result = await sendRequest("fetch", "request", [
581
+ { url, method, headers, body: bodyString }
582
+ ]);
583
+ const bodyText = typeof result.body === "string" ? result.body : "";
584
+ const responseHeaders = new Map(Object.entries(result.headers ?? {}));
585
+ class ResponseLike {
586
+ constructor() {
587
+ this.status = result.status;
588
+ this.statusText = result.statusText ?? "";
589
+ this.ok = result.ok ?? (result.status >= 200 && result.status < 300);
590
+ this.url = url;
591
+ this.headers = {
592
+ get: (k) => responseHeaders.get(k.toLowerCase()) ?? null,
593
+ has: (k) => responseHeaders.has(k.toLowerCase()),
594
+ forEach: (cb) => {
595
+ for (const [k, v] of responseHeaders) cb(v, k);
596
+ }
597
+ };
598
+ }
599
+ async text() {
600
+ return bodyText;
601
+ }
602
+ async json() {
603
+ try {
604
+ return JSON.parse(bodyText);
605
+ } catch (e) {
606
+ const err = new Error(
607
+ `Failed to parse JSON response from ${url}: ${e instanceof Error ? e.message : String(e)}`
608
+ );
609
+ err.name = "SyntaxError";
610
+ throw err;
611
+ }
612
+ }
613
+ async arrayBuffer() {
614
+ const enc = new g.TextEncoder();
615
+ return enc.encode(bodyText).buffer;
616
+ }
617
+ }
618
+ return new ResponseLike();
619
+ };
620
+ }
621
+ if (typeof g.WebSocket !== "function") {
622
+ let bytesToBase642 = function(bytes) {
623
+ const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
624
+ let out = "";
625
+ let i = 0;
626
+ while (i < bytes.length) {
627
+ const c1 = bytes[i++];
628
+ const c2 = i < bytes.length ? bytes[i++] : NaN;
629
+ const c3 = i < bytes.length ? bytes[i++] : NaN;
630
+ const e1 = c1 >> 2;
631
+ const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
632
+ const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
633
+ const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
634
+ out += b64[e1] + b64[e2] + (e3 === 64 ? "=" : b64[e3]) + (e4 === 64 ? "=" : b64[e4]);
635
+ }
636
+ return out;
637
+ }, base64ToBytes2 = function(s) {
638
+ const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
639
+ const clean = s.replace(/=+$/, "");
640
+ const out = [];
641
+ let buf = 0;
642
+ let bits = 0;
643
+ for (let i = 0; i < clean.length; i++) {
644
+ const idx = b64.indexOf(clean[i]);
645
+ if (idx < 0) continue;
646
+ buf = buf << 6 | idx;
647
+ bits += 6;
648
+ if (bits >= 8) {
649
+ bits -= 8;
650
+ out.push(buf >> bits & 255);
651
+ }
652
+ }
653
+ return new Uint8Array(out);
654
+ }, queueMicrotaskSafe2 = function(fn) {
655
+ const q = g.queueMicrotask;
656
+ if (typeof q === "function") q(fn);
657
+ else g.Promise.resolve().then(fn);
658
+ };
659
+ var bytesToBase64 = bytesToBase642, base64ToBytes = base64ToBytes2, queueMicrotaskSafe = queueMicrotaskSafe2;
660
+ const sockets = /* @__PURE__ */ new Map();
661
+ g.__mentraDeliverWebSocketEvent = (sid, type, payload) => {
662
+ const sock = sockets.get(sid);
663
+ if (!sock) return;
664
+ sock._deliver(type, payload ?? {});
665
+ };
666
+ class MentraWebSocket {
667
+ constructor(url, protocols) {
668
+ this.CONNECTING = 0;
669
+ this.OPEN = 1;
670
+ this.CLOSING = 2;
671
+ this.CLOSED = 3;
672
+ this.readyState = 0;
673
+ this.bufferedAmount = 0;
674
+ this.extensions = "";
675
+ this.protocol = "";
676
+ this.binaryType = "arraybuffer";
677
+ this.onopen = null;
678
+ this.onmessage = null;
679
+ this.onerror = null;
680
+ this.onclose = null;
681
+ this.listeners = {
682
+ open: /* @__PURE__ */ new Set(),
683
+ message: /* @__PURE__ */ new Set(),
684
+ error: /* @__PURE__ */ new Set(),
685
+ close: /* @__PURE__ */ new Set()
686
+ };
687
+ this.url = String(url);
688
+ const protoList = Array.isArray(protocols) ? protocols : protocols ? [protocols] : [];
689
+ this.sid = `ws-${Date.now()}-${Math.floor(Math.random() * 1e9)}`;
690
+ sockets.set(this.sid, this);
691
+ try {
692
+ __dispatch(
693
+ "ws",
694
+ "open",
695
+ JSON.stringify([{ sid: this.sid, url: this.url, protocols: protoList }])
696
+ );
697
+ } catch (e) {
698
+ this.readyState = 3;
699
+ queueMicrotaskSafe2(() => this._deliver("error", { message: String(e) }));
700
+ queueMicrotaskSafe2(() => this._deliver("close", { code: 1006, reason: "bridge unavailable" }));
701
+ }
702
+ }
703
+ addEventListener(type, cb) {
704
+ if (!this.listeners[type]) this.listeners[type] = /* @__PURE__ */ new Set();
705
+ this.listeners[type].add(cb);
706
+ }
707
+ removeEventListener(type, cb) {
708
+ this.listeners[type]?.delete(cb);
709
+ }
710
+ send(data) {
711
+ if (this.readyState === 3) {
712
+ throw new Error("WebSocket is already in CLOSING or CLOSED state.");
713
+ }
714
+ let kind;
715
+ let payload;
716
+ if (typeof data === "string") {
717
+ kind = "text";
718
+ payload = data;
719
+ } else {
720
+ kind = "binary";
721
+ const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
722
+ payload = bytesToBase642(bytes);
723
+ }
724
+ try {
725
+ __dispatch("ws", "send", JSON.stringify([{ sid: this.sid, kind, payload }]));
726
+ } catch (e) {
727
+ this._deliver("error", { message: String(e) });
728
+ }
729
+ }
730
+ close(code, reason) {
731
+ if (this.readyState === 2 || this.readyState === 3) return;
732
+ this.readyState = 2;
733
+ try {
734
+ __dispatch(
735
+ "ws",
736
+ "close",
737
+ JSON.stringify([{ sid: this.sid, code: code ?? 1e3, reason: reason ?? "" }])
738
+ );
739
+ } catch (e) {
740
+ this.readyState = 3;
741
+ this._deliver("close", { code: 1006, reason: String(e) });
742
+ }
743
+ }
744
+ /** @internal — called by __deliver via the global hook. */
745
+ _deliver(type, ev) {
746
+ if (type === "open") {
747
+ this.readyState = 1;
748
+ if (typeof ev.protocol === "string") this.protocol = ev.protocol;
749
+ } else if (type === "close") {
750
+ this.readyState = 3;
751
+ sockets.delete(this.sid);
752
+ }
753
+ const synth = { type, target: this, ...ev };
754
+ if (type === "message" && ev.kind === "binary" && typeof ev.data === "string") {
755
+ synth.data = base64ToBytes2(ev.data).buffer;
756
+ } else if (type === "message" && ev.kind === "text") {
757
+ synth.data = ev.data;
758
+ }
759
+ const propMap = {
760
+ open: "onopen",
761
+ message: "onmessage",
762
+ error: "onerror",
763
+ close: "onclose"
764
+ };
765
+ const prop = propMap[type];
766
+ const handler = this[prop];
767
+ if (handler) {
768
+ try {
769
+ handler(synth);
770
+ } catch (e) {
771
+ try {
772
+ __hostError(
773
+ JSON.stringify({
774
+ message: e instanceof Error ? e.message : String(e),
775
+ source: `WebSocket.${prop}`
776
+ })
777
+ );
778
+ } catch {
779
+ }
780
+ }
781
+ }
782
+ const set = this.listeners[type];
783
+ if (set) {
784
+ for (const cb of set) {
785
+ try {
786
+ cb(synth);
787
+ } catch (e) {
788
+ try {
789
+ __hostError(
790
+ JSON.stringify({
791
+ message: e instanceof Error ? e.message : String(e),
792
+ source: `WebSocket.addEventListener("${type}")`
793
+ })
794
+ );
795
+ } catch {
796
+ }
797
+ }
798
+ }
799
+ }
800
+ }
801
+ }
802
+ MentraWebSocket.CONNECTING = 0;
803
+ MentraWebSocket.OPEN = 1;
804
+ MentraWebSocket.CLOSING = 2;
805
+ MentraWebSocket.CLOSED = 3;
806
+ ;
807
+ g.WebSocket = MentraWebSocket;
808
+ }
809
+ try {
810
+ __dispatch("__runtime", "ready", JSON.stringify([]));
811
+ } catch {
812
+ }
813
+ })();
814
+ })();