@stacksjs/mobile 0.75.31 → 0.75.33

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/index.d.ts CHANGED
@@ -17,6 +17,16 @@ export declare const secureStorage: SecureStorageApi;
17
17
  export declare const share: ShareApi;
18
18
  export declare const appReview: AppReviewApi;
19
19
  export declare function normalizeDeepLinkURL(value: unknown): string | null;
20
+ /**
21
+ * Deep links, asked of the bridge once there is one.
22
+ *
23
+ * A page mounts before Craft installs its bridge, and a page that follows its
24
+ * links from mount (NativeAppShell does) asked too early: getInitialURL found
25
+ * no bridge and answered null, and the launch link, delivered a moment later
26
+ * marked `initial`, was skipped as already handled. An app opened from a link
27
+ * landed on its home screen. Both calls now wait for the bridge; Craft holds
28
+ * any link that arrives meanwhile until the first subscriber.
29
+ */
20
30
  export declare const deepLinks: DeepLinksApi;
21
31
  export declare const keepAwake: KeepAwakeApi;
22
32
  export declare const network: NetworkApi;
@@ -48,6 +58,15 @@ export declare function hasNativeMobileHost(): boolean;
48
58
  * decide something to render anything.
49
59
  */
50
60
  export declare function whenNativeMobile(timeoutMs?: number): Promise<boolean>;
61
+ /**
62
+ * Resolves once the bridge object (`window.craft`) is installed: `true` then,
63
+ * `false` in a browser at once, or after `timeoutMs` in a host that never
64
+ * installs it.
65
+ *
66
+ * Not whenNativeMobile(), which answers `true` as soon as the phone shell is
67
+ * recognisable, before the bridge exists and before anything can be asked of it.
68
+ */
69
+ export declare function whenBridgeReady(timeoutMs?: unknown): Promise<boolean>;
51
70
  export declare function onMobileReady(callback: (event: CraftReadyEvent) => void): () => void;
52
71
  export declare function withNativeFeedback<T>(action: () => T | Promise<T>): Promise<T>;
53
72
  export declare const mobile: MobileApi;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{appReview as O,biometrics as U,camera as _,deepLinks as M,device as B,haptics as I,health as Y,keepAwake as K,lifecycle as j,liveActivities as q,location as G,network as W,notifications as z,permissions as J,pushNotifications as Q,secureStorage as V,share as X,watchConnectivity as Z}from"craft-native/mobile";import{haptics as E}from"craft-native/mobile";function w(){if(typeof window>"u")return;return window}function v(e=w()){if(!e)return 0;if(typeof e.scrollY==="number")return e.scrollY;return e.document?.scrollingElement?.scrollTop??0}function Ae(e,t=w()){if(!t)return()=>{};let r=!1,n=typeof requestAnimationFrame==="function"?requestAnimationFrame:(o)=>setTimeout(o,16),i=()=>{if(r)return;r=!0,n(()=>{r=!1,e(v(t))})};return e(v(t)),t.addEventListener("scroll",i,{passive:!0}),()=>t.removeEventListener("scroll",i)}function H(e,t){let r=Math.max(0,-e),n=e<=0?Math.max(0,t)*0.5:0;return Math.round(Math.max(r,n))}function Re(e){let t=e.host??w();if(!t)return()=>{};let r=e.threshold??72,n=null,i=!1,o=!1,s=(a)=>e.onPull?.(a,i),d=(a)=>{let f=a.touches?.[0];return f?f.clientY:null},u=(a)=>{if(o||v(t)>0)return;n=d(a),i=!1},l=(a)=>{if(n===null)return;let f=d(a);if(f===null)return;let p=H(v(t),f-n);if(!i&&p>=r)i=!0,Promise.resolve(E.impact("medium")).catch(()=>{});else if(i&&p<r*0.8)i=!1;s(p)},m=async()=>{if(n===null)return;if(n=null,!i){s(0);return}i=!1,o=!0,e.onPull?.(r,!1);try{await e.onRefresh()}finally{o=!1,s(0)}},c=()=>{if(n===null)return;n=null,i=!1,s(0)};return t.addEventListener("touchstart",u,{passive:!0}),t.addEventListener("touchmove",l,{passive:!0}),t.addEventListener("touchend",m),t.addEventListener("touchcancel",c),()=>{t.removeEventListener("touchstart",u),t.removeEventListener("touchmove",l),t.removeEventListener("touchend",m),t.removeEventListener("touchcancel",c)}}function R(){if(typeof window>"u")return;return window}function T(e=R()){let t=e?.history?.state;return t!==null&&t!==void 0}function Le(e=R()){if(!T(e))return!1;return e.history.back(),!0}function C(e,t=N()){let r;try{r=new URL(e)}catch{return null}let n=`${r.search}${r.hash}`;if(r.protocol==="http:"||r.protocol==="https:"){if(!t||r.origin!==t)return null;return`${r.pathname||"/"}${n}`}return`${`/${[r.host,r.pathname.replace(/^\/+/,"")].filter(Boolean).join("/")}`}${n}`}function N(){if(typeof window>"u")return;return window.location?.origin}var A="stacks-mobile-deep-link";function Me(e,t){let r=(n)=>{let i=C(n);if(i)e(i)};return t.getInitialURL().then((n)=>{if(!n)return;try{if(sessionStorage.getItem(A)===n)return;sessionStorage.setItem(A,n)}catch{}r(n)}).catch(()=>{}),t.onLink((n,i)=>{if(i?.initial)return;r(n)})}var Pe=30;function F(e,t){let r=Math.PI/180,n=(t.latitude-e.latitude)*r,i=(t.longitude-e.longitude)*r,o=Math.sin(n/2)**2+Math.cos(e.latitude*r)*Math.cos(t.latitude*r)*Math.sin(i/2)**2;return 12742017.6*Math.asin(Math.min(1,Math.sqrt(o)))}function D(e,t=25){let r=new Set;return e.filter((n)=>Number.isFinite(n.latitude)&&Number.isFinite(n.longitude)&&Number.isFinite(n.timestamp)&&n.accuracy>=0&&n.accuracy<=t).sort((n,i)=>n.timestamp-i.timestamp).filter((n)=>{if(r.has(n.timestamp))return!1;return r.add(n.timestamp),!0})}function S(e,t={}){let r=D(e,t.maxAccuracyM??25),n=t.paceWindowS??30,i=[],o=0,s=0,d=null;for(let c of r){let a=i[i.length-1],f=d?(c.timestamp-d.timestamp)/1000:0;if(d=c,!a){i.push({fix:c,cumM:0});continue}if(f>30){i.push({fix:c,cumM:o});continue}let p=(c.timestamp-a.fix.timestamp)/1000,h=F(a.fix,c),P=Math.min(10,Math.max(3,a.fix.accuracy,c.accuracy));if(h<P)continue;if(o+=h,p>0&&h/p>=0.5)s+=p;i.push({fix:c,cumM:o})}let u=i[i.length-1],l=null,m=null;if(u){let c=u.fix.timestamp-n*1000,a=i.find((h)=>h.fix.timestamp>=c)??u,f=u.cumM-a.cumM,p=(u.fix.timestamp-a.fix.timestamp)/1000;if(f>=20&&p>0)m=f/p,l=p/(f/1000)}return{distanceM:o,movingS:s,paceSPerKm:l,averagePaceSPerKm:o>=50&&s>0?s/(o/1000):null,speedMps:m,accuracyM:r.length?r[r.length-1].accuracy:e.length?e[e.length-1].accuracy??null:null,fixes:r.length}}function Ee(e){if(!e||!Number.isFinite(e)||e>3600)return"–";let t=Math.round(e);return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function He(e){return e&&Number.isFinite(e)?(e*3.6).toFixed(1):"–"}var L={distanceM:0,movingS:0,paceSPerKm:null,averagePaceSPerKm:null,speedMps:null,accuracyM:null,fixes:0};function Te(e){let t=e.location,r=e.intervalMs??3000,n=L,i=null,o=()=>typeof document<"u"&&document.visibilityState==="hidden";async function s(){let l=await t.readRecording();return n=S(l,e),e.onUpdate?.(n),n}function d(){u(),i=setInterval(()=>{if(!o())s().catch(()=>{})},r)}function u(){if(i)clearInterval(i);i=null}return{get stats(){return n},async start(){return await t.startRecording({enableHighAccuracy:!0,...e.locationOptions}),n=L,e.onUpdate?.(n),d(),n},async attach(){let l=await t.getRecordingState().catch(()=>null);if(!l?.active)return null;if(await s().catch(()=>{}),!l.paused)d();return l},async pause(){u(),await t.pauseRecording(),await s().catch(()=>{})},async resume(){await t.resumeRecording(),d()},async stop(){u();let m=(await t.stopRecording())?.locations??[];return n=S(m,e),e.onUpdate?.(n),m},refresh:s}}var ee=U,te=_,ne=B,y=I,re=j,ie=G,oe=z,ae=J,se=V,ce=X,ue=O;function k(e){if(typeof e==="string")return e.trim()||null;if(!e||typeof e!=="object")return null;let t=e.url;return typeof t==="string"&&t.trim()?t:null}var le={async getInitialURL(){return k(await M.getInitialURL?.())},onLink(e){return M.onLink?.((t,r)=>{let n=k(t);if(n)e(n,{initial:r?.initial===!0})})??(()=>{})}},fe=K,pe=W,de=Q,me=Y,he=q,ve=Z;function x(){if(typeof window>"u")return;return window}function b(){let e=x()?.craft;if(!e||typeof e!=="object")return null;if(!("platform"in e)||e.platform!=="ios"&&e.platform!=="android")return null;let t="capabilities"in e?e.capabilities:void 0,r=t&&typeof t==="object"&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).filter(([,n])=>typeof n==="boolean")):{};return{platform:e.platform,capabilities:r}}function g(){return b()!==null}function ye(){if(typeof window>"u")return!1;let e=window;if(e.CraftAndroid)return!0;let t=typeof navigator>"u"?"":navigator.userAgent;return Boolean(e.webkit?.messageHandlers?.craft)&&/iPhone|iPad|iPod/.test(t)}function be(e=2000){if(g()||ye())return Promise.resolve(!0);let t=x(),r=t;if(!t||!(r?.craft||r?.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((n)=>{let i=()=>{clearTimeout(o),t.removeEventListener("craftReady",i),n(g())},o=setTimeout(i,e);t.addEventListener("craftReady",i,{once:!0})})}function we(e){let t=x();if(!t)return()=>{};if(b()){let n=!1;return queueMicrotask(()=>{if(!n)e(new Event("craftReady"))}),()=>{n=!0}}let r=(n)=>{if(!b())return;t.removeEventListener("craftReady",r),e(n)};return t.addEventListener("craftReady",r),()=>t.removeEventListener("craftReady",r)}async function ge(e){await y.impact("light");try{let t=await e();return await y.notification("success"),t}catch(t){throw await y.notification("error"),t}}var Fe={get nativeBridge(){return b()},biometrics:ee,camera:te,device:ne,haptics:y,lifecycle:re,location:ie,notifications:oe,permissions:ae,secureStorage:se,share:ce,appReview:ue,deepLinks:le,keepAwake:fe,network:pe,pushNotifications:de,health:me,liveActivities:he,watchConnectivity:ve,isNativeMobile:g,whenNative:be,onReady:we,withFeedback:ge};export{Pe as ROUTE_GAP_S,ue as appReview,ee as biometrics,te as camera,T as canGoBack,Te as createRouteRecorder,C as deepLinkPath,le as deepLinks,ne as device,F as fixDistance,Me as followDeepLinks,b as getNativeMobileBridge,Le as goBack,y as haptics,ye as hasNativeMobileHost,me as health,g as isNativeMobile,fe as keepAwake,re as lifecycle,he as liveActivities,ie as location,Fe as mobile,pe as network,k as normalizeDeepLinkURL,oe as notifications,Ae as observePageScroll,Re as observePullToRefresh,we as onMobileReady,Ee as paceLabel,v as pageScrollTop,ae as permissions,H as pullDistance,de as pushNotifications,S as routeStats,se as secureStorage,ce as share,He as speedLabel,D as usableFixes,ve as watchConnectivity,be as whenNativeMobile,ge as withNativeFeedback};
1
+ import{appReview as B,biometrics as _,camera as I,deepLinks as k,device as Y,haptics as K,health as j,keepAwake as q,lifecycle as G,liveActivities as W,location as z,network as J,notifications as Q,permissions as V,pushNotifications as X,secureStorage as Z,share as ee,watchConnectivity as te}from"craft-native/mobile";import{haptics as T}from"craft-native/mobile";function g(){if(typeof window>"u")return;return window}function y(e=g()){if(!e)return 0;if(typeof e.scrollY==="number")return e.scrollY;return e.document?.scrollingElement?.scrollTop??0}function Re(e,t=g()){if(!t)return()=>{};let r=!1,n=typeof requestAnimationFrame==="function"?requestAnimationFrame:(i)=>setTimeout(i,16),o=()=>{if(r)return;r=!0,n(()=>{r=!1,e(y(t))})};return e(y(t)),t.addEventListener("scroll",o,{passive:!0}),()=>t.removeEventListener("scroll",o)}function C(e,t){let r=Math.max(0,-e),n=e<=0?Math.max(0,t)*0.5:0;return Math.round(Math.max(r,n))}function Se(e){let t=e.host??g();if(!t)return()=>{};let r=e.threshold??72,n=null,o=!1,i=!1,a=(s)=>e.onPull?.(s,o),d=(s)=>{let f=s.touches?.[0];return f?f.clientY:null},u=(s)=>{if(i||y(t)>0)return;n=d(s),o=!1},l=(s)=>{if(n===null)return;let f=d(s);if(f===null)return;let p=C(y(t),f-n);if(!o&&p>=r)o=!0,Promise.resolve(T.impact("medium")).catch(()=>{});else if(o&&p<r*0.8)o=!1;a(p)},m=async()=>{if(n===null)return;if(n=null,!o){a(0);return}o=!1,i=!0,e.onPull?.(r,!1);try{await e.onRefresh()}finally{i=!1,a(0)}},c=()=>{if(n===null)return;n=null,o=!1,a(0)};return t.addEventListener("touchstart",u,{passive:!0}),t.addEventListener("touchmove",l,{passive:!0}),t.addEventListener("touchend",m),t.addEventListener("touchcancel",c),()=>{t.removeEventListener("touchstart",u),t.removeEventListener("touchmove",l),t.removeEventListener("touchend",m),t.removeEventListener("touchcancel",c)}}function R(){if(typeof window>"u")return;return window}function N(e=R()){let t=e?.history?.state;return t!==null&&t!==void 0}function ke(e=R()){if(!N(e))return!1;return e.history.back(),!0}function F(e,t=D()){let r;try{r=new URL(e)}catch{return null}let n=`${r.search}${r.hash}`;if(r.protocol==="http:"||r.protocol==="https:"){if(!t||r.origin!==t)return null;return`${r.pathname||"/"}${n}`}return`${`/${[r.host,r.pathname.replace(/^\/+/,"")].filter(Boolean).join("/")}`}${n}`}function D(){if(typeof window>"u")return;return window.location?.origin}var A="stacks-mobile-deep-link";function Me(e,t){let r=(n)=>{let o=F(n);if(o)e(o)};return t.getInitialURL().then((n)=>{if(!n)return;try{if(sessionStorage.getItem(A)===n)return;sessionStorage.setItem(A,n)}catch{}r(n)}).catch(()=>{}),t.onLink((n,o)=>{if(o?.initial)return;r(n)})}var Ee=30;function O(e,t){let r=Math.PI/180,n=(t.latitude-e.latitude)*r,o=(t.longitude-e.longitude)*r,i=Math.sin(n/2)**2+Math.cos(e.latitude*r)*Math.cos(t.latitude*r)*Math.sin(o/2)**2;return 12742017.6*Math.asin(Math.min(1,Math.sqrt(i)))}function U(e,t=25){let r=new Set;return e.filter((n)=>Number.isFinite(n.latitude)&&Number.isFinite(n.longitude)&&Number.isFinite(n.timestamp)&&n.accuracy>=0&&n.accuracy<=t).sort((n,o)=>n.timestamp-o.timestamp).filter((n)=>{if(r.has(n.timestamp))return!1;return r.add(n.timestamp),!0})}function S(e,t={}){let r=U(e,t.maxAccuracyM??25),n=t.paceWindowS??30,o=[],i=0,a=0,d=null;for(let c of r){let s=o[o.length-1],f=d?(c.timestamp-d.timestamp)/1000:0;if(d=c,!s){o.push({fix:c,cumM:0});continue}if(f>30){o.push({fix:c,cumM:i});continue}let p=(c.timestamp-s.fix.timestamp)/1000,v=O(s.fix,c),H=Math.min(10,Math.max(3,s.fix.accuracy,c.accuracy));if(v<H)continue;if(i+=v,p>0&&v/p>=0.5)a+=p;o.push({fix:c,cumM:i})}let u=o[o.length-1],l=null,m=null;if(u){let c=u.fix.timestamp-n*1000,s=o.find((v)=>v.fix.timestamp>=c)??u,f=u.cumM-s.cumM,p=(u.fix.timestamp-s.fix.timestamp)/1000;if(f>=20&&p>0)m=f/p,l=p/(f/1000)}return{distanceM:i,movingS:a,paceSPerKm:l,averagePaceSPerKm:i>=50&&a>0?a/(i/1000):null,speedMps:m,accuracyM:r.length?r[r.length-1].accuracy:e.length?e[e.length-1].accuracy??null:null,fixes:r.length}}function He(e){if(!e||!Number.isFinite(e)||e>3600)return"–";let t=Math.round(e);return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function Te(e){return e&&Number.isFinite(e)?(e*3.6).toFixed(1):"–"}var L={distanceM:0,movingS:0,paceSPerKm:null,averagePaceSPerKm:null,speedMps:null,accuracyM:null,fixes:0};function Ce(e){let t=e.location,r=e.intervalMs??3000,n=L,o=null,i=()=>typeof document<"u"&&document.visibilityState==="hidden";async function a(){let l=await t.readRecording();return n=S(l,e),e.onUpdate?.(n),n}function d(){u(),o=setInterval(()=>{if(!i())a().catch(()=>{})},r)}function u(){if(o)clearInterval(o);o=null}return{get stats(){return n},async start(){return await t.startRecording({enableHighAccuracy:!0,...e.locationOptions}),n=L,e.onUpdate?.(n),d(),n},async attach(){let l=await t.getRecordingState().catch(()=>null);if(!l?.active)return null;if(await a().catch(()=>{}),!l.paused)d();return l},async pause(){u(),await t.pauseRecording(),await a().catch(()=>{})},async resume(){await t.resumeRecording(),d()},async stop(){u();let m=(await t.stopRecording())?.locations??[];return n=S(m,e),e.onUpdate?.(n),m},refresh:a}}var ne=_,re=I,oe=Y,b=K,ie=G,ae=z,se=Q,ce=V,ue=Z,le=ee,fe=B;function M(e){if(typeof e==="string")return e.trim()||null;if(!e||typeof e!=="object")return null;let t=e.url;return typeof t==="string"&&t.trim()?t:null}var pe={async getInitialURL(){if(!await P())return null;return M(await k.getInitialURL?.())},onLink(e){let t=null,r=!1,n=()=>{if(r)return;t=k.onLink?.((o,i)=>{let a=M(o);if(a)e(a,{initial:i?.initial===!0})})??null};if(h()?.craft)n();else P().then(n);return()=>{r=!0,t?.()}}},de=q,me=J,ve=X,he=j,ye=W,be=te;function h(){if(typeof window>"u")return;return window}function w(){let e=h()?.craft;if(!e||typeof e!=="object")return null;if(!("platform"in e)||e.platform!=="ios"&&e.platform!=="android")return null;let t="capabilities"in e?e.capabilities:void 0,r=t&&typeof t==="object"&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).filter(([,n])=>typeof n==="boolean")):{};return{platform:e.platform,capabilities:r}}function x(){return w()!==null}function E(){if(typeof window>"u")return!1;let e=window;if(e.CraftAndroid)return!0;let t=typeof navigator>"u"?"":navigator.userAgent;return Boolean(e.webkit?.messageHandlers?.craft)&&/iPhone|iPad|iPod/.test(t)}function we(e=2000){if(x()||E())return Promise.resolve(!0);let t=h(),r=t;if(!t||!(r?.craft||r?.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((n)=>{let o=()=>{clearTimeout(i),t.removeEventListener("craftReady",o),n(x())},i=setTimeout(o,e);t.addEventListener("craftReady",o,{once:!0})})}function P(e=15000){let t=h();if(t?.craft)return Promise.resolve(!0);let r=t;if(!t||!(E()||r?.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((n)=>{let o=()=>{clearTimeout(i),t.removeEventListener("craftReady",o),n(Boolean(t.craft))},i=setTimeout(o,e);t.addEventListener("craftReady",o)})}function ge(e){let t=h();if(!t)return()=>{};if(w()){let n=!1;return queueMicrotask(()=>{if(!n)e(new Event("craftReady"))}),()=>{n=!0}}let r=(n)=>{if(!w())return;t.removeEventListener("craftReady",r),e(n)};return t.addEventListener("craftReady",r),()=>t.removeEventListener("craftReady",r)}async function xe(e){await b.impact("light");try{let t=await e();return await b.notification("success"),t}catch(t){throw await b.notification("error"),t}}var De={get nativeBridge(){return w()},biometrics:ne,camera:re,device:oe,haptics:b,lifecycle:ie,location:ae,notifications:se,permissions:ce,secureStorage:ue,share:le,appReview:fe,deepLinks:pe,keepAwake:de,network:me,pushNotifications:ve,health:he,liveActivities:ye,watchConnectivity:be,isNativeMobile:x,whenNative:we,onReady:ge,withFeedback:xe};export{Ee as ROUTE_GAP_S,fe as appReview,ne as biometrics,re as camera,N as canGoBack,Ce as createRouteRecorder,F as deepLinkPath,pe as deepLinks,oe as device,O as fixDistance,Me as followDeepLinks,w as getNativeMobileBridge,ke as goBack,b as haptics,E as hasNativeMobileHost,he as health,x as isNativeMobile,de as keepAwake,ie as lifecycle,ye as liveActivities,ae as location,De as mobile,me as network,M as normalizeDeepLinkURL,se as notifications,Re as observePageScroll,Se as observePullToRefresh,ge as onMobileReady,He as paceLabel,y as pageScrollTop,ce as permissions,C as pullDistance,ve as pushNotifications,S as routeStats,ue as secureStorage,le as share,Te as speedLabel,U as usableFixes,be as watchConnectivity,P as whenBridgeReady,we as whenNativeMobile,xe as withNativeFeedback};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/mobile",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.31",
5
+ "version": "0.75.33",
6
6
  "description": "Craft-powered native mobile runtime for Stacks and STX applications",
7
7
  "author": "Chris Breuer",
8
8
  "license": "MIT",
@@ -35,7 +35,7 @@
35
35
  "craft-native": ">=0.0.103"
36
36
  },
37
37
  "devDependencies": {
38
- "@stacksjs/build": "0.75.31",
38
+ "@stacksjs/build": "0.75.33",
39
39
  "better-dx": "^0.2.24"
40
40
  }
41
41
  }