@stacksjs/mobile 0.75.71 → 0.75.73

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
@@ -122,6 +122,24 @@ declare function canGoBack(host?: HistoryHost | undefined): boolean;
122
122
  * it did. When it answers `false` the caller follows its own link.
123
123
  */
124
124
  declare function goBack(host?: HistoryHost | undefined): boolean;
125
+ /**
126
+ * Records arriving at `path` on the trail of screens, and answers this
127
+ * screen's entry and the one a back button returns to.
128
+ *
129
+ * Arriving at the screen just before the current one is going back, so the
130
+ * current one is dropped; arriving at the current one again (a reload, a
131
+ * re-render) changes nothing; anything else is a push. The trail is capped,
132
+ * oldest first.
133
+ */
134
+ declare function enterNavTrail(trail: NavTrailEntry[], path: string, limit?: number): { current: NavTrailEntry, previous: NavTrailEntry | null };
135
+ /**
136
+ * What a back button says: the name of the screen it returns to, as iOS
137
+ * does, when that is short enough to sit beside the title; otherwise the
138
+ * button's own word ("Back", "Workout").
139
+ */
140
+ declare function backLabelFor(previous: NavTrailEntry | null, fallback: string, max?: number): string;
141
+ /** The trail for this window: it outlives each screen, not a full reload. */
142
+ declare function navTrail(): NavTrailEntry[];
125
143
  /**
126
144
  * The in-app path a deep link opens, or null when it is not this app's.
127
145
  *
@@ -143,6 +161,11 @@ declare function followDeepLinks(go: (path: string) => void, links: DeepLinksApi
143
161
  declare interface HistoryHost {
144
162
  history?: { state: unknown, back: () => void }
145
163
  }
164
+ /** A screen the app has shown, by the path it was at and the name it showed. */
165
+ declare interface NavTrailEntry {
166
+ path: string
167
+ title: string
168
+ }
146
169
 
147
170
  // From: src/route.ts
148
171
  /** Great-circle distance between two fixes, metres. */
@@ -766,4 +789,4 @@ type HealthWorkoutActivity = | 'running' | 'cycling' | 'walking' | 'hiking' | 's
766
789
  | 'stairClimbing' | 'yoga' | 'pilates' | 'strength' | 'hiit' | 'crossTraining'
767
790
  | 'crossCountrySkiing' | 'skiing' | 'paddling' | 'climbing' | 'dance' | 'mobility' | 'other';
768
791
 
769
- export { normalizeDeepLinkURL, getNativeMobileBridge, isNativeMobile, hasNativeMobileHost, whenNativeMobile, whenBridgeReady, onMobileReady, withNativeFeedback, biometrics, camera, device, haptics, lifecycle, location, notifications, permissions, secureStorage, share, appReview, deepLinks, keepAwake, network, pushNotifications, health, liveActivities, watchConnectivity, mobile, pageScrollTop, observePageScroll, pullDistance, observePullToRefresh, ScrollHost, PullToRefreshOptions, canGoBack, goBack, deepLinkPath, followDeepLinks, HistoryHost, fixDistance, usableFixes, routeStats, paceLabel, speedLabel, createRouteRecorder, ROUTE_GAP_S, RouteFix, RouteStats, RouteStatsOptions, RouteRecorderOptions, RouteRecorder, readSpotlightKinds, spotlightKind, spotlightAction, spotlightSlot, spotlightActions, spotlightActivityTypes, spotlightTitle, placeSpotlightItem, removeSpotlightItem, spotlightRoute, readSpotlightEntries, spotlightBridge, createSpotlightIndex, onSpotlightTap, MAX_SPOTLIGHT_SLOTS_PER_KIND, SpotlightKind, SpotlightKindInput, SpotlightItem, SpotlightEntry, SpotlightKindsResult, SpotlightPlacement, SpotlightBridge, SpotlightIndexOptions, SpotlightIndex, CraftMobileCapabilities, CraftMobileBridge, CraftReadyEvent, MobileApi, DeviceInfo, DeviceCapabilities, CameraOptions, PhotoResult, Location, LocationOptions, LocationRecordingState, LocationRecordingResult, ShareOptions, NotificationOptions, DeviceApi, HapticsApi, PermissionsApi, CameraApi, BiometricsApi, SecureStorageApi, LocationApi, ShareApi, LifecycleApi, NotificationsApi, KeepAwakeApi, DeepLinksApi, NetworkStatus, NetworkApi, AppReviewApi, PushNotificationsApi, HealthDataOptions, HealthDataResult, HealthWorkoutLocation, HealthWorkout, HealthWorkoutResult, HealthWorkoutQuery, HealthWorkoutSample, HealthDailyValue, HealthAuthorizationOptions, HealthApi, LiveActivityState, LiveActivityOptions, LiveActivitiesApi, WatchConnectivityApi, HapticStyle, HapticNotificationType, PermissionType, PermissionStatus, BiometricType, AppState, HealthDataType, HealthDailyType, HealthWorkoutType, HealthWorkoutActivity };
792
+ export { normalizeDeepLinkURL, getNativeMobileBridge, isNativeMobile, hasNativeMobileHost, whenNativeMobile, whenBridgeReady, onMobileReady, withNativeFeedback, biometrics, camera, device, haptics, lifecycle, location, notifications, permissions, secureStorage, share, appReview, deepLinks, keepAwake, network, pushNotifications, health, liveActivities, watchConnectivity, mobile, pageScrollTop, observePageScroll, pullDistance, observePullToRefresh, ScrollHost, PullToRefreshOptions, canGoBack, goBack, enterNavTrail, backLabelFor, navTrail, deepLinkPath, followDeepLinks, HistoryHost, NavTrailEntry, fixDistance, usableFixes, routeStats, paceLabel, speedLabel, createRouteRecorder, ROUTE_GAP_S, RouteFix, RouteStats, RouteStatsOptions, RouteRecorderOptions, RouteRecorder, readSpotlightKinds, spotlightKind, spotlightAction, spotlightSlot, spotlightActions, spotlightActivityTypes, spotlightTitle, placeSpotlightItem, removeSpotlightItem, spotlightRoute, readSpotlightEntries, spotlightBridge, createSpotlightIndex, onSpotlightTap, MAX_SPOTLIGHT_SLOTS_PER_KIND, SpotlightKind, SpotlightKindInput, SpotlightItem, SpotlightEntry, SpotlightKindsResult, SpotlightPlacement, SpotlightBridge, SpotlightIndexOptions, SpotlightIndex, CraftMobileCapabilities, CraftMobileBridge, CraftReadyEvent, MobileApi, DeviceInfo, DeviceCapabilities, CameraOptions, PhotoResult, Location, LocationOptions, LocationRecordingState, LocationRecordingResult, ShareOptions, NotificationOptions, DeviceApi, HapticsApi, PermissionsApi, CameraApi, BiometricsApi, SecureStorageApi, LocationApi, ShareApi, LifecycleApi, NotificationsApi, KeepAwakeApi, DeepLinksApi, NetworkStatus, NetworkApi, AppReviewApi, PushNotificationsApi, HealthDataOptions, HealthDataResult, HealthWorkoutLocation, HealthWorkout, HealthWorkoutResult, HealthWorkoutQuery, HealthWorkoutSample, HealthDailyValue, HealthAuthorizationOptions, HealthApi, LiveActivityState, LiveActivityOptions, LiveActivitiesApi, WatchConnectivityApi, HapticStyle, HapticNotificationType, PermissionType, PermissionStatus, BiometricType, AppState, HealthDataType, HealthDailyType, HealthWorkoutType, HealthWorkoutActivity };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{appReview as mt,biometrics as gt,camera as ht,deepLinks as U,device as yt,haptics as St,health as vt,keepAwake as bt,lifecycle as At,liveActivities as xt,location as wt,network as Rt,notifications as Tt,permissions as Et,pushNotifications as kt,secureStorage as Lt,share as Pt,watchConnectivity as Mt}from"craft-native/mobile";import{haptics as z}from"craft-native/mobile";function M(){if(typeof window>"u")return;return window}function k(t=M()){if(!t)return 0;if(typeof t.scrollY==="number")return t.scrollY;return t.document?.scrollingElement?.scrollTop??0}function Qt(t,n=M()){if(!n)return()=>{};let r=!1,e=typeof requestAnimationFrame==="function"?requestAnimationFrame:(i)=>setTimeout(i,16),o=()=>{if(r)return;r=!0,e(()=>{r=!1,t(k(n))})};return t(k(n)),n.addEventListener("scroll",o,{passive:!0}),()=>n.removeEventListener("scroll",o)}function J(t,n){let r=Math.max(0,-t),e=t<=0?Math.max(0,n)*0.5:0;return Math.round(Math.max(r,e))}function Zt(t){let n=t.host??M();if(!n)return()=>{};let r=t.threshold??72,e=null,o=!1,i=!1,s=typeof requestAnimationFrame==="function"?requestAnimationFrame:(g)=>setTimeout(g,16),l=null,a=(g)=>{l=null,t.onPull?.(g,o)},u=(g)=>{let b=l!==null;if(l=g,b)return;s(()=>{if(l!==null)a(l)})},h=(g)=>{let b=g.touches?.[0];return b?b.clientY:null},d=(g)=>{if(i||k(n)>0)return;e=h(g),o=!1},p=(g)=>{if(e===null)return;let b=h(g);if(b===null)return;let x=J(k(n),b-e);if(!o&&x>=r)o=!0,Promise.resolve(z.impact("medium")).catch(()=>{});else if(o&&x<r*0.8)o=!1;u(x)},v=async()=>{if(e===null)return;if(e=null,!o){a(0);return}o=!1,i=!0,a(r);try{await t.onRefresh()}finally{i=!1,a(0)}},m=()=>{if(e===null)return;e=null,o=!1,a(0)};return n.addEventListener("touchstart",d,{passive:!0}),n.addEventListener("touchmove",p,{passive:!0}),n.addEventListener("touchend",v),n.addEventListener("touchcancel",m),()=>{l=null,n.removeEventListener("touchstart",d),n.removeEventListener("touchmove",p),n.removeEventListener("touchend",v),n.removeEventListener("touchcancel",m)}}function O(){if(typeof window>"u")return;return window}function V(t=O()){let n=t?.history?.state;return n!==null&&n!==void 0}function ee(t=O()){if(!V(t))return!1;return t.history.back(),!0}function Q(t,n=Z()){let r;try{r=new URL(t)}catch{return null}let e=`${r.search}${r.hash}`;if(r.protocol==="http:"||r.protocol==="https:"){if(!n||r.origin!==n)return null;return`${r.pathname||"/"}${e}`}return`${`/${[r.host,r.pathname.replace(/^\/+/,"")].filter(Boolean).join("/")}`}${e}`}function Z(){if(typeof window>"u")return;return window.location?.origin}var _="stacks-mobile-deep-link";function ne(t,n){let r=(e)=>{let o=Q(e);if(o)t(o)};return n.getInitialURL().then((e)=>{if(!e)return;try{if(sessionStorage.getItem(_)===e)return;sessionStorage.setItem(_,e)}catch{}r(e)}).catch(()=>{}),n.onLink((e,o)=>{if(o?.initial)return;r(e)})}var oe=30;function tt(t,n){let r=Math.PI/180,e=(n.latitude-t.latitude)*r,o=(n.longitude-t.longitude)*r,i=Math.sin(e/2)**2+Math.cos(t.latitude*r)*Math.cos(n.latitude*r)*Math.sin(o/2)**2;return 12742017.6*Math.asin(Math.min(1,Math.sqrt(i)))}function et(t,n=25){let r=new Set;return t.filter((e)=>Number.isFinite(e.latitude)&&Number.isFinite(e.longitude)&&Number.isFinite(e.timestamp)&&e.accuracy>=0&&e.accuracy<=n).sort((e,o)=>e.timestamp-o.timestamp).filter((e)=>{if(r.has(e.timestamp))return!1;return r.add(e.timestamp),!0})}function H(t,n={}){let r=et(t,n.maxAccuracyM??25),e=n.paceWindowS??30,o=[],i=0,s=0,l=null;for(let d of r){let p=o[o.length-1],v=l?(d.timestamp-l.timestamp)/1000:0;if(l=d,!p){o.push({fix:d,cumM:0});continue}if(v>30){o.push({fix:d,cumM:i});continue}let m=(d.timestamp-p.fix.timestamp)/1000,g=tt(p.fix,d),b=Math.min(10,Math.max(3,p.fix.accuracy,d.accuracy));if(g<b)continue;if(i+=g,m>0&&g/m>=0.5)s+=m;o.push({fix:d,cumM:i})}let a=o[o.length-1],u=null,h=null;if(a){let d=a.fix.timestamp-e*1000,p=o.find((g)=>g.fix.timestamp>=d)??a,v=a.cumM-p.cumM,m=(a.fix.timestamp-p.fix.timestamp)/1000;if(v>=20&&m>0)h=v/m,u=m/(v/1000)}return{distanceM:i,movingS:s,paceSPerKm:u,averagePaceSPerKm:i>=50&&s>0?s/(i/1000):null,speedMps:h,accuracyM:r.length?r[r.length-1].accuracy:t.length?t[t.length-1].accuracy??null:null,fixes:r.length}}function ie(t){if(!t||!Number.isFinite(t)||t>3600)return"–";let n=Math.round(t);return`${Math.floor(n/60)}:${String(n%60).padStart(2,"0")}`}function se(t){return t&&Number.isFinite(t)?(t*3.6).toFixed(1):"–"}var K={distanceM:0,movingS:0,paceSPerKm:null,averagePaceSPerKm:null,speedMps:null,accuracyM:null,fixes:0};function ae(t){let n=t.location,r=t.intervalMs??3000,e=K,o=null,i=()=>typeof document<"u"&&document.visibilityState==="hidden";async function s(){let u=await n.readRecording();return e=H(u,t),t.onUpdate?.(e),e}function l(){a(),o=setInterval(()=>{if(!i())s().catch(()=>{})},r)}function a(){if(o)clearInterval(o);o=null}return{get stats(){return e},async start(){return await n.startRecording({enableHighAccuracy:!0,...t.locationOptions}),e=K,t.onUpdate?.(e),l(),e},async attach(){let u=await n.getRecordingState().catch(()=>null);if(!u?.active)return null;if(await s().catch(()=>{}),!u.paused)l();return u},async pause(){a(),await n.pauseRecording(),await s().catch(()=>{})},async resume(){await n.resumeRecording(),l()},async stop(){a();let h=(await n.stopRecording())?.locations??[];return e=H(h,t),t.onUpdate?.(e),h},refresh:s}}var ce=64;var nt=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/,rt=/^(?:0|[1-9]\d*)$/;function F(t){let n=[],r=[],e=t&&typeof t==="object"&&!Array.isArray(t)?t:{};for(let[o,i]of Object.entries(e)){let s=i&&typeof i==="object"?i:null;if(!s){r.push(`spotlight kind "${o}" is not an object`);continue}let{slots:l,route:a}=s,u=typeof s.noun==="string"&&s.noun.trim()?s.noun.trim():"Item";if(!nt.test(o)||o.includes("-slot-")){r.push(`spotlight kind "${o}" is not a usable name: lowercase letters, digits and single dashes, and never "-slot-"`);continue}if(typeof l!=="number"||!Number.isInteger(l)||l<=0||l>64){r.push(`spotlight kind "${o}" needs slots between 1 and 64, not ${String(l)}`);continue}if(typeof a!=="string"||!a.startsWith("/")||!a.includes(":id")){r.push(`spotlight kind "${o}" needs a route starting with "/" and carrying ":id", not ${String(a)}`);continue}n.push({name:o,slots:l,route:a,noun:u})}return{kinds:n,problems:r}}function T(t,n){return t.find((r)=>r.name===n)??null}function R(t,n,r){let e=T(t,n);if(!e||!Number.isInteger(r)||r<0||r>=e.slots)return null;return`${n}-slot-${r}`}function ot(t,n){if(typeof n!=="string")return null;let r=n.lastIndexOf("-slot-");if(r<=0)return null;let e=n.slice(0,r),o=n.slice(r+6);if(!rt.test(o))return null;let i=Number(o);return R(t,e,i)===n?{kind:e,slot:i}:null}function C(t){return t.flatMap((n)=>Array.from({length:n.slots},(r,e)=>`${n.name}-slot-${e}`))}function ue(t,n){let r=t&&typeof t==="object"?t:{};if(r.enabled===!1)return[];let o=[...(Array.isArray(r.activityTypes)?r.activityTypes.filter((i)=>typeof i==="string"&&i.trim().length>0):[]).map((i)=>i.trim()),...C(F(r.kinds).kinds)];return[...new Set(o)].map((i)=>`${n}.${i}`)}function D(t,n,r){let e=typeof r.name==="string"?r.name.replace(/\s+/g," ").trim():"";if(!e)return`${T(t,n)?.noun??"Item"} #${r.id}`;return e.length>120?`${e.slice(0,119).trimEnd()}…`:e}function it(t,n,r,e,o=Date.now()){let i=T(t,r);if(!i||!Number.isInteger(e.id)||e.id<=0)return null;let s=n.filter((m)=>m.kind===r),l=D(t,r,e),a=s.find((m)=>m.itemId===e.id)??null,u=a?null:ct(s,i.slots),h=a||u!==null?null:ut(s),d=a?.slot??u??h?.slot;if(d===void 0||d===null)return null;let p={kind:r,slot:d,itemId:e.id,title:l,donatedAt:o},v=n.filter((m)=>m.kind!==r||m.slot!==d&&m.itemId!==e.id);return{entries:B(t,[...v,p]),entry:p,evicted:h,changed:!a||a.title!==l}}function st(t,n,r){let e=t.find((o)=>o.kind===n&&o.itemId===r)??null;return{entries:e?t.filter((o)=>o!==e):[...t],removed:e}}function at(t,n,r){let e=ot(t,r);if(!e)return null;let o=n.find((s)=>s.kind===e.kind&&s.slot===e.slot),i=T(t,e.kind)?.route;return o&&i?i.replace(":id",String(o.itemId)):null}function lt(t,n){if(!Array.isArray(n))return[];let r=new Map,e=new Set;for(let o of n){if(!o||typeof o!=="object")continue;let i=o,{kind:s,slot:l,itemId:a,title:u,donatedAt:h}=i;if(typeof s!=="string"||typeof l!=="number"||R(t,s,l)===null)continue;if(typeof a!=="number"||!Number.isInteger(a)||a<=0)continue;let d=`${s}-slot-${l}`,p=`${s}#${a}`;if(r.has(d)||e.has(p))continue;r.set(d,{kind:s,slot:l,itemId:a,title:typeof u==="string"&&u.trim()?u:D(t,s,{id:a}),donatedAt:typeof h==="number"&&Number.isFinite(h)&&h>0?h:0}),e.add(p)}return B(t,[...r.values()])}function B(t,n){let r=new Map(t.map((e,o)=>[e.name,o]));return[...n].sort((e,o)=>(r.get(e.kind)??0)-(r.get(o.kind)??0)||e.slot-o.slot)}function ct(t,n){let r=new Set(t.map((e)=>e.slot));for(let e=0;e<n;e++)if(!r.has(e))return e;return null}function ut(t){return t.reduce((n,r)=>!n||r.donatedAt<n.donatedAt?r:n,null)}function dt(){let t=globalThis.craft;return t&&typeof t==="object"?t.siri:void 0}var ft="stacks_spotlight_index",pt=3000;function de(t){let n=t.onProblem??((c)=>console.warn(`[spotlight] ${c}`)),r=Array.isArray(t.kinds)?{kinds:[...t.kinds],problems:[]}:F(t.kinds);for(let c of r.problems)n(c);let e=t.enabled===!1?[]:r.kinds,o=t.storageKey??ft,i=t.legacyStorageKeys??[],s=t.timeoutMs??pt,l=t.now??(()=>Date.now()),a=t.bridge??dt,u=null;function h(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function d(){if(u)return u;u=[];let c=h();if(!c)return u;try{let f=[o,...i].map((y)=>c.getItem(y)).find((y)=>y);u=f?lt(e,JSON.parse(f)):[]}catch{u=[]}return u}function p(c){u=c;let f=h();if(!f)return;try{f.setItem(o,JSON.stringify(c));for(let y of i)f.removeItem(y)}catch{}}async function v(c){if(!c)return null;let f;try{return await Promise.race([c,new Promise((y)=>{f=setTimeout(()=>y(null),s)})])}catch{return null}finally{if(f!==void 0)clearTimeout(f)}}let m=Promise.resolve();function g(c){let f=m.then(c,c);return m=f.catch(()=>{return}),f}async function b(c,f){let y=a()?.register;if(!y||e.length===0)return!1;return g(async()=>{let S=it(e,d(),c,f,l()),A=S&&R(e,c,S.entry.slot);if(!S||!A)return!1;if(!S.changed)return p(S.entries),!0;let w=await v(y(S.entry.title,A))!==null;if(w)p(S.entries);return w})}async function x(c,f){let y=a()?.remove;if(!y)return!1;return g(async()=>{let{entries:S,removed:A}=st(d(),c,f);if(!A)return!1;let w=R(e,c,A.slot),X=w?await v(y(w))!==null:!1;return p(S),X})}async function Y(c,f){let y=T(e,c)?.slots;if(!y||!a()?.register)return 0;let S=0;for(let A of[...f].slice(0,y).reverse())if(await b(c,A))S++;return S}async function W(){let c=a()?.remove;if(!c)return p([]),0;return g(async()=>{let f=0;for(let y of d()){let S=R(e,y.kind,y.slot);if(S&&await v(c(S))!==null)f++}return p([]),f})}return{kinds:e,index:b,sync:Y,remove:x,clear:W,routeFor:(c)=>at(e,d(),c),entries:()=>d(),activityTypes:(c)=>C(e).map((f)=>`${c}.${f}`),reset:()=>{u=null}}}var N=["craftShortcut","craftSiriShortcut"];function fe(t,n){let r=(e)=>{let o=e.detail,i=typeof o==="string"?o:o&&typeof o==="object"?o.action??o.type:null,s=typeof i==="string"?t.routeFor(i):null;if(s)n(s)};if(typeof globalThis.addEventListener!=="function")return()=>{};for(let e of N)globalThis.addEventListener(e,r);return()=>{for(let e of N)globalThis.removeEventListener(e,r)}}var It=gt,_t=ht,Ot=yt,L=St,Ht=At,Kt=wt,Nt=Tt,$t=Et,Ft=Lt,Ct=Pt,Dt=mt;function j(t){if(typeof t==="string")return t.trim()||null;if(!t||typeof t!=="object")return null;let n=t.url;return typeof n==="string"&&n.trim()?n:null}var Bt={async getInitialURL(){if(!await G())return null;return j(await U.getInitialURL?.())},onLink(t){let n=null,r=!1,e=()=>{if(r)return;n=U.onLink?.((o,i)=>{let s=j(o);if(s)t(s,{initial:i?.initial===!0})})??null};if(E()?.craft)e();else G().then(e);return()=>{r=!0,n?.()}}},Ut=bt,jt=Rt,Gt=kt,qt=vt,Yt=xt,Wt=Mt;function E(){if(typeof window>"u")return;return window}function P(){let t=E()?.craft;if(!t||typeof t!=="object")return null;if(!("platform"in t)||t.platform!=="ios"&&t.platform!=="android")return null;let n="capabilities"in t?t.capabilities:void 0,r=n&&typeof n==="object"&&!Array.isArray(n)?Object.fromEntries(Object.entries(n).filter(([,e])=>typeof e==="boolean")):{};return{platform:t.platform,capabilities:r}}function I(){return P()!==null}function q(){if(typeof window>"u")return!1;let t=window;if(t.CraftAndroid)return!0;let n=typeof navigator>"u"?"":navigator.userAgent;return Boolean(t.webkit?.messageHandlers?.craft)&&/iPhone|iPad|iPod/.test(n)}function Xt(t=2000){if(I()||q())return Promise.resolve(!0);let n=E(),r=n;if(!n||!(r?.craft||r?.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((e)=>{let o=()=>{clearTimeout(i),n.removeEventListener("craftReady",o),e(I())},i=setTimeout(o,t);n.addEventListener("craftReady",o,{once:!0})})}function G(t=15000){let n=E();if(n?.craft)return Promise.resolve(!0);let r=n;if(!n||!(q()||r?.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((e)=>{let o=()=>{clearTimeout(i),n.removeEventListener("craftReady",o),e(Boolean(n.craft))},i=setTimeout(o,t);n.addEventListener("craftReady",o)})}function zt(t){let n=E();if(!n)return()=>{};if(P()){let e=!1;return queueMicrotask(()=>{if(!e)t(new Event("craftReady"))}),()=>{e=!0}}let r=(e)=>{if(!P())return;n.removeEventListener("craftReady",r),t(e)};return n.addEventListener("craftReady",r),()=>n.removeEventListener("craftReady",r)}async function Jt(t){await L.impact("light");try{let n=await t();return await L.notification("success"),n}catch(n){throw await L.notification("error"),n}}var ge={get nativeBridge(){return P()},biometrics:It,camera:_t,device:Ot,haptics:L,lifecycle:Ht,location:Kt,notifications:Nt,permissions:$t,secureStorage:Ft,share:Ct,appReview:Dt,deepLinks:Bt,keepAwake:Ut,network:jt,pushNotifications:Gt,health:qt,liveActivities:Yt,watchConnectivity:Wt,isNativeMobile:I,whenNative:Xt,onReady:zt,withFeedback:Jt};export{ce as MAX_SPOTLIGHT_SLOTS_PER_KIND,oe as ROUTE_GAP_S,Dt as appReview,It as biometrics,_t as camera,V as canGoBack,ae as createRouteRecorder,de as createSpotlightIndex,Q as deepLinkPath,Bt as deepLinks,Ot as device,tt as fixDistance,ne as followDeepLinks,P as getNativeMobileBridge,ee as goBack,L as haptics,q as hasNativeMobileHost,qt as health,I as isNativeMobile,Ut as keepAwake,Ht as lifecycle,Yt as liveActivities,Kt as location,ge as mobile,jt as network,j as normalizeDeepLinkURL,Nt as notifications,Qt as observePageScroll,Zt as observePullToRefresh,zt as onMobileReady,fe as onSpotlightTap,ie as paceLabel,k as pageScrollTop,$t as permissions,it as placeSpotlightItem,J as pullDistance,Gt as pushNotifications,lt as readSpotlightEntries,F as readSpotlightKinds,st as removeSpotlightItem,H as routeStats,Ft as secureStorage,Ct as share,se as speedLabel,R as spotlightAction,C as spotlightActions,ue as spotlightActivityTypes,dt as spotlightBridge,T as spotlightKind,at as spotlightRoute,ot as spotlightSlot,D as spotlightTitle,et as usableFixes,Wt as watchConnectivity,G as whenBridgeReady,Xt as whenNativeMobile,Jt as withNativeFeedback};
1
+ import{appReview as mt,biometrics as gt,camera as ht,deepLinks as U,device as yt,haptics as St,health as vt,keepAwake as bt,lifecycle as wt,liveActivities as xt,location as At,network as Rt,notifications as Tt,permissions as Et,pushNotifications as kt,secureStorage as Lt,share as Pt,watchConnectivity as Mt}from"craft-native/mobile";import{haptics as z}from"craft-native/mobile";function M(){if(typeof window>"u")return;return window}function k(t=M()){if(!t)return 0;if(typeof t.scrollY==="number")return t.scrollY;return t.document?.scrollingElement?.scrollTop??0}function Qt(t,n=M()){if(!n)return()=>{};let r=!1,e=typeof requestAnimationFrame==="function"?requestAnimationFrame:(i)=>setTimeout(i,16),o=()=>{if(r)return;r=!0,e(()=>{r=!1,t(k(n))})};return t(k(n)),n.addEventListener("scroll",o,{passive:!0}),()=>n.removeEventListener("scroll",o)}function J(t,n){let r=Math.max(0,-t),e=t<=0?Math.max(0,n)*0.5:0;return Math.round(Math.max(r,e))}function Zt(t){let n=t.host??M();if(!n)return()=>{};let r=t.threshold??72,e=null,o=!1,i=!1,s=typeof requestAnimationFrame==="function"?requestAnimationFrame:(g)=>setTimeout(g,16),l=null,a=(g)=>{l=null,t.onPull?.(g,o)},u=(g)=>{let b=l!==null;if(l=g,b)return;s(()=>{if(l!==null)a(l)})},h=(g)=>{let b=g.touches?.[0];return b?b.clientY:null},d=(g)=>{if(i||k(n)>0)return;e=h(g),o=!1},p=(g)=>{if(e===null)return;let b=h(g);if(b===null)return;let x=J(k(n),b-e);if(!o&&x>=r)o=!0,Promise.resolve(z.impact("medium")).catch(()=>{});else if(o&&x<r*0.8)o=!1;u(x)},v=async()=>{if(e===null)return;if(e=null,!o){a(0);return}o=!1,i=!0,a(r);try{await t.onRefresh()}finally{i=!1,a(0)}},m=()=>{if(e===null)return;e=null,o=!1,a(0)};return n.addEventListener("touchstart",d,{passive:!0}),n.addEventListener("touchmove",p,{passive:!0}),n.addEventListener("touchend",v),n.addEventListener("touchcancel",m),()=>{l=null,n.removeEventListener("touchstart",d),n.removeEventListener("touchmove",p),n.removeEventListener("touchend",v),n.removeEventListener("touchcancel",m)}}function N(){if(typeof window>"u")return;return window}function V(t=N()){let n=t?.history?.state;return n!==null&&n!==void 0}function ee(t=N()){if(!V(t))return!1;return t.history.back(),!0}function ne(t,n,r=50){let e=t[t.length-1];if(t.length>=2&&t[t.length-2].path===n)t.pop();else if(!e||e.path!==n)t.push({path:n,title:""});if(t.length>r)t.splice(0,t.length-r);return{current:t[t.length-1],previous:t[t.length-2]??null}}function re(t,n,r=12){let e=t?.title.trim()??"";return e&&e.length<=r?e:n}function oe(){if(typeof window>"u")return[];let t=window;return t.__stacksNavTrail??=[]}function Q(t,n=Z()){let r;try{r=new URL(t)}catch{return null}let e=`${r.search}${r.hash}`;if(r.protocol==="http:"||r.protocol==="https:"){if(!n||r.origin!==n)return null;return`${r.pathname||"/"}${e}`}return`${`/${[r.host,r.pathname.replace(/^\/+/,"")].filter(Boolean).join("/")}`}${e}`}function Z(){if(typeof window>"u")return;return window.location?.origin}var _="stacks-mobile-deep-link";function ie(t,n){let r=(e)=>{let o=Q(e);if(o)t(o)};return n.getInitialURL().then((e)=>{if(!e)return;try{if(sessionStorage.getItem(_)===e)return;sessionStorage.setItem(_,e)}catch{}r(e)}).catch(()=>{}),n.onLink((e,o)=>{if(o?.initial)return;r(e)})}var ae=30;function tt(t,n){let r=Math.PI/180,e=(n.latitude-t.latitude)*r,o=(n.longitude-t.longitude)*r,i=Math.sin(e/2)**2+Math.cos(t.latitude*r)*Math.cos(n.latitude*r)*Math.sin(o/2)**2;return 12742017.6*Math.asin(Math.min(1,Math.sqrt(i)))}function et(t,n=25){let r=new Set;return t.filter((e)=>Number.isFinite(e.latitude)&&Number.isFinite(e.longitude)&&Number.isFinite(e.timestamp)&&e.accuracy>=0&&e.accuracy<=n).sort((e,o)=>e.timestamp-o.timestamp).filter((e)=>{if(r.has(e.timestamp))return!1;return r.add(e.timestamp),!0})}function O(t,n={}){let r=et(t,n.maxAccuracyM??25),e=n.paceWindowS??30,o=[],i=0,s=0,l=null;for(let d of r){let p=o[o.length-1],v=l?(d.timestamp-l.timestamp)/1000:0;if(l=d,!p){o.push({fix:d,cumM:0});continue}if(v>30){o.push({fix:d,cumM:i});continue}let m=(d.timestamp-p.fix.timestamp)/1000,g=tt(p.fix,d),b=Math.min(10,Math.max(3,p.fix.accuracy,d.accuracy));if(g<b)continue;if(i+=g,m>0&&g/m>=0.5)s+=m;o.push({fix:d,cumM:i})}let a=o[o.length-1],u=null,h=null;if(a){let d=a.fix.timestamp-e*1000,p=o.find((g)=>g.fix.timestamp>=d)??a,v=a.cumM-p.cumM,m=(a.fix.timestamp-p.fix.timestamp)/1000;if(v>=20&&m>0)h=v/m,u=m/(v/1000)}return{distanceM:i,movingS:s,paceSPerKm:u,averagePaceSPerKm:i>=50&&s>0?s/(i/1000):null,speedMps:h,accuracyM:r.length?r[r.length-1].accuracy:t.length?t[t.length-1].accuracy??null:null,fixes:r.length}}function le(t){if(!t||!Number.isFinite(t)||t>3600)return"–";let n=Math.round(t);return`${Math.floor(n/60)}:${String(n%60).padStart(2,"0")}`}function ce(t){return t&&Number.isFinite(t)?(t*3.6).toFixed(1):"–"}var H={distanceM:0,movingS:0,paceSPerKm:null,averagePaceSPerKm:null,speedMps:null,accuracyM:null,fixes:0};function ue(t){let n=t.location,r=t.intervalMs??3000,e=H,o=null,i=()=>typeof document<"u"&&document.visibilityState==="hidden";async function s(){let u=await n.readRecording();return e=O(u,t),t.onUpdate?.(e),e}function l(){a(),o=setInterval(()=>{if(!i())s().catch(()=>{})},r)}function a(){if(o)clearInterval(o);o=null}return{get stats(){return e},async start(){return await n.startRecording({enableHighAccuracy:!0,...t.locationOptions}),e=H,t.onUpdate?.(e),l(),e},async attach(){let u=await n.getRecordingState().catch(()=>null);if(!u?.active)return null;if(await s().catch(()=>{}),!u.paused)l();return u},async pause(){a(),await n.pauseRecording(),await s().catch(()=>{})},async resume(){await n.resumeRecording(),l()},async stop(){a();let h=(await n.stopRecording())?.locations??[];return e=O(h,t),t.onUpdate?.(e),h},refresh:s}}var fe=64;var nt=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/,rt=/^(?:0|[1-9]\d*)$/;function F(t){let n=[],r=[],e=t&&typeof t==="object"&&!Array.isArray(t)?t:{};for(let[o,i]of Object.entries(e)){let s=i&&typeof i==="object"?i:null;if(!s){r.push(`spotlight kind "${o}" is not an object`);continue}let{slots:l,route:a}=s,u=typeof s.noun==="string"&&s.noun.trim()?s.noun.trim():"Item";if(!nt.test(o)||o.includes("-slot-")){r.push(`spotlight kind "${o}" is not a usable name: lowercase letters, digits and single dashes, and never "-slot-"`);continue}if(typeof l!=="number"||!Number.isInteger(l)||l<=0||l>64){r.push(`spotlight kind "${o}" needs slots between 1 and 64, not ${String(l)}`);continue}if(typeof a!=="string"||!a.startsWith("/")||!a.includes(":id")){r.push(`spotlight kind "${o}" needs a route starting with "/" and carrying ":id", not ${String(a)}`);continue}n.push({name:o,slots:l,route:a,noun:u})}return{kinds:n,problems:r}}function T(t,n){return t.find((r)=>r.name===n)??null}function R(t,n,r){let e=T(t,n);if(!e||!Number.isInteger(r)||r<0||r>=e.slots)return null;return`${n}-slot-${r}`}function ot(t,n){if(typeof n!=="string")return null;let r=n.lastIndexOf("-slot-");if(r<=0)return null;let e=n.slice(0,r),o=n.slice(r+6);if(!rt.test(o))return null;let i=Number(o);return R(t,e,i)===n?{kind:e,slot:i}:null}function C(t){return t.flatMap((n)=>Array.from({length:n.slots},(r,e)=>`${n.name}-slot-${e}`))}function pe(t,n){let r=t&&typeof t==="object"?t:{};if(r.enabled===!1)return[];let o=[...(Array.isArray(r.activityTypes)?r.activityTypes.filter((i)=>typeof i==="string"&&i.trim().length>0):[]).map((i)=>i.trim()),...C(F(r.kinds).kinds)];return[...new Set(o)].map((i)=>`${n}.${i}`)}function D(t,n,r){let e=typeof r.name==="string"?r.name.replace(/\s+/g," ").trim():"";if(!e)return`${T(t,n)?.noun??"Item"} #${r.id}`;return e.length>120?`${e.slice(0,119).trimEnd()}…`:e}function it(t,n,r,e,o=Date.now()){let i=T(t,r);if(!i||!Number.isInteger(e.id)||e.id<=0)return null;let s=n.filter((m)=>m.kind===r),l=D(t,r,e),a=s.find((m)=>m.itemId===e.id)??null,u=a?null:ct(s,i.slots),h=a||u!==null?null:ut(s),d=a?.slot??u??h?.slot;if(d===void 0||d===null)return null;let p={kind:r,slot:d,itemId:e.id,title:l,donatedAt:o},v=n.filter((m)=>m.kind!==r||m.slot!==d&&m.itemId!==e.id);return{entries:B(t,[...v,p]),entry:p,evicted:h,changed:!a||a.title!==l}}function st(t,n,r){let e=t.find((o)=>o.kind===n&&o.itemId===r)??null;return{entries:e?t.filter((o)=>o!==e):[...t],removed:e}}function at(t,n,r){let e=ot(t,r);if(!e)return null;let o=n.find((s)=>s.kind===e.kind&&s.slot===e.slot),i=T(t,e.kind)?.route;return o&&i?i.replace(":id",String(o.itemId)):null}function lt(t,n){if(!Array.isArray(n))return[];let r=new Map,e=new Set;for(let o of n){if(!o||typeof o!=="object")continue;let i=o,{kind:s,slot:l,itemId:a,title:u,donatedAt:h}=i;if(typeof s!=="string"||typeof l!=="number"||R(t,s,l)===null)continue;if(typeof a!=="number"||!Number.isInteger(a)||a<=0)continue;let d=`${s}-slot-${l}`,p=`${s}#${a}`;if(r.has(d)||e.has(p))continue;r.set(d,{kind:s,slot:l,itemId:a,title:typeof u==="string"&&u.trim()?u:D(t,s,{id:a}),donatedAt:typeof h==="number"&&Number.isFinite(h)&&h>0?h:0}),e.add(p)}return B(t,[...r.values()])}function B(t,n){let r=new Map(t.map((e,o)=>[e.name,o]));return[...n].sort((e,o)=>(r.get(e.kind)??0)-(r.get(o.kind)??0)||e.slot-o.slot)}function ct(t,n){let r=new Set(t.map((e)=>e.slot));for(let e=0;e<n;e++)if(!r.has(e))return e;return null}function ut(t){return t.reduce((n,r)=>!n||r.donatedAt<n.donatedAt?r:n,null)}function dt(){let t=globalThis.craft;return t&&typeof t==="object"?t.siri:void 0}var ft="stacks_spotlight_index",pt=3000;function me(t){let n=t.onProblem??((c)=>console.warn(`[spotlight] ${c}`)),r=Array.isArray(t.kinds)?{kinds:[...t.kinds],problems:[]}:F(t.kinds);for(let c of r.problems)n(c);let e=t.enabled===!1?[]:r.kinds,o=t.storageKey??ft,i=t.legacyStorageKeys??[],s=t.timeoutMs??pt,l=t.now??(()=>Date.now()),a=t.bridge??dt,u=null;function h(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function d(){if(u)return u;u=[];let c=h();if(!c)return u;try{let f=[o,...i].map((y)=>c.getItem(y)).find((y)=>y);u=f?lt(e,JSON.parse(f)):[]}catch{u=[]}return u}function p(c){u=c;let f=h();if(!f)return;try{f.setItem(o,JSON.stringify(c));for(let y of i)f.removeItem(y)}catch{}}async function v(c){if(!c)return null;let f;try{return await Promise.race([c,new Promise((y)=>{f=setTimeout(()=>y(null),s)})])}catch{return null}finally{if(f!==void 0)clearTimeout(f)}}let m=Promise.resolve();function g(c){let f=m.then(c,c);return m=f.catch(()=>{return}),f}async function b(c,f){let y=a()?.register;if(!y||e.length===0)return!1;return g(async()=>{let S=it(e,d(),c,f,l()),w=S&&R(e,c,S.entry.slot);if(!S||!w)return!1;if(!S.changed)return p(S.entries),!0;let A=await v(y(S.entry.title,w))!==null;if(A)p(S.entries);return A})}async function x(c,f){let y=a()?.remove;if(!y)return!1;return g(async()=>{let{entries:S,removed:w}=st(d(),c,f);if(!w)return!1;let A=R(e,c,w.slot),X=A?await v(y(A))!==null:!1;return p(S),X})}async function Y(c,f){let y=T(e,c)?.slots;if(!y||!a()?.register)return 0;let S=0;for(let w of[...f].slice(0,y).reverse())if(await b(c,w))S++;return S}async function W(){let c=a()?.remove;if(!c)return p([]),0;return g(async()=>{let f=0;for(let y of d()){let S=R(e,y.kind,y.slot);if(S&&await v(c(S))!==null)f++}return p([]),f})}return{kinds:e,index:b,sync:Y,remove:x,clear:W,routeFor:(c)=>at(e,d(),c),entries:()=>d(),activityTypes:(c)=>C(e).map((f)=>`${c}.${f}`),reset:()=>{u=null}}}var K=["craftShortcut","craftSiriShortcut"];function ge(t,n){let r=(e)=>{let o=e.detail,i=typeof o==="string"?o:o&&typeof o==="object"?o.action??o.type:null,s=typeof i==="string"?t.routeFor(i):null;if(s)n(s)};if(typeof globalThis.addEventListener!=="function")return()=>{};for(let e of K)globalThis.addEventListener(e,r);return()=>{for(let e of K)globalThis.removeEventListener(e,r)}}var It=gt,_t=ht,Nt=yt,L=St,Ot=wt,Ht=At,Kt=Tt,$t=Et,Ft=Lt,Ct=Pt,Dt=mt;function j(t){if(typeof t==="string")return t.trim()||null;if(!t||typeof t!=="object")return null;let n=t.url;return typeof n==="string"&&n.trim()?n:null}var Bt={async getInitialURL(){if(!await G())return null;return j(await U.getInitialURL?.())},onLink(t){let n=null,r=!1,e=()=>{if(r)return;n=U.onLink?.((o,i)=>{let s=j(o);if(s)t(s,{initial:i?.initial===!0})})??null};if(E()?.craft)e();else G().then(e);return()=>{r=!0,n?.()}}},Ut=bt,jt=Rt,Gt=kt,qt=vt,Yt=xt,Wt=Mt;function E(){if(typeof window>"u")return;return window}function P(){let t=E()?.craft;if(!t||typeof t!=="object")return null;if(!("platform"in t)||t.platform!=="ios"&&t.platform!=="android")return null;let n="capabilities"in t?t.capabilities:void 0,r=n&&typeof n==="object"&&!Array.isArray(n)?Object.fromEntries(Object.entries(n).filter(([,e])=>typeof e==="boolean")):{};return{platform:t.platform,capabilities:r}}function I(){return P()!==null}function q(){if(typeof window>"u")return!1;let t=window;if(t.CraftAndroid)return!0;let n=typeof navigator>"u"?"":navigator.userAgent;return Boolean(t.webkit?.messageHandlers?.craft)&&/iPhone|iPad|iPod/.test(n)}function Xt(t=2000){if(I()||q())return Promise.resolve(!0);let n=E(),r=n;if(!n||!(r?.craft||r?.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((e)=>{let o=()=>{clearTimeout(i),n.removeEventListener("craftReady",o),e(I())},i=setTimeout(o,t);n.addEventListener("craftReady",o,{once:!0})})}function G(t=15000){let n=E();if(n?.craft)return Promise.resolve(!0);let r=n;if(!n||!(q()||r?.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((e)=>{let o=()=>{clearTimeout(i),n.removeEventListener("craftReady",o),e(Boolean(n.craft))},i=setTimeout(o,t);n.addEventListener("craftReady",o)})}function zt(t){let n=E();if(!n)return()=>{};if(P()){let e=!1;return queueMicrotask(()=>{if(!e)t(new Event("craftReady"))}),()=>{e=!0}}let r=(e)=>{if(!P())return;n.removeEventListener("craftReady",r),t(e)};return n.addEventListener("craftReady",r),()=>n.removeEventListener("craftReady",r)}async function Jt(t){await L.impact("light");try{let n=await t();return await L.notification("success"),n}catch(n){throw await L.notification("error"),n}}var Se={get nativeBridge(){return P()},biometrics:It,camera:_t,device:Nt,haptics:L,lifecycle:Ot,location:Ht,notifications:Kt,permissions:$t,secureStorage:Ft,share:Ct,appReview:Dt,deepLinks:Bt,keepAwake:Ut,network:jt,pushNotifications:Gt,health:qt,liveActivities:Yt,watchConnectivity:Wt,isNativeMobile:I,whenNative:Xt,onReady:zt,withFeedback:Jt};export{fe as MAX_SPOTLIGHT_SLOTS_PER_KIND,ae as ROUTE_GAP_S,Dt as appReview,re as backLabelFor,It as biometrics,_t as camera,V as canGoBack,ue as createRouteRecorder,me as createSpotlightIndex,Q as deepLinkPath,Bt as deepLinks,Nt as device,ne as enterNavTrail,tt as fixDistance,ie as followDeepLinks,P as getNativeMobileBridge,ee as goBack,L as haptics,q as hasNativeMobileHost,qt as health,I as isNativeMobile,Ut as keepAwake,Ot as lifecycle,Yt as liveActivities,Ht as location,Se as mobile,oe as navTrail,jt as network,j as normalizeDeepLinkURL,Kt as notifications,Qt as observePageScroll,Zt as observePullToRefresh,zt as onMobileReady,ge as onSpotlightTap,le as paceLabel,k as pageScrollTop,$t as permissions,it as placeSpotlightItem,J as pullDistance,Gt as pushNotifications,lt as readSpotlightEntries,F as readSpotlightKinds,st as removeSpotlightItem,O as routeStats,Ft as secureStorage,Ct as share,ce as speedLabel,R as spotlightAction,C as spotlightActions,pe as spotlightActivityTypes,dt as spotlightBridge,T as spotlightKind,at as spotlightRoute,ot as spotlightSlot,D as spotlightTitle,et as usableFixes,Wt as watchConnectivity,G as whenBridgeReady,Xt as whenNativeMobile,Jt as withNativeFeedback};
@@ -6,6 +6,24 @@ export declare function canGoBack(host?: HistoryHost | undefined): boolean;
6
6
  * it did. When it answers `false` the caller follows its own link.
7
7
  */
8
8
  export declare function goBack(host?: HistoryHost | undefined): boolean;
9
+ /**
10
+ * Records arriving at `path` on the trail of screens, and answers this
11
+ * screen's entry and the one a back button returns to.
12
+ *
13
+ * Arriving at the screen just before the current one is going back, so the
14
+ * current one is dropped; arriving at the current one again (a reload, a
15
+ * re-render) changes nothing; anything else is a push. The trail is capped,
16
+ * oldest first.
17
+ */
18
+ export declare function enterNavTrail(trail: NavTrailEntry[], path: string, limit?: number): { current: NavTrailEntry, previous: NavTrailEntry | null };
19
+ /**
20
+ * What a back button says: the name of the screen it returns to, as iOS
21
+ * does, when that is short enough to sit beside the title; otherwise the
22
+ * button's own word ("Back", "Workout").
23
+ */
24
+ export declare function backLabelFor(previous: NavTrailEntry | null, fallback: string, max?: number): string;
25
+ /** The trail for this window: it outlives each screen, not a full reload. */
26
+ export declare function navTrail(): NavTrailEntry[];
9
27
  /**
10
28
  * The in-app path a deep link opens, or null when it is not this app's.
11
29
  *
@@ -27,3 +45,8 @@ export declare function followDeepLinks(go: (path: string) => void, links: DeepL
27
45
  export declare interface HistoryHost {
28
46
  history?: { state: unknown, back: () => void }
29
47
  }
48
+ /** A screen the app has shown, by the path it was at and the name it showed. */
49
+ export declare interface NavTrailEntry {
50
+ path: string
51
+ title: string
52
+ }
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.71",
5
+ "version": "0.75.73",
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.111"
36
36
  },
37
37
  "devDependencies": {
38
- "@stacksjs/build": "0.75.71",
38
+ "@stacksjs/build": "0.75.73",
39
39
  "better-dx": "^0.2.24"
40
40
  }
41
41
  }