@bty/feed_app-runtime-sdk 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ai/index.js CHANGED
@@ -1,3 +1,2 @@
1
- var Y={version:"0.0.7"};var A="/v1/feed-app/runtime/ai",U=`${A}/chat/completions`,H=`${A}/messages`,K=`${A}/images/generations`,X=`${A}/audio/speech`,W=`${A}/video/generations`,z="Authorization",Z="x-bty-extend",ee="x-bty-app",te=Y.version;var He=/\r\n|\r|\n/,Le=(()=>{let e=new TextDecoder;return (t,n)=>e.decode(t,{stream:n})})();async function*ne(e){let t=e.getReader(),n="",r="",s=[],o=()=>{if(s.length===0&&!r)return null;let c={event:r||"message",data:s.join(`
2
- `)};return r="",s=[],c};try{for(;;){let{done:c,value:p}=await t.read();if(c){let i=o();i&&(yield i);return}for(n+=Le(p,!0);;){let i=He.exec(n);if(!i)break;let d=n.slice(0,i.index);if(n=n.slice(i.index+i[0].length),d===""){let f=o();f&&(yield f);continue}if(d.startsWith(":"))continue;let _=d.indexOf(":"),I=_===-1?d:d.slice(0,_),l=_===-1?"":d.slice(_+1);l.startsWith(" ")&&(l=l.slice(1)),I==="event"?r=l:I==="data"&&s.push(l);}}}finally{t.releaseLock();}}async function*re(e){for await(let t of ne(e)){if(t.data==="[DONE]")return;t.data&&(yield JSON.parse(t.data));}}async function*se(e){for await(let t of ne(e))t.data&&(yield JSON.parse(t.data));}var De="https://reactus-api.betteryeah.com",oe=e=>{try{let t=e();if(typeof t=="string"&&t.length>0)return t}catch{}},Be=()=>oe(()=>typeof __BTY_RUNTIME_API_BASE_URL__=="string"?__BTY_RUNTIME_API_BASE_URL__:void 0),Fe=()=>oe(()=>typeof __BTY_RUNTIME_PROJECT_ID__=="string"?__BTY_RUNTIME_PROJECT_ID__:void 0),L={apiBaseUrl:(Be()??De).replace(/\/+$/,""),projectId:Fe()??""},qe=e=>{L={...L,...e,...e.apiBaseUrl?{apiBaseUrl:e.apiBaseUrl.replace(/\/+$/,"")}:{}};},x=()=>L;var m=class extends Error{status;code;body;constructor(t,n,r,s=null){super(t),this.name="AiError",this.code=n,this.status=r,this.body=s;}},g=class extends m{constructor(t="Auth required",n=null){super(t,"auth_required",401,n),this.name="AuthRequiredError";}},P=class extends m{constructor(t="Rate limit exceeded",n=null){super(t,"rate_limit",429,n),this.name="RateLimitError";}},k=class extends m{constructor(t="Quota exceeded",n=null){super(t,"quota_exceeded",402,n),this.name="QuotaExceededError";}},O=class extends m{constructor(t,n=400,r=null){super(t,"bad_input",n,r),this.name="BadInputError";}},N=class extends m{constructor(t,n=500,r=null){super(t,"server",n,r),this.name="ServerError";}},y=class extends m{constructor(t="Network error",n){super(t,"network",-1,n),this.name="NetworkError";}},S=class extends m{constructor(t="Request aborted"){super(t,"aborted",-1,null),this.name="AbortedError";}},ie=e=>typeof e=="object"&&e!==null,je=(e,t)=>{if(typeof e=="string")return e||t;if(!ie(e))return t;let n=e.message;if(typeof n=="string"&&n.length>0)return n;let r=e.error;if(typeof r=="string"&&r.length>0)return r;if(ie(r)&&typeof r.message=="string"&&r.message.length>0)return r.message;let s=e.detail;return typeof s=="string"&&s.length>0?s:t},D=(e,t)=>{let n=je(t,`HTTP ${e}`);return e===401||e===403?new g(n,t):e===402?new k(n,t):e===429?new P(n,t):e>=400&&e<500?new O(n,e,t):e>=500?new N(n,e,t):new m(n,"unknown",e,t)};var u=()=>typeof window<"u"&&typeof document<"u";var Ge="hostRuntime",B=class{listeners=new Map;on(t,n){let r=this.listeners.get(t),s=r??new Set;return r||this.listeners.set(t,s),s.add(n),()=>{s.delete(n),s.size===0&&this.listeners.delete(t);}}emit(t,n){let r=this.listeners.get(t);if(r)for(let s of r)s(n);}},a=new B,ae=0,F=e=>(ae+=1,`${e}.${ae}`),ce=false,pe=()=>{if(!u()||ce)return;ce=true,Reflect.set(window,Ge,{receiveMessage(t){if(!t)return;let n=t.endpoint;n&&a.emit(n,t.data??t);}});};var C=e=>typeof e=="object"&&e!==null,h=(e,t)=>{if(e)for(let n of t){let r=e[n];if(typeof r=="string"&&r.length>0)return r}},Ve=(e,t)=>{if(e)for(let n of t){let r=e[n];if(typeof r=="string"&&r.length>0||typeof r=="number"&&Number.isFinite(r))return r}},E=e=>{if(!C(e))return null;let t=C(e.credentials)?e.credentials:void 0,n=C(e.user)?e.user:void 0,r=h(e,["uid","userId","id"])??h(t,["uid","userId","id"])??h(n,["uid","userId","id"]),s=h(e,["token","authToken"])??h(t,["token","authToken"]);return !r||!s?null:{uid:r,token:s}},v=e=>{if(!C(e))return null;let t=C(e.data)?e.data:e,n=Ve(t,["userId","id","uid"]);if(n===void 0)return null;let r=h(t,["username","nickname","nickName","name"]),s=h(t,["nickname","nickName","username"]);return {...t,userId:n,...r?{username:r}:{},...s?{nickname:s}:{}}};var ue="HostApp",q="hostListener";var de="processUserCredentials",le="processUserInfo",me="user.getCredentials";var R="user.credentials",j="user.info",fe="user-credentials-request",Ee="user-credentials-response";var ge="user-info-response",he={iOS:[1,6,7],Android:[1,1,8]},_e=3e3,ye=500,Re=50,Te=1500;var Je=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"type")=="string",Ae=false,Se=()=>{!u()||Ae||(Ae=true,pe(),Reflect.set(window,de,e=>{E(e)&&a.emit(R,e);}),Reflect.set(window,le,e=>{v(e)&&a.emit(j,e);}),window.addEventListener("message",e=>{let t=e.data;if(Je(t))switch(t.type){case Ee:a.emit("iframe.credentials",t);break;case ge:a.emit("iframe.userinfo",t);break}}));};var $e=new RegExp(`${ue}\\/(\\d+\\.\\d+\\.\\d+)\\/(\\d+)\\/(iOS|Android)`),Qe=e=>{let t=e.split(".").map(n=>Number.parseInt(n,10));return [t[0]??0,t[1]??0,t[2]??0]},Ye=(e,t)=>{for(let n=0;n<3;n++){if(e[n]>t[n])return true;if(e[n]<t[n])return false}return true},Ke=e=>{let t=e.match($e);if(!t)return null;let[,n,r,s]=t;if(!n||!r||s!=="iOS"&&s!=="Android")return null;let o=Ye(Qe(n),he[s]);return {type:"native_app",platform:s,appVersion:n,buildNumber:r,meetsMinVersion:o}},Ce=()=>{if(!u())return {type:"web",meetsMinVersion:false};let e=Ke(navigator.userAgent??"");return e||(window.parent!==window?{type:"iframe",meetsMinVersion:false}:{type:"web",meetsMinVersion:false})};var Xe=(e,t,n)=>new Promise(r=>{let s=false,o=i=>{s||(s=true,c(),clearTimeout(p),r(i));},c=a.on(t,i=>{let d=n(i);d&&o(d);}),p=setTimeout(()=>o(null),ye);try{window.parent.postMessage({type:e,timestamp:Date.now()},"*");}catch{o(null);}}),we=()=>Xe(fe,"iframe.credentials",E);var Ie=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"postMessage")=="function",G=e=>{let t=Reflect.get(window,"webkit");if(typeof t=="object"&&t!==null){let r=Reflect.get(t,"messageHandlers");if(typeof r=="object"&&r!==null){let s=Reflect.get(r,e);if(Ie(s))return s}}let n=Reflect.get(window,e);return Ie(n)?n:null},xe=(e,t={})=>{let{pollIntervalMs:n=50,timeoutMs:r=1500}=t;return new Promise(s=>{let o=Date.now(),c=()=>{let p=G(e);if(p){s(p);return}if(Date.now()-o>=r){s(null);return}setTimeout(c,n);};c();})};var We=async(e,t,n,r)=>{let s=e.platform==="Android"?await xe(q,{pollIntervalMs:Re,timeoutMs:Te}):G(q);if(!s)return null;let o=F(n);return new Promise(c=>{let p=false,i=l=>{p||(p=true,d(),_(),clearTimeout(I),c(l));},d=a.on(o,l=>{let f=r(l);f&&i(f);}),_=a.on(n,l=>{let f=r(l);f&&i(f);}),I=setTimeout(()=>i(null),_e);try{s.postMessage({command:t,parameters:JSON.stringify({timestamp:Date.now(),endpoint:o})});}catch{i(null);}})},Pe=e=>We(e,me,R,E);Se();var V=null,w=null,ze=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?Pe(e):Promise.resolve(null);case "iframe":return we();case "web":return Promise.resolve(null)}};var ke=e=>{V=e;},Oe=()=>w||(w=ze(Ce()).then(e=>(e&&ke(e),e)).finally(()=>{w=null;}),w);u()&&a.on(R,e=>{let t=E(e);t&&ke(t);});var J=async()=>u()?V?V.token:(await Oe())?.token??"":"",Ne=async()=>u()?(await Oe())?.token??"":"";var Ze=e=>JSON.stringify({"sdk-version":te,...e}),ve=async(e={})=>{let t=await J(),n=new Headers;t&&n.set(z,`Bearer ${t}`),n.set(Z,Ze(e.extend));let{projectId:r}=x();if(r&&n.set(ee,r),e.contentType&&n.set("Content-Type",e.contentType),e.accept&&n.set("Accept",e.accept),e.extra)for(let[s,o]of Object.entries(e.extra))n.set(s,o);return n};var et="feed-app-runtime-sdk:auth-required",$=e=>{u()&&window.dispatchEvent(new CustomEvent(et,{detail:e}));};var tt=e=>e instanceof DOMException&&e.name==="AbortError",nt=async e=>{let t=e.headers.get("content-type")??"";try{return t.includes("application/json")?await e.json():await e.text()}catch{return null}},rt=e=>typeof e=="object"&&e!==null,st=(e,t)=>{if(!rt(e)||typeof e.success!="boolean")return e;if(e.success)return e.data;let n=typeof e.code=="number"?e.code:t;throw D(n,e)},be=async(e,t)=>{let{apiBaseUrl:n}=x(),r=`${n}${e}`,s=await ve(t),o;try{o=await fetch(r,{method:t.method??"POST",headers:s,body:t.body,signal:t.signal});}catch(p){throw tt(p)?new S:new y("Failed to reach AI backend",p)}if(o.ok)return o;let c=await nt(o);throw D(o.status,c)},Q=async(e,t={})=>{try{return await be(e,t)}catch(n){if(n instanceof g&&!t.skipAuthRetry&&!t.signal?.aborted){if(!await Ne())throw $({reason:"refresh_failed",error:n}),n;try{return await be(e,{...t,skipAuthRetry:!0})}catch(s){throw s instanceof g&&$({reason:"retry_rejected",error:s}),s}}throw n}},T=async(e,t,n={})=>{let r=await Q(e,{...n,method:"POST",contentType:"application/json",body:JSON.stringify(t)});return st(await r.json(),r.status)};var b=async(e,t,n={})=>{let r=await Q(e,{...n,method:"POST",contentType:"application/json",accept:"text/event-stream",body:JSON.stringify(t)});if(!r.body)throw new y("Streaming response has no body");return r.body},Me=async(e,t,n={})=>await(await Q(e,{...n,method:"POST",contentType:"application/json",body:JSON.stringify(t)})).blob();var M=e=>{let{signal:t,headers:n,...r}=e;return {transport:{signal:t,extra:n},payload:r}},ot=(async e=>{let{transport:t,payload:n}=M(e);if(e.stream){let r=await b(U,n,t);return re(r)}return await T(U,n,t)}),it={create:ot},at={async generate(e){let{transport:t,payload:n}=M(e);return T(K,n,t)}},ct={speech:{async create(e){let{transport:t,payload:n}=M(e);return Me(X,n,t)}}},pt={generations:{async create(e){let{transport:t,payload:n}=M(e);return T(W,n,t)}}},ut={chat:{completions:it},images:at,audio:ct,video:pt};var dt=e=>{let{signal:t,headers:n,...r}=e;return {transport:{signal:t,extra:n},payload:r}},lt=(async e=>{let{transport:t,payload:n}=dt(e);if(e.stream){let r=await b(H,n,t);return se(r)}return await T(H,n,t)}),mt={messages:{create:lt}};
3
- export{S as AbortedError,m as AiError,g as AuthRequiredError,O as BadInputError,y as NetworkError,k as QuotaExceededError,P as RateLimitError,N as ServerError,mt as anthropic,qe as configureRuntime,ut as openai};
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.9"};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
+ 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};
@@ -0,0 +1 @@
1
+ import {a as a$1,b,j as j$1,d,f,g,k,o,m,v,q,x,e,s,r,w,c as c$1,p,l,n,h,i}from'./chunk-ALNJCFV4.js';var E=e=>typeof e=="object"&&e!==null,a=(e,n)=>{if(e)for(let t of n){let r=e[t];if(typeof r=="string"&&r.length>0)return r}},$=(e,n)=>{if(e)for(let t of n){let r=e[t];if(typeof r=="string"&&r.length>0||typeof r=="number"&&Number.isFinite(r))return r}},u=e=>{if(!E(e))return null;let n=E(e.credentials)?e.credentials:void 0,t=E(e.user)?e.user:void 0,r=a(e,["uid","userId","id"])??a(n,["uid","userId","id"])??a(t,["uid","userId","id"]),o=a(e,["token","authToken"])??a(n,["token","authToken"]);return !r||!o?null:{uid:r,token:o}},c=e=>{if(!E(e))return null;let n=E(e.data)?e.data:e,t=$(n,["userId","id","uid"]);if(t===void 0)return null;let r=a(n,["username","nickname","nickName","name"]),o=a(n,["nickname","nickName","username"]);return {...n,userId:t,...r?{username:r}:{},...o?{nickname:o}:{}}};var ee=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"type")=="string",H=false,V=()=>{!a$1()||H||(H=true,d(),Reflect.set(window,f,e=>{u(e)&&b.emit(j$1,e);}),Reflect.set(window,g,e=>{c(e)&&b.emit(k,e);}),window.addEventListener("message",e=>{let n=e.data;if(ee(n))switch(n.type){case m:b.emit("iframe.credentials",n);break;case o:b.emit("iframe.userinfo",n);break}}));};var j=(e,n,t)=>new Promise(r=>{let o=false,f=i=>{o||(o=true,y(),clearTimeout(T),r(i));},y=b.on(n,i=>{let g=t(i);g&&f(g);}),T=setTimeout(()=>f(null),q);try{window.parent.postMessage({type:e,timestamp:Date.now()},"*");}catch{f(null);}}),G=()=>j(l,"iframe.credentials",u),Q=()=>j(n,"iframe.userinfo",c);var J=async(e$1,n,t,r$1)=>{let o=e$1.platform==="Android"?await x(e,{pollIntervalMs:r,timeoutMs:s}):w(e);if(!o)return null;let f=c$1(t);return new Promise(y=>{let T=false,i=d=>{T||(T=true,g(),Y(),clearTimeout(Z),y(d));},g=b.on(f,d=>{let p=r$1(d);p&&i(p);}),Y=b.on(t,d=>{let p=r$1(d);p&&i(p);}),Z=setTimeout(()=>i(null),p);try{o.postMessage({command:n,parameters:JSON.stringify({timestamp:Date.now(),endpoint:f})});}catch{i(null);}})},z=e=>J(e,h,j$1,u),K=e=>J(e,i,k,c);V();var C=null,I=null,R=new Set,ne=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?z(e):Promise.resolve(null);case "iframe":return G();case "web":return Promise.resolve(null)}},re=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?K(e):Promise.resolve(null);case "iframe":return Q();case "web":return Promise.resolve(null)}},W=e=>{let n=C?.token??"",t=e?.token??"";if(C=e,n!==t)for(let r of R)try{r();}catch{}},Ne=()=>C?.token??"",ve=e=>(R.add(e),()=>{R.delete(e);}),X=()=>I||(I=ne(v()).then(e=>(e&&W(e),e)).finally(()=>{I=null;}),I);a$1()&&b.on(j$1,e=>{let n=u(e);n&&W(n);});var te=async()=>a$1()?C?C.token:(await X())?.token??"":"",Pe=async()=>a$1()?(await X())?.token??"":"",se=async()=>a$1()?re(v()):null;export{Ne as a,ve as b,te as c,Pe as d,se as e};
@@ -0,0 +1 @@
1
+ var o=()=>typeof window<"u"&&typeof document<"u";var _="hostRuntime",p=class{listeners=new Map;on(e,t){let s=this.listeners.get(e),r=s??new Set;return s||this.listeners.set(e,r),r.add(t),()=>{r.delete(t),r.size===0&&this.listeners.delete(e);}}emit(e,t){let s=this.listeners.get(e);if(s)for(let r of s)r(t);}},R=new p,a=0,A=n=>(a+=1,`${n}.${a}`),l=false,I=()=>{if(!o()||l)return;l=true,Reflect.set(window,_,{receiveMessage(e){if(!e)return;let t=e.endpoint;t&&R.emit(t,e.data??e);}});};var E="HostApp",v="hostListener";var O="processUserCredentials",L="processUserInfo",H="user.getCredentials",b="user.getUserInfo",P="user.credentials",U="user.info",k="user-credentials-request",y="user-credentials-response",F="user-info-request",h="user-info-response",f={iOS:[1,6,7],Android:[1,1,8]},C=3e3,D=500,V=50,B=1500;var d=n=>{let e=n.split(".").map(t=>Number.parseInt(t,10));return [e[0]??0,e[1]??0,e[2]??0]},m=(n,e)=>{for(let t=0;t<3;t++){if(n[t]>e[t])return true;if(n[t]<e[t])return false}return true};var N=new RegExp(`${E}\\/(\\d+\\.\\d+\\.\\d+)\\/(\\d+)\\/(iOS|Android)`),g=n=>{let e=n.match(N);if(!e)return null;let[,t,s,r]=e;if(!t||!s||r!=="iOS"&&r!=="Android")return null;let i=m(d(t),f[r]);return {type:"native_app",platform:r,appVersion:t,buildNumber:s,meetsMinVersion:i}},Q=()=>{if(!o())return {type:"web",meetsMinVersion:false};let n=g(navigator.userAgent??"");return n||(window.parent!==window?{type:"iframe",meetsMinVersion:false}:{type:"web",meetsMinVersion:false})};var S=n=>typeof n!="object"||n===null?false:typeof Reflect.get(n,"postMessage")=="function",T=n=>{let e=Reflect.get(window,"webkit");if(typeof e=="object"&&e!==null){let s=Reflect.get(e,"messageHandlers");if(typeof s=="object"&&s!==null){let r=Reflect.get(s,n);if(S(r))return r}}let t=Reflect.get(window,n);return S(t)?t:null},X=(n,e={})=>{let{pollIntervalMs:t=50,timeoutMs:s=1500}=e;return new Promise(r=>{let i=Date.now(),u=()=>{let c=T(n);if(c){r(c);return}if(Date.now()-i>=s){r(null);return}setTimeout(u,t);};u();})};export{o as a,R as b,A as c,I as d,v as e,O as f,L as g,H as h,b as i,P as j,U as k,k as l,y as m,F as n,h as o,C as p,D as q,V as r,B as s,d as t,m as u,Q as v,T as w,X as x};
@@ -0,0 +1,260 @@
1
+ import { A as AppEnvironment } from '../types-DryABknE.js';
2
+
3
+ type HapticImpactStrength = "light" | "medium" | "heavy" | "soft" | "rigid";
4
+ type HapticNotificationKind = "success" | "warning" | "error";
5
+ interface PositionRequestOptions {
6
+ enableHighAccuracy?: boolean;
7
+ timeoutMs?: number;
8
+ maximumAgeMs?: number;
9
+ }
10
+ interface PositionSample {
11
+ latitude: number;
12
+ longitude: number;
13
+ accuracyMeters: number;
14
+ altitudeMeters?: number;
15
+ altitudeAccuracyMeters?: number;
16
+ headingDegrees?: number;
17
+ speedMetersPerSecond?: number;
18
+ timestamp: number;
19
+ }
20
+ interface Vector3 {
21
+ x: number;
22
+ y: number;
23
+ z: number;
24
+ }
25
+ interface MotionSample {
26
+ acceleration?: Vector3;
27
+ accelerationWithGravity: Vector3;
28
+ rotationRate: {
29
+ alpha: number;
30
+ beta: number;
31
+ gamma: number;
32
+ };
33
+ attitude?: {
34
+ yaw: number;
35
+ pitch: number;
36
+ roll: number;
37
+ };
38
+ timestamp: number;
39
+ }
40
+ interface OrientationSample {
41
+ alpha: number;
42
+ beta: number;
43
+ gamma: number;
44
+ timestamp: number;
45
+ }
46
+ interface MotionWatchOptions {
47
+ autoRequestPermission?: boolean;
48
+ }
49
+ type CameraFacing = "front" | "back";
50
+ type PhotoQuality = "low" | "medium" | "high";
51
+ type PhotoFormat = "jpeg" | "png" | "webp";
52
+ interface PhotoCaptureOptions {
53
+ quality?: PhotoQuality;
54
+ format?: PhotoFormat;
55
+ width?: number;
56
+ height?: number;
57
+ camera?: CameraFacing;
58
+ }
59
+ interface CapturedPhoto {
60
+ blob: Blob;
61
+ dataUrl: string;
62
+ width: number;
63
+ height: number;
64
+ }
65
+ interface StreamOptions {
66
+ camera?: CameraFacing;
67
+ width?: number;
68
+ height?: number;
69
+ }
70
+ interface PickFilesOptions {
71
+ accept?: string[];
72
+ multiple?: boolean;
73
+ directory?: boolean;
74
+ }
75
+ interface PickedFiles {
76
+ files: File[];
77
+ paths: string[];
78
+ }
79
+
80
+ declare const camera: {
81
+ isSupported(): boolean;
82
+ /**
83
+ * Open the camera, capture one photo, close the stream. The native bridge
84
+ * variant runs the host App's full-screen capture UI (better quality, save
85
+ * to gallery, etc.); the web fallback does a headless `getUserMedia +
86
+ * canvas` shot. Returns null on permission denial, hardware absence, or
87
+ * any failure on either path.
88
+ *
89
+ * Must be called inside a user-gesture handler to satisfy autoplay /
90
+ * permission requirements on iOS Safari and modern Android browsers.
91
+ */
92
+ capturePhoto(opts?: PhotoCaptureOptions): Promise<CapturedPhoto | null>;
93
+ /**
94
+ * Open a live MediaStream — for QR scanning, AR overlays, or any case
95
+ * where a single still photo is not enough. Web-only by design: streaming
96
+ * raw video frames through a JS bridge is impractical, and host Apps that
97
+ * need camera access usually push it through capturePhoto's full-screen UI
98
+ * instead.
99
+ *
100
+ * Returns null when getUserMedia is unavailable or the user denies access.
101
+ * Caller must invoke `camera.stopStream(stream)` when done.
102
+ */
103
+ openStream(opts?: StreamOptions): Promise<MediaStream | null>;
104
+ stopStream(stream: MediaStream): void;
105
+ };
106
+
107
+ declare const files: {
108
+ /**
109
+ * Whether the modern picker (File System Access API or native bridge) is
110
+ * available. False does not mean files cannot be picked — `<input
111
+ * type=file>` still works in any browser via the lib's legacy fallback; it
112
+ * just lacks path / write-back.
113
+ */
114
+ isPickerSupported(): boolean;
115
+ /**
116
+ * Pick one or more files. Returns null on user cancel or unavailability.
117
+ * `paths` is populated only when the native bridge serves the request;
118
+ * web fallbacks have no path concept.
119
+ */
120
+ pickFiles(opts?: PickFilesOptions): Promise<PickedFiles | null>;
121
+ /**
122
+ * Save a Blob to a file the user nominates. Native handler can prompt for
123
+ * a directory and write in place; web fallback uses the File System Access
124
+ * save dialog when available, otherwise triggers an anchor download.
125
+ *
126
+ * Returns once the save has been initiated. There is no progress callback —
127
+ * Blobs in web platforms write atomically.
128
+ */
129
+ saveFile(blob: Blob, filename: string): Promise<void>;
130
+ /**
131
+ * Read the contents of a File / Blob as a UTF-8 string. Pure web — does
132
+ * not consult the native bridge. The blob already lives in the page's
133
+ * memory by the time this is called.
134
+ */
135
+ readAsText(file: File | Blob): Promise<string>;
136
+ /**
137
+ * Read the contents of a File / Blob as a base64 data URL — useful for
138
+ * `<img src>` previews. Pure web.
139
+ */
140
+ readAsDataUrl(file: File | Blob): Promise<string>;
141
+ };
142
+
143
+ declare const geolocation: {
144
+ isSupported(): boolean;
145
+ /**
146
+ * Single position read. Returns null on permission denial, timeout, or
147
+ * absence of geolocation hardware. Default timeout is the browser/native
148
+ * default; pass `timeoutMs` to override.
149
+ */
150
+ getCurrentPosition(opts?: PositionRequestOptions): Promise<PositionSample | null>;
151
+ /**
152
+ * Continuous position updates. Returns a synchronous cleanup function —
153
+ * native subscription may be still warming up; cleanup is safe to call
154
+ * before that resolves, the subscription will be torn down as soon as it
155
+ * is installed.
156
+ */
157
+ watchPosition(onSample: (sample: PositionSample) => void, opts?: PositionRequestOptions): () => void;
158
+ };
159
+
160
+ declare const haptics: {
161
+ /**
162
+ * Whether at least one path can fire haptics in the current environment.
163
+ * Conservative — returns true if `navigator.vibrate` exists OR we're inside
164
+ * a native_app host. Does not guarantee any specific call will succeed
165
+ * (permissions, hardware capabilities, native version, ...).
166
+ */
167
+ isSupported(): boolean;
168
+ /**
169
+ * Tactile "tap" feedback. Maps to UIImpactFeedbackGenerator on iOS and
170
+ * VibrationEffect.EFFECT_CLICK / EFFECT_HEAVY_CLICK on Android (native
171
+ * bridge); a short navigator.vibrate pulse on the web. Default `medium`.
172
+ */
173
+ impact(strength?: HapticImpactStrength): Promise<void>;
174
+ /**
175
+ * "Tick" feedback for changing a selected item (segmented control, picker).
176
+ * Maps to UISelectionFeedbackGenerator on iOS; a very short pulse on web.
177
+ */
178
+ selection(): Promise<void>;
179
+ /**
180
+ * Status feedback after a discrete action (form submit, transaction).
181
+ * Maps to UINotificationFeedbackGenerator on iOS; a small multi-segment
182
+ * pattern on web.
183
+ */
184
+ notification(kind: HapticNotificationKind): Promise<void>;
185
+ /**
186
+ * Low-level Android-style pattern. Number = single pulse in ms; array =
187
+ * alternating vibrate/pause durations. Native bridge forwards verbatim;
188
+ * iOS handler may approximate by mapping pattern length/intensity to its
189
+ * Impact generator.
190
+ */
191
+ vibrate(pattern: number | number[]): Promise<void>;
192
+ };
193
+
194
+ declare const sensors: {
195
+ isMotionSupported(): boolean;
196
+ isOrientationSupported(): boolean;
197
+ /**
198
+ * Ask the host (native App or iOS Safari) for permission to read motion
199
+ * data. **Must be called inside a user-gesture handler on iOS Safari** —
200
+ * a non-gesture invocation silently resolves to false. The native-bridge
201
+ * variant has no such gesture requirement because the App's own iOS
202
+ * permission prompt is independent of the web view's gesture stack.
203
+ */
204
+ requestMotionPermission(): Promise<boolean>;
205
+ /**
206
+ * Subscribe to device motion samples. Native handler streams sensor-rate
207
+ * data through the bridge; web fallback uses the `devicemotion` event.
208
+ *
209
+ * iOS Safari requires a permission grant before the event fires. Pass
210
+ * `autoRequestPermission: true` from inside a click handler if you want
211
+ * the subscription to also request permission as part of setup.
212
+ */
213
+ watchMotion(onSample: (s: MotionSample) => void, opts?: MotionWatchOptions): () => void;
214
+ /**
215
+ * Subscribe to device orientation samples. Mirrors watchMotion but uses
216
+ * the `deviceorientation` event on the web fallback path.
217
+ */
218
+ watchOrientation(onSample: (s: OrientationSample) => void): () => void;
219
+ };
220
+
221
+ type DeviceFeature = "haptics" | "geolocation" | "sensors" | "camera" | "files";
222
+
223
+ declare const meetsFeatureMinVersion: (feature: DeviceFeature, env: AppEnvironment) => boolean;
224
+
225
+ declare const device: {
226
+ haptics: {
227
+ isSupported(): boolean;
228
+ impact(strength?: HapticImpactStrength): Promise<void>;
229
+ selection(): Promise<void>;
230
+ notification(kind: HapticNotificationKind): Promise<void>;
231
+ vibrate(pattern: number | number[]): Promise<void>;
232
+ };
233
+ geolocation: {
234
+ isSupported(): boolean;
235
+ getCurrentPosition(opts?: PositionRequestOptions): Promise<PositionSample | null>;
236
+ watchPosition(onSample: (sample: PositionSample) => void, opts?: PositionRequestOptions): () => void;
237
+ };
238
+ sensors: {
239
+ isMotionSupported(): boolean;
240
+ isOrientationSupported(): boolean;
241
+ requestMotionPermission(): Promise<boolean>;
242
+ watchMotion(onSample: (s: MotionSample) => void, opts?: MotionWatchOptions): () => void;
243
+ watchOrientation(onSample: (s: OrientationSample) => void): () => void;
244
+ };
245
+ camera: {
246
+ isSupported(): boolean;
247
+ capturePhoto(opts?: PhotoCaptureOptions): Promise<CapturedPhoto | null>;
248
+ openStream(opts?: StreamOptions): Promise<MediaStream | null>;
249
+ stopStream(stream: MediaStream): void;
250
+ };
251
+ files: {
252
+ isPickerSupported(): boolean;
253
+ pickFiles(opts?: PickFilesOptions): Promise<PickedFiles | null>;
254
+ saveFile(blob: Blob, filename: string): Promise<void>;
255
+ readAsText(file: File | Blob): Promise<string>;
256
+ readAsDataUrl(file: File | Blob): Promise<string>;
257
+ };
258
+ };
259
+
260
+ 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 };
@@ -0,0 +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,4 +1,4 @@
1
- import { U as UserInfo } from '../types-CLujY9ck.js';
1
+ import { U as UserInfo } from '../types-DryABknE.js';
2
2
 
3
3
  interface UseAuthTokenResult {
4
4
  token: string;
@@ -10,6 +10,10 @@ interface UseAuthTokenResult {
10
10
  /**
11
11
  * 鉴权 token。挂载时拉一次,业务需要刷新时调用 refetch。
12
12
  *
13
+ * Token 通过 `useSyncExternalStore` 订阅 SDK 内部凭证缓存——宿主通过桥
14
+ * (EP_CREDENTIALS) 推送新 token、或 AI 模块 401 自动 refresh 后,组件会
15
+ * 自动 re-render,业务不必手动 refetch。
16
+ *
13
17
  * 注意:token 是字符串,不是 Credentials。如果你需要 userId,配合
14
18
  * `useUserInfo()` 用。
15
19
  */
@@ -1 +1 @@
1
- import {useState,useCallback,useEffect}from'react';var l=()=>typeof window<"u"&&typeof document<"u";var ue="hostRuntime",N=class{listeners=new Map;on(t,r){let n=this.listeners.get(t),s=n??new Set;return n||this.listeners.set(t,s),s.add(r),()=>{s.delete(r),s.size===0&&this.listeners.delete(t);}}emit(t,r){let n=this.listeners.get(t);if(n)for(let s of n)s(r);}},i=new N,C=0,U=e=>(C+=1,`${e}.${C}`),M=false,h=()=>{if(!l()||M)return;M=true,Reflect.set(window,ue,{receiveMessage(t){if(!t)return;let r=t.endpoint;r&&i.emit(r,t.data??t);}});};var _=e=>typeof e=="object"&&e!==null,p=(e,t)=>{if(e)for(let r of t){let n=e[r];if(typeof n=="string"&&n.length>0)return n}},le=(e,t)=>{if(e)for(let r of t){let n=e[r];if(typeof n=="string"&&n.length>0||typeof n=="number"&&Number.isFinite(n))return n}},f=e=>{if(!_(e))return null;let t=_(e.credentials)?e.credentials:void 0,r=_(e.user)?e.user:void 0,n=p(e,["uid","userId","id"])??p(t,["uid","userId","id"])??p(r,["uid","userId","id"]),s=p(e,["token","authToken"])??p(t,["token","authToken"]);return !n||!s?null:{uid:n,token:s}},m=e=>{if(!_(e))return null;let t=_(e.data)?e.data:e,r=le(t,["userId","id","uid"]);if(r===void 0)return null;let n=p(t,["username","nickname","nickName","name"]),s=p(t,["nickname","nickName","username"]);return {...t,userId:r,...n?{username:n}:{},...s?{nickname:s}:{}}};var O="HostApp",k="hostListener";var x="processUserCredentials",P="processUserInfo",L="user.getCredentials",b="user.getUserInfo",d="user.credentials",g="user.info",F="user-credentials-request",H="user-credentials-response",D="user-info-request",q="user-info-response",B={iOS:[1,6,7],Android:[1,1,8]},V=3e3,j=500,G=50,Q=1500;var ae=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"type")=="string",$=false,K=()=>{!l()||$||($=true,h(),Reflect.set(window,x,e=>{f(e)&&i.emit(d,e);}),Reflect.set(window,P,e=>{m(e)&&i.emit(g,e);}),window.addEventListener("message",e=>{let t=e.data;if(ae(t))switch(t.type){case H:i.emit("iframe.credentials",t);break;case q:i.emit("iframe.userinfo",t);break}}));};var fe=new RegExp(`${O}\\/(\\d+\\.\\d+\\.\\d+)\\/(\\d+)\\/(iOS|Android)`),ce=e=>{let t=e.split(".").map(r=>Number.parseInt(r,10));return [t[0]??0,t[1]??0,t[2]??0]},pe=(e,t)=>{for(let r=0;r<3;r++){if(e[r]>t[r])return true;if(e[r]<t[r])return false}return true},me=e=>{let t=e.match(fe);if(!t)return null;let[,r,n,s]=t;if(!r||!n||s!=="iOS"&&s!=="Android")return null;let o=pe(ce(r),B[s]);return {type:"native_app",platform:s,appVersion:r,buildNumber:n,meetsMinVersion:o}},w=()=>{if(!l())return {type:"web",meetsMinVersion:false};let e=me(navigator.userAgent??"");return e||(window.parent!==window?{type:"iframe",meetsMinVersion:false}:{type:"web",meetsMinVersion:false})};var z=(e,t,r)=>new Promise(n=>{let s=false,o=a=>{s||(s=true,u(),clearTimeout(c),n(a));},u=i.on(t,a=>{let S=r(a);S&&o(S);}),c=setTimeout(()=>o(null),j);try{window.parent.postMessage({type:e,timestamp:Date.now()},"*");}catch{o(null);}}),J=()=>z(F,"iframe.credentials",f),X=()=>z(D,"iframe.userinfo",m);var W=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"postMessage")=="function",v=e=>{let t=Reflect.get(window,"webkit");if(typeof t=="object"&&t!==null){let n=Reflect.get(t,"messageHandlers");if(typeof n=="object"&&n!==null){let s=Reflect.get(n,e);if(W(s))return s}}let r=Reflect.get(window,e);return W(r)?r:null},Y=(e,t={})=>{let{pollIntervalMs:r=50,timeoutMs:n=1500}=t;return new Promise(s=>{let o=Date.now(),u=()=>{let c=v(e);if(c){s(c);return}if(Date.now()-o>=n){s(null);return}setTimeout(u,r);};u();})};var Z=async(e,t,r,n)=>{let s=e.platform==="Android"?await Y(k,{pollIntervalMs:G,timeoutMs:Q}):v(k);if(!s)return null;let o=U(r);return new Promise(u=>{let c=false,a=E=>{c||(c=true,S(),oe(),clearTimeout(ie),u(E));},S=i.on(o,E=>{let I=n(E);I&&a(I);}),oe=i.on(r,E=>{let I=n(E);I&&a(I);}),ie=setTimeout(()=>a(null),V);try{s.postMessage({command:t,parameters:JSON.stringify({timestamp:Date.now(),endpoint:o})});}catch{a(null);}})},ee=e=>Z(e,L,d,f),te=e=>Z(e,b,g,m);K();var y=null,T=null,de=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?ee(e):Promise.resolve(null);case "iframe":return J();case "web":return Promise.resolve(null)}},Ee=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?te(e):Promise.resolve(null);case "iframe":return X();case "web":return Promise.resolve(null)}},ne=e=>{y=e;},Ie=()=>T||(T=de(w()).then(e=>(e&&ne(e),e)).finally(()=>{T=null;}),T);l()&&i.on(d,e=>{let t=f(e);t&&ne(t);});var R=async()=>l()?y?y.token:(await Ie())?.token??"":"";var A=async()=>l()?Ee(w()):null;var Se=()=>{let[e,t]=useState(""),[r,n]=useState(true),s=useCallback(()=>{n(true),R().then(o=>{t(o),n(false);});},[]);return useEffect(()=>{let o=true;return R().then(u=>{o&&(t(u),n(false));}),()=>{o=false;}},[]),{token:e,loading:r,refetch:s}};var Ae=()=>{let[e,t]=useState(null),[r,n]=useState(true),s=useCallback(()=>{n(true),A().then(o=>{t(o),n(false);});},[]);return useEffect(()=>{let o=true;return A().then(u=>{o&&(t(u),n(false));}),()=>{o=false;}},[]),{user:e,loading:r,refetch:s}};export{Se as useAuthToken,Ae as useUserInfo};
1
+ import {b,a,c,e}from'../chunk-AKZVV563.js';import'../chunk-ALNJCFV4.js';import {useSyncExternalStore,useState,useCallback,useEffect}from'react';var d="",k=()=>{let u=useSyncExternalStore(b,a,()=>d),[o,e]=useState(()=>a()===""),t=useCallback(()=>{e(true),c().then(()=>e(false));},[]);return useEffect(()=>{if(a()!==""){e(false);return}let s=true;return c().then(()=>{s&&e(false);}),()=>{s=false;}},[]),{token:u,loading:o,refetch:t}};var I=()=>{let[u,o]=useState(null),[e$1,t]=useState(true),s=useCallback(()=>{t(true),e().then(r=>{o(r),t(false);});},[]);return useEffect(()=>{let r=true;return e().then(c=>{r&&(o(c),t(false));}),()=>{r=false;}},[]),{user:u,loading:e$1,refetch:s}};export{k as useAuthToken,I as useUserInfo};
@@ -0,0 +1,23 @@
1
+ interface Credentials {
2
+ uid: string;
3
+ token: string;
4
+ }
5
+ interface UserInfo {
6
+ userId: string | number;
7
+ username?: string;
8
+ nickname?: string;
9
+ avatar?: string | null;
10
+ phone?: string | null;
11
+ email?: string;
12
+ [key: string]: unknown;
13
+ }
14
+ type AppEnvironmentType = "native_app" | "iframe" | "web";
15
+ interface AppEnvironment {
16
+ type: AppEnvironmentType;
17
+ platform?: "iOS" | "Android";
18
+ appVersion?: string;
19
+ buildNumber?: string;
20
+ meetsMinVersion: boolean;
21
+ }
22
+
23
+ export type { AppEnvironment as A, Credentials as C, UserInfo as U };
@@ -1,5 +1,5 @@
1
- import { U as UserInfo } from '../types-CLujY9ck.js';
2
- export { C as Credentials } from '../types-CLujY9ck.js';
1
+ import { U as UserInfo } from '../types-DryABknE.js';
2
+ export { C as Credentials } from '../types-DryABknE.js';
3
3
 
4
4
  declare const getAuthTokenAsync: () => Promise<string>;
5
5
  declare const getUserInfoAsync: () => Promise<UserInfo | null>;
@@ -1 +1 @@
1
- var u=()=>typeof window<"u"&&typeof document<"u";var re="hostRuntime",g=class{listeners=new Map;on(n,t){let r=this.listeners.get(n),s=r??new Set;return r||this.listeners.set(n,s),s.add(t),()=>{s.delete(t),s.size===0&&this.listeners.delete(n);}}emit(n,t){let r=this.listeners.get(n);if(r)for(let s of r)s(t);}},o=new g,y=0,N=e=>(y+=1,`${e}.${y}`),k=false,v=()=>{if(!u()||k)return;k=true,Reflect.set(window,re,{receiveMessage(n){if(!n)return;let t=n.endpoint;t&&o.emit(t,n.data??n);}});};var _=e=>typeof e=="object"&&e!==null,f=(e,n)=>{if(e)for(let t of n){let r=e[t];if(typeof r=="string"&&r.length>0)return r}},se=(e,n)=>{if(e)for(let t of n){let r=e[t];if(typeof r=="string"&&r.length>0||typeof r=="number"&&Number.isFinite(r))return r}},a=e=>{if(!_(e))return null;let n=_(e.credentials)?e.credentials:void 0,t=_(e.user)?e.user:void 0,r=f(e,["uid","userId","id"])??f(n,["uid","userId","id"])??f(t,["uid","userId","id"]),s=f(e,["token","authToken"])??f(n,["token","authToken"]);return !r||!s?null:{uid:r,token:s}},m=e=>{if(!_(e))return null;let n=_(e.data)?e.data:e,t=se(n,["userId","id","uid"]);if(t===void 0)return null;let r=f(n,["username","nickname","nickName","name"]),s=f(n,["nickname","nickName","username"]);return {...n,userId:t,...r?{username:r}:{},...s?{nickname:s}:{}}};var O="HostApp",A="hostListener";var U="processUserCredentials",P="processUserInfo",x="user.getCredentials",L="user.getUserInfo",d="user.credentials",R="user.info",h="user-credentials-request",b="user-credentials-response",F="user-info-request",H="user-info-response",D={iOS:[1,6,7],Android:[1,1,8]},q=3e3,B=500,V=50,j=1500;var oe=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"type")=="string",G=false,Q=()=>{!u()||G||(G=true,v(),Reflect.set(window,U,e=>{a(e)&&o.emit(d,e);}),Reflect.set(window,P,e=>{m(e)&&o.emit(R,e);}),window.addEventListener("message",e=>{let n=e.data;if(oe(n))switch(n.type){case b:o.emit("iframe.credentials",n);break;case H:o.emit("iframe.userinfo",n);break}}));};var ie=new RegExp(`${O}\\/(\\d+\\.\\d+\\.\\d+)\\/(\\d+)\\/(iOS|Android)`),ue=e=>{let n=e.split(".").map(t=>Number.parseInt(t,10));return [n[0]??0,n[1]??0,n[2]??0]},le=(e,n)=>{for(let t=0;t<3;t++){if(e[t]>n[t])return true;if(e[t]<n[t])return false}return true},ae=e=>{let n=e.match(ie);if(!n)return null;let[,t,r,s]=n;if(!t||!r||s!=="iOS"&&s!=="Android")return null;let i=le(ue(t),D[s]);return {type:"native_app",platform:s,appVersion:t,buildNumber:r,meetsMinVersion:i}},w=()=>{if(!u())return {type:"web",meetsMinVersion:false};let e=ae(navigator.userAgent??"");return e||(window.parent!==window?{type:"iframe",meetsMinVersion:false}:{type:"web",meetsMinVersion:false})};var $=(e,n,t)=>new Promise(r=>{let s=false,i=l=>{s||(s=true,p(),clearTimeout(c),r(l));},p=o.on(n,l=>{let T=t(l);T&&i(T);}),c=setTimeout(()=>i(null),B);try{window.parent.postMessage({type:e,timestamp:Date.now()},"*");}catch{i(null);}}),K=()=>$(h,"iframe.credentials",a),z=()=>$(F,"iframe.userinfo",m);var J=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"postMessage")=="function",M=e=>{let n=Reflect.get(window,"webkit");if(typeof n=="object"&&n!==null){let r=Reflect.get(n,"messageHandlers");if(typeof r=="object"&&r!==null){let s=Reflect.get(r,e);if(J(s))return s}}let t=Reflect.get(window,e);return J(t)?t:null},X=(e,n={})=>{let{pollIntervalMs:t=50,timeoutMs:r=1500}=n;return new Promise(s=>{let i=Date.now(),p=()=>{let c=M(e);if(c){s(c);return}if(Date.now()-i>=r){s(null);return}setTimeout(p,t);};p();})};var W=async(e,n,t,r)=>{let s=e.platform==="Android"?await X(A,{pollIntervalMs:V,timeoutMs:j}):M(A);if(!s)return null;let i=N(t);return new Promise(p=>{let c=false,l=E=>{c||(c=true,T(),ne(),clearTimeout(te),p(E));},T=o.on(i,E=>{let I=r(E);I&&l(I);}),ne=o.on(t,E=>{let I=r(E);I&&l(I);}),te=setTimeout(()=>l(null),q);try{s.postMessage({command:n,parameters:JSON.stringify({timestamp:Date.now(),endpoint:i})});}catch{l(null);}})},Y=e=>W(e,x,d,a),Z=e=>W(e,L,R,m);Q();var C=null,S=null,ce=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?Y(e):Promise.resolve(null);case "iframe":return K();case "web":return Promise.resolve(null)}},fe=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?Z(e):Promise.resolve(null);case "iframe":return z();case "web":return Promise.resolve(null)}},ee=e=>{C=e;},pe=()=>S||(S=ce(w()).then(e=>(e&&ee(e),e)).finally(()=>{S=null;}),S);u()&&o.on(d,e=>{let n=a(e);n&&ee(n);});var me=async()=>u()?C?C.token:(await pe())?.token??"":"";var de=async()=>u()?fe(w()):null;export{me as getAuthTokenAsync,de as getUserInfoAsync};
1
+ export{c as getAuthTokenAsync,e as getUserInfoAsync}from'../chunk-AKZVV563.js';import'../chunk-ALNJCFV4.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bty/feed_app-runtime-sdk",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "browser": true,
6
6
  "description": "Runtime SDK for feed-app template: auth / AI capabilities, multi-environment bridge (native App / iframe / web).",
@@ -21,6 +21,10 @@
21
21
  "types": "./dist/react/index.d.ts",
22
22
  "import": "./dist/react/index.js"
23
23
  },
24
+ "./device": {
25
+ "types": "./dist/device/index.d.ts",
26
+ "import": "./dist/device/index.js"
27
+ },
24
28
  "./package.json": "./package.json"
25
29
  },
26
30
  "publishConfig": {
@@ -52,5 +56,9 @@
52
56
  "typescript": "catalog:",
53
57
  "vite": "catalog:",
54
58
  "vitest": "^2.1.8"
59
+ },
60
+ "dependencies": {
61
+ "browser-fs-access": "^0.38.0",
62
+ "eventsource-parser": "^3.1.0"
55
63
  }
56
64
  }
@@ -1,15 +0,0 @@
1
- interface Credentials {
2
- uid: string;
3
- token: string;
4
- }
5
- interface UserInfo {
6
- userId: string | number;
7
- username?: string;
8
- nickname?: string;
9
- avatar?: string | null;
10
- phone?: string | null;
11
- email?: string;
12
- [key: string]: unknown;
13
- }
14
-
15
- export type { Credentials as C, UserInfo as U };