@bty/feed_app-runtime-sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -3
- package/dist/ai/index.d.ts +17 -1
- package/dist/ai/index.js +2 -2
- package/dist/device/index.d.ts +66 -2
- package/dist/device/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,6 +82,20 @@ The AI entry supports:
|
|
|
82
82
|
- `AbortSignal` cancellation
|
|
83
83
|
- Structured AI errors
|
|
84
84
|
|
|
85
|
+
When an AI HTTP request receives a non-2xx response, the SDK emits a sanitized
|
|
86
|
+
host notification before throwing the typed `AiError`. In the product page:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
window.addEventListener('feed-app-runtime-sdk:ai-error', (event) => {
|
|
90
|
+
// event.detail: { status, code, message, path, method, ... }
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
When the product runs inside a host iframe, the same payload is also sent to
|
|
95
|
+
`window.parent.postMessage({ type: 'feed-app-runtime-sdk:ai-error', detail }, '*')`.
|
|
96
|
+
The payload intentionally omits raw provider bodies and headers; branch on
|
|
97
|
+
`detail.status` / `detail.code` for host-level UI.
|
|
98
|
+
|
|
85
99
|
> **Media payloads are pass-through.** `images.generate` / `audio.speech.create`
|
|
86
100
|
> / `video.generations.create` forward the body verbatim to the upstream
|
|
87
101
|
> provider — there is no client-side reshaping, and each model has its own
|
|
@@ -137,9 +151,9 @@ entry do not need to install React.
|
|
|
137
151
|
|
|
138
152
|
## Device
|
|
139
153
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
individual capabilities for tree-shaking.
|
|
154
|
+
Six host-bridged capabilities, each with a layered fallback: native App bridge
|
|
155
|
+
→ iframe parent relay → browser Web API → safe default. Import the `device`
|
|
156
|
+
namespace, or the individual capabilities for tree-shaking.
|
|
143
157
|
|
|
144
158
|
```ts
|
|
145
159
|
import {
|
|
@@ -148,6 +162,7 @@ import {
|
|
|
148
162
|
sensors,
|
|
149
163
|
camera,
|
|
150
164
|
files,
|
|
165
|
+
microphone,
|
|
151
166
|
} from '@bty/feed_app-runtime-sdk/device'
|
|
152
167
|
|
|
153
168
|
await haptics.impact('medium')
|
|
@@ -156,6 +171,7 @@ const stop = sensors.watchMotion((s) => console.log(s.accelerationWithGravity))
|
|
|
156
171
|
const photo = await camera.capturePhoto({ camera: 'back' }) // CapturedPhoto | null
|
|
157
172
|
const picked = await files.pickFiles({ accept: ['image/*'], multiple: true })
|
|
158
173
|
const result = await files.saveFile(blob, 'export.json') // "saved" | "cancelled" | "failed"
|
|
174
|
+
const clip = await microphone.recordAudio({ maxDurationMs: 5000 }) // AudioRecording | null
|
|
159
175
|
stop() // dispose the motion subscription
|
|
160
176
|
```
|
|
161
177
|
|
|
@@ -173,11 +189,19 @@ Capability detection (synchronous, cheap — gate UI ahead of a call):
|
|
|
173
189
|
| Camera | `camera.isSupported()` |
|
|
174
190
|
| Sensors | `sensors.isMotionSupported()` / `sensors.isOrientationSupported()` |
|
|
175
191
|
| Files | `files.isPickerSupported()` (the *modern* picker; plain pick always works) |
|
|
192
|
+
| Microphone | `microphone.isSupported()` |
|
|
176
193
|
|
|
177
194
|
`requestMotionPermission()`, `capturePhoto()`, `saveFile()`, and `pickFiles()`
|
|
178
195
|
must be called from inside a user-gesture handler (tap / click) — browsers
|
|
179
196
|
silently deny these outside a gesture.
|
|
180
197
|
|
|
198
|
+
When a feed-app runs inside the host SPA iframe, one-shot device calls reuse the
|
|
199
|
+
same native command frame through `window.parent.postMessage`. The parent shell
|
|
200
|
+
forwards supported commands to the native App and returns the App envelope to
|
|
201
|
+
the child frame. If the parent cannot relay, SDK calls fall through to their web
|
|
202
|
+
fallback. `camera.openStream()` and `microphone.startRecording()` remain
|
|
203
|
+
web-only streaming APIs.
|
|
204
|
+
|
|
181
205
|
## Published Files
|
|
182
206
|
|
|
183
207
|
The npm package publishes only built output and this README:
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -332,4 +332,20 @@ declare class AbortedError extends AiError {
|
|
|
332
332
|
constructor(message?: string);
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
declare const AI_ERROR_EVENT = "feed-app-runtime-sdk:ai-error";
|
|
336
|
+
interface AiErrorEventDetail {
|
|
337
|
+
source: "feed-app-runtime-sdk/ai";
|
|
338
|
+
status: number;
|
|
339
|
+
code: AiErrorCode;
|
|
340
|
+
message: string;
|
|
341
|
+
path: string;
|
|
342
|
+
method: "GET" | "POST";
|
|
343
|
+
sdkVersion: string;
|
|
344
|
+
timestamp: number;
|
|
345
|
+
requestId?: string;
|
|
346
|
+
traceId?: string;
|
|
347
|
+
/** True for the first 401/403 response when the SDK will still refresh + retry. */
|
|
348
|
+
willRetryAuth?: boolean;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export { AI_ERROR_EVENT, AbortedError, AiError, type AiErrorCode, type AiErrorEventDetail, type AnthropicContentBlock, type AnthropicMessage, type AnthropicMessageResponse, type AnthropicStreamEvent, type AnthropicTool, type AudioSpeechCreateParams, AuthRequiredError, BadInputError, type ChatCompletion, type ChatCompletionChunk, type ChatCompletionCreateParams, type ChatContentPart, type ChatMessage, type ChatTool, type ChatToolCall, type ImageGenerateParams, type ImageGenerateResponse, type MessagesCreateParams, NetworkError, QuotaExceededError, RateLimitError, type RuntimeConfig, ServerError, type VideoGenerateParams, type VideoGenerateResponse, anthropic, configureRuntime, openai };
|
package/dist/ai/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {d as d$1,c}from'../chunk-AKZVV563.js';import {a}from'../chunk-ALNJCFV4.js';import {createParser}from'eventsource-parser';var
|
|
2
|
-
export{l as AbortedError,
|
|
1
|
+
import {d as d$1,c}from'../chunk-AKZVV563.js';import {a as a$1}from'../chunk-ALNJCFV4.js';import {createParser}from'eventsource-parser';var D={version:"0.1.2"};var m="/v1/feed-app/runtime/ai",T=`${m}/chat/completions`,_=`${m}/messages`,B=`${m}/images/generations`,M=`${m}/audio/speech`,N=`${m}/video/generations`,H="Authorization",j="x-bty-extend",G="x-bty-app",h=D.version;var q=()=>{};async function*U(e){let t=e.getReader(),r=new TextDecoder,n=[],o=createParser({onEvent(c){n.push({event:c.event||"message",data:c.data});},onRetry:q,onComment:q}),s=false;try{for(;;){let{done:c,value:p}=await t.read();for(p&&o.feed(r.decode(p,{stream:!0}));n.length>0;)yield n.shift();if(c){for(o.reset({consume:!0});n.length>0;)yield n.shift();s=!0;return}}}finally{if(!s)try{await t.cancel();}catch{}t.releaseLock();}}async function*J(e){for await(let t of U(e)){if(t.data==="[DONE]")return;t.data&&(yield JSON.parse(t.data));}}async function*V(e){for await(let t of U(e))t.data&&(yield JSON.parse(t.data));}var Z="https://reactus-api.happyseeds.ai",$=e=>{try{let t=e();if(typeof t=="string"&&t.length>0)return t}catch{}},ee=()=>$(()=>typeof __BTY_RUNTIME_API_BASE_URL__=="string"?__BTY_RUNTIME_API_BASE_URL__:void 0),te=()=>$(()=>typeof __BTY_RUNTIME_PROJECT_ID__=="string"?__BTY_RUNTIME_PROJECT_ID__:void 0),x={apiBaseUrl:(ee()??Z).replace(/\/+$/,""),projectId:te()??""},re=e=>{x={...x,...e,...e.apiBaseUrl?{apiBaseUrl:e.apiBaseUrl.replace(/\/+$/,"")}:{}};},g=()=>x;var a=class extends Error{status;code;body;constructor(t,r,n,o=null){super(t),this.name="AiError",this.code=r,this.status=n,this.body=o;}},i=class extends a{constructor(t="Auth required",r=null){super(t,"auth_required",401,r),this.name="AuthRequiredError";}},y=class extends a{constructor(t="Rate limit exceeded",r=null){super(t,"rate_limit",429,r),this.name="RateLimitError";}},E=class extends a{constructor(t="Quota exceeded",r=null){super(t,"quota_exceeded",402,r),this.name="QuotaExceededError";}},A=class extends a{constructor(t,r=400,n=null){super(t,"bad_input",r,n),this.name="BadInputError";}},R=class extends a{constructor(t,r=500,n=null){super(t,"server",r,n),this.name="ServerError";}},d=class extends a{constructor(t="Network error",r){super(t,"network",-1,r),this.name="NetworkError";}},l=class extends a{constructor(t="Request aborted"){super(t,"aborted",-1,null),this.name="AbortedError";}},L=e=>typeof e=="object"&&e!==null,ne=(e,t)=>{if(typeof e=="string")return e||t;if(!L(e))return t;let r=e.message;if(typeof r=="string"&&r.length>0)return r;let n=e.error;if(typeof n=="string"&&n.length>0)return n;if(L(n)&&typeof n.message=="string"&&n.message.length>0)return n.message;let o=e.detail;return typeof o=="string"&&o.length>0?o:t},P=(e,t)=>{let r=ne(t,`HTTP ${e}`);return e===401||e===403?new i(r,t):e===402?new E(r,t):e===429?new y(r,t):e>=400&&e<500?new A(r,e,t):e>=500?new R(r,e,t):new a(r,"unknown",e,t)};var oe=e=>JSON.stringify({"sdk-version":h,...e}),F=async(e={})=>{let t=await c(),r=new Headers;t&&r.set(H,`Bearer ${t}`),r.set(j,oe(e.extend));let{projectId:n}=g();if(n&&r.set(G,n),e.contentType&&r.set("Content-Type",e.contentType),e.accept&&r.set("Accept",e.accept),e.extra)for(let[o,s]of Object.entries(e.extra))r.set(o,s);return r};var S="feed-app-runtime-sdk:ai-error",se=e=>typeof e=="object"&&e!==null,ae=(e,t)=>{if(se(e))for(let r of t){let n=e[r];if(typeof n=="string"&&n.length>0)return n}},Y=e=>{let t=ae(e.body,["request_id","requestId"]);return {source:"feed-app-runtime-sdk/ai",status:e.error.status,code:e.error.code,message:e.error.message,path:e.path,method:e.method,sdkVersion:h,timestamp:Date.now(),...t?{requestId:t}:{},...e.traceId?{traceId:e.traceId}:{},...e.willRetryAuth!==void 0?{willRetryAuth:e.willRetryAuth}:{}}},K=e=>{if(a$1()&&(window.dispatchEvent(new CustomEvent(S,{detail:e})),window.parent!==window))try{window.parent.postMessage({type:S,detail:e},"*");}catch{}};var ie="feed-app-runtime-sdk:auth-required",k=e=>{a$1()&&window.dispatchEvent(new CustomEvent(ie,{detail:e}));};var ce=e=>e instanceof DOMException&&e.name==="AbortError",pe=async e=>{let t=e.headers.get("content-type")??"";try{return t.includes("application/json")?await e.json():await e.text()}catch{return null}},de=e=>typeof e=="object"&&e!==null,ue=(e,t)=>{if(!de(e)||typeof e.success!="boolean")return e;if(e.success)return e.data;let r=typeof e.code=="number"?e.code:t;throw P(r,e)},Q=async(e,t)=>{let{apiBaseUrl:r}=g(),n=`${r}${e}`,o=await F(t),s;try{s=await fetch(n,{method:t.method??"POST",headers:o,body:t.body,signal:t.signal});}catch(b){throw ce(b)?new l:new d("Failed to reach AI backend",b)}if(s.ok)return s;let c=await pe(s),p=P(s.status,c);throw K(Y({error:p,path:e,method:t.method??"POST",body:c,traceId:s.headers.get("x-trace-id")??void 0,willRetryAuth:p instanceof i&&!t.skipAuthRetry&&!t.signal?.aborted})),p},v=async(e,t={})=>{try{return await Q(e,t)}catch(r){if(r instanceof i&&!t.skipAuthRetry&&!t.signal?.aborted){if(!await d$1())throw k({reason:"refresh_failed",error:r}),r;try{return await Q(e,{...t,skipAuthRetry:!0})}catch(o){throw o instanceof i&&k({reason:"retry_rejected",error:o}),o}}throw r}},u=async(e,t,r={})=>{let n=await v(e,{...r,method:"POST",contentType:"application/json",body:JSON.stringify(t)});return ue(await n.json(),n.status)};var w=async(e,t,r={})=>{let n=await v(e,{...r,method:"POST",contentType:"application/json",accept:"text/event-stream",body:JSON.stringify(t)});if(!n.body)throw new d("Streaming response has no body");return n.body},X=async(e,t,r={})=>await(await v(e,{...r,method:"POST",contentType:"application/json",body:JSON.stringify(t)})).blob();var C=e=>{let{signal:t,headers:r,...n}=e;return {transport:{signal:t,extra:r},payload:n}},me=(async e=>{let{transport:t,payload:r}=C(e);if(e.stream){let n=await w(T,r,t);return J(n)}return await u(T,r,t)}),le={create:me},fe={async generate(e){let{transport:t,payload:r}=C(e);return u(B,r,t)}},he={speech:{async create(e){let{transport:t,payload:r}=C(e);return X(M,r,t)}}},ge={generations:{async create(e){let{transport:t,payload:r}=C(e);return u(N,r,t)}}},ye={chat:{completions:le},images:fe,audio:he,video:ge};var Ee=e=>{let{signal:t,headers:r,...n}=e;return {transport:{signal:t,extra:r},payload:n}},Ae=(async e=>{let{transport:t,payload:r}=Ee(e);if(e.stream){let n=await w(_,r,t);return V(n)}return await u(_,r,t)}),Re={messages:{create:Ae}};
|
|
2
|
+
export{S as AI_ERROR_EVENT,l as AbortedError,a as AiError,i as AuthRequiredError,A as BadInputError,d as NetworkError,E as QuotaExceededError,y as RateLimitError,R as ServerError,Re as anthropic,re as configureRuntime,ye as openai};
|
package/dist/device/index.d.ts
CHANGED
|
@@ -80,6 +80,22 @@ interface PickedFiles {
|
|
|
80
80
|
files: PickedFile[];
|
|
81
81
|
}
|
|
82
82
|
type FileSaveResult = "saved" | "cancelled" | "failed";
|
|
83
|
+
interface AudioRecordingOptions {
|
|
84
|
+
maxDurationMs?: number;
|
|
85
|
+
mimeType?: string;
|
|
86
|
+
audioBitsPerSecond?: number;
|
|
87
|
+
}
|
|
88
|
+
interface AudioRecording {
|
|
89
|
+
blob: Blob;
|
|
90
|
+
mimeType: string;
|
|
91
|
+
durationMs: number;
|
|
92
|
+
size: number;
|
|
93
|
+
}
|
|
94
|
+
interface AudioRecorder {
|
|
95
|
+
stop(): Promise<AudioRecording | null>;
|
|
96
|
+
cancel(): void;
|
|
97
|
+
readonly active: boolean;
|
|
98
|
+
}
|
|
83
99
|
|
|
84
100
|
declare const camera: {
|
|
85
101
|
isSupported(): boolean;
|
|
@@ -201,6 +217,48 @@ declare const haptics: {
|
|
|
201
217
|
vibrate(pattern: number | number[]): Promise<void>;
|
|
202
218
|
};
|
|
203
219
|
|
|
220
|
+
declare const microphone: {
|
|
221
|
+
isSupported(): boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Ask the host (native App or browser) for microphone permission. The web
|
|
224
|
+
* path opens a short-lived `getUserMedia({audio:true})` stream purely to
|
|
225
|
+
* trigger the permission prompt, then releases it immediately — so it
|
|
226
|
+
* **must be called inside a user-gesture handler** on iOS Safari, same as
|
|
227
|
+
* camera/sensors. The native-bridge variant routes through the App's own
|
|
228
|
+
* permission prompt and has no gesture requirement.
|
|
229
|
+
*
|
|
230
|
+
* Returns true if recording is permitted, false on denial / no hardware.
|
|
231
|
+
*/
|
|
232
|
+
requestPermission(): Promise<boolean>;
|
|
233
|
+
/**
|
|
234
|
+
* Record one audio clip and resolve when capture finishes. The native
|
|
235
|
+
* bridge runs the host App's recording UI (record button, waveform, native
|
|
236
|
+
* encoder) and returns a finished file; the web fallback records via
|
|
237
|
+
* `MediaRecorder` and **requires `maxDurationMs`** to know when to stop,
|
|
238
|
+
* since the headless path has no UI for the user to tap "done".
|
|
239
|
+
*
|
|
240
|
+
* Must be called inside a user-gesture handler to satisfy mic-permission /
|
|
241
|
+
* autoplay rules on iOS Safari and modern Android browsers. Returns null on
|
|
242
|
+
* permission denial, hardware absence, or any failure on either path.
|
|
243
|
+
*
|
|
244
|
+
* For press-and-hold or tap-to-stop UIs where the caller decides when to
|
|
245
|
+
* stop, use `startRecording` instead.
|
|
246
|
+
*/
|
|
247
|
+
recordAudio(opts?: AudioRecordingOptions): Promise<AudioRecording | null>;
|
|
248
|
+
/**
|
|
249
|
+
* Begin caller-controlled recording and return a handle to stop / cancel on
|
|
250
|
+
* your own schedule — for push-to-talk, tap-to-start/tap-to-stop, or any UI
|
|
251
|
+
* that shows a live "recording…" state. Web-only by design: streaming raw
|
|
252
|
+
* audio through a JS bridge is impractical, and host Apps that need mic
|
|
253
|
+
* access route it through `recordAudio`'s full-screen UI instead.
|
|
254
|
+
*
|
|
255
|
+
* Must be called inside a user-gesture handler. Returns null when the mic is
|
|
256
|
+
* unavailable or the user denies access. The caller MUST eventually call
|
|
257
|
+
* `.stop()` or `.cancel()` to release the microphone.
|
|
258
|
+
*/
|
|
259
|
+
startRecording(opts?: AudioRecordingOptions): Promise<AudioRecorder | null>;
|
|
260
|
+
};
|
|
261
|
+
|
|
204
262
|
declare const sensors: {
|
|
205
263
|
isMotionSupported(): boolean;
|
|
206
264
|
isOrientationSupported(): boolean;
|
|
@@ -228,7 +286,7 @@ declare const sensors: {
|
|
|
228
286
|
watchOrientation(onSample: (s: OrientationSample) => void): () => void;
|
|
229
287
|
};
|
|
230
288
|
|
|
231
|
-
type DeviceFeature = "haptics" | "geolocation" | "sensors" | "camera" | "files";
|
|
289
|
+
type DeviceFeature = "haptics" | "geolocation" | "sensors" | "camera" | "files" | "microphone";
|
|
232
290
|
|
|
233
291
|
declare const meetsFeatureMinVersion: (feature: DeviceFeature, env: AppEnvironment) => boolean;
|
|
234
292
|
|
|
@@ -265,6 +323,12 @@ declare const device: {
|
|
|
265
323
|
readAsText(file: File | Blob): Promise<string>;
|
|
266
324
|
readAsDataUrl(file: File | Blob): Promise<string>;
|
|
267
325
|
};
|
|
326
|
+
readonly microphone: {
|
|
327
|
+
isSupported(): boolean;
|
|
328
|
+
requestPermission(): Promise<boolean>;
|
|
329
|
+
recordAudio(opts?: AudioRecordingOptions): Promise<AudioRecording | null>;
|
|
330
|
+
startRecording(opts?: AudioRecordingOptions): Promise<AudioRecorder | null>;
|
|
331
|
+
};
|
|
268
332
|
};
|
|
269
333
|
|
|
270
|
-
export { type CameraFacing, type CapturedPhoto, type DeviceFeature, type HapticImpactStrength, type HapticNotificationKind, type MotionSample, type MotionWatchOptions, type OrientationSample, type PhotoCaptureOptions, type PhotoFormat, type PhotoQuality, type PickFilesOptions, type PickedFiles, type PositionRequestOptions, type PositionSample, type StreamOptions, type Vector3, camera, device, files, geolocation, haptics, meetsFeatureMinVersion, sensors };
|
|
334
|
+
export { type AudioRecorder, type AudioRecording, type AudioRecordingOptions, type CameraFacing, type CapturedPhoto, type DeviceFeature, type HapticImpactStrength, type HapticNotificationKind, type MotionSample, type MotionWatchOptions, type OrientationSample, type PhotoCaptureOptions, type PhotoFormat, type PhotoQuality, type PickFilesOptions, type PickedFiles, type PositionRequestOptions, type PositionSample, type StreamOptions, type Vector3, camera, device, files, geolocation, haptics, meetsFeatureMinVersion, microphone, sensors };
|
package/dist/device/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {a,d as d$1,u,t,v,c,b,x,e,s,r,w}from'../chunk-ALNJCFV4.js';import {fileSave,directoryOpen,fileOpen}from'browser-fs-access';var L=false,S=()=>{!a()||L||(L=true,d$1());};var B="device.haptics",M="device.geolocation",H="device.sensors.motion",V="device.sensors.orientation",W="device.sensors.permission",G="device.camera",R="device.files",q="device.haptics.impact",j="device.haptics.selection",z="device.haptics.notification",K="device.haptics.vibrate",Q="device.geolocation.get",J="device.geolocation.watch.start",Y="device.geolocation.watch.stop",$="device.sensors.motion.start",X="device.sensors.motion.stop",Z="device.sensors.orientation.start",ee="device.sensors.orientation.stop",te="device.sensors.requestPermission",ne="device.camera.capture",oe="device.files.pick",ie="device.files.save";var re={haptics:{iOS:null,Android:null},geolocation:{iOS:null,Android:null},sensors:{iOS:null,Android:null},camera:{iOS:null,Android:null},files:{iOS:null,Android:null}};var C=(e,t$1)=>{if(t$1.type!=="native_app"||!t$1.platform||!t$1.appVersion)return false;let n=re[e][t$1.platform];return n?u(t(t$1.appVersion),n):false},I=e=>JSON.stringify(e),ae=(e,t)=>{if(typeof e!="object"||e===null||Reflect.get(e,"ok")!==true)return null;let o=Reflect.get(e,"result");return t(o)},se=async e$1=>e$1.platform==="Android"?x(e,{pollIntervalMs:r,timeoutMs:s}):w(e),d=async e=>{if(!a())return null;S();let t=v();if(!C(e.feature,t))return null;let n=await se(t);if(!n)return null;let o=c(e.endpointPrefix),i=e.timeoutMs??3e3;return new Promise(r=>{let a=false,l=v=>{a||(a=true,c(),clearTimeout(u),r(v));},c=b.on(o,v=>{let P=ae(v,e.parseResult);l(P);}),u=setTimeout(()=>l(null),i);try{n.postMessage({command:e.command,parameters:I({endpoint:o,timestamp:Date.now(),payload:e.payload})});}catch{l(null);}})},E=async e=>{if(!a())return null;S();let t=v();if(!C(e.feature,t))return null;let n=await se(t);if(!n)return null;let o=c(e.endpointPrefix),i=b.on(o,r=>{let a=ae(r,e.parseEvent);a&&e.onEvent(a);});try{n.postMessage({command:e.startCommand,parameters:I({endpoint:o,timestamp:Date.now(),payload:e.payload})});}catch{return i(),null}return ()=>{i();try{n.postMessage({command:e.stopCommand,parameters:I({endpoint:o,timestamp:Date.now(),payload:null})});}catch{}}};var p=async e=>{if(!a())return e.safeDefault;let t=await e.native();if(t!==null)return t;try{let n=await e.web();if(n!==null)return n}catch{}return e.safeDefault};var le=e=>e==="front"?"user":"environment",be={low:.5,medium:.8,high:.95},Me=e=>{let t=e.indexOf(",");if(t<0)return null;let n=e.slice(5,t),o=e.slice(t+1),r=/^([^;]+)/.exec(n)?.[1]??"application/octet-stream";try{if(/;base64/.test(n)){let l=atob(o),c=new Uint8Array(l.length);for(let u=0;u<l.length;u++)c[u]=l.charCodeAt(u);return new Blob([c],{type:r})}return new Blob([decodeURIComponent(o)],{type:r})}catch{return null}},Re=e=>{if(typeof e!="object"||e===null)return null;let t=Reflect.get(e,"dataUrl"),n=Reflect.get(e,"width"),o=Reflect.get(e,"height");if(typeof t!="string"||t.length===0||typeof n!="number"||typeof o!="number")return null;let i=Me(t);return i?{blob:i,dataUrl:t,width:n,height:o}:null},Ie=async e=>{if(!a()||!navigator.mediaDevices?.getUserMedia)return null;let t=null;try{t=await navigator.mediaDevices.getUserMedia({video:{facingMode:le(e?.camera),width:e?.width,height:e?.height}});let n=document.createElement("video");n.srcObject=t,n.muted=!0,n.playsInline=!0,await n.play(),await new Promise(y=>{requestAnimationFrame(()=>y());});let o=e?.width??n.videoWidth??640,i=e?.height??n.videoHeight??480,r=document.createElement("canvas");r.width=o,r.height=i;let a=r.getContext("2d");if(!a)return null;a.drawImage(n,0,0,o,i);let c=`image/${e?.format??"jpeg"}`,u=be[e?.quality??"medium"],v=r.toDataURL(c,u),P=await new Promise(y=>{r.toBlob(_e=>y(_e),c,u);});return P?{blob:P,dataUrl:v,width:o,height:i}:null}catch{return null}finally{if(t)for(let n of t.getTracks())n.stop();}},ce={isSupported(){return a()?!!navigator.mediaDevices?.getUserMedia:false},capturePhoto(e){return p({native:()=>d({feature:"camera",command:ne,endpointPrefix:G,payload:e??{},parseResult:Re,timeoutMs:6e4}),web:()=>Ie(e),safeDefault:null})},async openStream(e){if(!a()||!navigator.mediaDevices?.getUserMedia)return null;try{return await navigator.mediaDevices.getUserMedia({video:{facingMode:le(e?.camera),width:e?.width,height:e?.height}})}catch{return null}},stopStream(e){try{for(let t of e.getTracks())t.stop();}catch{}}};var me=(e,t)=>{let n=atob(e),o=new Uint8Array(n.length);for(let i=0;i<n.length;i++)o[i]=n.charCodeAt(i);return new Blob([o],{type:t})},Ne=e=>{let t=null;if(e.dataUrl){let n=e.dataUrl.indexOf(",");if(n>0){let o=e.dataUrl.slice(5,n),i=e.dataUrl.slice(n+1),r=/^([^;]+)/.exec(o)?.[1]??"application/octet-stream";try{t=/;base64/.test(o)?me(i,r):new Blob([decodeURIComponent(i)],{type:r});}catch{t=null;}}}else e.base64&&(t=me(e.base64,e.mime??"application/octet-stream"));return t?new File([t],e.name,{type:e.mime??t.type,lastModified:Date.now()}):null},De=e=>{if(typeof e!="object"||e===null)return null;let t=Reflect.get(e,"files");if(!Array.isArray(t))return null;let n=Reflect.get(e,"paths"),o=r=>{if(!Array.isArray(n))return;let a=n[r];return typeof a=="string"?a:void 0},i=[];for(let r=0;r<t.length;r++){let a=t[r];if(typeof a!="object"||a===null)continue;let l=a,c=Ne(l);if(!c)continue;let u=typeof l.path=="string"?l.path:o(r);i.push(u!==void 0?{file:c,path:u}:{file:c});}return i.length===0?null:{files:i}},we=e=>{let t=[],n=[];if(!e)return {mimeTypes:t,extensions:n};for(let o of e)for(let i of o.split(",")){let r=i.trim();r&&(r.startsWith(".")?n.push(r):t.push(r));}return {mimeTypes:t,extensions:n}},pe=e=>e instanceof DOMException&&e.name==="AbortError",de=e=>e.length>0?{files:e.map(t=>({file:t}))}:null,xe=async e=>{if(!a())return null;try{if(e?.directory){let i=await directoryOpen({recursive:!0});return de(i)}let{mimeTypes:t,extensions:n}=we(e?.accept);if(e?.multiple){let i=await fileOpen({mimeTypes:t,extensions:n,multiple:!0});return de(i)}return {files:[{file:await fileOpen({mimeTypes:t,extensions:n})}]}}catch(t){return pe(t),null}},Fe=async(e,t)=>{if(!a())return "failed";try{return await fileSave(e,{fileName:t}),"saved"}catch(n){return pe(n)?"cancelled":"failed"}},fe={isPickerSupported(){return a()?typeof window.showOpenFilePicker=="function":false},pickFiles(e){return p({native:()=>d({feature:"files",command:oe,endpointPrefix:R,payload:e??{},parseResult:De,timeoutMs:6e4}),web:()=>xe(e),safeDefault:null})},async saveFile(e,t){return a()?await d({feature:"files",command:ie,endpointPrefix:R,payload:{filename:t,mime:e.type,size:e.size},parseResult:()=>true,timeoutMs:6e4})?"saved":Fe(e,t):"failed"},readAsText(e){return typeof e.text=="function"?e.text():new Promise((t,n)=>{let o=new FileReader;o.onload=()=>{t(typeof o.result=="string"?o.result:"");},o.onerror=()=>n(o.error),o.readAsText(e);})},readAsDataUrl(e){return new Promise((t,n)=>{let o=new FileReader;o.onload=()=>{t(typeof o.result=="string"?o.result:"");},o.onerror=()=>n(o.error),o.readAsDataURL(e);})}};var f=(e,...t)=>{for(let n of t){let o=Reflect.get(e,n);if(typeof o=="number"&&!Number.isNaN(o))return o}},ve=e=>{if(typeof e!="object"||e===null)return null;let t=f(e,"latitude"),n=f(e,"longitude"),o=f(e,"accuracyMeters","accuracy");if(t===void 0||n===void 0||o===void 0)return null;let i={latitude:t,longitude:n,accuracyMeters:o,timestamp:f(e,"timestamp")??Date.now()},r=f(e,"altitudeMeters","altitude");r!==void 0&&(i.altitudeMeters=r);let a=f(e,"altitudeAccuracyMeters","altitudeAccuracy");a!==void 0&&(i.altitudeAccuracyMeters=a);let l=f(e,"headingDegrees","heading");l!==void 0&&(i.headingDegrees=l);let c=f(e,"speedMetersPerSecond","speed");return c!==void 0&&(i.speedMetersPerSecond=c),i},Se=e=>({latitude:e.coords.latitude,longitude:e.coords.longitude,accuracyMeters:e.coords.accuracy,altitudeMeters:e.coords.altitude??void 0,altitudeAccuracyMeters:e.coords.altitudeAccuracy??void 0,headingDegrees:e.coords.heading??void 0,speedMetersPerSecond:e.coords.speed??void 0,timestamp:e.timestamp}),Ee=e=>e?{enableHighAccuracy:e.enableHighAccuracy,timeout:e.timeoutMs,maximumAge:e.maximumAgeMs}:void 0,ke=e=>!a()||!navigator.geolocation?Promise.resolve(null):new Promise(t=>{navigator.geolocation.getCurrentPosition(n=>t(Se(n)),()=>t(null),Ee(e));}),Pe={isSupported(){return a()?!!navigator.geolocation:false},getCurrentPosition(e){return p({native:()=>d({feature:"geolocation",command:Q,endpointPrefix:M,payload:e??{},parseResult:ve,timeoutMs:e?.timeoutMs}),web:()=>ke(e),safeDefault:null})},watchPosition(e,t){let n=false,o=null,i=null;return E({feature:"geolocation",startCommand:J,stopCommand:Y,endpointPrefix:M,payload:t??{},parseEvent:ve,onEvent:r=>{n||e(r);}}).then(r=>{if(n){r?.();return}if(r){o=r;return}if(!(!a()||!navigator.geolocation))try{i=navigator.geolocation.watchPosition(a=>{n||e(Se(a));},()=>{},Ee(t));}catch{}}),()=>{if(n=true,o&&o(),i!==null&&a()&&navigator.geolocation)try{navigator.geolocation.clearWatch(i);}catch{}}}};var Ue={light:10,medium:20,heavy:40,soft:15,rigid:30},Le={success:[20,60,20],warning:[40,40,40],error:[50,30,100]},Be=e=>{if(typeof navigator>"u"||typeof navigator.vibrate!="function")return false;try{return navigator.vibrate(e)}catch{return false}},O=(e,t,n)=>p({native:()=>d({feature:"haptics",command:e,endpointPrefix:B,payload:t,parseResult:()=>true}),web:async()=>Be(n),safeDefault:false}),ge={isSupported(){return a()?typeof navigator<"u"&&"vibrate"in navigator:false},async impact(e="medium"){await O(q,{strength:e},Ue[e]);},async selection(){await O(j,{},8);},async notification(e){await O(z,{kind:e},Le[e]);},async vibrate(e){await O(K,{pattern:e},e);}};var ye=()=>typeof DeviceMotionEvent>"u"?false:typeof DeviceMotionEvent.requestPermission=="function",Oe=async()=>{if(!ye())return true;try{let e=DeviceMotionEvent.requestPermission;return e?await e()==="granted":!0}catch{return false}},m=(e,...t)=>{for(let n of t){let o=Reflect.get(e,n);if(typeof o=="number"&&!Number.isNaN(o))return o}},A=(e,t)=>{let n=Reflect.get(e,t);if(typeof n!="object"||n===null)return;let o=m(n,"x"),i=m(n,"y"),r=m(n,"z");if(!(o===void 0||i===void 0||r===void 0))return {x:o,y:i,z:r}},He=e=>{if(typeof e!="object"||e===null)return null;let t=A(e,"accelerationWithGravity")??A(e,"accelerationIncludingGravity");if(!t)return null;let n=Reflect.get(e,"rotationRate"),o={alpha:0,beta:0,gamma:0};typeof n=="object"&&n!==null&&(o={alpha:m(n,"alpha")??0,beta:m(n,"beta")??0,gamma:m(n,"gamma")??0});let i={accelerationWithGravity:t,rotationRate:o,timestamp:m(e,"timestamp")??Date.now()},r=A(e,"acceleration");r&&(i.acceleration=r);let a=Reflect.get(e,"attitude");if(typeof a=="object"&&a!==null){let l=m(a,"yaw"),c=m(a,"pitch"),u=m(a,"roll");l!==void 0&&c!==void 0&&u!==void 0&&(i.attitude={yaw:l,pitch:c,roll:u});}return i},Ve=e=>{if(typeof e!="object"||e===null)return null;let t=m(e,"alpha"),n=m(e,"beta"),o=m(e,"gamma");return t===void 0||n===void 0||o===void 0?null:{alpha:t,beta:n,gamma:o,timestamp:m(e,"timestamp")??Date.now()}},We=e=>{let t=e.accelerationIncludingGravity,n=e.acceleration,o=e.rotationRate,i={accelerationWithGravity:{x:t?.x??0,y:t?.y??0,z:t?.z??0},rotationRate:{alpha:o?.alpha??0,beta:o?.beta??0,gamma:o?.gamma??0},timestamp:e.timeStamp||Date.now()};return n&&(n.x!==null||n.y!==null||n.z!==null)&&(i.acceleration={x:n.x??0,y:n.y??0,z:n.z??0}),i},Ge=e=>({alpha:e.alpha??0,beta:e.beta??0,gamma:e.gamma??0,timestamp:e.timeStamp||Date.now()}),he={isMotionSupported(){return a()?typeof DeviceMotionEvent<"u":false},isOrientationSupported(){return a()?typeof DeviceOrientationEvent<"u":false},async requestMotionPermission(){if(!a())return false;let e=await d({feature:"sensors",command:te,endpointPrefix:W,payload:{},parseResult:t=>{if(typeof t=="boolean")return t;if(typeof t=="object"&&t!==null){let n=Reflect.get(t,"granted");if(typeof n=="boolean")return n}return null}});return e!==null?e:Oe()},watchMotion(e,t){let n=false,o=null,i=null,r=()=>{if(n||!a())return;let l=c=>{n||e(We(c));};window.addEventListener("devicemotion",l),i=l;};return (async()=>{let l=await E({feature:"sensors",startCommand:$,stopCommand:X,endpointPrefix:H,payload:t??{},parseEvent:He,onEvent:c=>{n||e(c);}});if(n){l?.();return}if(l){o=l;return}t?.autoRequestPermission&&ye()&&(!await Oe()||n)||r();})(),()=>{n=true,o&&o(),i&&a()&&(window.removeEventListener("devicemotion",i),i=null);}},watchOrientation(e){let t=false,n=null,o=null,i=()=>{if(t||!a())return;let a$1=l=>{t||e(Ge(l));};window.addEventListener("deviceorientation",a$1),o=a$1;};return (async()=>{let a=await E({feature:"sensors",startCommand:Z,stopCommand:ee,endpointPrefix:V,payload:{},parseEvent:Ve,onEvent:l=>{t||e(l);}});if(t){a?.();return}if(a){n=a;return}i();})(),()=>{t=true,n&&n(),o&&a()&&(window.removeEventListener("deviceorientation",o),o=null);}}};S();var At={haptics:ge,geolocation:Pe,sensors:he,camera:ce,files:fe};export{ce as camera,At as device,fe as files,Pe as geolocation,ge as haptics,C as meetsFeatureMinVersion,he as sensors};
|
|
1
|
+
import {a,d as d$1,b as b$1,u,t,v,c,x as x$1,e,s,r,w}from'../chunk-ALNJCFV4.js';import {fileSave,directoryOpen,fileOpen}from'browser-fs-access';var G="device.haptics",C="device.geolocation",j="device.sensors.motion",z="device.sensors.orientation",Q="device.sensors.permission",K="device.camera",A="device.files",J="device.microphone",Y="device.microphone.permission",$="device.haptics.impact",X="device.haptics.selection",Z="device.haptics.notification",ee="device.haptics.vibrate",te="device.geolocation.get",ne="device.geolocation.watch.start",oe="device.geolocation.watch.stop",ie="device.sensors.motion.start",re="device.sensors.motion.stop",ae="device.sensors.orientation.start",se="device.sensors.orientation.stop",le="device.sensors.requestPermission",ce="device.camera.capture",ue="device.files.pick",de="device.files.save",me="device.microphone.record",pe="device.microphone.requestPermission",fe="device-request",ge="device-response";var ye={haptics:{iOS:null,Android:null},geolocation:{iOS:null,Android:null},sensors:{iOS:null,Android:null},camera:{iOS:null,Android:null},files:{iOS:null,Android:null},microphone:{iOS:null,Android:null}};var Ee=false,Ve=e=>typeof e!="object"||e===null?false:Reflect.get(e,"type")===ge&&typeof Reflect.get(e,"endpoint")=="string",T=()=>{!a()||Ee||(Ee=true,d$1(),window.addEventListener("message",e=>{let t=e.data;Ve(t)&&b$1.emit(t.endpoint,t.data??t);}));};var D=(e,t$1)=>{if(t$1.type!=="native_app"||!t$1.platform||!t$1.appVersion)return false;let n=ye[e][t$1.platform];return n?u(t(t$1.appVersion),n):false},b=e=>JSON.stringify(e),qe=()=>a()&&window.parent!==window,N=(e,t)=>{if(typeof e!="object"||e===null||Reflect.get(e,"ok")!==true)return null;let o=Reflect.get(e,"result");return t(o)},he=async e$1=>e$1.platform==="Android"?x$1(e,{pollIntervalMs:r,timeoutMs:s}):w(e),We=async e=>{let t=v();if(!D(e.feature,t))return null;let n=await he(t);if(!n)return null;let o=c(e.endpointPrefix),i=e.timeoutMs??3e3;return new Promise(r=>{let a=false,s=f=>{a||(a=true,l(),clearTimeout(u),r(f));},l=b$1.on(o,f=>{let h=N(f,e.parseResult);s(h);}),u=setTimeout(()=>s(null),i);try{n.postMessage({command:e.command,parameters:b({endpoint:o,timestamp:Date.now(),payload:e.payload})});}catch{s(null);}})},Ge=async e=>{if(!qe())return null;let t=c(e.endpointPrefix),n=e.timeoutMs??3e3;return new Promise(o=>{let i=false,r=l=>{i||(i=true,a(),clearTimeout(s),o(l));},a=b$1.on(t,l=>{let u=N(l,e.parseResult);r(u);}),s=setTimeout(()=>r(null),n);try{window.parent.postMessage({type:fe,command:e.command,parameters:b({endpoint:t,timestamp:Date.now(),payload:e.payload})},"*");}catch{r(null);}})},d=async e=>{if(!a())return null;T();let t=await We(e);return t!==null?t:Ge(e)},O=async e=>{if(!a())return null;T();let t=v();if(!D(e.feature,t))return null;let n=await he(t);if(!n)return null;let o=c(e.endpointPrefix),i=b$1.on(o,r=>{let a=N(r,e.parseEvent);a&&e.onEvent(a);});try{n.postMessage({command:e.startCommand,parameters:b({endpoint:o,timestamp:Date.now(),payload:e.payload})});}catch{return i(),null}return ()=>{i();try{n.postMessage({command:e.stopCommand,parameters:b({endpoint:o,timestamp:Date.now(),payload:null})});}catch{}}};var g=async e=>{if(!a())return e.safeDefault;let t=await e.native();if(t!==null)return t;try{let n=await e.web();if(n!==null)return n}catch{}return e.safeDefault};var Se=e=>e==="front"?"user":"environment",je={low:.5,medium:.8,high:.95},ze=e=>{let t=e.indexOf(",");if(t<0)return null;let n=e.slice(5,t),o=e.slice(t+1),r=/^([^;]+)/.exec(n)?.[1]??"application/octet-stream";try{if(/;base64/.test(n)){let s=atob(o),l=new Uint8Array(s.length);for(let u=0;u<s.length;u++)l[u]=s.charCodeAt(u);return new Blob([l],{type:r})}return new Blob([decodeURIComponent(o)],{type:r})}catch{return null}},Qe=e=>new Promise(t=>{let n=new FileReader;n.onload=()=>t(typeof n.result=="string"?n.result:null),n.onerror=()=>t(null),n.readAsDataURL(e);}),Ke=e=>new Promise(t=>{let n=new Image;n.onload=()=>{t({width:n.naturalWidth,height:n.naturalHeight}),n.remove();},n.onerror=()=>{t(null),n.remove();},n.src=e;}),Je=e=>{if(typeof e!="object"||e===null)return null;let t=Reflect.get(e,"dataUrl"),n=Reflect.get(e,"width"),o=Reflect.get(e,"height");if(typeof t!="string"||t.length===0||typeof n!="number"||typeof o!="number")return null;let i=ze(t);return i?{blob:i,dataUrl:t,width:n,height:o}:null},Ye=async(e,t)=>{if(t?.format!==void 0||t?.quality!==void 0||t?.width!==void 0||t?.height!==void 0)return null;let n=Reflect.get(window,"ImageCapture");if(typeof n!="function")return null;let o=e.getVideoTracks()[0];if(!o)return null;try{let r=await new n(o).takePhoto(),a=await Qe(r);if(!a)return null;let s=await Ke(a);return s?{blob:r,dataUrl:a,width:s.width,height:s.height}:null}catch{return null}},Pe=()=>new Promise(e=>requestAnimationFrame(()=>e())),x=(e,t,n)=>new Promise(o=>{let i=false,r=()=>{i||(i=true,window.clearTimeout(a),e.removeEventListener(t,r),o());},a=window.setTimeout(r,n);e.addEventListener(t,r,{once:true});}),Re=(e,t)=>new Promise(n=>{let o=e.requestVideoFrameCallback;if(!o){requestAnimationFrame(()=>requestAnimationFrame(()=>n()));return}let i=false,r=()=>{i||(i=true,window.clearTimeout(a),n());},a=window.setTimeout(r,t);o.call(e,r);}),$e=async e=>{let t=()=>e.videoWidth>0&&e.videoHeight>0;return t()||await x(e,"loadedmetadata",2e3),e.readyState<HTMLMediaElement.HAVE_CURRENT_DATA&&await x(e,"loadeddata",2e3),e.readyState<HTMLMediaElement.HAVE_CURRENT_DATA&&await x(e,"canplay",2e3),await Re(e,1e3),await Pe(),t()},Xe=e=>{if(e.videoWidth<=0||e.videoHeight<=0)return true;let t=document.createElement("canvas");t.width=24,t.height=24;let n=t.getContext("2d");if(!n)return false;try{n.drawImage(e,0,0,t.width,t.height);let o=n.getImageData(0,0,t.width,t.height).data,i=0,r=0;for(let s=0;s<o.length;s+=4){let l=o[s]*.2126+o[s+1]*.7152+o[s+2]*.0722;i=Math.max(i,l),r+=l;}let a=r/(o.length/4);return i<18&&a<6}catch{return false}},Ze=async(e,t)=>{let n=performance.now();for(;performance.now()-n<t;)if(await Re(e,700),await Pe(),!Xe(e))return},et=async e=>{if(!a()||!navigator.mediaDevices?.getUserMedia)return null;let t=null,n=null;try{t=await navigator.mediaDevices.getUserMedia({video:{facingMode:Se(e?.camera),width:e?.width,height:e?.height}});let o=await Ye(t,e);if(o)return o;if(n=document.createElement("video"),n.srcObject=t,n.autoplay=!0,n.muted=!0,n.playsInline=!0,n.style.position="fixed",n.style.left="0",n.style.top="0",n.style.width="2px",n.style.height="2px",n.style.opacity="0.01",n.style.pointerEvents="none",n.style.zIndex="-1",(document.body??document.documentElement).appendChild(n),await n.play(),!await $e(n))return null;await Ze(n,3e3);let a=e?.width??n.videoWidth??640,s=e?.height??n.videoHeight??480,l=document.createElement("canvas");l.width=a,l.height=s;let u=l.getContext("2d");if(!u)return null;u.drawImage(n,0,0,a,s);let h=`image/${e?.format??"jpeg"}`,E=je[e?.quality??"medium"],R=l.toDataURL(h,E),p=await new Promise(S=>{l.toBlob(Be=>S(Be),h,E);});return p?{blob:p,dataUrl:R,width:a,height:s}:null}catch{return null}finally{if(n&&(n.pause(),n.srcObject=null,n.remove()),t)for(let o of t.getTracks())o.stop();}},Te={isSupported(){return a()?!!navigator.mediaDevices?.getUserMedia:false},capturePhoto(e){return g({native:()=>d({feature:"camera",command:ce,endpointPrefix:K,payload:e??{},parseResult:Je,timeoutMs:6e4}),web:()=>et(e),safeDefault:null})},async openStream(e){if(!a()||!navigator.mediaDevices?.getUserMedia)return null;try{return await navigator.mediaDevices.getUserMedia({video:{facingMode:Se(e?.camera),width:e?.width,height:e?.height}})}catch{return null}},stopStream(e){try{for(let t of e.getTracks())t.stop();}catch{}}};var Me=(e,t)=>{let n=atob(e),o=new Uint8Array(n.length);for(let i=0;i<n.length;i++)o[i]=n.charCodeAt(i);return new Blob([o],{type:t})},ot=e=>{let t=null;if(e.dataUrl){let n=e.dataUrl.indexOf(",");if(n>0){let o=e.dataUrl.slice(5,n),i=e.dataUrl.slice(n+1),r=/^([^;]+)/.exec(o)?.[1]??"application/octet-stream";try{t=/;base64/.test(o)?Me(i,r):new Blob([decodeURIComponent(i)],{type:r});}catch{t=null;}}}else e.base64&&(t=Me(e.base64,e.mime??"application/octet-stream"));return t?new File([t],e.name,{type:e.mime??t.type,lastModified:Date.now()}):null},it=e=>{if(typeof e!="object"||e===null)return null;let t=Reflect.get(e,"files");if(!Array.isArray(t))return null;let n=Reflect.get(e,"paths"),o=r=>{if(!Array.isArray(n))return;let a=n[r];return typeof a=="string"?a:void 0},i=[];for(let r=0;r<t.length;r++){let a=t[r];if(typeof a!="object"||a===null)continue;let s=a,l=ot(s);if(!l)continue;let u=typeof s.path=="string"?s.path:o(r);i.push(u!==void 0?{file:l,path:u}:{file:l});}return i.length===0?null:{files:i}},rt=e=>{let t=[],n=[];if(!e)return {mimeTypes:t,extensions:n};for(let o of e)for(let i of o.split(",")){let r=i.trim();r&&(r.startsWith(".")?n.push(r):t.push(r));}return {mimeTypes:t,extensions:n}},_e=e=>e instanceof DOMException&&e.name==="AbortError",be=e=>e.length>0?{files:e.map(t=>({file:t}))}:null,at=async e=>{if(!a())return null;try{if(e?.directory){let i=await directoryOpen({recursive:!0});return be(i)}let{mimeTypes:t,extensions:n}=rt(e?.accept);if(e?.multiple){let i=await fileOpen({mimeTypes:t,extensions:n,multiple:!0});return be(i)}return {files:[{file:await fileOpen({mimeTypes:t,extensions:n})}]}}catch(t){return _e(t),null}},st=async(e,t)=>{if(!a())return "failed";try{return await fileSave(e,{fileName:t}),"saved"}catch(n){return _e(n)?"cancelled":"failed"}},we={isPickerSupported(){return a()?typeof window.showOpenFilePicker=="function":false},pickFiles(e){return g({native:()=>d({feature:"files",command:ue,endpointPrefix:A,payload:e??{},parseResult:it,timeoutMs:6e4}),web:()=>at(e),safeDefault:null})},async saveFile(e,t){return a()?await d({feature:"files",command:de,endpointPrefix:A,payload:{filename:t,mime:e.type,size:e.size},parseResult:()=>true,timeoutMs:6e4})?"saved":st(e,t):"failed"},readAsText(e){return typeof e.text=="function"?e.text():new Promise((t,n)=>{let o=new FileReader;o.onload=()=>{t(typeof o.result=="string"?o.result:"");},o.onerror=()=>n(o.error),o.readAsText(e);})},readAsDataUrl(e){return new Promise((t,n)=>{let o=new FileReader;o.onload=()=>{t(typeof o.result=="string"?o.result:"");},o.onerror=()=>n(o.error),o.readAsDataURL(e);})}};var y=(e,...t)=>{for(let n of t){let o=Reflect.get(e,n);if(typeof o=="number"&&!Number.isNaN(o))return o}},Ie=e=>{if(typeof e!="object"||e===null)return null;let t=y(e,"latitude"),n=y(e,"longitude"),o=y(e,"accuracyMeters","accuracy");if(t===void 0||n===void 0||o===void 0)return null;let i={latitude:t,longitude:n,accuracyMeters:o,timestamp:y(e,"timestamp")??Date.now()},r=y(e,"altitudeMeters","altitude");r!==void 0&&(i.altitudeMeters=r);let a=y(e,"altitudeAccuracyMeters","altitudeAccuracy");a!==void 0&&(i.altitudeAccuracyMeters=a);let s=y(e,"headingDegrees","heading");s!==void 0&&(i.headingDegrees=s);let l=y(e,"speedMetersPerSecond","speed");return l!==void 0&&(i.speedMetersPerSecond=l),i},Ce=e=>({latitude:e.coords.latitude,longitude:e.coords.longitude,accuracyMeters:e.coords.accuracy,altitudeMeters:e.coords.altitude??void 0,altitudeAccuracyMeters:e.coords.altitudeAccuracy??void 0,headingDegrees:e.coords.heading??void 0,speedMetersPerSecond:e.coords.speed??void 0,timestamp:e.timestamp}),Ae=e=>e?{enableHighAccuracy:e.enableHighAccuracy,timeout:e.timeoutMs,maximumAge:e.maximumAgeMs}:void 0,lt=e=>!a()||!navigator.geolocation?Promise.resolve(null):new Promise(t=>{navigator.geolocation.getCurrentPosition(n=>t(Ce(n)),()=>t(null),Ae(e));}),De={isSupported(){return a()?!!navigator.geolocation:false},getCurrentPosition(e){return g({native:()=>d({feature:"geolocation",command:te,endpointPrefix:C,payload:e??{},parseResult:Ie,timeoutMs:e?.timeoutMs}),web:()=>lt(e),safeDefault:null})},watchPosition(e,t){let n=false,o=null,i=null;return O({feature:"geolocation",startCommand:ne,stopCommand:oe,endpointPrefix:C,payload:t??{},parseEvent:Ie,onEvent:r=>{n||e(r);}}).then(r=>{if(n){r?.();return}if(r){o=r;return}if(!(!a()||!navigator.geolocation))try{i=navigator.geolocation.watchPosition(a=>{n||e(Ce(a));},()=>{},Ae(t));}catch{}}),()=>{if(n=true,o&&o(),i!==null&&a()&&navigator.geolocation)try{navigator.geolocation.clearWatch(i);}catch{}}}};var ct={light:10,medium:20,heavy:40,soft:15,rigid:30},ut={success:[20,60,20],warning:[40,40,40],error:[50,30,100]},dt=e=>{if(typeof navigator>"u"||typeof navigator.vibrate!="function")return false;try{return navigator.vibrate(e)}catch{return false}},_=(e,t,n)=>g({native:()=>d({feature:"haptics",command:e,endpointPrefix:G,payload:t,parseResult:()=>true}),web:async()=>dt(n),safeDefault:false}),Ne={isSupported(){return a()?typeof navigator<"u"&&"vibrate"in navigator:false},async impact(e="medium"){await _($,{strength:e},ct[e]);},async selection(){await _(X,{},8);},async notification(e){await _(Z,{kind:e},ut[e]);},async vibrate(e){await _(ee,{pattern:e},e);}};var F=()=>{if(!a())return null;let e=window.MediaRecorder;return typeof e=="function"?e:null},Fe=()=>a()&&!!navigator.mediaDevices?.getUserMedia&&F()!==null,mt=e=>{let t=e.indexOf(",");if(t<0)return null;let n=e.slice(5,t),o=e.slice(t+1),r=/^([^;]+)/.exec(n)?.[1]??"application/octet-stream";try{if(/;base64/.test(n)){let a=atob(o),s=new Uint8Array(a.length);for(let l=0;l<a.length;l++)s[l]=a.charCodeAt(l);return new Blob([s],{type:r})}return new Blob([decodeURIComponent(o)],{type:r})}catch{return null}},pt=e=>{if(typeof e!="object"||e===null)return null;let t=Reflect.get(e,"dataUrl");if(typeof t!="string"||t.length===0)return null;let n=mt(t);if(!n)return null;let o=Reflect.get(e,"mimeType"),i=Reflect.get(e,"durationMs"),r=typeof o=="string"&&o.length>0?o:n.type||"audio/octet-stream",a=typeof i=="number"&&i>=0?i:0;return {blob:n,mimeType:r,durationMs:a,size:n.size}},ft=e=>{let t=F();if(!(!e||!t?.isTypeSupported))return t.isTypeSupported(e)?e:void 0},xe=async e=>{if(!Fe())return null;let t=F();if(!t)return null;let n;try{n=await navigator.mediaDevices.getUserMedia({audio:!0});}catch{return null}let o=()=>{for(let p of n.getTracks())p.stop();},i;try{i=new t(n,{mimeType:ft(e?.mimeType),audioBitsPerSecond:e?.audioBitsPerSecond});}catch{return o(),null}let r=[],a=Date.now(),s=false,l=false,u=null,f,h=new Promise(p=>{f=p;}),E=()=>{u!==null&&(clearTimeout(u),u=null);};i.ondataavailable=p=>{p.data&&p.data.size>0&&r.push(p.data);},i.onstop=()=>{if(E(),o(),s){f(null);return}let p=i.mimeType||e?.mimeType||"audio/webm",S=new Blob(r,{type:p});f(S.size===0?null:{blob:S,mimeType:S.type||p,durationMs:Date.now()-a,size:S.size});},i.onerror=()=>{E(),o(),f(null);};let R=()=>{if(!l){if(l=true,i.state==="inactive"){E(),o(),f(null);return}try{i.stop();}catch{E(),o(),f(null);}}};try{i.start();}catch{return o(),null}return e?.maxDurationMs&&e.maxDurationMs>0&&(u=setTimeout(R,e.maxDurationMs)),{get active(){return !l&&!s&&i.state==="recording"},stop(){return R(),h},cancel(){l||s||(s=true,R());}}},ke={isSupported(){return Fe()},async requestPermission(){if(!a())return false;let e=await d({feature:"microphone",command:pe,endpointPrefix:Y,payload:{},parseResult:t=>{if(typeof t=="boolean")return t;if(typeof t=="object"&&t!==null){let n=Reflect.get(t,"granted");if(typeof n=="boolean")return n}return null}});if(e!==null)return e;if(!a()||!navigator.mediaDevices?.getUserMedia)return false;try{let t=await navigator.mediaDevices.getUserMedia({audio:!0});for(let n of t.getTracks())n.stop();return !0}catch{return false}},async recordAudio(e){return g({native:()=>d({feature:"microphone",command:me,endpointPrefix:J,payload:e??{},parseResult:pt,timeoutMs:6e4}),web:async()=>{let n=await xe(e);if(!n)return null;let o=e?.maxDurationMs??6e4;return new Promise(i=>{setTimeout(()=>{n.stop().then(i);},o);})},safeDefault:null})},startRecording(e){return a()?xe(e):Promise.resolve(null)}};var Le=()=>typeof DeviceMotionEvent>"u"?false:typeof DeviceMotionEvent.requestPermission=="function",Ue=async()=>{if(!Le())return true;try{let e=DeviceMotionEvent.requestPermission;return e?await e()==="granted":!0}catch{return false}},m=(e,...t)=>{for(let n of t){let o=Reflect.get(e,n);if(typeof o=="number"&&!Number.isNaN(o))return o}},k=(e,t)=>{let n=Reflect.get(e,t);if(typeof n!="object"||n===null)return;let o=m(n,"x"),i=m(n,"y"),r=m(n,"z");if(!(o===void 0||i===void 0||r===void 0))return {x:o,y:i,z:r}},gt=e=>{if(typeof e!="object"||e===null)return null;let t=k(e,"accelerationWithGravity")??k(e,"accelerationIncludingGravity");if(!t)return null;let n=Reflect.get(e,"rotationRate"),o={alpha:0,beta:0,gamma:0};typeof n=="object"&&n!==null&&(o={alpha:m(n,"alpha")??0,beta:m(n,"beta")??0,gamma:m(n,"gamma")??0});let i={accelerationWithGravity:t,rotationRate:o,timestamp:m(e,"timestamp")??Date.now()},r=k(e,"acceleration");r&&(i.acceleration=r);let a=Reflect.get(e,"attitude");if(typeof a=="object"&&a!==null){let s=m(a,"yaw"),l=m(a,"pitch"),u=m(a,"roll");s!==void 0&&l!==void 0&&u!==void 0&&(i.attitude={yaw:s,pitch:l,roll:u});}return i},yt=e=>{if(typeof e!="object"||e===null)return null;let t=m(e,"alpha"),n=m(e,"beta"),o=m(e,"gamma");return t===void 0||n===void 0||o===void 0?null:{alpha:t,beta:n,gamma:o,timestamp:m(e,"timestamp")??Date.now()}},Et=e=>{let t=e.accelerationIncludingGravity,n=e.acceleration,o=e.rotationRate,i={accelerationWithGravity:{x:t?.x??0,y:t?.y??0,z:t?.z??0},rotationRate:{alpha:o?.alpha??0,beta:o?.beta??0,gamma:o?.gamma??0},timestamp:e.timeStamp||Date.now()};return n&&(n.x!==null||n.y!==null||n.z!==null)&&(i.acceleration={x:n.x??0,y:n.y??0,z:n.z??0}),i},vt=e=>({alpha:e.alpha??0,beta:e.beta??0,gamma:e.gamma??0,timestamp:e.timeStamp||Date.now()}),He={isMotionSupported(){return a()?typeof DeviceMotionEvent<"u":false},isOrientationSupported(){return a()?typeof DeviceOrientationEvent<"u":false},async requestMotionPermission(){if(!a())return false;let e=await d({feature:"sensors",command:le,endpointPrefix:Q,payload:{},parseResult:t=>{if(typeof t=="boolean")return t;if(typeof t=="object"&&t!==null){let n=Reflect.get(t,"granted");if(typeof n=="boolean")return n}return null}});return e!==null?e:Ue()},watchMotion(e,t){let n=false,o=null,i=null,r=()=>{if(n||!a())return;let s=l=>{n||e(Et(l));};window.addEventListener("devicemotion",s),i=s;};return (async()=>{let s=await O({feature:"sensors",startCommand:ie,stopCommand:re,endpointPrefix:j,payload:t??{},parseEvent:gt,onEvent:l=>{n||e(l);}});if(n){s?.();return}if(s){o=s;return}t?.autoRequestPermission&&Le()&&(!await Ue()||n)||r();})(),()=>{n=true,o&&o(),i&&a()&&(window.removeEventListener("devicemotion",i),i=null);}},watchOrientation(e){let t=false,n=null,o=null,i=()=>{if(t||!a())return;let a$1=s=>{t||e(vt(s));};window.addEventListener("deviceorientation",a$1),o=a$1;};return (async()=>{let a=await O({feature:"sensors",startCommand:ae,stopCommand:se,endpointPrefix:z,payload:{},parseEvent:yt,onEvent:s=>{t||e(s);}});if(t){a?.();return}if(a){n=a;return}i();})(),()=>{t=true,n&&n(),o&&a()&&(window.removeEventListener("deviceorientation",o),o=null);}}};T();var mn={haptics:Ne,geolocation:De,sensors:He,camera:Te,files:we,microphone:ke};export{Te as camera,mn as device,we as files,De as geolocation,Ne as haptics,D as meetsFeatureMinVersion,ke as microphone,He as sensors};
|
package/package.json
CHANGED