@aippy/runtime 0.2.4-dev.4 → 0.2.4-dev.5

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.
@@ -1,4 +1,4 @@
1
- import { a as d, A as f, C as u, E as A, R as _, b as m, c as R, p as g } from "../runtime-Boz38wSz.js";
1
+ import { a as d, A as f, C as u, E as A, R as _, b as m, c as R, p as g } from "../runtime-DjBdOttl.js";
2
2
  const s = {
3
3
  mode: "development",
4
4
  debug: !1,
@@ -22,7 +22,7 @@ function c(e) {
22
22
  }
23
23
  };
24
24
  }
25
- const r = "0.2.4-dev.4", a = {
25
+ const r = "0.2.4-dev.5", a = {
26
26
  version: r
27
27
  }, i = a.version, t = "@aippy/runtime";
28
28
  function p() {
@@ -39,18 +39,19 @@ export declare class AippyRuntime {
39
39
  receiveChannel: ReceiveChannel;
40
40
  private seq;
41
41
  private motionListeners;
42
+ private noListenersWarned;
42
43
  /**
43
44
  * Unified native data receiver - Routes to specific handlers based on message type
44
45
  * Called by native code via: window.aippyRuntime.receiveMessage(message)
45
46
  *
46
47
  * Supports two message formats:
47
- * 1. Motion: { endpoint: "0", payload: { motion: {...} } }
48
+ * 1. Motion: { command: "navigator.motion", endpoint: "0", data: { motion: {...} } }
48
49
  * 2. Tweaks: { "tweakKey": { value: ..., type: ... }, ... }
49
50
  */
50
51
  receiveMessage(message: any): Promise<void>;
51
52
  /**
52
53
  * Check if message is Motion format
53
- * Motion: { endpoint: string, payload: object }
54
+ * Motion: { command: "navigator.motion", endpoint: string, data: object }
54
55
  */
55
56
  private isMotionMessage;
56
57
  /**
@@ -60,16 +61,12 @@ export declare class AippyRuntime {
60
61
  private isTweaksMessage;
61
62
  /**
62
63
  * Create a subscription to native events
63
- * @param handler - WebKit message handler (e.g., deviceMotionHandler)
64
- * @param subscribePayload - Subscription parameters (e.g., { type: "motion" })
64
+ * @param handler - WebKit message handler (e.g., aippyListener)
65
+ * @param subscribePayload - Subscription parameters (e.g., { command: "navigator.motion", type: "motion" })
65
66
  * @param callback - Callback to handle received data
66
67
  * @returns Cancellable subscription
67
68
  */
68
69
  createSubscription(handler: any, subscribePayload: any, callback: (data: any) => void): Cancellable;
69
- /**
70
- * Make a subscription message with unique endpoint
71
- */
72
- private makeSubscriptionMessage;
73
70
  /**
74
71
  * Add motion listener (convenience method)
75
72
  * @param callback - Callback to handle motion data
@@ -1,10 +1,10 @@
1
- var v = Object.defineProperty;
2
- var f = (c, t, e) => t in c ? v(c, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[t] = e;
3
- var p = (c, t, e) => f(c, typeof t != "symbol" ? t + "" : t, e);
4
- import { c as a, b as E } from "../runtime-Boz38wSz.js";
5
- class P {
1
+ var U = Object.defineProperty;
2
+ var M = (n, e, t) => e in n ? U(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
3
+ var A = (n, e, t) => M(n, typeof e != "symbol" ? e + "" : e, t);
4
+ import { c as s, b as L } from "../runtime-DjBdOttl.js";
5
+ class k {
6
6
  constructor() {
7
- p(this, "stream", null);
7
+ A(this, "stream", null);
8
8
  }
9
9
  /**
10
10
  * Check if camera is supported
@@ -15,21 +15,21 @@ class P {
15
15
  /**
16
16
  * Get camera stream
17
17
  */
18
- async getStream(t = {}) {
18
+ async getStream(e = {}) {
19
19
  if (!this.isSupported())
20
- throw a("Camera API is not supported", "NOT_SUPPORTED");
20
+ throw s("Camera API is not supported", "NOT_SUPPORTED");
21
21
  try {
22
- const e = {
22
+ const t = {
23
23
  video: {
24
- width: t.width,
25
- height: t.height,
26
- facingMode: t.facingMode || "environment"
24
+ width: e.width,
25
+ height: e.height,
26
+ facingMode: e.facingMode || "environment"
27
27
  }
28
28
  };
29
- return this.stream = await navigator.mediaDevices.getUserMedia(e), this.stream;
30
- } catch (e) {
31
- throw a(
32
- `Failed to access camera: ${e instanceof Error ? e.message : "Unknown error"}`,
29
+ return this.stream = await navigator.mediaDevices.getUserMedia(t), this.stream;
30
+ } catch (t) {
31
+ throw s(
32
+ `Failed to access camera: ${t instanceof Error ? t.message : "Unknown error"}`,
33
33
  "PERMISSION_DENIED"
34
34
  );
35
35
  }
@@ -37,30 +37,30 @@ class P {
37
37
  /**
38
38
  * Capture photo from stream
39
39
  */
40
- async capturePhoto(t = {}) {
40
+ async capturePhoto(e = {}) {
41
41
  if (!this.stream)
42
- throw a("No camera stream available", "NOT_SUPPORTED");
42
+ throw s("No camera stream available", "NOT_SUPPORTED");
43
43
  try {
44
- const e = document.createElement("video");
45
- e.srcObject = this.stream, e.play();
44
+ const t = document.createElement("video");
45
+ t.srcObject = this.stream, t.play();
46
46
  const i = document.createElement("canvas"), o = i.getContext("2d");
47
47
  if (!o)
48
- throw a("Failed to get canvas context", "UNKNOWN_ERROR");
49
- i.width = t.width || e.videoWidth, i.height = t.height || e.videoHeight, o.drawImage(e, 0, 0, i.width, i.height);
50
- const n = t.format || "jpeg", d = t.quality === "high" ? 0.9 : t.quality === "medium" ? 0.7 : 0.5, r = await new Promise((l, u) => {
51
- i.toBlob((w) => {
52
- w ? l(w) : u(new Error("Failed to create blob"));
53
- }, `image/${n}`, d);
54
- }), s = i.toDataURL(`image/${n}`, d);
48
+ throw s("Failed to get canvas context", "UNKNOWN_ERROR");
49
+ i.width = e.width || t.videoWidth, i.height = e.height || t.videoHeight, o.drawImage(t, 0, 0, i.width, i.height);
50
+ const r = e.format || "jpeg", c = e.quality === "high" ? 0.9 : e.quality === "medium" ? 0.7 : 0.5, a = await new Promise((u, m) => {
51
+ i.toBlob((l) => {
52
+ l ? u(l) : m(new Error("Failed to create blob"));
53
+ }, `image/${r}`, c);
54
+ }), d = i.toDataURL(`image/${r}`, c);
55
55
  return {
56
- blob: r,
57
- dataUrl: s,
56
+ blob: a,
57
+ dataUrl: d,
58
58
  width: i.width,
59
59
  height: i.height
60
60
  };
61
- } catch (e) {
62
- throw a(
63
- `Failed to capture photo: ${e instanceof Error ? e.message : "Unknown error"}`,
61
+ } catch (t) {
62
+ throw s(
63
+ `Failed to capture photo: ${t instanceof Error ? t.message : "Unknown error"}`,
64
64
  "UNKNOWN_ERROR"
65
65
  );
66
66
  }
@@ -69,11 +69,11 @@ class P {
69
69
  * Stop camera stream
70
70
  */
71
71
  stopStream() {
72
- this.stream && (this.stream.getTracks().forEach((t) => t.stop()), this.stream = null);
72
+ this.stream && (this.stream.getTracks().forEach((e) => e.stop()), this.stream = null);
73
73
  }
74
74
  }
75
- const D = new P();
76
- class O {
75
+ const H = new k();
76
+ class T {
77
77
  /**
78
78
  * Check if geolocation is supported
79
79
  */
@@ -83,43 +83,43 @@ class O {
83
83
  /**
84
84
  * Get current position
85
85
  */
86
- async getCurrentPosition(t = {}) {
86
+ async getCurrentPosition(e = {}) {
87
87
  if (!this.isSupported())
88
- throw a("Geolocation API is not supported", "NOT_SUPPORTED");
89
- return new Promise((e, i) => {
88
+ throw s("Geolocation API is not supported", "NOT_SUPPORTED");
89
+ return new Promise((t, i) => {
90
90
  const o = {
91
- enableHighAccuracy: t.enableHighAccuracy ?? !0,
92
- timeout: t.timeout ?? 1e4,
93
- maximumAge: t.maximumAge ?? 6e4
91
+ enableHighAccuracy: e.enableHighAccuracy ?? !0,
92
+ timeout: e.timeout ?? 1e4,
93
+ maximumAge: e.maximumAge ?? 6e4
94
94
  };
95
95
  navigator.geolocation.getCurrentPosition(
96
- (n) => {
97
- const d = {
98
- latitude: n.coords.latitude,
99
- longitude: n.coords.longitude,
100
- accuracy: n.coords.accuracy,
101
- altitude: n.coords.altitude ?? void 0,
102
- altitudeAccuracy: n.coords.altitudeAccuracy ?? void 0,
103
- heading: n.coords.heading ?? void 0,
104
- speed: n.coords.speed ?? void 0,
105
- timestamp: n.timestamp
96
+ (r) => {
97
+ const c = {
98
+ latitude: r.coords.latitude,
99
+ longitude: r.coords.longitude,
100
+ accuracy: r.coords.accuracy,
101
+ altitude: r.coords.altitude ?? void 0,
102
+ altitudeAccuracy: r.coords.altitudeAccuracy ?? void 0,
103
+ heading: r.coords.heading ?? void 0,
104
+ speed: r.coords.speed ?? void 0,
105
+ timestamp: r.timestamp
106
106
  };
107
- e(d);
107
+ t(c);
108
108
  },
109
- (n) => {
110
- let d = "UNKNOWN_ERROR", r = "Unknown geolocation error";
111
- switch (n.code) {
112
- case n.PERMISSION_DENIED:
113
- d = "PERMISSION_DENIED", r = "Geolocation permission denied";
109
+ (r) => {
110
+ let c = "UNKNOWN_ERROR", a = "Unknown geolocation error";
111
+ switch (r.code) {
112
+ case r.PERMISSION_DENIED:
113
+ c = "PERMISSION_DENIED", a = "Geolocation permission denied";
114
114
  break;
115
- case n.POSITION_UNAVAILABLE:
116
- r = "Position unavailable";
115
+ case r.POSITION_UNAVAILABLE:
116
+ a = "Position unavailable";
117
117
  break;
118
- case n.TIMEOUT:
119
- r = "Geolocation timeout";
118
+ case r.TIMEOUT:
119
+ a = "Geolocation timeout";
120
120
  break;
121
121
  }
122
- i(a(r, d));
122
+ i(s(a, c));
123
123
  },
124
124
  o
125
125
  );
@@ -128,17 +128,17 @@ class O {
128
128
  /**
129
129
  * Watch position changes
130
130
  */
131
- watchPosition(t, e = {}) {
131
+ watchPosition(e, t = {}) {
132
132
  if (!this.isSupported())
133
- throw a("Geolocation API is not supported", "NOT_SUPPORTED");
133
+ throw s("Geolocation API is not supported", "NOT_SUPPORTED");
134
134
  const i = {
135
- enableHighAccuracy: e.enableHighAccuracy ?? !0,
136
- timeout: e.timeout ?? 1e4,
137
- maximumAge: e.maximumAge ?? 6e4
135
+ enableHighAccuracy: t.enableHighAccuracy ?? !0,
136
+ timeout: t.timeout ?? 1e4,
137
+ maximumAge: t.maximumAge ?? 6e4
138
138
  };
139
139
  return navigator.geolocation.watchPosition(
140
140
  (o) => {
141
- const n = {
141
+ const r = {
142
142
  latitude: o.coords.latitude,
143
143
  longitude: o.coords.longitude,
144
144
  accuracy: o.coords.accuracy,
@@ -148,7 +148,7 @@ class O {
148
148
  speed: o.coords.speed ?? void 0,
149
149
  timestamp: o.timestamp
150
150
  };
151
- t(n);
151
+ e(r);
152
152
  },
153
153
  (o) => {
154
154
  console.error("Geolocation watch error:", o);
@@ -159,164 +159,192 @@ class O {
159
159
  /**
160
160
  * Clear position watch
161
161
  */
162
- clearWatch(t) {
163
- navigator.geolocation.clearWatch(t);
162
+ clearWatch(e) {
163
+ navigator.geolocation.clearWatch(e);
164
164
  }
165
165
  }
166
- const A = new O();
167
- function m() {
166
+ const q = new T();
167
+ function f() {
168
168
  return "DeviceMotionEvent" in window;
169
169
  }
170
- function h() {
170
+ function N() {
171
171
  return "DeviceOrientationEvent" in window;
172
172
  }
173
- function g() {
174
- return typeof window < "u" && !!window.webkit?.messageHandlers?.aippyListener;
173
+ function R() {
174
+ const n = typeof window < "u", e = n && !!window.webkit, t = e && !!window.webkit?.messageHandlers, i = t && !!window.webkit?.messageHandlers?.aippyListener;
175
+ return console.log("🔍 [Aippy Sensors] hasNativeBridge check:", {
176
+ hasWindow: n,
177
+ hasWebkit: e,
178
+ hasMessageHandlers: t,
179
+ hasAippyListener: i,
180
+ result: i
181
+ }), i;
175
182
  }
176
- async function y() {
177
- if (g())
178
- return !0;
179
- if (!m())
180
- return !1;
181
- if (typeof DeviceMotionEvent < "u" && typeof DeviceMotionEvent.requestPermission == "function")
183
+ function I() {
184
+ return typeof window < "u" && typeof window.orientation < "u" ? window.orientation : typeof window < "u" && window.screen?.orientation?.angle !== void 0 ? window.screen.orientation.angle : 0;
185
+ }
186
+ function y(n, e, t) {
187
+ switch (t) {
188
+ case 0:
189
+ return [-n, -e];
190
+ case 180:
191
+ return [n, e];
192
+ case 90:
193
+ return [-e, n];
194
+ case -90:
195
+ return [e, -n];
196
+ default:
197
+ return [-n, -e];
198
+ }
199
+ }
200
+ async function b() {
201
+ if (console.log("🔐 [Aippy Sensors] requestMotionPermission called"), R())
202
+ return console.log("✅ [Aippy Sensors] Native bridge available, skipping permission request"), !0;
203
+ if (!f())
204
+ return console.warn("❌ [Aippy Sensors] Device motion not supported"), !1;
205
+ const n = typeof DeviceMotionEvent < "u" && typeof DeviceMotionEvent.requestPermission == "function";
206
+ if (console.log("🔍 [Aippy Sensors] Permission API available:", n), n)
182
207
  try {
183
- return await DeviceMotionEvent.requestPermission() === "granted";
184
- } catch {
185
- return !1;
208
+ console.log("🙏 [Aippy Sensors] Requesting device motion permission...");
209
+ const e = await DeviceMotionEvent.requestPermission();
210
+ return console.log("📋 [Aippy Sensors] Permission result:", e), e === "granted";
211
+ } catch (e) {
212
+ return console.warn("❌ [Aippy Sensors] Permission request failed:", e), !1;
186
213
  }
187
- return !0;
214
+ return console.log("✅ [Aippy Sensors] No permission needed (granted by default)"), !0;
188
215
  }
189
- function R(c) {
190
- return E.addMotionListener((e) => {
191
- const i = {
216
+ function _(n) {
217
+ console.log("🔧 [Aippy Sensors] watchMotionNative - Setting up native bridge listener");
218
+ const e = L.addMotionListener((t) => {
219
+ const i = I(), o = t.gravity?.x ?? 0, r = t.gravity?.y ?? 0, c = t.gravity?.z ?? 0, a = t.acceleration?.x ?? 0, d = t.acceleration?.y ?? 0, u = t.acceleration?.z ?? 0, [m, l] = y(o, r, i), [g, h] = y(a, d, i), v = {
192
220
  gravity: {
193
- x: e.gravity?.x ?? 0,
194
- y: e.gravity?.y ?? 0,
195
- z: e.gravity?.z ?? 0
221
+ x: m,
222
+ y: l,
223
+ z: c
224
+ // Z轴不受屏幕旋转影响
196
225
  },
197
226
  acceleration: {
198
- x: e.acceleration?.x ?? 0,
199
- y: e.acceleration?.y ?? 0,
200
- z: e.acceleration?.z ?? 0
227
+ x: g,
228
+ y: h,
229
+ z: u
230
+ // Z轴不受屏幕旋转影响
201
231
  },
202
232
  accelerationIncludingGravity: {
203
- x: (e.gravity?.x ?? 0) + (e.acceleration?.x ?? 0),
204
- y: (e.gravity?.y ?? 0) + (e.acceleration?.y ?? 0),
205
- z: (e.gravity?.z ?? 0) + (e.acceleration?.z ?? 0)
233
+ x: m + g,
234
+ y: l + h,
235
+ z: c + u
206
236
  },
207
237
  rotation: {
208
- alpha: e.rotation?.alpha ?? 0,
209
- beta: e.rotation?.beta ?? 0,
210
- gamma: e.rotation?.gamma ?? 0
238
+ alpha: t.rotation?.alpha ?? 0,
239
+ beta: t.rotation?.beta ?? 0,
240
+ gamma: t.rotation?.gamma ?? 0
211
241
  },
212
242
  timestamp: Date.now()
213
243
  };
214
- c(i);
244
+ n(v);
215
245
  });
246
+ return console.log("✅ [Aippy Sensors] watchMotionNative - Listener setup complete"), e;
216
247
  }
217
- function N(c, t = !0) {
218
- if (!m())
219
- throw a("Device motion API is not supported", "NOT_SUPPORTED");
220
- let e = !1, i = null;
221
- const o = (r) => {
222
- if (!e) return;
223
- const s = {
248
+ function F(n, e = !0) {
249
+ if (!f())
250
+ throw s("Device motion API is not supported", "NOT_SUPPORTED");
251
+ let t = !1, i = null;
252
+ const o = (a) => {
253
+ if (!t) return;
254
+ const d = I();
255
+ let u, m, l;
256
+ if (a.acceleration) {
257
+ const w = a.accelerationIncludingGravity, p = a.acceleration;
258
+ u = (w?.x ?? 0) - (p?.x ?? 0), m = (w?.y ?? 0) - (p?.y ?? 0), l = (w?.z ?? 0) - (p?.z ?? 0);
259
+ } else {
260
+ const w = a.accelerationIncludingGravity, p = 9.8;
261
+ u = (w?.x ?? 0) / p, m = (w?.y ?? 0) / p, l = (w?.z ?? 0) / p;
262
+ }
263
+ const g = a.acceleration?.x ?? 0, h = a.acceleration?.y ?? 0, v = a.acceleration?.z ?? 0, [E, P] = y(u, m, d), [O, S] = y(g, h, d), D = {
224
264
  gravity: {
225
- x: r.acceleration?.x ?? 0,
226
- y: r.acceleration?.y ?? 0,
227
- z: r.acceleration?.z ?? 0
265
+ x: E,
266
+ y: P,
267
+ z: l
268
+ // Z轴不受屏幕旋转影响
228
269
  },
229
270
  acceleration: {
230
- x: r.acceleration?.x ?? 0,
231
- y: r.acceleration?.y ?? 0,
232
- z: r.acceleration?.z ?? 0
271
+ x: O,
272
+ y: S,
273
+ z: v
274
+ // Z轴不受屏幕旋转影响
233
275
  },
234
276
  accelerationIncludingGravity: {
235
- x: r.accelerationIncludingGravity?.x ?? 0,
236
- y: r.accelerationIncludingGravity?.y ?? 0,
237
- z: r.accelerationIncludingGravity?.z ?? 0
277
+ x: E + O,
278
+ y: P + S,
279
+ z: l + v
238
280
  },
239
281
  rotation: {
240
- alpha: r.rotationRate?.alpha ?? 0,
241
- beta: r.rotationRate?.beta ?? 0,
242
- gamma: r.rotationRate?.gamma ?? 0
282
+ alpha: a.rotationRate?.alpha ?? 0,
283
+ beta: a.rotationRate?.beta ?? 0,
284
+ gamma: a.rotationRate?.gamma ?? 0
243
285
  },
244
286
  timestamp: Date.now()
245
287
  };
246
- if (r.acceleration) {
247
- const l = r.accelerationIncludingGravity, u = r.acceleration;
248
- s.gravity = {
249
- x: (l?.x ?? 0) - (u?.x ?? 0),
250
- y: (l?.y ?? 0) - (u?.y ?? 0),
251
- z: (l?.z ?? 0) - (u?.z ?? 0)
252
- };
253
- } else {
254
- const l = r.accelerationIncludingGravity, u = 9.8;
255
- s.gravity = {
256
- x: (l?.x ?? 0) / u,
257
- y: (l?.y ?? 0) / u,
258
- z: (l?.z ?? 0) / u
259
- };
260
- }
261
- c(s);
262
- }, n = async () => {
263
- t && !await y() || (e = !0, window.addEventListener("devicemotion", o));
288
+ n(D);
289
+ }, r = async () => {
290
+ e && !await b() || (t = !0, window.addEventListener("devicemotion", o));
264
291
  };
265
292
  return (async () => {
266
- if (typeof DeviceMotionEvent < "u" && typeof DeviceMotionEvent.requestPermission == "function" && t) {
267
- const s = async () => {
268
- i = null, await n();
293
+ if (typeof DeviceMotionEvent < "u" && typeof DeviceMotionEvent.requestPermission == "function" && e) {
294
+ const d = async () => {
295
+ i = null, await r();
269
296
  };
270
- window.addEventListener("click", s, { once: !0 }), window.addEventListener("touchstart", s, { once: !0 }), i = () => {
271
- window.removeEventListener("click", s), window.removeEventListener("touchstart", s);
297
+ window.addEventListener("click", d, { once: !0 }), window.addEventListener("touchstart", d, { once: !0 }), i = () => {
298
+ window.removeEventListener("click", d), window.removeEventListener("touchstart", d);
272
299
  };
273
300
  } else
274
- await n();
301
+ await r();
275
302
  })(), () => {
276
- e = !1, window.removeEventListener("devicemotion", o), i && (i(), i = null);
303
+ t = !1, window.removeEventListener("devicemotion", o), i && (i(), i = null);
277
304
  };
278
305
  }
279
- function L(c, t = !0) {
280
- return g() ? R(c) : N(c, t);
306
+ function C(n, e = !0) {
307
+ const t = R();
308
+ return console.log(`🎯 [Aippy Sensors] watchMotion - Using ${t ? "NATIVE BRIDGE" : "WEB API"} mode`), t ? (console.log("📱 [Aippy Sensors] Starting native bridge motion listener"), _(n)) : (console.log("🌐 [Aippy Sensors] Starting Web API motion listener (may require permission)"), F(n, e));
281
309
  }
282
- function x(c) {
283
- if (!h())
284
- throw a("Device orientation API is not supported", "NOT_SUPPORTED");
285
- const t = (e) => {
310
+ function B(n) {
311
+ if (!N())
312
+ throw s("Device orientation API is not supported", "NOT_SUPPORTED");
313
+ const e = (t) => {
286
314
  const i = {
287
- alpha: e.alpha ?? 0,
288
- beta: e.beta ?? 0,
289
- gamma: e.gamma ?? 0,
315
+ alpha: t.alpha ?? 0,
316
+ beta: t.beta ?? 0,
317
+ gamma: t.gamma ?? 0,
290
318
  timestamp: Date.now()
291
319
  };
292
- c(i);
320
+ n(i);
293
321
  };
294
- return window.addEventListener("deviceorientation", t), () => {
295
- window.removeEventListener("deviceorientation", t);
322
+ return window.addEventListener("deviceorientation", e), () => {
323
+ window.removeEventListener("deviceorientation", e);
296
324
  };
297
325
  }
298
- class S {
326
+ class x {
299
327
  /**
300
328
  * Check if device orientation is supported
301
329
  */
302
330
  isOrientationSupported() {
303
- return h();
331
+ return N();
304
332
  }
305
333
  /**
306
334
  * Check if device motion is supported
307
335
  */
308
336
  isMotionSupported() {
309
- return m();
337
+ return f();
310
338
  }
311
339
  /**
312
340
  * Get device orientation data
313
341
  */
314
342
  async getOrientation() {
315
343
  if (!this.isOrientationSupported())
316
- throw a("Device orientation API is not supported", "NOT_SUPPORTED");
317
- return new Promise((t, e) => {
344
+ throw s("Device orientation API is not supported", "NOT_SUPPORTED");
345
+ return new Promise((e, t) => {
318
346
  const i = (o) => {
319
- window.removeEventListener("deviceorientation", i), t({
347
+ window.removeEventListener("deviceorientation", i), e({
320
348
  x: o.alpha ?? 0,
321
349
  y: o.beta ?? 0,
322
350
  z: o.gamma ?? 0,
@@ -324,7 +352,7 @@ class S {
324
352
  });
325
353
  };
326
354
  window.addEventListener("deviceorientation", i), setTimeout(() => {
327
- window.removeEventListener("deviceorientation", i), e(a("Device orientation timeout", "UNKNOWN_ERROR"));
355
+ window.removeEventListener("deviceorientation", i), t(s("Device orientation timeout", "UNKNOWN_ERROR"));
328
356
  }, 5e3);
329
357
  });
330
358
  }
@@ -332,19 +360,19 @@ class S {
332
360
  * Watch device orientation changes
333
361
  * @deprecated Use watchOrientation() function instead
334
362
  */
335
- watchOrientation(t) {
363
+ watchOrientation(e) {
336
364
  if (!this.isOrientationSupported())
337
- throw a("Device orientation API is not supported", "NOT_SUPPORTED");
338
- const e = (i) => {
339
- t({
365
+ throw s("Device orientation API is not supported", "NOT_SUPPORTED");
366
+ const t = (i) => {
367
+ e({
340
368
  x: i.alpha ?? 0,
341
369
  y: i.beta ?? 0,
342
370
  z: i.gamma ?? 0,
343
371
  timestamp: Date.now()
344
372
  });
345
373
  };
346
- return window.addEventListener("deviceorientation", e), () => {
347
- window.removeEventListener("deviceorientation", e);
374
+ return window.addEventListener("deviceorientation", t), () => {
375
+ window.removeEventListener("deviceorientation", t);
348
376
  };
349
377
  }
350
378
  /**
@@ -352,10 +380,10 @@ class S {
352
380
  */
353
381
  async getMotion() {
354
382
  if (!this.isMotionSupported())
355
- throw a("Device motion API is not supported", "NOT_SUPPORTED");
356
- return new Promise((t, e) => {
383
+ throw s("Device motion API is not supported", "NOT_SUPPORTED");
384
+ return new Promise((e, t) => {
357
385
  const i = (o) => {
358
- window.removeEventListener("devicemotion", i), t({
386
+ window.removeEventListener("devicemotion", i), e({
359
387
  x: o.acceleration?.x ?? 0,
360
388
  y: o.acceleration?.y ?? 0,
361
389
  z: o.acceleration?.z ?? 0,
@@ -363,7 +391,7 @@ class S {
363
391
  });
364
392
  };
365
393
  window.addEventListener("devicemotion", i), setTimeout(() => {
366
- window.removeEventListener("devicemotion", i), e(a("Device motion timeout", "UNKNOWN_ERROR"));
394
+ window.removeEventListener("devicemotion", i), t(s("Device motion timeout", "UNKNOWN_ERROR"));
367
395
  }, 5e3);
368
396
  });
369
397
  }
@@ -371,30 +399,30 @@ class S {
371
399
  * Watch device motion changes
372
400
  * @deprecated Use watchMotion() function instead
373
401
  */
374
- watchMotion(t) {
402
+ watchMotion(e) {
375
403
  if (!this.isMotionSupported())
376
- throw a("Device motion API is not supported", "NOT_SUPPORTED");
377
- const e = (i) => {
378
- t({
404
+ throw s("Device motion API is not supported", "NOT_SUPPORTED");
405
+ const t = (i) => {
406
+ e({
379
407
  x: i.acceleration?.x ?? 0,
380
408
  y: i.acceleration?.y ?? 0,
381
409
  z: i.acceleration?.z ?? 0,
382
410
  timestamp: Date.now()
383
411
  });
384
412
  };
385
- return window.addEventListener("devicemotion", e), () => {
386
- window.removeEventListener("devicemotion", e);
413
+ return window.addEventListener("devicemotion", t), () => {
414
+ window.removeEventListener("devicemotion", t);
387
415
  };
388
416
  }
389
417
  /**
390
418
  * Request permission for motion sensors (iOS 13+)
391
419
  */
392
420
  async requestPermission() {
393
- return y();
421
+ return b();
394
422
  }
395
423
  }
396
- const M = new S();
397
- class I {
424
+ const K = new x();
425
+ class G {
398
426
  /**
399
427
  * Check if file system access is supported
400
428
  */
@@ -410,28 +438,28 @@ class I {
410
438
  /**
411
439
  * Open file picker (modern API)
412
440
  */
413
- async openFilePicker(t = {}) {
441
+ async openFilePicker(e = {}) {
414
442
  if (!this.isSupported())
415
- throw a("File System Access API is not supported", "NOT_SUPPORTED");
443
+ throw s("File System Access API is not supported", "NOT_SUPPORTED");
416
444
  try {
417
- const e = {
418
- types: t.accept ? [{
445
+ const t = {
446
+ types: e.accept ? [{
419
447
  description: "Files",
420
448
  accept: Object.fromEntries(
421
- t.accept.map((n) => [n, [n]])
449
+ e.accept.map((r) => [r, [r]])
422
450
  )
423
451
  }] : void 0,
424
- multiple: t.multiple ?? !1
425
- }, i = await window.showOpenFilePicker(e), o = await Promise.all(
426
- i.map(async (n) => n.getFile())
452
+ multiple: e.multiple ?? !1
453
+ }, i = await window.showOpenFilePicker(t), o = await Promise.all(
454
+ i.map(async (r) => r.getFile())
427
455
  );
428
456
  return {
429
457
  files: o,
430
- paths: o.map((n) => n.name)
458
+ paths: o.map((r) => r.name)
431
459
  };
432
- } catch (e) {
433
- throw e instanceof Error && e.name === "AbortError" ? a("File picker was cancelled", "PERMISSION_DENIED") : a(
434
- `Failed to open file picker: ${e instanceof Error ? e.message : "Unknown error"}`,
460
+ } catch (t) {
461
+ throw t instanceof Error && t.name === "AbortError" ? s("File picker was cancelled", "PERMISSION_DENIED") : s(
462
+ `Failed to open file picker: ${t instanceof Error ? t.message : "Unknown error"}`,
435
463
  "PERMISSION_DENIED"
436
464
  );
437
465
  }
@@ -439,37 +467,37 @@ class I {
439
467
  /**
440
468
  * Open file picker (legacy fallback)
441
469
  */
442
- async openFilePickerLegacy(t = {}) {
470
+ async openFilePickerLegacy(e = {}) {
443
471
  if (!this.isLegacySupported())
444
- throw a("File input is not supported", "NOT_SUPPORTED");
445
- return new Promise((e, i) => {
472
+ throw s("File input is not supported", "NOT_SUPPORTED");
473
+ return new Promise((t, i) => {
446
474
  const o = document.createElement("input");
447
- o.type = "file", o.multiple = t.multiple ?? !1, o.accept = t.accept?.join(",") ?? "", o.onchange = (n) => {
448
- const d = n.target, r = Array.from(d.files || []);
449
- e({
450
- files: r,
451
- paths: r.map((s) => s.name)
475
+ o.type = "file", o.multiple = e.multiple ?? !1, o.accept = e.accept?.join(",") ?? "", o.onchange = (r) => {
476
+ const c = r.target, a = Array.from(c.files || []);
477
+ t({
478
+ files: a,
479
+ paths: a.map((d) => d.name)
452
480
  });
453
481
  }, o.oncancel = () => {
454
- i(a("File picker was cancelled", "PERMISSION_DENIED"));
482
+ i(s("File picker was cancelled", "PERMISSION_DENIED"));
455
483
  }, o.click();
456
484
  });
457
485
  }
458
486
  /**
459
487
  * Open file picker with fallback
460
488
  */
461
- async openFile(t = {}) {
462
- return this.isSupported() ? await this.openFilePicker(t) : await this.openFilePickerLegacy(t);
489
+ async openFile(e = {}) {
490
+ return this.isSupported() ? await this.openFilePicker(e) : await this.openFilePickerLegacy(e);
463
491
  }
464
492
  /**
465
493
  * Save file
466
494
  */
467
- async saveFile(t, e) {
495
+ async saveFile(e, t) {
468
496
  try {
469
- const i = URL.createObjectURL(t), o = document.createElement("a");
470
- o.href = i, o.download = e, document.body.appendChild(o), o.click(), document.body.removeChild(o), URL.revokeObjectURL(i);
497
+ const i = URL.createObjectURL(e), o = document.createElement("a");
498
+ o.href = i, o.download = t, document.body.appendChild(o), o.click(), document.body.removeChild(o), URL.revokeObjectURL(i);
471
499
  } catch (i) {
472
- throw a(
500
+ throw s(
473
501
  `Failed to save file: ${i instanceof Error ? i.message : "Unknown error"}`,
474
502
  "UNKNOWN_ERROR"
475
503
  );
@@ -478,51 +506,51 @@ class I {
478
506
  /**
479
507
  * Read file as text
480
508
  */
481
- async readAsText(t) {
482
- return new Promise((e, i) => {
509
+ async readAsText(e) {
510
+ return new Promise((t, i) => {
483
511
  const o = new FileReader();
484
- o.onload = () => e(o.result), o.onerror = () => i(a("Failed to read file", "UNKNOWN_ERROR")), o.readAsText(t);
512
+ o.onload = () => t(o.result), o.onerror = () => i(s("Failed to read file", "UNKNOWN_ERROR")), o.readAsText(e);
485
513
  });
486
514
  }
487
515
  /**
488
516
  * Read file as data URL
489
517
  */
490
- async readAsDataURL(t) {
491
- return new Promise((e, i) => {
518
+ async readAsDataURL(e) {
519
+ return new Promise((t, i) => {
492
520
  const o = new FileReader();
493
- o.onload = () => e(o.result), o.onerror = () => i(a("Failed to read file", "UNKNOWN_ERROR")), o.readAsDataURL(t);
521
+ o.onload = () => t(o.result), o.onerror = () => i(s("Failed to read file", "UNKNOWN_ERROR")), o.readAsDataURL(e);
494
522
  });
495
523
  }
496
524
  }
497
- const T = new I();
498
- function k(c) {
499
- return new Promise((t) => {
525
+ const X = new G();
526
+ function Y(n) {
527
+ return new Promise((e) => {
500
528
  if ("vibrate" in navigator)
501
- navigator.vibrate(c), t();
529
+ navigator.vibrate(n), e();
502
530
  else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.aippyListener) {
503
- const e = {
531
+ const t = {
504
532
  command: "navigator.vibrate",
505
- parameters: c
533
+ parameters: n
506
534
  };
507
- window.webkit.messageHandlers.aippyListener.postMessage(e), t();
535
+ window.webkit.messageHandlers.aippyListener.postMessage(t), e();
508
536
  } else
509
- console.warn("Vibration not supported in this environment"), t();
537
+ console.warn("Vibration not supported in this environment"), e();
510
538
  });
511
539
  }
512
540
  export {
513
- P as CameraAPI,
514
- I as FileSystemAPI,
515
- O as GeolocationAPI,
516
- S as SensorsAPI,
517
- D as camera,
518
- T as fileSystem,
519
- A as geolocation,
520
- g as hasNativeBridge,
521
- m as isMotionSupported,
522
- h as isOrientationSupported,
523
- y as requestMotionPermission,
524
- M as sensors,
525
- k as vibrate,
526
- L as watchMotion,
527
- x as watchOrientation
541
+ k as CameraAPI,
542
+ G as FileSystemAPI,
543
+ T as GeolocationAPI,
544
+ x as SensorsAPI,
545
+ H as camera,
546
+ X as fileSystem,
547
+ q as geolocation,
548
+ R as hasNativeBridge,
549
+ f as isMotionSupported,
550
+ N as isOrientationSupported,
551
+ b as requestMotionPermission,
552
+ K as sensors,
553
+ Y as vibrate,
554
+ C as watchMotion,
555
+ B as watchOrientation
528
556
  };
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_CONFIG as o, SDK_NAME as t, VERSION as r, getConfigFromEnv as i, getVersionInfo as s, mergeConfig as n } from "../core/index.js";
2
- import { a as m, A as c, C as d, E as f, R as u, b as l, c as A, p as S } from "../runtime-Boz38wSz.js";
2
+ import { a as m, A as c, C as d, E as f, R as u, b as l, c as A, p as S } from "../runtime-DjBdOttl.js";
3
3
  import { CameraAPI as C, FileSystemAPI as R, GeolocationAPI as x, SensorsAPI as M, camera as P, fileSystem as I, geolocation as g, hasNativeBridge as y, isMotionSupported as O, isOrientationSupported as b, requestMotionPermission as v, sensors as D, vibrate as h, watchMotion as w, watchOrientation as F } from "../device/index.js";
4
4
  import { c as T, a as V, P as _, b as k, p as G, d as H } from "../pwa-8DGmPqLV.js";
5
5
  import { a as q, b as B } from "../useTweaks-QxMRmg7i.js";
@@ -0,0 +1,243 @@
1
+ var u = Object.defineProperty;
2
+ var m = (o, e, n) => e in o ? u(o, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : o[e] = n;
3
+ var r = (o, e, n) => m(o, typeof e != "symbol" ? e + "" : e, n);
4
+ class d extends Error {
5
+ constructor(n, i = "AIPPY_ERROR", t) {
6
+ super(n);
7
+ r(this, "code");
8
+ r(this, "context");
9
+ this.name = "AippyRuntimeError", this.code = i, this.context = t;
10
+ }
11
+ }
12
+ const R = {
13
+ NOT_SUPPORTED: "NOT_SUPPORTED",
14
+ PERMISSION_DENIED: "PERMISSION_DENIED",
15
+ INVALID_CONFIG: "INVALID_CONFIG",
16
+ NETWORK_ERROR: "NETWORK_ERROR",
17
+ UNKNOWN_ERROR: "UNKNOWN_ERROR"
18
+ };
19
+ function g(o, e = "UNKNOWN_ERROR", n) {
20
+ return new d(o, R[e], n);
21
+ }
22
+ class a {
23
+ constructor(e) {
24
+ r(this, "cancelled", !1);
25
+ this.cancelFn = e;
26
+ }
27
+ cancel() {
28
+ this.cancelled || (this.cancelled = !0, this.cancelFn?.());
29
+ }
30
+ get isCancelled() {
31
+ return this.cancelled;
32
+ }
33
+ }
34
+ class f {
35
+ constructor() {
36
+ r(this, "listeners", /* @__PURE__ */ new Map());
37
+ }
38
+ addEventListener(e, n) {
39
+ this.listeners.has(e) || this.listeners.set(e, []), this.listeners.get(e).push(n);
40
+ }
41
+ removeEventListener(e, n) {
42
+ const i = this.listeners.get(e);
43
+ if (i) {
44
+ const t = i.indexOf(n);
45
+ t > -1 && i.splice(t, 1);
46
+ }
47
+ }
48
+ emit(e, n) {
49
+ const i = this.listeners.get(e);
50
+ i && i.forEach((t) => t(n));
51
+ }
52
+ }
53
+ class y {
54
+ constructor() {
55
+ r(this, "emitter", new f());
56
+ }
57
+ /**
58
+ * Emit a message to subscribers
59
+ */
60
+ emit(e) {
61
+ this.emitter.emit(e.endpoint, e.payload);
62
+ }
63
+ /**
64
+ * Subscribe to messages on a specific endpoint
65
+ */
66
+ subscribe(e, n) {
67
+ const i = (t) => {
68
+ n(t);
69
+ };
70
+ return this.emitter.addEventListener(e, i), new a(() => {
71
+ this.emitter.removeEventListener(e, i);
72
+ });
73
+ }
74
+ /**
75
+ * Subscribe to a single message (auto-unsubscribe after first message)
76
+ */
77
+ once(e, n) {
78
+ const i = this.subscribe(e, (t) => {
79
+ i.cancel(), n(t);
80
+ });
81
+ return i;
82
+ }
83
+ }
84
+ class h {
85
+ constructor() {
86
+ r(this, "receiveChannel", new y());
87
+ r(this, "seq", 0);
88
+ r(this, "motionListeners", []);
89
+ r(this, "noListenersWarned", !1);
90
+ }
91
+ /**
92
+ * Unified native data receiver - Routes to specific handlers based on message type
93
+ * Called by native code via: window.aippyRuntime.receiveMessage(message)
94
+ *
95
+ * Supports two message formats:
96
+ * 1. Motion: { command: "navigator.motion", endpoint: "0", data: { motion: {...} } }
97
+ * 2. Tweaks: { "tweakKey": { value: ..., type: ... }, ... }
98
+ */
99
+ receiveMessage(e) {
100
+ return console.log("📩 [Aippy Runtime] receiveMessage called with:", e), !e || typeof e != "object" ? (console.warn("⚠️ [Aippy Runtime] Invalid message type:", typeof e), Promise.resolve()) : this.isMotionMessage(e) ? (console.log("✅ [Aippy Runtime] Detected MOTION message format, emitting to receive channel"), this.receiveChannel.emit({
101
+ endpoint: e.endpoint,
102
+ payload: e.data
103
+ }), Promise.resolve()) : this.isTweaksMessage(e) ? (console.log("✅ [Aippy Runtime] Detected TWEAKS message format, calling processNativeData"), typeof window < "u" && window.processNativeData && window.processNativeData(e), Promise.resolve()) : (console.warn("⚠️ [Aippy Runtime] Unknown message format:", e), Promise.resolve());
104
+ }
105
+ /**
106
+ * Check if message is Motion format
107
+ * Motion: { command: "navigator.motion", endpoint: string, data: object }
108
+ */
109
+ isMotionMessage(e) {
110
+ return typeof e == "object" && "command" in e && e.command === "navigator.motion" && "endpoint" in e && typeof e.endpoint == "string" && "data" in e && typeof e.data == "object" && e.data !== null;
111
+ }
112
+ /**
113
+ * Check if message is Tweaks format
114
+ * Tweaks: { "key": { value: any, type?: string, ... }, ... }
115
+ */
116
+ isTweaksMessage(e) {
117
+ if (typeof e != "object" || e === null || "endpoint" in e || "payload" in e)
118
+ return !1;
119
+ const n = Object.keys(e);
120
+ return n.length === 0 ? !1 : n.some((t) => {
121
+ const c = e[t];
122
+ return typeof c == "object" && c !== null && "value" in c;
123
+ });
124
+ }
125
+ /**
126
+ * Create a subscription to native events
127
+ * @param handler - WebKit message handler (e.g., aippyListener)
128
+ * @param subscribePayload - Subscription parameters (e.g., { command: "navigator.motion", type: "motion" })
129
+ * @param callback - Callback to handle received data
130
+ * @returns Cancellable subscription
131
+ */
132
+ createSubscription(e, n, i) {
133
+ const t = (this.seq++).toString(), c = {
134
+ command: n.command,
135
+ parameters: {
136
+ type: n.type,
137
+ action: "subscribe",
138
+ endpoint: t
139
+ }
140
+ };
141
+ console.log("📨 [Aippy Runtime] Creating subscription with message:", JSON.stringify(c, null, 2));
142
+ const l = this.receiveChannel.subscribe(t, (s) => {
143
+ if (console.log(`📬 [Aippy Runtime] Received data on endpoint ${t}:`, s), s.error !== void 0) {
144
+ console.warn("⚠️ [Aippy Runtime] Received error, skipping:", s.error);
145
+ return;
146
+ }
147
+ i(s);
148
+ });
149
+ try {
150
+ console.log("📤 [Aippy Runtime] Sending postMessage to native iOS:", c), e.postMessage(c), console.log("✅ [Aippy Runtime] postMessage sent successfully");
151
+ } catch (s) {
152
+ console.error("❌ [Aippy Runtime] Failed to send postMessage:", s);
153
+ }
154
+ return new a(() => {
155
+ console.log(`🔌 [Aippy Runtime] Unsubscribing from endpoint ${t}`), l.cancel();
156
+ try {
157
+ const s = {
158
+ command: n.command,
159
+ parameters: {
160
+ type: n.type,
161
+ action: "unsubscribe",
162
+ endpoint: t
163
+ }
164
+ };
165
+ e.postMessage(s), console.log("✅ [Aippy Runtime] Unsubscribe message sent:", s);
166
+ } catch (s) {
167
+ console.error("❌ [Aippy Runtime] Failed to send unsubscribe message:", s);
168
+ }
169
+ });
170
+ }
171
+ /**
172
+ * Add motion listener (convenience method)
173
+ * @param callback - Callback to handle motion data
174
+ * @returns Cleanup function
175
+ */
176
+ addMotionListener(e) {
177
+ console.log("🎬 [Aippy Runtime] addMotionListener called"), this.motionListeners.push(e), console.log(`📝 [Aippy Runtime] Total motion listeners: ${this.motionListeners.length}`);
178
+ const n = window.webkit?.messageHandlers?.aippyListener;
179
+ if (!n)
180
+ return console.warn("⚠️ [Aippy Runtime] No webkit message handler found, using fallback mode"), () => {
181
+ const t = this.motionListeners.indexOf(e);
182
+ t > -1 && this.motionListeners.splice(t, 1);
183
+ };
184
+ console.log("✅ [Aippy Runtime] Webkit handler found, creating subscription");
185
+ const i = this.createSubscription(
186
+ n,
187
+ {
188
+ command: "navigator.motion",
189
+ type: "motion"
190
+ },
191
+ (t) => {
192
+ console.log("📥 [Aippy Runtime] Received motion data from native:", t), t.motion && e(t.motion);
193
+ }
194
+ );
195
+ return () => {
196
+ console.log("🧹 [Aippy Runtime] Cleaning up motion listener"), i.cancel();
197
+ const t = this.motionListeners.indexOf(e);
198
+ t > -1 && this.motionListeners.splice(t, 1);
199
+ };
200
+ }
201
+ /**
202
+ * Broadcast motion data to all registered listeners
203
+ * Called by processMotionData when iOS sends data directly
204
+ * @param data - Motion data from iOS
205
+ */
206
+ broadcastMotionData(e) {
207
+ if (this.motionListeners.length === 0) {
208
+ this.noListenersWarned || (console.warn("⚠️ [Aippy Runtime] No motion listeners to broadcast to"), this.noListenersWarned = !0);
209
+ return;
210
+ }
211
+ const n = e.motion || e;
212
+ this.motionListeners.forEach((i) => {
213
+ try {
214
+ i(n);
215
+ } catch (t) {
216
+ console.error("⚠️ [Aippy Runtime] Error in motion listener:", t);
217
+ }
218
+ });
219
+ }
220
+ }
221
+ function w(o) {
222
+ if (!o || typeof o != "object") {
223
+ console.warn("⚠️ [Aippy Runtime] Invalid motion data type:", typeof o);
224
+ return;
225
+ }
226
+ if (!("motion" in o) || typeof o.motion != "object") {
227
+ console.warn("⚠️ [Aippy Runtime] Motion data missing valid motion field");
228
+ return;
229
+ }
230
+ p.broadcastMotionData(o);
231
+ }
232
+ const p = new h();
233
+ typeof window < "u" && (window.aippyRuntime = p, window.processMotionData = w);
234
+ export {
235
+ d as A,
236
+ a as C,
237
+ R as E,
238
+ y as R,
239
+ h as a,
240
+ p as b,
241
+ g as c,
242
+ w as p
243
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aippy/runtime",
3
- "version": "0.2.4-dev.4",
3
+ "version": "0.2.4-dev.5",
4
4
  "description": "Aippy Runtime SDK - Runtime SDK for Aippy projects",
5
5
  "private": false,
6
6
  "type": "module",
@@ -1,227 +0,0 @@
1
- var l = Object.defineProperty;
2
- var u = (o, e, t) => e in o ? l(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
3
- var s = (o, e, t) => u(o, typeof e != "symbol" ? e + "" : e, t);
4
- class d extends Error {
5
- constructor(t, n = "AIPPY_ERROR", i) {
6
- super(t);
7
- s(this, "code");
8
- s(this, "context");
9
- this.name = "AippyRuntimeError", this.code = n, this.context = i;
10
- }
11
- }
12
- const f = {
13
- NOT_SUPPORTED: "NOT_SUPPORTED",
14
- PERMISSION_DENIED: "PERMISSION_DENIED",
15
- INVALID_CONFIG: "INVALID_CONFIG",
16
- NETWORK_ERROR: "NETWORK_ERROR",
17
- UNKNOWN_ERROR: "UNKNOWN_ERROR"
18
- };
19
- function E(o, e = "UNKNOWN_ERROR", t) {
20
- return new d(o, f[e], t);
21
- }
22
- class a {
23
- constructor(e) {
24
- s(this, "cancelled", !1);
25
- this.cancelFn = e;
26
- }
27
- cancel() {
28
- this.cancelled || (this.cancelled = !0, this.cancelFn?.());
29
- }
30
- get isCancelled() {
31
- return this.cancelled;
32
- }
33
- }
34
- class h {
35
- constructor() {
36
- s(this, "listeners", /* @__PURE__ */ new Map());
37
- }
38
- addEventListener(e, t) {
39
- this.listeners.has(e) || this.listeners.set(e, []), this.listeners.get(e).push(t);
40
- }
41
- removeEventListener(e, t) {
42
- const n = this.listeners.get(e);
43
- if (n) {
44
- const i = n.indexOf(t);
45
- i > -1 && n.splice(i, 1);
46
- }
47
- }
48
- emit(e, t) {
49
- const n = this.listeners.get(e);
50
- n && n.forEach((i) => i(t));
51
- }
52
- }
53
- class m {
54
- constructor() {
55
- s(this, "emitter", new h());
56
- }
57
- /**
58
- * Emit a message to subscribers
59
- */
60
- emit(e) {
61
- this.emitter.emit(e.endpoint, e.payload);
62
- }
63
- /**
64
- * Subscribe to messages on a specific endpoint
65
- */
66
- subscribe(e, t) {
67
- const n = (i) => {
68
- t(i);
69
- };
70
- return this.emitter.addEventListener(e, n), new a(() => {
71
- this.emitter.removeEventListener(e, n);
72
- });
73
- }
74
- /**
75
- * Subscribe to a single message (auto-unsubscribe after first message)
76
- */
77
- once(e, t) {
78
- const n = this.subscribe(e, (i) => {
79
- n.cancel(), t(i);
80
- });
81
- return n;
82
- }
83
- }
84
- class R {
85
- constructor() {
86
- s(this, "receiveChannel", new m());
87
- s(this, "seq", 0);
88
- s(this, "motionListeners", []);
89
- }
90
- /**
91
- * Unified native data receiver - Routes to specific handlers based on message type
92
- * Called by native code via: window.aippyRuntime.receiveMessage(message)
93
- *
94
- * Supports two message formats:
95
- * 1. Motion: { endpoint: "0", payload: { motion: {...} } }
96
- * 2. Tweaks: { "tweakKey": { value: ..., type: ... }, ... }
97
- */
98
- receiveMessage(e) {
99
- return !e || typeof e != "object" ? (console.warn("⚠️ [Aippy Runtime] Invalid message type:", typeof e), Promise.resolve()) : this.isMotionMessage(e) ? (this.receiveChannel.emit(e), Promise.resolve()) : this.isTweaksMessage(e) ? (typeof window < "u" && window.processNativeData && window.processNativeData(e), Promise.resolve()) : (console.warn("⚠️ [Aippy Runtime] Unknown message format:", e), Promise.resolve());
100
- }
101
- /**
102
- * Check if message is Motion format
103
- * Motion: { endpoint: string, payload: object }
104
- */
105
- isMotionMessage(e) {
106
- return typeof e == "object" && "endpoint" in e && typeof e.endpoint == "string" && "payload" in e && typeof e.payload == "object" && e.payload !== null;
107
- }
108
- /**
109
- * Check if message is Tweaks format
110
- * Tweaks: { "key": { value: any, type?: string, ... }, ... }
111
- */
112
- isTweaksMessage(e) {
113
- if (typeof e != "object" || e === null || "endpoint" in e || "payload" in e)
114
- return !1;
115
- const t = Object.keys(e);
116
- return t.length === 0 ? !1 : t.some((i) => {
117
- const r = e[i];
118
- return typeof r == "object" && r !== null && "value" in r;
119
- });
120
- }
121
- /**
122
- * Create a subscription to native events
123
- * @param handler - WebKit message handler (e.g., deviceMotionHandler)
124
- * @param subscribePayload - Subscription parameters (e.g., { type: "motion" })
125
- * @param callback - Callback to handle received data
126
- * @returns Cancellable subscription
127
- */
128
- createSubscription(e, t, n) {
129
- const i = this.makeSubscriptionMessage(t), r = this.receiveChannel.subscribe(i.endpoint, (c) => {
130
- c.error === void 0 && n(c);
131
- });
132
- try {
133
- e.postMessage(i);
134
- } catch {
135
- }
136
- return new a(() => {
137
- r.cancel();
138
- try {
139
- e.postMessage({
140
- endpoint: i.endpoint,
141
- payload: "unsubscribe"
142
- });
143
- } catch {
144
- }
145
- });
146
- }
147
- /**
148
- * Make a subscription message with unique endpoint
149
- */
150
- makeSubscriptionMessage(e) {
151
- return {
152
- endpoint: (this.seq++).toString(),
153
- payload: {
154
- subscribe: e
155
- }
156
- };
157
- }
158
- /**
159
- * Add motion listener (convenience method)
160
- * @param callback - Callback to handle motion data
161
- * @returns Cleanup function
162
- */
163
- addMotionListener(e) {
164
- this.motionListeners.push(e);
165
- const t = window.webkit?.messageHandlers?.aippyListener;
166
- if (!t)
167
- return () => {
168
- const i = this.motionListeners.indexOf(e);
169
- i > -1 && this.motionListeners.splice(i, 1);
170
- };
171
- const n = this.createSubscription(
172
- t,
173
- {
174
- command: "navigator.motion",
175
- type: "motion"
176
- },
177
- (i) => {
178
- i.motion && e(i.motion);
179
- }
180
- );
181
- return () => {
182
- n.cancel();
183
- const i = this.motionListeners.indexOf(e);
184
- i > -1 && this.motionListeners.splice(i, 1);
185
- };
186
- }
187
- /**
188
- * Broadcast motion data to all registered listeners
189
- * Called by processMotionData when iOS sends data directly
190
- * @param data - Motion data from iOS
191
- */
192
- broadcastMotionData(e) {
193
- if (this.motionListeners.length === 0)
194
- return;
195
- const t = e.motion || e;
196
- this.motionListeners.forEach((n) => {
197
- try {
198
- n(t);
199
- } catch (i) {
200
- console.error("⚠️ [Aippy Runtime] Error in motion listener:", i);
201
- }
202
- });
203
- }
204
- }
205
- function y(o) {
206
- if (!o || typeof o != "object") {
207
- console.warn("⚠️ [Aippy Runtime] Invalid motion data type:", typeof o);
208
- return;
209
- }
210
- if (!("motion" in o) || typeof o.motion != "object") {
211
- console.warn("⚠️ [Aippy Runtime] Motion data missing valid motion field");
212
- return;
213
- }
214
- p.broadcastMotionData(o);
215
- }
216
- const p = new R();
217
- typeof window < "u" && (window.aippyRuntime = p, window.processMotionData = y);
218
- export {
219
- d as A,
220
- a as C,
221
- f as E,
222
- m as R,
223
- R as a,
224
- p as b,
225
- E as c,
226
- y as p
227
- };