@aippy/runtime 0.2.0 → 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.
- package/dist/audio/index.js +7 -7
- package/dist/core/index.js +29 -43
- package/dist/device/index.js +208 -270
- package/dist/errors-CDEBaBxB.js +26 -0
- package/dist/index/index.js +38 -38
- package/dist/pwa-DPd78fwK.js +342 -0
- package/dist/tweaks/index.js +3 -3
- package/dist/useAudioContext-DaLkaQ8P.js +223 -0
- package/dist/useTweaks-Bc26i-fJ.js +195 -0
- package/dist/utils/index.js +7 -7
- package/package.json +1 -1
- package/dist/errors-DAz5_jDJ.js +0 -25
- package/dist/pwa-BkviTQoN.js +0 -408
- package/dist/useAudioContext-D9Y4gIw9.js +0 -358
- package/dist/useTweaks-mK5PAWOs.js +0 -258
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
var e = Object.defineProperty;
|
|
2
|
+
var o = (E, R, N) => R in E ? e(E, R, { enumerable: !0, configurable: !0, writable: !0, value: N }) : E[R] = N;
|
|
3
|
+
var O = (E, R, N) => o(E, typeof R != "symbol" ? R + "" : R, N);
|
|
4
|
+
class I extends Error {
|
|
5
|
+
constructor(N, r = "AIPPY_ERROR", t) {
|
|
6
|
+
super(N);
|
|
7
|
+
O(this, "code");
|
|
8
|
+
O(this, "context");
|
|
9
|
+
this.name = "AippyRuntimeError", this.code = r, this.context = t;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const _ = {
|
|
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 s(E, R = "UNKNOWN_ERROR", N) {
|
|
20
|
+
return new I(E, _[R], N);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
I as A,
|
|
24
|
+
_ as E,
|
|
25
|
+
s as c
|
|
26
|
+
};
|
package/dist/index/index.js
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import { DEFAULT_CONFIG, SDK_NAME, VERSION, getConfigFromEnv, getVersionInfo, mergeConfig } from "../core/index.js";
|
|
2
|
-
import { A, E, c } from "../errors-
|
|
3
|
-
import { CameraAPI, FileSystemAPI, GeolocationAPI, SensorsAPI, camera, fileSystem, geolocation, sensors, vibrate } from "../device/index.js";
|
|
4
|
-
import { c as
|
|
5
|
-
import { a as
|
|
6
|
-
import { c as
|
|
1
|
+
import { DEFAULT_CONFIG as o, SDK_NAME as r, VERSION as t, getConfigFromEnv as s, getVersionInfo as i, mergeConfig as m } from "../core/index.js";
|
|
2
|
+
import { A as p, E as c, c as f } from "../errors-CDEBaBxB.js";
|
|
3
|
+
import { CameraAPI as A, FileSystemAPI as E, GeolocationAPI as l, SensorsAPI as S, camera as u, fileSystem as x, geolocation as I, sensors as P, vibrate as C } from "../device/index.js";
|
|
4
|
+
import { c as R, a as y, P as D, b as M, p as O, d as b } from "../pwa-DPd78fwK.js";
|
|
5
|
+
import { a as v, b as w } from "../useTweaks-Bc26i-fJ.js";
|
|
6
|
+
import { c as T, a as V, i as _, b as k, p as G, u as H } from "../useAudioContext-DaLkaQ8P.js";
|
|
7
7
|
export {
|
|
8
|
-
|
|
9
|
-
CameraAPI,
|
|
10
|
-
DEFAULT_CONFIG,
|
|
11
|
-
|
|
12
|
-
FileSystemAPI,
|
|
13
|
-
GeolocationAPI,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
SDK_NAME,
|
|
18
|
-
SensorsAPI,
|
|
19
|
-
VERSION,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
camera,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
fileSystem,
|
|
27
|
-
geolocation,
|
|
28
|
-
getConfigFromEnv,
|
|
29
|
-
getVersionInfo,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
mergeConfig,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
sensors,
|
|
38
|
-
|
|
39
|
-
vibrate
|
|
8
|
+
p as AippyRuntimeError,
|
|
9
|
+
A as CameraAPI,
|
|
10
|
+
o as DEFAULT_CONFIG,
|
|
11
|
+
c as ERROR_CODES,
|
|
12
|
+
E as FileSystemAPI,
|
|
13
|
+
l as GeolocationAPI,
|
|
14
|
+
R as PWAUtils,
|
|
15
|
+
y as PerformanceMonitor,
|
|
16
|
+
D as PlatformDetector,
|
|
17
|
+
r as SDK_NAME,
|
|
18
|
+
S as SensorsAPI,
|
|
19
|
+
t as VERSION,
|
|
20
|
+
v as aippyTweaks,
|
|
21
|
+
w as aippyTweaksRuntime,
|
|
22
|
+
u as camera,
|
|
23
|
+
f as createError,
|
|
24
|
+
T as createHiddenMediaElement,
|
|
25
|
+
V as createHiddenVideoElement,
|
|
26
|
+
x as fileSystem,
|
|
27
|
+
I as geolocation,
|
|
28
|
+
s as getConfigFromEnv,
|
|
29
|
+
i as getVersionInfo,
|
|
30
|
+
_ as isIOSDevice,
|
|
31
|
+
k as isMediaStreamAudioSupported,
|
|
32
|
+
m as mergeConfig,
|
|
33
|
+
G as patchAudioContext,
|
|
34
|
+
M as performanceMonitor,
|
|
35
|
+
O as platform,
|
|
36
|
+
b as pwa,
|
|
37
|
+
P as sensors,
|
|
38
|
+
H as useAudioContext,
|
|
39
|
+
C as vibrate
|
|
40
40
|
};
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
var u = Object.defineProperty;
|
|
2
|
+
var f = (o, e, r) => e in o ? u(o, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : o[e] = r;
|
|
3
|
+
var l = (o, e, r) => f(o, typeof e != "symbol" ? e + "" : e, r);
|
|
4
|
+
import { UAParser as m } from "ua-parser-js";
|
|
5
|
+
class p {
|
|
6
|
+
constructor() {
|
|
7
|
+
l(this, "parser");
|
|
8
|
+
this.parser = new m();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get platform information
|
|
12
|
+
*/
|
|
13
|
+
getPlatformInfo() {
|
|
14
|
+
const e = this.parser.getResult(), r = this.normalizePlatformName(e.os.name), t = this.normalizeBrowserName(e.browser.name), n = this.isMobileDevice(), i = !n;
|
|
15
|
+
return {
|
|
16
|
+
name: r,
|
|
17
|
+
version: e.os.version,
|
|
18
|
+
browser: t,
|
|
19
|
+
browserVersion: e.browser.version,
|
|
20
|
+
isMobile: n,
|
|
21
|
+
isDesktop: i
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get platform capabilities
|
|
26
|
+
*/
|
|
27
|
+
getCapabilities() {
|
|
28
|
+
return {
|
|
29
|
+
serviceWorker: "serviceWorker" in navigator,
|
|
30
|
+
pushNotifications: "PushManager" in window,
|
|
31
|
+
webShare: "share" in navigator,
|
|
32
|
+
clipboard: "clipboard" in navigator,
|
|
33
|
+
webRTC: !!(window.RTCPeerConnection || window.webkitRTCPeerConnection),
|
|
34
|
+
webGL: !!this.getWebGLContext(),
|
|
35
|
+
webAssembly: "WebAssembly" in window
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if device is mobile
|
|
40
|
+
*/
|
|
41
|
+
isMobileDevice() {
|
|
42
|
+
const e = navigator.userAgent;
|
|
43
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(e) || this.isTouchDevice();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if device supports touch
|
|
47
|
+
*/
|
|
48
|
+
isTouchDevice() {
|
|
49
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if running in standalone mode (PWA)
|
|
53
|
+
*/
|
|
54
|
+
isStandalone() {
|
|
55
|
+
return window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === !0;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if running in iOS Safari
|
|
59
|
+
*/
|
|
60
|
+
isIOSSafari() {
|
|
61
|
+
const e = this.getPlatformInfo();
|
|
62
|
+
return e.name === "ios" && e.browser === "safari";
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if running in Android Chrome
|
|
66
|
+
*/
|
|
67
|
+
isAndroidChrome() {
|
|
68
|
+
const e = this.getPlatformInfo();
|
|
69
|
+
return e.name === "android" && e.browser === "chrome";
|
|
70
|
+
}
|
|
71
|
+
normalizePlatformName(e) {
|
|
72
|
+
if (!e) return "unknown";
|
|
73
|
+
const r = e.toLowerCase();
|
|
74
|
+
return r.includes("ios") ? "ios" : r.includes("android") ? "android" : r.includes("windows") ? "windows" : r.includes("mac") ? "macos" : r.includes("linux") ? "linux" : "unknown";
|
|
75
|
+
}
|
|
76
|
+
normalizeBrowserName(e) {
|
|
77
|
+
if (!e) return "unknown";
|
|
78
|
+
const r = e.toLowerCase();
|
|
79
|
+
return r.includes("chrome") ? "chrome" : r.includes("firefox") ? "firefox" : r.includes("safari") ? "safari" : r.includes("edge") ? "edge" : "unknown";
|
|
80
|
+
}
|
|
81
|
+
getWebGLContext() {
|
|
82
|
+
try {
|
|
83
|
+
const e = document.createElement("canvas");
|
|
84
|
+
return e.getContext("webgl") || e.getContext("experimental-webgl");
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const y = new p();
|
|
91
|
+
class w {
|
|
92
|
+
/**
|
|
93
|
+
* Get Core Web Vitals metrics
|
|
94
|
+
*/
|
|
95
|
+
async getCoreWebVitals() {
|
|
96
|
+
const e = {};
|
|
97
|
+
try {
|
|
98
|
+
const r = performance.getEntriesByName("first-contentful-paint")[0];
|
|
99
|
+
r && (e.fcp = r.startTime);
|
|
100
|
+
const t = performance.getEntriesByType("largest-contentful-paint");
|
|
101
|
+
if (t.length > 0) {
|
|
102
|
+
const s = t[t.length - 1];
|
|
103
|
+
e.lcp = s.startTime;
|
|
104
|
+
}
|
|
105
|
+
const n = performance.getEntriesByType("first-input");
|
|
106
|
+
if (n.length > 0) {
|
|
107
|
+
const s = n[0];
|
|
108
|
+
e.fid = s.processingStart - s.startTime;
|
|
109
|
+
}
|
|
110
|
+
const i = performance.getEntriesByType("layout-shift");
|
|
111
|
+
if (i.length > 0) {
|
|
112
|
+
let s = 0;
|
|
113
|
+
for (const d of i) {
|
|
114
|
+
const c = d;
|
|
115
|
+
c.hadRecentInput || (s += c.value);
|
|
116
|
+
}
|
|
117
|
+
e.cls = s;
|
|
118
|
+
}
|
|
119
|
+
const a = this.calculateTTI();
|
|
120
|
+
a && (e.tti = a);
|
|
121
|
+
} catch (r) {
|
|
122
|
+
console.warn("Failed to get Core Web Vitals:", r);
|
|
123
|
+
}
|
|
124
|
+
return e;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get navigation timing metrics
|
|
128
|
+
*/
|
|
129
|
+
getNavigationTiming() {
|
|
130
|
+
const e = performance.getEntriesByType("navigation")[0];
|
|
131
|
+
return e ? {
|
|
132
|
+
// DNS lookup time
|
|
133
|
+
dns: e.domainLookupEnd - e.domainLookupStart,
|
|
134
|
+
// TCP connection time
|
|
135
|
+
tcp: e.connectEnd - e.connectStart,
|
|
136
|
+
// Request time
|
|
137
|
+
request: e.responseStart - e.requestStart,
|
|
138
|
+
// Response time
|
|
139
|
+
response: e.responseEnd - e.responseStart,
|
|
140
|
+
// DOM processing time
|
|
141
|
+
domProcessing: e.domComplete - e.domInteractive,
|
|
142
|
+
// Total page load time
|
|
143
|
+
total: e.loadEventEnd - e.fetchStart
|
|
144
|
+
} : null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get resource timing metrics
|
|
148
|
+
*/
|
|
149
|
+
getResourceTiming() {
|
|
150
|
+
return performance.getEntriesByType("resource").map((r) => ({
|
|
151
|
+
name: r.name,
|
|
152
|
+
duration: r.duration,
|
|
153
|
+
size: r.transferSize,
|
|
154
|
+
type: this.getResourceType(r.name)
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Measure function execution time
|
|
159
|
+
*/
|
|
160
|
+
measureFunction(e, r) {
|
|
161
|
+
const t = performance.now(), n = e(), i = performance.now();
|
|
162
|
+
return r && (performance.mark(`${r}-start`), performance.mark(`${r}-end`), performance.measure(r, `${r}-start`, `${r}-end`)), console.log(`Function ${r || "anonymous"} took ${i - t} milliseconds`), n;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Measure async function execution time
|
|
166
|
+
*/
|
|
167
|
+
async measureAsyncFunction(e, r) {
|
|
168
|
+
const t = performance.now(), n = await e(), i = performance.now();
|
|
169
|
+
return r && (performance.mark(`${r}-start`), performance.mark(`${r}-end`), performance.measure(r, `${r}-start`, `${r}-end`)), console.log(`Async function ${r || "anonymous"} took ${i - t} milliseconds`), n;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get memory usage (if available)
|
|
173
|
+
*/
|
|
174
|
+
getMemoryUsage() {
|
|
175
|
+
if ("memory" in performance) {
|
|
176
|
+
const e = performance.memory;
|
|
177
|
+
return {
|
|
178
|
+
used: e.usedJSHeapSize,
|
|
179
|
+
total: e.totalJSHeapSize,
|
|
180
|
+
limit: e.jsHeapSizeLimit
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
calculateTTI() {
|
|
186
|
+
const e = performance.getEntriesByType("navigation")[0];
|
|
187
|
+
return e ? e.domContentLoadedEventEnd - e.fetchStart : null;
|
|
188
|
+
}
|
|
189
|
+
getResourceType(e) {
|
|
190
|
+
return e.includes(".js") ? "script" : e.includes(".css") ? "stylesheet" : e.includes(".png") || e.includes(".jpg") || e.includes(".gif") ? "image" : e.includes(".woff") || e.includes(".ttf") ? "font" : "other";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const b = new w();
|
|
194
|
+
class g {
|
|
195
|
+
/**
|
|
196
|
+
* Get PWA information
|
|
197
|
+
*/
|
|
198
|
+
getPWAInfo() {
|
|
199
|
+
return {
|
|
200
|
+
isInstalled: this.isInstalled(),
|
|
201
|
+
isInstallable: this.isInstallable(),
|
|
202
|
+
canInstall: this.canInstall(),
|
|
203
|
+
isStandalone: this.isStandalone()
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Check if PWA is installed
|
|
208
|
+
*/
|
|
209
|
+
isInstalled() {
|
|
210
|
+
return this.isStandalone() || this.isInApp();
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Check if PWA is installable
|
|
214
|
+
*/
|
|
215
|
+
isInstallable() {
|
|
216
|
+
return "serviceWorker" in navigator && "PushManager" in window;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Check if install prompt is available
|
|
220
|
+
*/
|
|
221
|
+
canInstall() {
|
|
222
|
+
return this.isInstallable() && !this.isInstalled();
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Check if running in standalone mode
|
|
226
|
+
*/
|
|
227
|
+
isStandalone() {
|
|
228
|
+
return window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === !0;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Check if running in app (iOS)
|
|
232
|
+
*/
|
|
233
|
+
isInApp() {
|
|
234
|
+
return window.navigator.standalone === !0;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Register service worker
|
|
238
|
+
*/
|
|
239
|
+
async registerServiceWorker(e) {
|
|
240
|
+
if (!("serviceWorker" in navigator))
|
|
241
|
+
return console.warn("Service Worker not supported"), null;
|
|
242
|
+
try {
|
|
243
|
+
const r = await navigator.serviceWorker.register(e);
|
|
244
|
+
return console.log("Service Worker registered:", r), r;
|
|
245
|
+
} catch (r) {
|
|
246
|
+
return console.error("Service Worker registration failed:", r), null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Unregister service worker
|
|
251
|
+
*/
|
|
252
|
+
async unregisterServiceWorker() {
|
|
253
|
+
if (!("serviceWorker" in navigator))
|
|
254
|
+
return !1;
|
|
255
|
+
try {
|
|
256
|
+
const e = await navigator.serviceWorker.getRegistrations();
|
|
257
|
+
for (const r of e)
|
|
258
|
+
await r.unregister();
|
|
259
|
+
return !0;
|
|
260
|
+
} catch (e) {
|
|
261
|
+
return console.error("Service Worker unregistration failed:", e), !1;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Request notification permission
|
|
266
|
+
*/
|
|
267
|
+
async requestNotificationPermission() {
|
|
268
|
+
if (!("Notification" in window))
|
|
269
|
+
throw new Error("Notifications not supported");
|
|
270
|
+
return Notification.permission === "granted" ? "granted" : Notification.permission === "denied" ? "denied" : await Notification.requestPermission();
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Send notification
|
|
274
|
+
*/
|
|
275
|
+
async sendNotification(e, r) {
|
|
276
|
+
if (!("Notification" in window))
|
|
277
|
+
throw new Error("Notifications not supported");
|
|
278
|
+
if (Notification.permission !== "granted")
|
|
279
|
+
throw new Error("Notification permission not granted");
|
|
280
|
+
const t = new Notification(e, r);
|
|
281
|
+
setTimeout(() => {
|
|
282
|
+
t.close();
|
|
283
|
+
}, 5e3);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Share content using Web Share API
|
|
287
|
+
*/
|
|
288
|
+
async share(e) {
|
|
289
|
+
if (!("share" in navigator))
|
|
290
|
+
throw new Error("Web Share API not supported");
|
|
291
|
+
try {
|
|
292
|
+
await navigator.share(e);
|
|
293
|
+
} catch (r) {
|
|
294
|
+
if (r instanceof Error && r.name !== "AbortError")
|
|
295
|
+
throw new Error(`Share failed: ${r.message}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Copy text to clipboard
|
|
300
|
+
*/
|
|
301
|
+
async copyToClipboard(e) {
|
|
302
|
+
if (!("clipboard" in navigator))
|
|
303
|
+
throw new Error("Clipboard API not supported");
|
|
304
|
+
try {
|
|
305
|
+
await navigator.clipboard.writeText(e);
|
|
306
|
+
} catch (r) {
|
|
307
|
+
throw new Error(`Copy to clipboard failed: ${r instanceof Error ? r.message : "Unknown error"}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Read text from clipboard
|
|
312
|
+
*/
|
|
313
|
+
async readFromClipboard() {
|
|
314
|
+
if (!("clipboard" in navigator))
|
|
315
|
+
throw new Error("Clipboard API not supported");
|
|
316
|
+
try {
|
|
317
|
+
return await navigator.clipboard.readText();
|
|
318
|
+
} catch (e) {
|
|
319
|
+
throw new Error(`Read from clipboard failed: ${e instanceof Error ? e.message : "Unknown error"}`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get install prompt event
|
|
324
|
+
*/
|
|
325
|
+
getInstallPromptEvent() {
|
|
326
|
+
return new Promise((e) => {
|
|
327
|
+
const r = (t) => {
|
|
328
|
+
t.preventDefault(), e(t), window.removeEventListener("beforeinstallprompt", r);
|
|
329
|
+
};
|
|
330
|
+
window.addEventListener("beforeinstallprompt", r);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const E = new g();
|
|
335
|
+
export {
|
|
336
|
+
p as P,
|
|
337
|
+
w as a,
|
|
338
|
+
b,
|
|
339
|
+
g as c,
|
|
340
|
+
E as d,
|
|
341
|
+
y as p
|
|
342
|
+
};
|
package/dist/tweaks/index.js
CHANGED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
var v = Object.defineProperty;
|
|
2
|
+
var S = (e, t, n) => t in e ? v(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
|
|
3
|
+
var s = (e, t, n) => S(e, typeof t != "symbol" ? t + "" : t, n);
|
|
4
|
+
import { useState as k, useRef as w, useEffect as p } from "react";
|
|
5
|
+
function T() {
|
|
6
|
+
const e = navigator.userAgent;
|
|
7
|
+
return !!(/iPad|iPhone|iPod/.test(e) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
|
|
8
|
+
}
|
|
9
|
+
function P() {
|
|
10
|
+
try {
|
|
11
|
+
if (!window.AudioContext)
|
|
12
|
+
return !1;
|
|
13
|
+
const e = new AudioContext(), t = typeof e.createMediaStreamDestination == "function";
|
|
14
|
+
return e.close(), t;
|
|
15
|
+
} catch {
|
|
16
|
+
return !1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function D(e = "video", t = !1) {
|
|
20
|
+
const n = document.createElement(e);
|
|
21
|
+
return n.muted = !1, n.autoplay = !0, e === "video" && (n.playsInline = !0), t ? n.style.cssText = "position:fixed;bottom:10px;right:10px;width:200px;background:#ff0000;z-index:9999;" : n.style.cssText = "position:fixed;width:1px;height:1px;opacity:0;pointer-events:none;", n;
|
|
22
|
+
}
|
|
23
|
+
function M(e = !1) {
|
|
24
|
+
return D("video", e);
|
|
25
|
+
}
|
|
26
|
+
class E {
|
|
27
|
+
constructor(t, n, i, a = !1) {
|
|
28
|
+
s(this, "analyser");
|
|
29
|
+
s(this, "dataArray");
|
|
30
|
+
s(this, "rafId", null);
|
|
31
|
+
s(this, "silenceStartTime", 0);
|
|
32
|
+
s(this, "isPaused", !1);
|
|
33
|
+
s(this, "lastCheckTime", 0);
|
|
34
|
+
s(this, "silenceThreshold");
|
|
35
|
+
s(this, "silenceDuration");
|
|
36
|
+
s(this, "checkInterval");
|
|
37
|
+
s(this, "debug");
|
|
38
|
+
/**
|
|
39
|
+
* Check audio levels and pause/resume as needed
|
|
40
|
+
*/
|
|
41
|
+
s(this, "check", () => {
|
|
42
|
+
const t = performance.now();
|
|
43
|
+
t - this.lastCheckTime >= this.checkInterval && (this.lastCheckTime = t, this.getAudioLevel() < this.silenceThreshold ? this.silenceStartTime === 0 ? this.silenceStartTime = t : t - this.silenceStartTime >= this.silenceDuration && !this.isPaused && this.pauseMedia() : (this.silenceStartTime = 0, this.isPaused && this.resumeMedia())), this.rafId = requestAnimationFrame(this.check);
|
|
44
|
+
});
|
|
45
|
+
this.audioContext = t, this.mediaElement = n, this.silenceThreshold = i.silenceThreshold, this.silenceDuration = i.silenceDuration, this.checkInterval = i.checkInterval, this.debug = a, this.analyser = t.createAnalyser(), this.analyser.fftSize = 512, this.analyser.smoothingTimeConstant = 0.3, this.dataArray = new Uint8Array(this.analyser.frequencyBinCount);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Connect the detector to the audio stream
|
|
49
|
+
*/
|
|
50
|
+
connect(t) {
|
|
51
|
+
t.connect(this.analyser);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Start monitoring audio levels
|
|
55
|
+
*/
|
|
56
|
+
start() {
|
|
57
|
+
this.rafId === null && (this.lastCheckTime = performance.now(), this.check(), this.debug && console.log("[AudioSilenceDetector] Started monitoring"));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Stop monitoring
|
|
61
|
+
*/
|
|
62
|
+
stop() {
|
|
63
|
+
this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.debug && console.log("[AudioSilenceDetector] Stopped monitoring");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Cleanup resources
|
|
67
|
+
*/
|
|
68
|
+
dispose() {
|
|
69
|
+
this.stop(), this.analyser.disconnect();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get current audio level (0-1)
|
|
73
|
+
*/
|
|
74
|
+
getAudioLevel() {
|
|
75
|
+
this.analyser.getByteTimeDomainData(this.dataArray);
|
|
76
|
+
let t = 0;
|
|
77
|
+
for (let n = 0; n < this.dataArray.length; n++) {
|
|
78
|
+
const i = (this.dataArray[n] - 128) / 128;
|
|
79
|
+
t += i * i;
|
|
80
|
+
}
|
|
81
|
+
return Math.sqrt(t / this.dataArray.length);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Pause media element to stop audio output
|
|
85
|
+
*/
|
|
86
|
+
pauseMedia() {
|
|
87
|
+
try {
|
|
88
|
+
this.mediaElement.pause(), this.isPaused = !0, this.debug && console.log("[AudioSilenceDetector] Paused media element (silence detected)");
|
|
89
|
+
} catch (t) {
|
|
90
|
+
console.error("[AudioSilenceDetector] Failed to pause:", t);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Resume media element playback
|
|
95
|
+
*/
|
|
96
|
+
resumeMedia() {
|
|
97
|
+
try {
|
|
98
|
+
this.audioContext.state === "running" && this.mediaElement.play().catch((t) => {
|
|
99
|
+
this.debug && console.warn("[AudioSilenceDetector] Failed to resume:", t);
|
|
100
|
+
}), this.isPaused = !1, this.debug && console.log("[AudioSilenceDetector] Resumed media element (audio detected)");
|
|
101
|
+
} catch (t) {
|
|
102
|
+
console.error("[AudioSilenceDetector] Failed to resume:", t);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function x(e, t = {}) {
|
|
107
|
+
const {
|
|
108
|
+
forceEnable: n = !1,
|
|
109
|
+
autoCleanup: i = !0,
|
|
110
|
+
debug: a = !1,
|
|
111
|
+
mediaElementType: m = "video",
|
|
112
|
+
autoPause: d = {}
|
|
113
|
+
} = t, h = {
|
|
114
|
+
enabled: d.enabled ?? !0,
|
|
115
|
+
silenceThreshold: d.silenceThreshold ?? 1e-3,
|
|
116
|
+
silenceDuration: d.silenceDuration ?? 50,
|
|
117
|
+
checkInterval: d.checkInterval ?? 16
|
|
118
|
+
};
|
|
119
|
+
if (!(n || T()))
|
|
120
|
+
return Object.assign(e, {
|
|
121
|
+
unlock: async () => {
|
|
122
|
+
e.state === "suspended" && await e.resume();
|
|
123
|
+
},
|
|
124
|
+
cleanup: () => {
|
|
125
|
+
},
|
|
126
|
+
isPatched: !1,
|
|
127
|
+
originalDestination: e.destination
|
|
128
|
+
});
|
|
129
|
+
if (!P())
|
|
130
|
+
return console.warn(
|
|
131
|
+
"[AudioContext] MediaStreamAudioDestinationNode not supported, falling back to native"
|
|
132
|
+
), Object.assign(e, {
|
|
133
|
+
unlock: async () => e.resume(),
|
|
134
|
+
cleanup: () => {
|
|
135
|
+
},
|
|
136
|
+
isPatched: !1,
|
|
137
|
+
originalDestination: e.destination
|
|
138
|
+
});
|
|
139
|
+
const c = e.destination, g = e.createMediaStreamDestination(), f = e.createGain();
|
|
140
|
+
f.gain.value = 1, f.connect(g);
|
|
141
|
+
const l = D(m, a);
|
|
142
|
+
l.srcObject = g.stream, document.body.appendChild(l);
|
|
143
|
+
let u = null;
|
|
144
|
+
h.enabled && (u = new E(
|
|
145
|
+
e,
|
|
146
|
+
l,
|
|
147
|
+
h,
|
|
148
|
+
a
|
|
149
|
+
), u.connect(f)), Object.defineProperty(e, "destination", {
|
|
150
|
+
get: () => f,
|
|
151
|
+
enumerable: !0,
|
|
152
|
+
configurable: !0
|
|
153
|
+
}), "maxChannelCount" in f || Object.defineProperty(f, "maxChannelCount", {
|
|
154
|
+
get: () => c.maxChannelCount,
|
|
155
|
+
enumerable: !0
|
|
156
|
+
});
|
|
157
|
+
let y = !1;
|
|
158
|
+
const b = async () => {
|
|
159
|
+
if (!y)
|
|
160
|
+
try {
|
|
161
|
+
await l.play(), e.state === "suspended" && await e.resume(), u && u.start(), y = !0, a && console.log("[AudioContext] iOS unlock successful");
|
|
162
|
+
} catch (o) {
|
|
163
|
+
throw o instanceof DOMException && o.name === "NotAllowedError" ? (a && console.log("[AudioContext] Unlock requires user interaction"), o) : (console.error("[AudioContext] Unlock failed:", o), o);
|
|
164
|
+
}
|
|
165
|
+
}, A = () => {
|
|
166
|
+
try {
|
|
167
|
+
u && (u.dispose(), u = null), l.pause(), l.srcObject = null, l.remove(), a && console.log("[AudioContext] Cleanup completed");
|
|
168
|
+
} catch (o) {
|
|
169
|
+
console.error("[AudioContext] Cleanup error:", o);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
if (i) {
|
|
173
|
+
const o = e.close.bind(e);
|
|
174
|
+
e.close = async () => (A(), o());
|
|
175
|
+
}
|
|
176
|
+
return Object.assign(e, {
|
|
177
|
+
unlock: b,
|
|
178
|
+
cleanup: A,
|
|
179
|
+
isPatched: !0,
|
|
180
|
+
originalDestination: c
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function O(e = {}) {
|
|
184
|
+
const { autoUnlock: t = !0, ...n } = e, [i, a] = k(null), [m, d] = k(!1), h = w(null);
|
|
185
|
+
return p(() => {
|
|
186
|
+
const r = new AudioContext(), c = x(r, n);
|
|
187
|
+
return a(c), () => {
|
|
188
|
+
c.cleanup(), c.close();
|
|
189
|
+
};
|
|
190
|
+
}, []), p(() => {
|
|
191
|
+
i && (h.current = async () => {
|
|
192
|
+
if (!m)
|
|
193
|
+
try {
|
|
194
|
+
await i.unlock(), d(!0);
|
|
195
|
+
} catch (r) {
|
|
196
|
+
if (r instanceof DOMException && r.name === "NotAllowedError")
|
|
197
|
+
return;
|
|
198
|
+
console.warn("Failed to unlock audio:", r);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}, [i, m]), p(() => {
|
|
202
|
+
if (!t || !i) return;
|
|
203
|
+
const r = async (c) => {
|
|
204
|
+
c.isTrusted && await h.current?.();
|
|
205
|
+
};
|
|
206
|
+
return document.addEventListener("click", r, { once: !0, capture: !0 }), document.addEventListener("touchstart", r, { once: !0, capture: !0 }), () => {
|
|
207
|
+
document.removeEventListener("click", r, { capture: !0 }), document.removeEventListener("touchstart", r, { capture: !0 });
|
|
208
|
+
};
|
|
209
|
+
}, [t, i]), {
|
|
210
|
+
audioContext: i,
|
|
211
|
+
isUnlocked: m,
|
|
212
|
+
unlock: h.current || (async () => {
|
|
213
|
+
})
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
export {
|
|
217
|
+
M as a,
|
|
218
|
+
P as b,
|
|
219
|
+
D as c,
|
|
220
|
+
T as i,
|
|
221
|
+
x as p,
|
|
222
|
+
O as u
|
|
223
|
+
};
|