@aippy/runtime 0.2.0-dev.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,195 @@
1
+ var h = Object.defineProperty;
2
+ var b = (l, e, t) => e in l ? h(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
+ var c = (l, e, t) => b(l, typeof e != "symbol" ? e + "" : e, t);
4
+ import { useReducer as v, useEffect as T } from "react";
5
+ class m {
6
+ constructor(e) {
7
+ c(this, "cancelled", !1);
8
+ this.cancelFn = e;
9
+ }
10
+ cancel() {
11
+ this.cancelled || (this.cancelled = !0, this.cancelFn?.());
12
+ }
13
+ get isCancelled() {
14
+ return this.cancelled;
15
+ }
16
+ }
17
+ class y {
18
+ constructor() {
19
+ c(this, "listeners", []);
20
+ }
21
+ send(e) {
22
+ this.listeners.forEach((t) => t(e));
23
+ }
24
+ subscribe(e) {
25
+ return this.listeners.push(e), new m(() => {
26
+ const t = this.listeners.indexOf(e);
27
+ t > -1 && this.listeners.splice(t, 1);
28
+ });
29
+ }
30
+ }
31
+ class A {
32
+ constructor(e, t) {
33
+ c(this, "values", {});
34
+ c(this, "subject", new y());
35
+ c(this, "observable");
36
+ this.observable = e;
37
+ for (const [n, a] of Object.entries(t))
38
+ this.values[n] = a.value;
39
+ this.observable.subscribe((n) => {
40
+ if (n && n.values) {
41
+ console.log("🔄 [Aippy Tweaks] Processing external update:", n.values);
42
+ const a = [];
43
+ for (const [s, i] of Object.entries(n.values)) {
44
+ let o = i;
45
+ if (this.values[s] !== void 0) {
46
+ const r = typeof this.values[s];
47
+ r === "number" && typeof i == "string" ? o = parseFloat(i) : r === "boolean" && typeof i != "boolean" && (o = i === "true" || i === !0);
48
+ }
49
+ if (this.values[s] !== o) {
50
+ const r = this.values[s];
51
+ this.values[s] = o, this.subject.send(s), a.push(s), console.log(`📝 [Aippy Tweaks] Updated ${s}: ${r} → ${o} (type: ${typeof o})`);
52
+ }
53
+ }
54
+ a.length > 0 ? console.log(`✨ [Aippy Tweaks] Successfully updated ${a.length} tweak(s):`, a) : console.log("💡 [Aippy Tweaks] No values changed in this update");
55
+ }
56
+ });
57
+ }
58
+ getValue(e) {
59
+ const t = this.values[e];
60
+ if (t === void 0)
61
+ throw new Error(`Tweak key not found in values: ${e}`);
62
+ return t;
63
+ }
64
+ // React Hook integration
65
+ useState(e) {
66
+ const [t, n] = v(() => this.getValue(e), this.getValue(e));
67
+ return T(() => {
68
+ const a = this.subject.subscribe((s) => {
69
+ s === e && n();
70
+ });
71
+ return () => {
72
+ a.cancel();
73
+ };
74
+ }, [e]), t;
75
+ }
76
+ }
77
+ class S {
78
+ constructor() {
79
+ c(this, "tweaksInstance", null);
80
+ c(this, "tweaksDidWarn", !1);
81
+ c(this, "updateCallback");
82
+ // Store update callback function
83
+ c(this, "originalConfig");
84
+ }
85
+ // Store original config for merging
86
+ tweaks(e) {
87
+ if (this.tweaksInstance)
88
+ return this.tweaksDidWarn || (this.tweaksDidWarn = !0, console.warn("⚠️ [Aippy Tweaks] tweaks() is expected to only be called once, returning previous value")), this.tweaksInstance;
89
+ console.log("🚀 [Aippy Tweaks] Creating new tweaks runtime instance"), this.originalConfig = { ...e };
90
+ const t = new y(), n = new A(t, e), a = {};
91
+ for (const s of Object.keys(e))
92
+ a[s] = {
93
+ useState: () => n.useState(s)
94
+ };
95
+ return this.tweaksInstance = a, console.log("📋 [Aippy Tweaks] Created tweaks instance with keys:", Object.keys(e)), typeof window < "u" && window.aippyTweaksRuntime && (window.aippyTweaksRuntime.tweaksInstance = a, console.log("🌐 [Aippy Tweaks] Exposed tweaksInstance to window.aippyTweaksRuntime.tweaksInstance")), this.initializeExternalCommunication(e, (s) => {
96
+ t.send(s);
97
+ }), a;
98
+ }
99
+ initializeExternalCommunication(e, t) {
100
+ this.updateCallback = t, console.log("🎛️ [Aippy Tweaks] Initializing tweaks with config:", e), console.log("🎛️ [Aippy Tweaks] Total tweaks count:", Object.keys(e).length);
101
+ const n = window.webkit?.messageHandlers?.aippyListener;
102
+ if (n)
103
+ try {
104
+ const s = {
105
+ command: "tweaks.initialize",
106
+ parameters: JSON.stringify(e)
107
+ };
108
+ n.postMessage(s), console.log("✅ [Aippy Tweaks] Successfully sent tweaks config to iOS app via aippyListener"), console.log("📤 [Aippy Tweaks] Sent data:", s);
109
+ } catch (s) {
110
+ console.warn("❌ [Aippy Tweaks] Failed to send tweaks config to iOS app:", s);
111
+ }
112
+ else
113
+ console.warn("⚠️ [Aippy Tweaks] webkit.messageHandlers.aippyListener not available"), console.log(
114
+ "🔍 [Aippy Tweaks] Available webkit handlers:",
115
+ window.webkit?.messageHandlers ? Object.keys(window.webkit.messageHandlers) : "none"
116
+ );
117
+ if (window.parent && window.parent !== window)
118
+ try {
119
+ const s = {
120
+ type: "tweaks-initialize",
121
+ config: JSON.stringify(e)
122
+ };
123
+ window.parent.postMessage(s, "*"), console.log("📡 [Aippy Tweaks] Sent tweaks config to parent window:", s);
124
+ const i = {
125
+ type: "aippy-tweaks-ready",
126
+ aippyTweaksRuntime: {
127
+ tweaks: window.aippyTweaksRuntime?.tweaks,
128
+ tweaksInstance: window.aippyTweaksRuntime?.tweaksInstance
129
+ }
130
+ };
131
+ window.parent.postMessage(i, "*"), console.log("📡 [Aippy Tweaks] Sent aippyTweaksRuntime to parent window:", i);
132
+ } catch (s) {
133
+ console.warn("❌ [Aippy Tweaks] Failed to send to parent window:", s);
134
+ }
135
+ const a = (s) => {
136
+ s.data && s.data.type === "tweaks-update" && (console.log("📥 [Aippy Tweaks] Received tweaks update:", s.data), t(s.data));
137
+ };
138
+ window.addEventListener("message", a), console.log("👂 [Aippy Tweaks] Listening for tweaks updates via window.postMessage");
139
+ }
140
+ // Process native data updates - Public method for external calls
141
+ processNativeData(e) {
142
+ if (!this.tweaksInstance) {
143
+ console.warn("⚠️ [Aippy Tweaks] processNativeData called but no tweaks instance exists");
144
+ return;
145
+ }
146
+ if (!this.updateCallback) {
147
+ console.warn("⚠️ [Aippy Tweaks] processNativeData called but no update callback available");
148
+ return;
149
+ }
150
+ try {
151
+ if (!e || typeof e != "object") {
152
+ console.warn("⚠️ [Aippy Tweaks] Invalid data type received from native:", typeof e);
153
+ return;
154
+ }
155
+ if (!this.originalConfig) {
156
+ console.warn("⚠️ [Aippy Tweaks] No original config available for merging");
157
+ return;
158
+ }
159
+ const t = {}, n = {};
160
+ let a = 0;
161
+ console.log("📱 [DEBUG] Starting to process iOS data and merge with original config...");
162
+ for (const [i, o] of Object.entries(e))
163
+ if (console.log(`📱 [DEBUG] Processing key: ${i}`, o), o && typeof o == "object" && "value" in o) {
164
+ const r = o, u = this.originalConfig[i];
165
+ if (!u) {
166
+ console.warn(`⚠️ [Aippy Tweaks] Key "${i}" not found in original config, skipping`);
167
+ continue;
168
+ }
169
+ const f = /* @__PURE__ */ new Set(["tweakKey", "valueBefore", "tweaksType", "editType"]), d = { ...u };
170
+ for (const [k, p] of Object.entries(r))
171
+ f.has(k) || p != null && (d[k] = p);
172
+ n[i] = d, t[i] = r.value, a++;
173
+ }
174
+ if (a === 0) {
175
+ console.warn("⚠️ [Aippy Tweaks] No valid values found in iOS data:", e);
176
+ return;
177
+ }
178
+ const s = {
179
+ type: "tweaks-update",
180
+ values: t
181
+ };
182
+ this.updateCallback(s);
183
+ } catch (t) {
184
+ console.error("❌ [Aippy Tweaks] Error processing native data:", t);
185
+ }
186
+ }
187
+ }
188
+ const w = new S(), g = {
189
+ tweaks: (l) => w.tweaks(l)
190
+ }, j = g.tweaks;
191
+ typeof window < "u" && (window.aippyTweaksRuntime = g, window.processNativeData = w.processNativeData.bind(w), console.log("🌐 [Aippy Tweaks] Exposed processNativeData to window.processNativeData"));
192
+ export {
193
+ j as a,
194
+ g as b
195
+ };
@@ -1,9 +1,9 @@
1
- import { c, a, P, b, p, d } from "../pwa-BkviTQoN.js";
1
+ import { c as r, a as t, P as e, b as s, p as f, d as m } from "../pwa-DPd78fwK.js";
2
2
  export {
3
- c as PWAUtils,
4
- a as PerformanceMonitor,
5
- P as PlatformDetector,
6
- b as performanceMonitor,
7
- p as platform,
8
- d as pwa
3
+ r as PWAUtils,
4
+ t as PerformanceMonitor,
5
+ e as PlatformDetector,
6
+ s as performanceMonitor,
7
+ f as platform,
8
+ m as pwa
9
9
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aippy/runtime",
3
- "version": "0.2.0-dev.5",
3
+ "version": "0.2.1",
4
4
  "description": "Aippy Runtime SDK - Runtime SDK for Aippy projects",
5
5
  "private": false,
6
6
  "type": "module",
@@ -1,25 +0,0 @@
1
- class AippyRuntimeError extends Error {
2
- code;
3
- context;
4
- constructor(message, code = "AIPPY_ERROR", context) {
5
- super(message);
6
- this.name = "AippyRuntimeError";
7
- this.code = code;
8
- this.context = context;
9
- }
10
- }
11
- const ERROR_CODES = {
12
- NOT_SUPPORTED: "NOT_SUPPORTED",
13
- PERMISSION_DENIED: "PERMISSION_DENIED",
14
- INVALID_CONFIG: "INVALID_CONFIG",
15
- NETWORK_ERROR: "NETWORK_ERROR",
16
- UNKNOWN_ERROR: "UNKNOWN_ERROR"
17
- };
18
- function createError(message, code = "UNKNOWN_ERROR", context) {
19
- return new AippyRuntimeError(message, ERROR_CODES[code], context);
20
- }
21
- export {
22
- AippyRuntimeError as A,
23
- ERROR_CODES as E,
24
- createError as c
25
- };
@@ -1,408 +0,0 @@
1
- import { UAParser } from "ua-parser-js";
2
- class PlatformDetector {
3
- parser;
4
- constructor() {
5
- this.parser = new UAParser();
6
- }
7
- /**
8
- * Get platform information
9
- */
10
- getPlatformInfo() {
11
- const result = this.parser.getResult();
12
- const platformName = this.normalizePlatformName(result.os.name);
13
- const browserName = this.normalizeBrowserName(result.browser.name);
14
- const isMobile = this.isMobileDevice();
15
- const isDesktop = !isMobile;
16
- return {
17
- name: platformName,
18
- version: result.os.version,
19
- browser: browserName,
20
- browserVersion: result.browser.version,
21
- isMobile,
22
- isDesktop
23
- };
24
- }
25
- /**
26
- * Get platform capabilities
27
- */
28
- getCapabilities() {
29
- return {
30
- serviceWorker: "serviceWorker" in navigator,
31
- pushNotifications: "PushManager" in window,
32
- webShare: "share" in navigator,
33
- clipboard: "clipboard" in navigator,
34
- webRTC: !!(window.RTCPeerConnection || window.webkitRTCPeerConnection),
35
- webGL: !!this.getWebGLContext(),
36
- webAssembly: "WebAssembly" in window
37
- };
38
- }
39
- /**
40
- * Check if device is mobile
41
- */
42
- isMobileDevice() {
43
- const userAgent = navigator.userAgent;
44
- const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
45
- return mobileRegex.test(userAgent) || this.isTouchDevice();
46
- }
47
- /**
48
- * Check if device supports touch
49
- */
50
- isTouchDevice() {
51
- return "ontouchstart" in window || navigator.maxTouchPoints > 0;
52
- }
53
- /**
54
- * Check if running in standalone mode (PWA)
55
- */
56
- isStandalone() {
57
- return window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true;
58
- }
59
- /**
60
- * Check if running in iOS Safari
61
- */
62
- isIOSSafari() {
63
- const info = this.getPlatformInfo();
64
- return info.name === "ios" && info.browser === "safari";
65
- }
66
- /**
67
- * Check if running in Android Chrome
68
- */
69
- isAndroidChrome() {
70
- const info = this.getPlatformInfo();
71
- return info.name === "android" && info.browser === "chrome";
72
- }
73
- normalizePlatformName(name) {
74
- if (!name) return "unknown";
75
- const normalized = name.toLowerCase();
76
- if (normalized.includes("ios")) return "ios";
77
- if (normalized.includes("android")) return "android";
78
- if (normalized.includes("windows")) return "windows";
79
- if (normalized.includes("mac")) return "macos";
80
- if (normalized.includes("linux")) return "linux";
81
- return "unknown";
82
- }
83
- normalizeBrowserName(name) {
84
- if (!name) return "unknown";
85
- const normalized = name.toLowerCase();
86
- if (normalized.includes("chrome")) return "chrome";
87
- if (normalized.includes("firefox")) return "firefox";
88
- if (normalized.includes("safari")) return "safari";
89
- if (normalized.includes("edge")) return "edge";
90
- return "unknown";
91
- }
92
- getWebGLContext() {
93
- try {
94
- const canvas = document.createElement("canvas");
95
- return canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
96
- } catch {
97
- return null;
98
- }
99
- }
100
- }
101
- const platform = new PlatformDetector();
102
- class PerformanceMonitor {
103
- /**
104
- * Get Core Web Vitals metrics
105
- */
106
- async getCoreWebVitals() {
107
- const metrics = {};
108
- try {
109
- const fcpEntry = performance.getEntriesByName("first-contentful-paint")[0];
110
- if (fcpEntry) {
111
- metrics.fcp = fcpEntry.startTime;
112
- }
113
- const lcpEntries = performance.getEntriesByType("largest-contentful-paint");
114
- if (lcpEntries.length > 0) {
115
- const lcpEntry = lcpEntries[lcpEntries.length - 1];
116
- metrics.lcp = lcpEntry.startTime;
117
- }
118
- const fidEntries = performance.getEntriesByType("first-input");
119
- if (fidEntries.length > 0) {
120
- const fidEntry = fidEntries[0];
121
- metrics.fid = fidEntry.processingStart - fidEntry.startTime;
122
- }
123
- const clsEntries = performance.getEntriesByType("layout-shift");
124
- if (clsEntries.length > 0) {
125
- let clsValue = 0;
126
- for (const entry of clsEntries) {
127
- const clsEntry = entry;
128
- if (!clsEntry.hadRecentInput) {
129
- clsValue += clsEntry.value;
130
- }
131
- }
132
- metrics.cls = clsValue;
133
- }
134
- const tti = this.calculateTTI();
135
- if (tti) {
136
- metrics.tti = tti;
137
- }
138
- } catch (error) {
139
- console.warn("Failed to get Core Web Vitals:", error);
140
- }
141
- return metrics;
142
- }
143
- /**
144
- * Get navigation timing metrics
145
- */
146
- getNavigationTiming() {
147
- const navigation = performance.getEntriesByType("navigation")[0];
148
- if (!navigation) {
149
- return null;
150
- }
151
- return {
152
- // DNS lookup time
153
- dns: navigation.domainLookupEnd - navigation.domainLookupStart,
154
- // TCP connection time
155
- tcp: navigation.connectEnd - navigation.connectStart,
156
- // Request time
157
- request: navigation.responseStart - navigation.requestStart,
158
- // Response time
159
- response: navigation.responseEnd - navigation.responseStart,
160
- // DOM processing time
161
- domProcessing: navigation.domComplete - navigation.domInteractive,
162
- // Total page load time
163
- total: navigation.loadEventEnd - navigation.fetchStart
164
- };
165
- }
166
- /**
167
- * Get resource timing metrics
168
- */
169
- getResourceTiming() {
170
- const resources = performance.getEntriesByType("resource");
171
- return resources.map((resource) => ({
172
- name: resource.name,
173
- duration: resource.duration,
174
- size: resource.transferSize,
175
- type: this.getResourceType(resource.name)
176
- }));
177
- }
178
- /**
179
- * Measure function execution time
180
- */
181
- measureFunction(fn, name) {
182
- const start = performance.now();
183
- const result = fn();
184
- const end = performance.now();
185
- if (name) {
186
- performance.mark(`${name}-start`);
187
- performance.mark(`${name}-end`);
188
- performance.measure(name, `${name}-start`, `${name}-end`);
189
- }
190
- console.log(`Function ${name || "anonymous"} took ${end - start} milliseconds`);
191
- return result;
192
- }
193
- /**
194
- * Measure async function execution time
195
- */
196
- async measureAsyncFunction(fn, name) {
197
- const start = performance.now();
198
- const result = await fn();
199
- const end = performance.now();
200
- if (name) {
201
- performance.mark(`${name}-start`);
202
- performance.mark(`${name}-end`);
203
- performance.measure(name, `${name}-start`, `${name}-end`);
204
- }
205
- console.log(`Async function ${name || "anonymous"} took ${end - start} milliseconds`);
206
- return result;
207
- }
208
- /**
209
- * Get memory usage (if available)
210
- */
211
- getMemoryUsage() {
212
- if ("memory" in performance) {
213
- const memory = performance.memory;
214
- return {
215
- used: memory.usedJSHeapSize,
216
- total: memory.totalJSHeapSize,
217
- limit: memory.jsHeapSizeLimit
218
- };
219
- }
220
- return null;
221
- }
222
- calculateTTI() {
223
- const navigation = performance.getEntriesByType("navigation")[0];
224
- if (navigation) {
225
- return navigation.domContentLoadedEventEnd - navigation.fetchStart;
226
- }
227
- return null;
228
- }
229
- getResourceType(url) {
230
- if (url.includes(".js")) return "script";
231
- if (url.includes(".css")) return "stylesheet";
232
- if (url.includes(".png") || url.includes(".jpg") || url.includes(".gif")) return "image";
233
- if (url.includes(".woff") || url.includes(".ttf")) return "font";
234
- return "other";
235
- }
236
- }
237
- const performanceMonitor = new PerformanceMonitor();
238
- class PWAUtils {
239
- /**
240
- * Get PWA information
241
- */
242
- getPWAInfo() {
243
- return {
244
- isInstalled: this.isInstalled(),
245
- isInstallable: this.isInstallable(),
246
- canInstall: this.canInstall(),
247
- isStandalone: this.isStandalone()
248
- };
249
- }
250
- /**
251
- * Check if PWA is installed
252
- */
253
- isInstalled() {
254
- return this.isStandalone() || this.isInApp();
255
- }
256
- /**
257
- * Check if PWA is installable
258
- */
259
- isInstallable() {
260
- return "serviceWorker" in navigator && "PushManager" in window;
261
- }
262
- /**
263
- * Check if install prompt is available
264
- */
265
- canInstall() {
266
- return this.isInstallable() && !this.isInstalled();
267
- }
268
- /**
269
- * Check if running in standalone mode
270
- */
271
- isStandalone() {
272
- return window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true;
273
- }
274
- /**
275
- * Check if running in app (iOS)
276
- */
277
- isInApp() {
278
- return window.navigator.standalone === true;
279
- }
280
- /**
281
- * Register service worker
282
- */
283
- async registerServiceWorker(swPath) {
284
- if (!("serviceWorker" in navigator)) {
285
- console.warn("Service Worker not supported");
286
- return null;
287
- }
288
- try {
289
- const registration = await navigator.serviceWorker.register(swPath);
290
- console.log("Service Worker registered:", registration);
291
- return registration;
292
- } catch (error) {
293
- console.error("Service Worker registration failed:", error);
294
- return null;
295
- }
296
- }
297
- /**
298
- * Unregister service worker
299
- */
300
- async unregisterServiceWorker() {
301
- if (!("serviceWorker" in navigator)) {
302
- return false;
303
- }
304
- try {
305
- const registrations = await navigator.serviceWorker.getRegistrations();
306
- for (const registration of registrations) {
307
- await registration.unregister();
308
- }
309
- return true;
310
- } catch (error) {
311
- console.error("Service Worker unregistration failed:", error);
312
- return false;
313
- }
314
- }
315
- /**
316
- * Request notification permission
317
- */
318
- async requestNotificationPermission() {
319
- if (!("Notification" in window)) {
320
- throw new Error("Notifications not supported");
321
- }
322
- if (Notification.permission === "granted") {
323
- return "granted";
324
- }
325
- if (Notification.permission === "denied") {
326
- return "denied";
327
- }
328
- return await Notification.requestPermission();
329
- }
330
- /**
331
- * Send notification
332
- */
333
- async sendNotification(title, options) {
334
- if (!("Notification" in window)) {
335
- throw new Error("Notifications not supported");
336
- }
337
- if (Notification.permission !== "granted") {
338
- throw new Error("Notification permission not granted");
339
- }
340
- const notification = new Notification(title, options);
341
- setTimeout(() => {
342
- notification.close();
343
- }, 5e3);
344
- }
345
- /**
346
- * Share content using Web Share API
347
- */
348
- async share(data) {
349
- if (!("share" in navigator)) {
350
- throw new Error("Web Share API not supported");
351
- }
352
- try {
353
- await navigator.share(data);
354
- } catch (error) {
355
- if (error instanceof Error && error.name !== "AbortError") {
356
- throw new Error(`Share failed: ${error.message}`);
357
- }
358
- }
359
- }
360
- /**
361
- * Copy text to clipboard
362
- */
363
- async copyToClipboard(text) {
364
- if (!("clipboard" in navigator)) {
365
- throw new Error("Clipboard API not supported");
366
- }
367
- try {
368
- await navigator.clipboard.writeText(text);
369
- } catch (error) {
370
- throw new Error(`Copy to clipboard failed: ${error instanceof Error ? error.message : "Unknown error"}`);
371
- }
372
- }
373
- /**
374
- * Read text from clipboard
375
- */
376
- async readFromClipboard() {
377
- if (!("clipboard" in navigator)) {
378
- throw new Error("Clipboard API not supported");
379
- }
380
- try {
381
- return await navigator.clipboard.readText();
382
- } catch (error) {
383
- throw new Error(`Read from clipboard failed: ${error instanceof Error ? error.message : "Unknown error"}`);
384
- }
385
- }
386
- /**
387
- * Get install prompt event
388
- */
389
- getInstallPromptEvent() {
390
- return new Promise((resolve) => {
391
- const handleBeforeInstallPrompt = (e) => {
392
- e.preventDefault();
393
- resolve(e);
394
- window.removeEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
395
- };
396
- window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
397
- });
398
- }
399
- }
400
- const pwa = new PWAUtils();
401
- export {
402
- PlatformDetector as P,
403
- PerformanceMonitor as a,
404
- performanceMonitor as b,
405
- PWAUtils as c,
406
- pwa as d,
407
- platform as p
408
- };