@bty/feed_app-runtime-sdk 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -3
- package/dist/ai/index.d.ts +9 -15
- package/dist/ai/index.js +1 -1
- package/dist/device/index.d.ts +23 -13
- package/dist/device/index.js +1 -1
- package/dist/react/index.d.ts +7 -3
- package/dist/react/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Runtime SDK for Feed-App pages.
|
|
4
4
|
|
|
5
|
-
It provides a small set of browser-safe APIs for reading host user context
|
|
6
|
-
calling the Feed-App AI gateway
|
|
7
|
-
capability sub-entries directly
|
|
5
|
+
It provides a small set of browser-safe APIs for reading host user context,
|
|
6
|
+
calling the Feed-App AI gateway, and reaching native device capabilities. The
|
|
7
|
+
package has no root entry; import from the capability sub-entries directly
|
|
8
|
+
(`/user`, `/ai`, `/react`, `/device`).
|
|
8
9
|
|
|
9
10
|
## Install
|
|
10
11
|
|
|
@@ -12,6 +13,23 @@ capability sub-entries directly.
|
|
|
12
13
|
pnpm add @bty/feed_app-runtime-sdk
|
|
13
14
|
```
|
|
14
15
|
|
|
16
|
+
## Failure conventions
|
|
17
|
+
|
|
18
|
+
Two failure styles, split by sub-entry — know which you're calling:
|
|
19
|
+
|
|
20
|
+
| Sub-entry | On failure | Why |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `/ai` | **throws** a typed `AiError` subclass | callers must distinguish 401 / 402 / 429 / 4xx / 5xx to react correctly |
|
|
23
|
+
| `/user`, `/device` | **returns an empty value** (never throws) | "no host / denied / cancelled" is a normal runtime state, not an exception — branch on the value |
|
|
24
|
+
|
|
25
|
+
Empty value = `""` for the one string API (`getAuthTokenAsync`), `null`
|
|
26
|
+
everywhere else (`getUserInfoAsync`, every `/device` call). `saveFile` is the
|
|
27
|
+
one richer case — it resolves to `"saved" | "cancelled" | "failed"` so an
|
|
28
|
+
export button can tell a real save from a dismissed dialog.
|
|
29
|
+
|
|
30
|
+
Rule of thumb: wrap `/ai` calls in `try/catch`; branch on the return value for
|
|
31
|
+
`/user` and `/device`.
|
|
32
|
+
|
|
15
33
|
## User
|
|
16
34
|
|
|
17
35
|
```ts
|
|
@@ -64,6 +82,14 @@ The AI entry supports:
|
|
|
64
82
|
- `AbortSignal` cancellation
|
|
65
83
|
- Structured AI errors
|
|
66
84
|
|
|
85
|
+
> **Media payloads are pass-through.** `images.generate` / `audio.speech.create`
|
|
86
|
+
> / `video.generations.create` forward the body verbatim to the upstream
|
|
87
|
+
> provider — there is no client-side reshaping, and each model has its own
|
|
88
|
+
> shape. The param types only require `model`; build the rest of the body from
|
|
89
|
+
> the model's `parameters.shape` in the runtime model catalog, not from generic
|
|
90
|
+
> OpenAI SDK fields (`quality: 'standard'`, `style: 'vivid'`, … may be ignored
|
|
91
|
+
> or rejected by the target model).
|
|
92
|
+
|
|
67
93
|
```ts
|
|
68
94
|
import {
|
|
69
95
|
AuthRequiredError,
|
|
@@ -109,6 +135,49 @@ varies enough that a generic hook tends to leak abstractions.
|
|
|
109
135
|
React is an optional peer dependency. Projects that do not import the `/react`
|
|
110
136
|
entry do not need to install React.
|
|
111
137
|
|
|
138
|
+
## Device
|
|
139
|
+
|
|
140
|
+
Five host-bridged capabilities, each with a three-layer fallback: native App
|
|
141
|
+
bridge → browser Web API → safe default. Import the `device` namespace, or the
|
|
142
|
+
individual capabilities for tree-shaking.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import {
|
|
146
|
+
haptics,
|
|
147
|
+
geolocation,
|
|
148
|
+
sensors,
|
|
149
|
+
camera,
|
|
150
|
+
files,
|
|
151
|
+
} from '@bty/feed_app-runtime-sdk/device'
|
|
152
|
+
|
|
153
|
+
await haptics.impact('medium')
|
|
154
|
+
const pos = await geolocation.getCurrentPosition() // PositionSample | null
|
|
155
|
+
const stop = sensors.watchMotion((s) => console.log(s.accelerationWithGravity))
|
|
156
|
+
const photo = await camera.capturePhoto({ camera: 'back' }) // CapturedPhoto | null
|
|
157
|
+
const picked = await files.pickFiles({ accept: ['image/*'], multiple: true })
|
|
158
|
+
const result = await files.saveFile(blob, 'export.json') // "saved" | "cancelled" | "failed"
|
|
159
|
+
stop() // dispose the motion subscription
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Every call returns the safe default (`null`, or `false` for `haptics`) on
|
|
163
|
+
denial / cancel / unavailability — none of them throw. `pickFiles` resolves to
|
|
164
|
+
`{ files: { file, path? }[] }` (path present only on the native bridge),
|
|
165
|
+
`saveFile` to a `FileSaveResult`.
|
|
166
|
+
|
|
167
|
+
Capability detection (synchronous, cheap — gate UI ahead of a call):
|
|
168
|
+
|
|
169
|
+
| Capability | Probe |
|
|
170
|
+
|---|---|
|
|
171
|
+
| Haptics | `haptics.isSupported()` |
|
|
172
|
+
| Geolocation | `geolocation.isSupported()` |
|
|
173
|
+
| Camera | `camera.isSupported()` |
|
|
174
|
+
| Sensors | `sensors.isMotionSupported()` / `sensors.isOrientationSupported()` |
|
|
175
|
+
| Files | `files.isPickerSupported()` (the *modern* picker; plain pick always works) |
|
|
176
|
+
|
|
177
|
+
`requestMotionPermission()`, `capturePhoto()`, `saveFile()`, and `pickFiles()`
|
|
178
|
+
must be called from inside a user-gesture handler (tap / click) — browsers
|
|
179
|
+
silently deny these outside a gesture.
|
|
180
|
+
|
|
112
181
|
## Published Files
|
|
113
182
|
|
|
114
183
|
The npm package publishes only built output and this README:
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -99,13 +99,9 @@ interface ChatCompletionChunk {
|
|
|
99
99
|
[key: string]: unknown;
|
|
100
100
|
}
|
|
101
101
|
interface ImageGenerateParams extends ApiRequestOptions {
|
|
102
|
-
|
|
103
|
-
model
|
|
104
|
-
|
|
105
|
-
size?: string;
|
|
106
|
-
quality?: "standard" | "hd";
|
|
107
|
-
style?: "vivid" | "natural";
|
|
108
|
-
response_format?: "url" | "b64_json";
|
|
102
|
+
/** Required. A concrete backend-allowlisted image model id. */
|
|
103
|
+
model: string;
|
|
104
|
+
/** Provider-shape fields — copy keys from the model's `parameters.shape`. */
|
|
109
105
|
[key: string]: unknown;
|
|
110
106
|
}
|
|
111
107
|
interface ImageGenerateResponse {
|
|
@@ -115,20 +111,18 @@ interface ImageGenerateResponse {
|
|
|
115
111
|
b64_json?: string;
|
|
116
112
|
revised_prompt?: string;
|
|
117
113
|
}[];
|
|
114
|
+
[key: string]: unknown;
|
|
118
115
|
}
|
|
119
116
|
interface AudioSpeechCreateParams extends ApiRequestOptions {
|
|
117
|
+
/** Required. A concrete backend-allowlisted TTS model id. */
|
|
120
118
|
model: string;
|
|
121
|
-
|
|
122
|
-
voice: string;
|
|
123
|
-
response_format?: "mp3" | "opus" | "aac" | "flac" | "wav" | "pcm";
|
|
124
|
-
speed?: number;
|
|
119
|
+
/** Provider-shape fields — copy keys from the model's `parameters.shape`. */
|
|
125
120
|
[key: string]: unknown;
|
|
126
121
|
}
|
|
127
122
|
interface VideoGenerateParams extends ApiRequestOptions {
|
|
128
|
-
|
|
129
|
-
model
|
|
130
|
-
|
|
131
|
-
size?: string;
|
|
123
|
+
/** Required. A concrete backend-allowlisted video model id. */
|
|
124
|
+
model: string;
|
|
125
|
+
/** Provider-shape fields — copy keys from the model's `parameters.shape`. */
|
|
132
126
|
[key: string]: unknown;
|
|
133
127
|
}
|
|
134
128
|
interface VideoGenerateResponse {
|
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 O={version:"0.0
|
|
1
|
+
import {d as d$1,c}from'../chunk-AKZVV563.js';import {a}from'../chunk-ALNJCFV4.js';import {createParser}from'eventsource-parser';var O={version:"0.1.0"};var m="/v1/feed-app/runtime/ai",E=`${m}/chat/completions`,_=`${m}/messages`,v=`${m}/images/generations`,I=`${m}/audio/speech`,B=`${m}/video/generations`,M="Authorization",H="x-bty-extend",N="x-bty-app",D=O.version;var j=()=>{};async function*U(e){let t=e.getReader(),r=new TextDecoder,n=[],s=createParser({onEvent(c){n.push({event:c.event||"message",data:c.data});},onRetry:j,onComment:j}),a=false;try{for(;;){let{done:c,value:u}=await t.read();for(u&&s.feed(r.decode(u,{stream:!0}));n.length>0;)yield n.shift();if(c){for(s.reset({consume:!0});n.length>0;)yield n.shift();a=!0;return}}}finally{if(!a)try{await t.cancel();}catch{}t.releaseLock();}}async function*G(e){for await(let t of U(e)){if(t.data==="[DONE]")return;t.data&&(yield JSON.parse(t.data));}}async function*q(e){for await(let t of U(e))t.data&&(yield JSON.parse(t.data));}var Q="https://reactus-api.happyseeds.ai",J=e=>{try{let t=e();if(typeof t=="string"&&t.length>0)return t}catch{}},X=()=>J(()=>typeof __BTY_RUNTIME_API_BASE_URL__=="string"?__BTY_RUNTIME_API_BASE_URL__:void 0),z=()=>J(()=>typeof __BTY_RUNTIME_PROJECT_ID__=="string"?__BTY_RUNTIME_PROJECT_ID__:void 0),T={apiBaseUrl:(X()??Q).replace(/\/+$/,""),projectId:z()??""},W=e=>{T={...T,...e,...e.apiBaseUrl?{apiBaseUrl:e.apiBaseUrl.replace(/\/+$/,"")}:{}};},f=()=>T;var o=class extends Error{status;code;body;constructor(t,r,n,s=null){super(t),this.name="AiError",this.code=r,this.status=n,this.body=s;}},i=class extends o{constructor(t="Auth required",r=null){super(t,"auth_required",401,r),this.name="AuthRequiredError";}},h=class extends o{constructor(t="Rate limit exceeded",r=null){super(t,"rate_limit",429,r),this.name="RateLimitError";}},g=class extends o{constructor(t="Quota exceeded",r=null){super(t,"quota_exceeded",402,r),this.name="QuotaExceededError";}},y=class extends o{constructor(t,r=400,n=null){super(t,"bad_input",r,n),this.name="BadInputError";}},A=class extends o{constructor(t,r=500,n=null){super(t,"server",r,n),this.name="ServerError";}},p=class extends o{constructor(t="Network error",r){super(t,"network",-1,r),this.name="NetworkError";}},l=class extends o{constructor(t="Request aborted"){super(t,"aborted",-1,null),this.name="AbortedError";}},V=e=>typeof e=="object"&&e!==null,Z=(e,t)=>{if(typeof e=="string")return e||t;if(!V(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(V(n)&&typeof n.message=="string"&&n.message.length>0)return n.message;let s=e.detail;return typeof s=="string"&&s.length>0?s:t},x=(e,t)=>{let r=Z(t,`HTTP ${e}`);return e===401||e===403?new i(r,t):e===402?new g(r,t):e===429?new h(r,t):e>=400&&e<500?new y(r,e,t):e>=500?new A(r,e,t):new o(r,"unknown",e,t)};var ee=e=>JSON.stringify({"sdk-version":D,...e}),$=async(e={})=>{let t=await c(),r=new Headers;t&&r.set(M,`Bearer ${t}`),r.set(H,ee(e.extend));let{projectId:n}=f();if(n&&r.set(N,n),e.contentType&&r.set("Content-Type",e.contentType),e.accept&&r.set("Accept",e.accept),e.extra)for(let[s,a]of Object.entries(e.extra))r.set(s,a);return r};var te="feed-app-runtime-sdk:auth-required",w=e=>{a()&&window.dispatchEvent(new CustomEvent(te,{detail:e}));};var re=e=>e instanceof DOMException&&e.name==="AbortError",ne=async e=>{let t=e.headers.get("content-type")??"";try{return t.includes("application/json")?await e.json():await e.text()}catch{return null}},se=e=>typeof e=="object"&&e!==null,oe=(e,t)=>{if(!se(e)||typeof e.success!="boolean")return e;if(e.success)return e.data;let r=typeof e.code=="number"?e.code:t;throw x(r,e)},L=async(e,t)=>{let{apiBaseUrl:r}=f(),n=`${r}${e}`,s=await $(t),a;try{a=await fetch(n,{method:t.method??"POST",headers:s,body:t.body,signal:t.signal});}catch(u){throw re(u)?new l:new p("Failed to reach AI backend",u)}if(a.ok)return a;let c=await ne(a);throw x(a.status,c)},P=async(e,t={})=>{try{return await L(e,t)}catch(r){if(r instanceof i&&!t.skipAuthRetry&&!t.signal?.aborted){if(!await d$1())throw w({reason:"refresh_failed",error:r}),r;try{return await L(e,{...t,skipAuthRetry:!0})}catch(s){throw s instanceof i&&w({reason:"retry_rejected",error:s}),s}}throw r}},d=async(e,t,r={})=>{let n=await P(e,{...r,method:"POST",contentType:"application/json",body:JSON.stringify(t)});return oe(await n.json(),n.status)};var C=async(e,t,r={})=>{let n=await P(e,{...r,method:"POST",contentType:"application/json",accept:"text/event-stream",body:JSON.stringify(t)});if(!n.body)throw new p("Streaming response has no body");return n.body},F=async(e,t,r={})=>await(await P(e,{...r,method:"POST",contentType:"application/json",body:JSON.stringify(t)})).blob();var R=e=>{let{signal:t,headers:r,...n}=e;return {transport:{signal:t,extra:r},payload:n}},ae=(async e=>{let{transport:t,payload:r}=R(e);if(e.stream){let n=await C(E,r,t);return G(n)}return await d(E,r,t)}),ie={create:ae},ce={async generate(e){let{transport:t,payload:r}=R(e);return d(v,r,t)}},pe={speech:{async create(e){let{transport:t,payload:r}=R(e);return F(I,r,t)}}},de={generations:{async create(e){let{transport:t,payload:r}=R(e);return d(B,r,t)}}},ue={chat:{completions:ie},images:ce,audio:pe,video:de};var me=e=>{let{signal:t,headers:r,...n}=e;return {transport:{signal:t,extra:r},payload:n}},le=(async e=>{let{transport:t,payload:r}=me(e);if(e.stream){let n=await C(_,r,t);return q(n)}return await d(_,r,t)}),fe={messages:{create:le}};
|
|
2
2
|
export{l as AbortedError,o as AiError,i as AuthRequiredError,y as BadInputError,p as NetworkError,g as QuotaExceededError,h as RateLimitError,A as ServerError,fe as anthropic,W as configureRuntime,ue as openai};
|
package/dist/device/index.d.ts
CHANGED
|
@@ -72,10 +72,14 @@ interface PickFilesOptions {
|
|
|
72
72
|
multiple?: boolean;
|
|
73
73
|
directory?: boolean;
|
|
74
74
|
}
|
|
75
|
+
interface PickedFile {
|
|
76
|
+
file: File;
|
|
77
|
+
path?: string;
|
|
78
|
+
}
|
|
75
79
|
interface PickedFiles {
|
|
76
|
-
files:
|
|
77
|
-
paths: string[];
|
|
80
|
+
files: PickedFile[];
|
|
78
81
|
}
|
|
82
|
+
type FileSaveResult = "saved" | "cancelled" | "failed";
|
|
79
83
|
|
|
80
84
|
declare const camera: {
|
|
81
85
|
isSupported(): boolean;
|
|
@@ -114,8 +118,10 @@ declare const files: {
|
|
|
114
118
|
isPickerSupported(): boolean;
|
|
115
119
|
/**
|
|
116
120
|
* Pick one or more files. Returns null on user cancel or unavailability.
|
|
117
|
-
* `
|
|
118
|
-
* web fallbacks have no path concept
|
|
121
|
+
* Each entry is a `{ file, path? }` — `path` is set only when the native
|
|
122
|
+
* bridge serves the request; web fallbacks have no path concept and omit
|
|
123
|
+
* it. Pairing path with its file avoids the index drift a separate
|
|
124
|
+
* `paths[]` array invites.
|
|
119
125
|
*/
|
|
120
126
|
pickFiles(opts?: PickFilesOptions): Promise<PickedFiles | null>;
|
|
121
127
|
/**
|
|
@@ -123,10 +129,14 @@ declare const files: {
|
|
|
123
129
|
* a directory and write in place; web fallback uses the File System Access
|
|
124
130
|
* save dialog when available, otherwise triggers an anchor download.
|
|
125
131
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
132
|
+
* Resolves to a `FileSaveResult` — `"saved"` on success, `"cancelled"` when
|
|
133
|
+
* the user dismisses the dialog, `"failed"` on any error or unavailable
|
|
134
|
+
* environment. Never throws, so a "Export" button can branch on the outcome
|
|
135
|
+
* (toast on saved, stay quiet on cancelled, error hint on failed) instead of
|
|
136
|
+
* assuming success. There is no progress callback — web Blobs write
|
|
137
|
+
* atomically.
|
|
128
138
|
*/
|
|
129
|
-
saveFile(blob: Blob, filename: string): Promise<
|
|
139
|
+
saveFile(blob: Blob, filename: string): Promise<FileSaveResult>;
|
|
130
140
|
/**
|
|
131
141
|
* Read the contents of a File / Blob as a UTF-8 string. Pure web — does
|
|
132
142
|
* not consult the native bridge. The blob already lives in the page's
|
|
@@ -223,35 +233,35 @@ type DeviceFeature = "haptics" | "geolocation" | "sensors" | "camera" | "files";
|
|
|
223
233
|
declare const meetsFeatureMinVersion: (feature: DeviceFeature, env: AppEnvironment) => boolean;
|
|
224
234
|
|
|
225
235
|
declare const device: {
|
|
226
|
-
haptics: {
|
|
236
|
+
readonly haptics: {
|
|
227
237
|
isSupported(): boolean;
|
|
228
238
|
impact(strength?: HapticImpactStrength): Promise<void>;
|
|
229
239
|
selection(): Promise<void>;
|
|
230
240
|
notification(kind: HapticNotificationKind): Promise<void>;
|
|
231
241
|
vibrate(pattern: number | number[]): Promise<void>;
|
|
232
242
|
};
|
|
233
|
-
geolocation: {
|
|
243
|
+
readonly geolocation: {
|
|
234
244
|
isSupported(): boolean;
|
|
235
245
|
getCurrentPosition(opts?: PositionRequestOptions): Promise<PositionSample | null>;
|
|
236
246
|
watchPosition(onSample: (sample: PositionSample) => void, opts?: PositionRequestOptions): () => void;
|
|
237
247
|
};
|
|
238
|
-
sensors: {
|
|
248
|
+
readonly sensors: {
|
|
239
249
|
isMotionSupported(): boolean;
|
|
240
250
|
isOrientationSupported(): boolean;
|
|
241
251
|
requestMotionPermission(): Promise<boolean>;
|
|
242
252
|
watchMotion(onSample: (s: MotionSample) => void, opts?: MotionWatchOptions): () => void;
|
|
243
253
|
watchOrientation(onSample: (s: OrientationSample) => void): () => void;
|
|
244
254
|
};
|
|
245
|
-
camera: {
|
|
255
|
+
readonly camera: {
|
|
246
256
|
isSupported(): boolean;
|
|
247
257
|
capturePhoto(opts?: PhotoCaptureOptions): Promise<CapturedPhoto | null>;
|
|
248
258
|
openStream(opts?: StreamOptions): Promise<MediaStream | null>;
|
|
249
259
|
stopStream(stream: MediaStream): void;
|
|
250
260
|
};
|
|
251
|
-
files: {
|
|
261
|
+
readonly files: {
|
|
252
262
|
isPickerSupported(): boolean;
|
|
253
263
|
pickFiles(opts?: PickFilesOptions): Promise<PickedFiles | null>;
|
|
254
|
-
saveFile(blob: Blob, filename: string): Promise<
|
|
264
|
+
saveFile(blob: Blob, filename: string): Promise<FileSaveResult>;
|
|
255
265
|
readAsText(file: File | Blob): Promise<string>;
|
|
256
266
|
readAsDataUrl(file: File | Blob): Promise<string>;
|
|
257
267
|
};
|
package/dist/device/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {a,d as d$1,u as u$1,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,n)=>{if(n.type!=="native_app"||!n.platform||!n.appVersion)return false;let t$1=re[e][n.platform];return t$1?u$1(t(n.appVersion),t$1):false},I=e=>JSON.stringify(e),ae=(e,n)=>{if(typeof e!="object"||e===null||Reflect.get(e,"ok")!==true)return null;let o=Reflect.get(e,"result");return n(o)},se=async e$1=>e$1.platform==="Android"?x(e,{pollIntervalMs:r,timeoutMs:s}):w(e),p=async e=>{if(!a())return null;S();let n=v();if(!C(e.feature,n))return null;let t=await se(n);if(!t)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(m),r(v));},c=b.on(o,v=>{let g=ae(v,e.parseResult);l(g);}),m=setTimeout(()=>l(null),i);try{t.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 n=v();if(!C(e.feature,n))return null;let t=await se(n);if(!t)return null;let o=c(e.endpointPrefix),i=b.on(o,r=>{let a=ae(r,e.parseEvent);a&&e.onEvent(a);});try{t.postMessage({command:e.startCommand,parameters:I({endpoint:o,timestamp:Date.now(),payload:e.payload})});}catch{return i(),null}return ()=>{i();try{t.postMessage({command:e.stopCommand,parameters:I({endpoint:o,timestamp:Date.now(),payload:null})});}catch{}}};var d=async e=>{if(!a())return e.safeDefault;let n=await e.native();if(n!==null)return n;try{let t=await e.web();if(t!==null)return t}catch{}return e.safeDefault};var le=e=>e==="front"?"user":"environment",_e={low:.5,medium:.8,high:.95},Te=e=>{let n=e.indexOf(",");if(n<0)return null;let t=e.slice(5,n),o=e.slice(n+1),r=/^([^;]+)/.exec(t)?.[1]??"application/octet-stream";try{if(/;base64/.test(t)){let l=atob(o),c=new Uint8Array(l.length);for(let m=0;m<l.length;m++)c[m]=l.charCodeAt(m);return new Blob([c],{type:r})}return new Blob([decodeURIComponent(o)],{type:r})}catch{return null}},be=e=>{if(typeof e!="object"||e===null)return null;let n=Reflect.get(e,"dataUrl"),t=Reflect.get(e,"width"),o=Reflect.get(e,"height");if(typeof n!="string"||n.length===0||typeof t!="number"||typeof o!="number")return null;let i=Te(n);return i?{blob:i,dataUrl:n,width:t,height:o}:null},Me=async e=>{if(!a()||!navigator.mediaDevices?.getUserMedia)return null;let n=null;try{n=await navigator.mediaDevices.getUserMedia({video:{facingMode:le(e?.camera),width:e?.width,height:e?.height}});let t=document.createElement("video");t.srcObject=n,t.muted=!0,t.playsInline=!0,await t.play(),await new Promise(h=>{requestAnimationFrame(()=>h());});let o=e?.width??t.videoWidth??640,i=e?.height??t.videoHeight??480,r=document.createElement("canvas");r.width=o,r.height=i;let a=r.getContext("2d");if(!a)return null;a.drawImage(t,0,0,o,i);let c=`image/${e?.format??"jpeg"}`,m=_e[e?.quality??"medium"],v=r.toDataURL(c,m),g=await new Promise(h=>{r.toBlob(he=>h(he),c,m);});return g?{blob:g,dataUrl:v,width:o,height:i}:null}catch{return null}finally{if(n)for(let t of n.getTracks())t.stop();}},ce={isSupported(){return a()?!!navigator.mediaDevices?.getUserMedia:false},capturePhoto(e){return d({native:()=>p({feature:"camera",command:ne,endpointPrefix:G,payload:e??{},parseResult:be,timeoutMs:6e4}),web:()=>Me(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 n of e.getTracks())n.stop();}catch{}}};var me=(e,n)=>{let t=atob(e),o=new Uint8Array(t.length);for(let i=0;i<t.length;i++)o[i]=t.charCodeAt(i);return new Blob([o],{type:n})},Ce=e=>{let n=null;if(e.dataUrl){let t=e.dataUrl.indexOf(",");if(t>0){let o=e.dataUrl.slice(5,t),i=e.dataUrl.slice(t+1),r=/^([^;]+)/.exec(o)?.[1]??"application/octet-stream";try{n=/;base64/.test(o)?me(i,r):new Blob([decodeURIComponent(i)],{type:r});}catch{n=null;}}}else e.base64&&(n=me(e.base64,e.mime??"application/octet-stream"));return n?new File([n],e.name,{type:e.mime??n.type,lastModified:Date.now()}):null},Ae=e=>{if(typeof e!="object"||e===null)return null;let n=Reflect.get(e,"files");if(!Array.isArray(n))return null;let t=[],o=[];for(let r of n){if(typeof r!="object"||r===null)continue;let a=r,l=Ce(a);l&&(t.push(l),typeof a.path=="string"&&o.push(a.path));}if(t.length===0)return null;let i=Reflect.get(e,"paths");if(Array.isArray(i)){o.length=0;for(let r of i)typeof r=="string"&&o.push(r);}return {files:t,paths:o}},Ne=e=>{let n=[],t=[];if(!e)return {mimeTypes:n,extensions:t};for(let o of e)for(let i of o.split(",")){let r=i.trim();r&&(r.startsWith(".")?t.push(r):n.push(r));}return {mimeTypes:n,extensions:t}},De=e=>e instanceof DOMException&&e.name==="AbortError",we=async e=>{if(!a())return null;try{if(e?.directory){let i=await directoryOpen({recursive:!0});return i.length>0?{files:i,paths:[]}:null}let{mimeTypes:n,extensions:t}=Ne(e?.accept);if(e?.multiple){let i=await fileOpen({mimeTypes:n,extensions:t,multiple:!0});return i.length>0?{files:i,paths:[]}:null}return {files:[await fileOpen({mimeTypes:n,extensions:t})],paths:[]}}catch(n){return De(n),null}},xe=async(e,n)=>{if(a())try{await fileSave(e,{fileName:n});}catch{}},pe={isPickerSupported(){return a()?typeof window.showOpenFilePicker=="function":false},pickFiles(e){return d({native:()=>p({feature:"files",command:oe,endpointPrefix:R,payload:e??{},parseResult:Ae,timeoutMs:6e4}),web:()=>we(e),safeDefault:null})},async saveFile(e,n){!a()||await p({feature:"files",command:ie,endpointPrefix:R,payload:{filename:n,mime:e.type,size:e.size},parseResult:()=>true,timeoutMs:6e4})||await xe(e,n);},readAsText(e){return typeof e.text=="function"?e.text():new Promise((n,t)=>{let o=new FileReader;o.onload=()=>{n(typeof o.result=="string"?o.result:"");},o.onerror=()=>t(o.error),o.readAsText(e);})},readAsDataUrl(e){return new Promise((n,t)=>{let o=new FileReader;o.onload=()=>{n(typeof o.result=="string"?o.result:"");},o.onerror=()=>t(o.error),o.readAsDataURL(e);})}};var f=(e,...n)=>{for(let t of n){let o=Reflect.get(e,t);if(typeof o=="number"&&!Number.isNaN(o))return o}},de=e=>{if(typeof e!="object"||e===null)return null;let n=f(e,"latitude"),t=f(e,"longitude"),o=f(e,"accuracyMeters","accuracy");if(n===void 0||t===void 0||o===void 0)return null;let i={latitude:n,longitude:t,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},fe=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}),ve=e=>e?{enableHighAccuracy:e.enableHighAccuracy,timeout:e.timeoutMs,maximumAge:e.maximumAgeMs}:void 0,Fe=e=>!a()||!navigator.geolocation?Promise.resolve(null):new Promise(n=>{navigator.geolocation.getCurrentPosition(t=>n(fe(t)),()=>n(null),ve(e));}),Se={isSupported(){return a()?!!navigator.geolocation:false},getCurrentPosition(e){return d({native:()=>p({feature:"geolocation",command:Q,endpointPrefix:M,payload:e??{},parseResult:de,timeoutMs:e?.timeoutMs}),web:()=>Fe(e),safeDefault:null})},watchPosition(e,n){let t=false,o=null,i=null;return E({feature:"geolocation",startCommand:J,stopCommand:Y,endpointPrefix:M,payload:n??{},parseEvent:de,onEvent:r=>{t||e(r);}}).then(r=>{if(t){r?.();return}if(r){o=r;return}if(!(!a()||!navigator.geolocation))try{i=navigator.geolocation.watchPosition(a=>{t||e(fe(a));},()=>{},ve(n));}catch{}}),()=>{if(t=true,o&&o(),i!==null&&a()&&navigator.geolocation)try{navigator.geolocation.clearWatch(i);}catch{}}}};var ke={light:10,medium:20,heavy:40,soft:15,rigid:30},Ue={success:[20,60,20],warning:[40,40,40],error:[50,30,100]},Le=e=>{if(typeof navigator>"u"||typeof navigator.vibrate!="function")return false;try{return navigator.vibrate(e)}catch{return false}},O=(e,n,t)=>d({native:()=>p({feature:"haptics",command:e,endpointPrefix:B,payload:n,parseResult:()=>true}),web:async()=>Le(t),safeDefault:false}),Ee={isSupported(){return a()?typeof navigator<"u"&&"vibrate"in navigator:false},async impact(e="medium"){await O(q,{strength:e},ke[e]);},async selection(){await O(j,{},8);},async notification(e){await O(z,{kind:e},Ue[e]);},async vibrate(e){await O(K,{pattern:e},e);}};var Pe=()=>typeof DeviceMotionEvent>"u"?false:typeof DeviceMotionEvent.requestPermission=="function",ge=async()=>{if(!Pe())return true;try{let e=DeviceMotionEvent.requestPermission;return e?await e()==="granted":!0}catch{return false}},u=(e,...n)=>{for(let t of n){let o=Reflect.get(e,t);if(typeof o=="number"&&!Number.isNaN(o))return o}},A=(e,n)=>{let t=Reflect.get(e,n);if(typeof t!="object"||t===null)return;let o=u(t,"x"),i=u(t,"y"),r=u(t,"z");if(!(o===void 0||i===void 0||r===void 0))return {x:o,y:i,z:r}},Be=e=>{if(typeof e!="object"||e===null)return null;let n=A(e,"accelerationWithGravity")??A(e,"accelerationIncludingGravity");if(!n)return null;let t=Reflect.get(e,"rotationRate"),o={alpha:0,beta:0,gamma:0};typeof t=="object"&&t!==null&&(o={alpha:u(t,"alpha")??0,beta:u(t,"beta")??0,gamma:u(t,"gamma")??0});let i={accelerationWithGravity:n,rotationRate:o,timestamp:u(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=u(a,"yaw"),c=u(a,"pitch"),m=u(a,"roll");l!==void 0&&c!==void 0&&m!==void 0&&(i.attitude={yaw:l,pitch:c,roll:m});}return i},He=e=>{if(typeof e!="object"||e===null)return null;let n=u(e,"alpha"),t=u(e,"beta"),o=u(e,"gamma");return n===void 0||t===void 0||o===void 0?null:{alpha:n,beta:t,gamma:o,timestamp:u(e,"timestamp")??Date.now()}},Ve=e=>{let n=e.accelerationIncludingGravity,t=e.acceleration,o=e.rotationRate,i={accelerationWithGravity:{x:n?.x??0,y:n?.y??0,z:n?.z??0},rotationRate:{alpha:o?.alpha??0,beta:o?.beta??0,gamma:o?.gamma??0},timestamp:e.timeStamp||Date.now()};return t&&(t.x!==null||t.y!==null||t.z!==null)&&(i.acceleration={x:t.x??0,y:t.y??0,z:t.z??0}),i},We=e=>({alpha:e.alpha??0,beta:e.beta??0,gamma:e.gamma??0,timestamp:e.timeStamp||Date.now()}),Oe={isMotionSupported(){return a()?typeof DeviceMotionEvent<"u":false},isOrientationSupported(){return a()?typeof DeviceOrientationEvent<"u":false},async requestMotionPermission(){if(!a())return false;let e=await p({feature:"sensors",command:te,endpointPrefix:W,payload:{},parseResult:n=>{if(typeof n=="boolean")return n;if(typeof n=="object"&&n!==null){let t=Reflect.get(n,"granted");if(typeof t=="boolean")return t}return null}});return e!==null?e:ge()},watchMotion(e,n){let t=false,o=null,i=null,r=()=>{if(t||!a())return;let l=c=>{t||e(Ve(c));};window.addEventListener("devicemotion",l),i=l;};return (async()=>{let l=await E({feature:"sensors",startCommand:$,stopCommand:X,endpointPrefix:H,payload:n??{},parseEvent:Be,onEvent:c=>{t||e(c);}});if(t){l?.();return}if(l){o=l;return}n?.autoRequestPermission&&Pe()&&(!await ge()||t)||r();})(),()=>{t=true,o&&o(),i&&a()&&(window.removeEventListener("devicemotion",i),i=null);}},watchOrientation(e){let n=false,t=null,o=null,i=()=>{if(n||!a())return;let a$1=l=>{n||e(We(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:He,onEvent:l=>{n||e(l);}});if(n){a?.();return}if(a){t=a;return}i();})(),()=>{n=true,t&&t(),o&&a()&&(window.removeEventListener("deviceorientation",o),o=null);}}};S();var Ct={haptics:Ee,geolocation:Se,sensors:Oe,camera:ce,files:pe};export{ce as camera,Ct as device,pe as files,Se as geolocation,Ee as haptics,C as meetsFeatureMinVersion,Oe as sensors};
|
|
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};
|
package/dist/react/index.d.ts
CHANGED
|
@@ -4,8 +4,11 @@ interface UseAuthTokenResult {
|
|
|
4
4
|
token: string;
|
|
5
5
|
/** 首次 fetch 或主动 refetch 未完成期间为 true。 */
|
|
6
6
|
loading: boolean;
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* 主动重新拉取;命中 SDK 凭证缓存时不会重复访问宿主。返回的 Promise 在
|
|
9
|
+
* 本次拉取完成后 resolve,便于业务 `await refetch()` 后再做后续动作。
|
|
10
|
+
*/
|
|
11
|
+
refetch: () => Promise<void>;
|
|
9
12
|
}
|
|
10
13
|
/**
|
|
11
14
|
* 鉴权 token。挂载时拉一次,业务需要刷新时调用 refetch。
|
|
@@ -22,7 +25,8 @@ declare const useAuthToken: () => UseAuthTokenResult;
|
|
|
22
25
|
interface UseUserInfoResult {
|
|
23
26
|
user: UserInfo | null;
|
|
24
27
|
loading: boolean;
|
|
25
|
-
|
|
28
|
+
/** 主动重新拉取。返回的 Promise 在拉取完成后 resolve。 */
|
|
29
|
+
refetch: () => Promise<void>;
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
28
32
|
* 用户信息。同 useAuthToken:挂载拉一次,业务需要刷新时调用 refetch。
|
package/dist/react/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {b,a,c,e}from'../chunk-AKZVV563.js';import'../chunk-ALNJCFV4.js';import {useSyncExternalStore,useState,useCallback,useEffect}from'react';var
|
|
1
|
+
import {b,a,c,e}from'../chunk-AKZVV563.js';import'../chunk-ALNJCFV4.js';import {useSyncExternalStore,useState,useCallback,useEffect}from'react';var k="",d=()=>{let u=useSyncExternalStore(b,a,()=>k),[s,e]=useState(()=>a()===""),t=useCallback(async()=>{e(true),await c(),e(false);},[]);return useEffect(()=>{if(a()!==""){e(false);return}let o=true;return c().then(()=>{o&&e(false);}),()=>{o=false;}},[]),{token:u,loading:s,refetch:t}};var I=()=>{let[u,s]=useState(null),[e$1,t]=useState(true),o=useCallback(async()=>{t(true);let r=await e();s(r),t(false);},[]);return useEffect(()=>{let r=true;return e().then(c=>{r&&(s(c),t(false));}),()=>{r=false;}},[]),{user:u,loading:e$1,refetch:o}};export{d as useAuthToken,I as useUserInfo};
|
package/package.json
CHANGED