@buoy-gg/ota-inspector 0.0.0-stage → 7.0.80
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/LICENSE +58 -0
- package/README.md +20 -2
- package/lib/commonjs/OtaInspectorRoot.js +1 -0
- package/lib/commonjs/components/OtaBody.js +1 -0
- package/lib/commonjs/components/OtaToolView.js +1 -0
- package/lib/commonjs/engine/expoSDK.js +1 -0
- package/lib/commonjs/engine/expoSDK.web.js +1 -0
- package/lib/commonjs/engine/findings.js +1 -0
- package/lib/commonjs/engine/otaStore.js +1 -0
- package/lib/commonjs/engine/sanitize.js +1 -0
- package/lib/commonjs/index.js +1 -0
- package/lib/commonjs/index.web.js +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +1 -0
- package/lib/commonjs/sync/otaInspectorSyncAdapter.js +1 -0
- package/lib/commonjs/types.js +1 -0
- package/lib/module/OtaInspectorRoot.js +1 -0
- package/lib/module/components/OtaBody.js +1 -0
- package/lib/module/components/OtaToolView.js +1 -0
- package/lib/module/engine/expoSDK.js +1 -0
- package/lib/module/engine/expoSDK.web.js +1 -0
- package/lib/module/engine/findings.js +1 -0
- package/lib/module/engine/otaStore.js +1 -0
- package/lib/module/engine/sanitize.js +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.web.js +1 -0
- package/lib/module/preset.js +1 -0
- package/lib/module/sync/otaInspectorSyncAdapter.js +1 -0
- package/lib/module/types.js +1 -0
- package/lib/typescript/OtaInspectorRoot.d.ts +3 -0
- package/lib/typescript/components/OtaBody.d.ts +3 -0
- package/lib/typescript/components/OtaToolView.d.ts +11 -0
- package/lib/typescript/engine/expoSDK.d.ts +7 -0
- package/lib/typescript/engine/expoSDK.web.d.ts +6 -0
- package/lib/typescript/engine/findings.d.ts +3 -0
- package/lib/typescript/engine/otaStore.d.ts +21 -0
- package/lib/typescript/engine/sanitize.d.ts +13 -0
- package/lib/typescript/index.d.ts +9 -0
- package/lib/typescript/index.web.d.ts +5 -0
- package/lib/typescript/preset.d.ts +33 -0
- package/lib/typescript/sync/otaInspectorSyncAdapter.d.ts +9 -0
- package/lib/typescript/types.d.ts +121 -0
- package/lib/web/index.mjs +1 -0
- package/package.json +100 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present Buoy. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its source code are proprietary and confidential.
|
|
6
|
+
|
|
7
|
+
NOTICE: This is NOT open source software. This software is licensed,
|
|
8
|
+
not sold, and is protected by copyright laws and international treaties.
|
|
9
|
+
|
|
10
|
+
TERMS AND CONDITIONS:
|
|
11
|
+
|
|
12
|
+
1. LICENSE GRANT
|
|
13
|
+
Subject to the terms of this Agreement and payment of applicable fees,
|
|
14
|
+
Buoy grants you a limited, non-exclusive, non-transferable license
|
|
15
|
+
to use the compiled software packages in your applications.
|
|
16
|
+
|
|
17
|
+
2. RESTRICTIONS
|
|
18
|
+
You may NOT:
|
|
19
|
+
- Copy, modify, or distribute the source code
|
|
20
|
+
- Reverse engineer, decompile, or disassemble the software
|
|
21
|
+
- Remove or alter any proprietary notices or labels
|
|
22
|
+
- Sublicense, rent, lease, or lend the software
|
|
23
|
+
- Use the software to create competing products
|
|
24
|
+
- Share access credentials with unauthorized parties
|
|
25
|
+
|
|
26
|
+
3. OWNERSHIP
|
|
27
|
+
React Buoy retains all right, title, and interest in the software,
|
|
28
|
+
including all intellectual property rights. This license does not
|
|
29
|
+
grant you any rights to trademarks or service marks.
|
|
30
|
+
|
|
31
|
+
4. TERMINATION
|
|
32
|
+
This license is effective until terminated. Your rights under this
|
|
33
|
+
license will terminate automatically without notice if you fail to
|
|
34
|
+
comply with any of its terms. Upon termination, you must cease all
|
|
35
|
+
use and destroy all copies of the software.
|
|
36
|
+
|
|
37
|
+
5. DISCLAIMER OF WARRANTIES
|
|
38
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
|
39
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
40
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
41
|
+
|
|
42
|
+
6. LIMITATION OF LIABILITY
|
|
43
|
+
IN NO EVENT SHALL BUOY BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
|
|
44
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN
|
|
45
|
+
CONNECTION WITH THIS LICENSE OR THE USE OF THE SOFTWARE.
|
|
46
|
+
|
|
47
|
+
7. GOVERNING LAW
|
|
48
|
+
This Agreement shall be governed by and construed in accordance with
|
|
49
|
+
the laws of the United States, without regard to its conflict of
|
|
50
|
+
law provisions.
|
|
51
|
+
|
|
52
|
+
For licensing inquiries and subscription information:
|
|
53
|
+
- Website: https://buoy.gg
|
|
54
|
+
- Email: AustinLovesWorking@gmail.com
|
|
55
|
+
|
|
56
|
+
Unauthorized reproduction or distribution of this software, or any
|
|
57
|
+
portion of it, may result in severe civil and criminal penalties,
|
|
58
|
+
and will be prosecuted to the maximum extent possible under the law.
|
package/README.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OTA Update Inspector
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
See which Expo update runs on your app.
|
|
4
|
+
Check for a new one, fetch it, then reload.
|
|
5
|
+
The view shows why a saved update did not run.
|
|
6
|
+
|
|
7
|
+
This tool is in test. It is not on npm yet.
|
|
8
|
+
It needs Buoy Pro and `expo-updates` for SDK 56.
|
|
9
|
+
Expo is an optional peer. Missing or disabled builds show a hint.
|
|
10
|
+
Core mounts the state hook and adds the menu item.
|
|
11
|
+
|
|
12
|
+
See the [tool guide](../../public/buoy/docs/tools/ota-update-inspector.md)
|
|
13
|
+
for config hints, source changes, and release sync rules.
|
|
14
|
+
|
|
15
|
+
The shared `OtaToolView` has no native SDK import.
|
|
16
|
+
Desktop uses this view with a device snapshot.
|
|
17
|
+
|
|
18
|
+
Release writes are off by default, on all surfaces.
|
|
19
|
+
The host may set `allowActionsInRelease: true` with `configureOtaInspector`.
|
|
20
|
+
Sync writes also need `externalSync.releaseActions`.
|
|
21
|
+
Pass `allowActionsInRelease: false` to turn writes off again.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.OtaInspectorRoot=OtaInspectorRoot;var _react=_interopRequireWildcard(require("react"));var _expoSDK=require("./engine/expoSDK");var _otaStore=require("./engine/otaStore");var _jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var u=new WeakMap,c=new WeakMap;return(_interopRequireWildcard=function(t,i){if(!i&&t&&t.__esModule)return t;var o,s,a={__proto__:null,default:t};if(null===t||"object"!=typeof t&&"function"!=typeof t)return a;if(o=i?c:u){if(o.has(t))return o.get(t);o.set(t,a)}for(const n in t)"default"!==n&&{}.hasOwnProperty.call(t,n)&&((s=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(t,n))&&(s.get||s.set)?o(a,n,s):a[n]=t[n]);return a})(e,r)}const Bridge=(0,_react.memo)(function e({sdk:r}){const u=r.useUpdates();(0,_react.useEffect)(()=>{_otaStore.otaStore.attach(r);return()=>_otaStore.otaStore.attach(null,"waiting")},[r]);(0,_react.useEffect)(()=>{_otaStore.otaStore.ingest(u)},[u]);return null});function OtaInspectorRoot(){const[e,r]=(0,_react.useState)(null);(0,_react.useEffect)(()=>{r((0,_expoSDK.loadExpoSDK)())},[]);(0,_react.useEffect)(()=>{if(!e||e.sdk?.useUpdates)return;_otaStore.otaStore.attach(e.sdk,e.status||"load-error");return()=>_otaStore.otaStore.attach(null,"waiting")},[e]);return e?.sdk?.useUpdates?(0,_jsxRuntime.jsx)(Bridge,{sdk:e.sdk}):null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.OtaBody=OtaBody;var _react=_interopRequireWildcard(require("react"));var _sharedUi=require("@buoy-gg/shared-ui");var _otaStore=require("../engine/otaStore");var _otaInspectorSyncAdapter=require("../sync/otaInspectorSyncAdapter");var _OtaToolView=require("./OtaToolView");var _jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(n,i){if("function"==typeof WeakMap)var s=new WeakMap,c=new WeakMap;return(_interopRequireWildcard=function(e,u){if(!u&&e&&e.__esModule)return e;var t,a,o={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return o;if(t=u?c:s){if(t.has(e))return t.get(e);t.set(e,o)}for(const r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((a=(t=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,r))&&(a.get||a.set)?t(o,r,a):o[r]=e[r]);return o})(n,i)}function OtaBody(){const n=(0,_react.useSyncExternalStore)(_otaStore.otaStore.subscribe,_otaStore.otaStore.getSnapshot,_otaStore.otaStore.getSnapshot);return(0,_jsxRuntime.jsx)(_sharedUi.FeatureGate,{featureName:"OTA Update Inspector",children:(0,_jsxRuntime.jsx)(_OtaToolView.OtaToolView,{snapshot:n,onAction:async(i,s)=>_otaInspectorSyncAdapter.otaInspectorSyncAdapter.actions[i](s)})})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.OtaToolView=OtaToolView;var _react=_interopRequireWildcard(require("react"));var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(e,d){if("function"==typeof WeakMap)var n=new WeakMap,c=new WeakMap;return(_interopRequireWildcard=function(a,s){if(!s&&a&&a.__esModule)return a;var r,i,u={__proto__:null,default:a};if(null===a||"object"!=typeof a&&"function"!=typeof a)return u;if(r=s?c:n){if(r.has(a))return r.get(a);r.set(a,u)}for(const l in a)"default"!==l&&{}.hasOwnProperty.call(a,l)&&((i=(r=Object.defineProperty)&&Object.getOwnPropertyDescriptor(a,l))&&(i.get||i.set)?r(u,l,i):u[l]=a[l]);return u})(e,d)}const show=e=>e==null?"Unknown":typeof e==="object"?JSON.stringify(e,null,2):String(e);function OtaToolView({snapshot:e,onAction:d,offline:n=false}){const[c,a]=(0,_react.useState)(null);const[s,r]=(0,_react.useState)(null);const[i,u]=(0,_react.useState)(false);const[l,v]=(0,_react.useState)("");const[x,m]=(0,_react.useState)("");const[b,w]=(0,_react.useState)("");const[j,S]=(0,_react.useState)("{}");const f=async(t,o)=>{r(null);a(null);try{if(n)throw new Error("The app is offline. Connect it first.");await d(t,o)}catch(p){a(p instanceof Error?p.message:"The call failed.")}};if(!e)return(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Waiting for the app\u2026"});const h=(t,o,p,C=false)=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.gap,children:[(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{testID:`ota-${t}${o.startsWith("Clear")?"-clear":""}`,label:o,disabled:n||!e.capabilities[t].enabled,onPress:()=>C?r({action:t,params:p}):void f(t,p)}),e.capabilities[t].reason?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:e.capabilities[t].reason}):null]},o);const g=e.updates.downloadedUpdate;const N=()=>{const t=JSON.parse(j);if(!t||typeof t!=="object"||Array.isArray(t))throw new Error("Use a JSON header map.");return t};const y=t=>{try{const o=N();a(null);r({action:t,params:t==="setHeaders"?{requestHeaders:o}:{configOverride:{updateUrl:b,requestHeaders:o}}})}catch{a("Use a JSON header map.")}};return(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{style:{flex:1},testID:"ota-scroll",keyboardShouldPersistTaps:"handled",children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.content,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"OTA Update Inspector"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.text,testID:"ota-status",children:e.status}),n?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{tone:"warning",children:"Offline. This is the last saved view."}):null,e.statusReason?(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:e.statusReason}):null,c||e.actionError?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.error,testID:"ota-error",children:c||e.actionError?.message}):null,(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"What runs now"}),(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.card,children:[(0,_jsxRuntime.jsx)(Row,{label:"Expo isEnabled",value:e.running.isEnabled}),(0,_jsxRuntime.jsx)(Row,{label:"Update ID",value:e.running.updateId,id:"ota-running-id"}),(0,_jsxRuntime.jsx)(Row,{label:"Built in",value:e.running.isEmbeddedLaunch,id:"ota-embedded"}),(0,_jsxRuntime.jsx)(Row,{label:"Channel",value:e.running.channel}),(0,_jsxRuntime.jsx)(Row,{label:"Runtime",value:e.running.runtimeVersion,id:"ota-runtime"}),(0,_jsxRuntime.jsx)(Row,{label:"Launch time (ms)",value:e.running.launchDuration}),(0,_jsxRuntime.jsx)(Row,{label:"Emergency launch",value:e.running.isEmergencyLaunch}),e.running.emergencyLaunchReason?(0,_jsxRuntime.jsx)(Row,{label:"Launch fault",value:e.running.emergencyLaunchReason}):null]})}),(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Why did it not run?"}),e.findings.length?e.findings.map(t=>(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.text,testID:`ota-finding-${t.code}`,children:t.message}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.hint,children:[t.kind," \xB7 ",t.source]})]},t.code)):(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"No fault found from these facts."}),(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Next update"}),(0,_jsxRuntime.jsx)(Row,{label:"Found",value:e.updates.availableUpdate,id:"ota-found"}),(0,_jsxRuntime.jsx)(Row,{label:"Saved",value:g,id:"ota-pending-detail"}),(0,_jsxRuntime.jsx)(Row,{label:"Ready to apply",value:e.updates.isUpdatePending,id:"ota-pending"}),(0,_jsxRuntime.jsx)(Row,{label:"Now",value:e.busy||(e.updates.isChecking?"Checking":e.updates.isDownloading?"Fetching":"Idle")}),(0,_jsxRuntime.jsx)(Row,{label:"Fetch progress",value:e.updates.downloadProgress==null?null:`${Math.round(e.updates.downloadProgress*100)}%`}),(0,_jsxRuntime.jsx)(Row,{label:"Last check",value:e.updates.lastCheckForUpdateTimeSinceRestart}),e.lastCheck?.reason?(0,_jsxRuntime.jsx)(Row,{label:"Check result",value:e.lastCheck.reason}):null,e.updates.checkError?(0,_jsxRuntime.jsx)(Row,{label:"Check fault",value:e.updates.checkError.message}):null,e.updates.downloadError?(0,_jsxRuntime.jsx)(Row,{label:"Fetch fault",value:e.updates.downloadError.message}):null,h("check","Check now"),h("fetch","Fetch update"),h("reload",g?.type==="rollback"?"Apply server rollback":"Reload to apply",{expectedType:g?.type,expectedUpdateId:g?.type==="new"?g.updateId:void 0},true),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Reload restarts the app. Unsaved work may be lost."}),s?(0,_jsxRuntime.jsx)(_sharedUi.NightCard,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.card,testID:"ota-confirm",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.text,children:s.action==="reload"?"Apply this saved update and restart?":"Save this change? It lasts through app restarts."}),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:s.action==="reload"?show(g):"This sends the full header map. Left out keys will be cleared."}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Apply",testID:"ota-confirm-apply",onPress:()=>void f(s.action,s.params)}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Cancel",testID:"ota-confirm-cancel",onPress:()=>r(null)})]})}):null,(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:i?"Hide details":"Show details",testID:"ota-details",onPress:()=>u(!i)}),i?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.gap,children:[(0,_jsxRuntime.jsx)(Row,{label:"Created at",value:e.running.createdAt}),(0,_jsxRuntime.jsx)(Row,{label:"Manifest summary",value:e.running.manifest}),(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Config hints"}),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"These are app hints, not a native readback. Secrets are hidden. Prior saved changes may be unknown."}),(0,_jsxRuntime.jsx)(Row,{label:"Hint source",value:e.config.source}),(0,_jsxRuntime.jsx)(Row,{label:"Update URL",value:e.config.updateUrl}),(0,_jsxRuntime.jsx)(Row,{label:"Headers",value:e.config.requestHeaders}),(0,_jsxRuntime.jsx)(Row,{label:"Last write source",value:e.config.overrideSource}),(0,_jsxRuntime.jsx)(Row,{label:"Last write",value:e.config.override}),(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Compare a target"}),(0,_jsxRuntime.jsx)(Field,{label:"Target runtime",value:l,set:v,id:"ota-target-runtime"}),(0,_jsxRuntime.jsx)(Field,{label:"Target channel",value:x,set:m,id:"ota-target-channel"}),h("setExpected","Compare",{runtimeVersion:l,channel:x}),(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Change the source"}),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"Use a full header map. Keys must exist in the build. Clearing a change restores the build config."}),(0,_jsxRuntime.jsx)(Field,{label:"Headers (JSON)",value:j,set:S,id:"ota-headers"}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Set headers",testID:"ota-setHeaders",disabled:n||!e.capabilities.setHeaders.enabled,onPress:()=>y("setHeaders")}),h("setHeaders","Clear header change",{requestHeaders:null},true),(0,_jsxRuntime.jsx)(Field,{label:"Update URL",value:b,set:w,id:"ota-url"}),(0,_jsxRuntime.jsx)(_sharedUi.NightButton,{label:"Set URL",testID:"ota-setURL",disabled:n||!e.capabilities.setURL.enabled,onPress:()=>y("setURL")}),h("setURL","Clear URL change",{configOverride:null},true),(0,_jsxRuntime.jsx)(_sharedUi.NightFootnote,{children:"URL changes need an opted in test build."})]}):null]})})}function Row({label:e,value:d,id:n}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.gap,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{selectable:true,style:styles.text,testID:n,children:show(d)})]})}function Field({label:e,value:d,set:n,id:c}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.input,testID:c,accessibilityLabel:e,value:d,onChangeText:n,autoCapitalize:"none",autoCorrect:false,spellCheck:false,smartInsertDelete:false,keyboardType:_reactNative.Platform.OS==="ios"?"ascii-capable":"default"})]})}const styles=_reactNative.StyleSheet.create({content:{padding:16,paddingBottom:48,gap:14},title:{color:_sharedUi.night.color.text,fontSize:22,fontWeight:"600"},text:{color:_sharedUi.night.color.text,fontSize:14},hint:{color:_sharedUi.night.color.textSecondary,fontSize:12},error:{color:_sharedUi.night.color.danger},card:{padding:14,gap:12},gap:{gap:6},input:{color:_sharedUi.night.color.text,backgroundColor:_sharedUi.night.color.bg,borderColor:_sharedUi.night.color.border,borderWidth:1,borderRadius:8,padding:10}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.classifyLoadError=classifyLoadError;exports.loadExpoSDK=loadExpoSDK;function classifyLoadError(e){const t=e instanceof Error?e.message:String(e);if(/Cannot find native module.*ExpoUpdates|ExpoUpdates.*not.*found/i.test(t))return"native-missing";if(/Cannot find module ['"]expo-updates['"]|Unable to resolve module expo-updates|Requiring unknown module.*expo-updates/i.test(t))return"missing";return"load-error"}function hasNativeUpdates(){const e=globalThis.expo?.modules;return!!e?.ExpoUpdates}function loadExpoSDK(){if(!hasNativeUpdates())return{sdk:null,status:"native-missing"};try{const e=require("expo-updates");return{sdk:{...e,isDevelopmentLaunch:typeof __DEV__!=="undefined"&&__DEV__&&!e.updateId}}}catch(e){return{sdk:null,status:classifyLoadError(e)}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.loadExpoSDK=loadExpoSDK;function loadExpoSDK(){return{sdk:null,status:"unsupported"}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.findings=findings;function findings(e){const a=[];const n=(i,o,s,c)=>a.push({code:i,kind:o,source:s,message:c});if(e.status!=="ready")n(e.status,"observed","expo",e.statusReason||"Waiting for the app.");if(e.updates.isUpdatePending)n("pending","observed","expo","The update is fetched. Reload lets Expo choose what runs.");if(e.running.isEmergencyLaunch)n("emergency","observed","expo",e.running.emergencyLaunchReason||"Expo used a safe launch. Read the app logs.");const r=e.expected.runtimeVersion||(e.updates.availableUpdate?.type==="new"?e.updates.availableUpdate.runtimeVersion:null);if(r&&e.running.runtimeVersion&&r!==e.running.runtimeVersion){n("runtime-mismatch","comparison",e.expected.runtimeVersion?"user":"expo",`This build uses ${e.running.runtimeVersion}. The target uses ${r}. They must match.`)}else if(!r)n("runtime-check","check","user","Check that the update uses this build's runtime.");const t=e.running.channel;if(e.expected.channel&&t&&t!==e.expected.channel)n("channel-mismatch","comparison","user",`The running channel is ${t}. The target is ${e.expected.channel}. Check both.`);else if(!e.expected.channel||!t)n("channel-check","check","user","Check the channel set in the build and server.");if(e.lastCheck?.reason)n("check-reason","observed","expo",`Expo reports: ${e.lastCheck.reason}`);if(e.updates.checkError)n("check-error","observed","expo",e.updates.checkError.message);if(e.updates.downloadError)n("download-error","observed","expo",e.updates.downloadError.message);return a}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.configureOtaInspector=void 0;exports.createOtaStore=createOtaStore;exports.subscribeOta=exports.otaStore=exports.getOtaSnapshot=void 0;var _types=require("../types");var _sanitize=require("./sanitize");var _findings=require("./findings");const reasons={waiting:"Waiting for the app.",missing:"expo-updates is not installed.","native-missing":"Expo native code is missing. Build the app again.",disabled:"Updates are off in this build. Debug often loads Metro.",ready:null,unsupported:"Expo updates run on iOS and Android.","load-error":"The Expo SDK could not load."};function createOtaStore(R=u=>{const c=setTimeout(u,1e3);return()=>clearTimeout(c)}){let u=null;let c=0;let g;const b=()=>typeof __DEV__!=="undefined"&&__DEV__||l.allowActionsInRelease===true;let l={};let p=[];const U=new Set;let e={schemaVersion:1,capturedAt:new Date().toISOString(),status:"waiting",statusReason:reasons.waiting,running:{isEnabled:null,channel:null,runtimeVersion:null,updateId:null,createdAt:null,isEmbeddedLaunch:null,isEmergencyLaunch:null,emergencyLaunchReason:null,launchDuration:null,manifest:null},updates:{availableUpdate:null,downloadedUpdate:null,isUpdateAvailable:false,isUpdatePending:false,isChecking:false,isDownloading:false,isRestarting:false,isStartupProcedureRunning:false,downloadProgress:null,checkError:null,downloadError:null,lastCheckForUpdateTimeSinceRestart:null},config:{source:"unknown",updateUrl:null,requestHeaders:null,overrideSource:"unknown",override:null},expected:{},lastCheck:null,busy:null,actionError:null,findings:[],capabilities:{}};const m=t=>{for(const[s,n]of Object.entries(t||{}))if(s.toLowerCase()!=="expo-channel-name"&&n)p.push(n);p=[...new Set(p)].slice(-128)};function h(){const t={check:u?.checkForUpdateAsync,fetch:u?.fetchUpdateAsync,reload:u?.reloadAsync,setHeaders:u?.setUpdateRequestHeadersOverride,setURL:u?.setUpdateURLAndRequestHeadersOverride};const s=e.busy||e.updates.isChecking||e.updates.isDownloading||e.updates.isRestarting||e.updates.isStartupProcedureRunning;const n=Object.fromEntries(_types.OTA_ACTIONS.map(o=>{let d=null;if(o!=="getState"&&o!=="setExpected"){if(!b())d="This app has not opted in to release actions.";else if(e.status!=="ready")d=e.statusReason;else if(s)d="Wait for the current step to end.";else if(typeof t[o]!=="function")d="This SDK has no such action.";else if(o==="reload"&&!e.updates.isUpdatePending)d="Fetch an update first.";else if(o==="setURL"&&(!l.allowURLOverride||l.config?.disableAntiBrickingMeasures!==true))d="This build has not opted in to URL changes."}return[o,{enabled:!d,reason:d}]}));e={...e,capturedAt:new Date().toISOString(),capabilities:n};e.findings=(0,_findings.findings)(e);for(const o of U)o()}function y(t){l={...l,...t};if(!b()&&e.busy==="reload"){c++;g?.();g=void 0;e={...e,busy:null,actionError:{name:"Error",message:"Reload was stopped."}}}m(l.config?.requestHeaders);e={...e,expected:{runtimeVersion:(0,_sanitize.str)(l.expected?.runtimeVersion)||void 0,channel:(0,_sanitize.str)(l.expected?.channel)||void 0},config:{...e.config,source:l.config?"app-config":"unknown",updateUrl:(0,_sanitize.safeURL)(l.config?.updateUrl),requestHeaders:(0,_sanitize.headers)(l.config?.requestHeaders)}};h()}const v=e.updates;function S(t,s){c++;g?.();g=void 0;u=t;const n=s||(t?t.isEnabled&&!t.isDevelopmentLaunch?"ready":"disabled":"missing");e={...e,busy:null,actionError:null,lastCheck:null,updates:v,status:n,statusReason:reasons[n],running:{isEnabled:(0,_sanitize.bool)(t?.isEnabled),channel:(0,_sanitize.str)(t?.channel),runtimeVersion:(0,_sanitize.str)(t?.runtimeVersion),updateId:(0,_sanitize.str)(t?.updateId),createdAt:(0,_sanitize.iso)(t?.createdAt),isEmbeddedLaunch:(0,_sanitize.bool)(t?.isEmbeddedLaunch),isEmergencyLaunch:(0,_sanitize.bool)(t?.isEmergencyLaunch),emergencyLaunchReason:(0,_sanitize.safeText)(t?.emergencyLaunchReason,p),launchDuration:(0,_sanitize.num)(t?.launchDuration),manifest:(0,_sanitize.manifest)(t?.manifest)}};h()}function O(t){const s=(0,_sanitize.record)(t);e={...e,updates:{availableUpdate:(0,_sanitize.candidate)(s.availableUpdate),downloadedUpdate:(0,_sanitize.candidate)(s.downloadedUpdate),isUpdateAvailable:s.isUpdateAvailable===true,isUpdatePending:s.isUpdatePending===true,isChecking:s.isChecking===true,isDownloading:s.isDownloading===true,isRestarting:s.isRestarting===true,isStartupProcedureRunning:s.isStartupProcedureRunning===true,downloadProgress:(0,_sanitize.num)(s.downloadProgress),checkError:(0,_sanitize.error)(s.checkError,p),downloadError:(0,_sanitize.error)(s.downloadError,p),lastCheckForUpdateTimeSinceRestart:(0,_sanitize.iso)(s.lastCheckForUpdateTimeSinceRestart)}};h()}function E(t){if(t===null)return null;if(!t||typeof t!=="object"||Array.isArray(t))throw new Error("Pass a full header map or null.");const s=Object.entries(t);if(s.length>32)throw new Error("Use at most 32 headers.");for(const[n,o]of s){if(!/^[A-Za-z0-9-]{1,80}$/.test(n)||typeof o!=="string"||o.length>4096||/[\r\n]/.test(o))throw new Error("Use valid header names and text values.")}if(s.reduce((n,[o,d])=>n+o.length+d.length,0)>16384)throw new Error("Keep the full header map under 16K chars.");return Object.fromEntries(s)}async function A(t,s){if(!_types.OTA_ACTIONS.includes(t))throw new Error("Unknown OTA action.");if(s!==void 0&&(!s||typeof s!=="object"||Array.isArray(s)))throw new Error("Pass an object for action params.");const n=(0,_sanitize.record)(s);const o={getState:[],check:[],fetch:[],reload:["expectedType","expectedUpdateId"],setHeaders:["requestHeaders"],setURL:["configOverride"],setExpected:["channel","runtimeVersion"]};if(Object.keys(n).some(r=>!o[t].includes(r)))throw new Error("Unknown action param.");if(t==="getState")return e;if(!e.capabilities[t]?.enabled)throw new Error(e.capabilities[t]?.reason||"This action is off.");if(t==="setExpected"){for(const r of Object.keys(n))if(!["channel","runtimeVersion"].includes(r))throw new Error("Use channel or runtimeVersion.");for(const r of Object.values(n))if(typeof r!=="string"||r.length>128)throw new Error("Use target text under 129 chars.");y({expected:n});return e}const d=u;const w=c;const k=()=>{if(w!==c)throw new Error("The tool stopped. Try again.")};e={...e,busy:t,actionError:null};h();try{if(t==="check"){const r=(0,_sanitize.record)(await d.checkForUpdateAsync());k();e={...e,lastCheck:{isAvailable:r.isAvailable===true,isRollBackToEmbedded:r.isRollBackToEmbedded===true,reason:(0,_sanitize.safeText)(r.reason,p)},updates:{...e.updates,checkError:null,lastCheckForUpdateTimeSinceRestart:new Date().toISOString(),isUpdateAvailable:r.isAvailable===true||r.isRollBackToEmbedded===true,availableUpdate:r.isRollBackToEmbedded===true?{type:"rollback",createdAt:null}:(0,_sanitize.candidate)(r.manifest)}}}else if(t==="fetch"){const r=(0,_sanitize.record)(await d.fetchUpdateAsync());k();const a=r.isNew===true||r.isRollBackToEmbedded===true;e={...e,updates:{...e.updates,downloadError:null,isUpdatePending:a||e.updates.isUpdatePending,downloadedUpdate:r.isRollBackToEmbedded===true?{type:"rollback",createdAt:null}:(0,_sanitize.candidate)(r.manifest)||e.updates.downloadedUpdate}}}else if(t==="reload"){const r=e.updates.downloadedUpdate;if(!e.updates.isUpdatePending||!r||n.expectedType!==r.type||r.type==="new"&&(!r.updateId||n.expectedUpdateId!==r.updateId))throw new Error("The pending update changed. Read it and try again.");g=R(()=>{g=void 0;if(w!==c)return;const a=f=>{if(w!==c)return;e={...e,busy:null,actionError:(0,_sanitize.error)(f,p)};h()};const i=e.updates.downloadedUpdate;if(!b()||!e.updates.isUpdatePending||i?.type!==r.type||i.type==="new"&&r.type==="new"&&i.updateId!==r.updateId){a(new Error("The pending update or app opt-in changed. Try again."));return}try{void d.reloadAsync().catch(a)}catch(f){a(f)}});return{accepted:true,expectedType:r.type,expectedUpdateId:r.type==="new"?r.updateId:null}}else if(t==="setHeaders"){const r=E(n.requestHeaders);if(r&&l.config?.requestHeaders){const a=new Set(Object.keys(l.config.requestHeaders).map(i=>i.toLowerCase()));if(Object.keys(r).some(i=>!a.has(i.toLowerCase())))throw new Error("Each header key must exist in the native build.")}m(r);d.setUpdateRequestHeadersOverride(r);e={...e,config:{...e.config,overrideSource:"session-write",override:{...e.config.override,requestHeaders:r?(0,_sanitize.headers)(r):void 0}}}}else if(t==="setURL"){const r=n.configOverride;let a=null;if(r!==null){const i=(0,_sanitize.record)(r);if(Object.keys(i).some(T=>!["updateUrl","requestHeaders"].includes(T)))throw new Error("Use updateUrl and requestHeaders.");if(typeof i.updateUrl!=="string"||i.updateUrl.length>2048)throw new Error("Pass an update URL or null.");const f=new URL(i.updateUrl);if(!["https:","http:"].includes(f.protocol)||f.username||f.password)throw new Error("Use an HTTP URL with no user or password.");if(f.protocol==="http:"&&!["127.0.0.1","localhost","[::1]"].includes(f.hostname))throw new Error("Use HTTPS outside localhost.");a={updateUrl:i.updateUrl,requestHeaders:E(i.requestHeaders)||{}}}m(a?.requestHeaders);d.setUpdateURLAndRequestHeadersOverride(a);e={...e,config:{...e.config,overrideSource:"session-write",override:a?{updateUrl:(0,_sanitize.safeURL)(a.updateUrl),requestHeaders:(0,_sanitize.headers)(a.requestHeaders)}:null}}}e={...e,busy:null};h();return e}catch(r){const a=(0,_sanitize.error)(r,p)||{name:"Error",message:"The call failed."};if(w!==c)throw new Error(a.message);e={...e,busy:null,actionError:a,updates:{...e.updates,...t==="check"?{checkError:a}:t==="fetch"?{downloadError:a}:{}}};h();throw new Error(a.message)}}h();return{configure:y,attach:S,ingest:O,act:A,getSnapshot:()=>e,subscribe:t=>{U.add(t);return()=>{U.delete(t)}}}}const otaStore=exports.otaStore=createOtaStore();const configureOtaInspector=exports.configureOtaInspector=otaStore.configure;const getOtaSnapshot=exports.getOtaSnapshot=otaStore.getSnapshot;const subscribeOta=exports.subscribeOta=otaStore.subscribe;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.bool=void 0;exports.candidate=candidate;exports.error=error;exports.headers=headers;exports.iso=iso;exports.manifest=manifest;exports.record=exports.num=void 0;exports.safeText=safeText;exports.safeURL=safeURL;exports.str=void 0;const record=e=>e&&typeof e==="object"&&!Array.isArray(e)?e:{};exports.record=record;const str=e=>typeof e==="string"?e.slice(0,512):null;exports.str=str;const bool=e=>typeof e==="boolean"?e:null;exports.bool=bool;const num=e=>typeof e==="number"&&Number.isFinite(e)?e:null;exports.num=num;function iso(e){if(!(e instanceof Date)&&typeof e!=="string"&&typeof e!=="number")return null;const t=new Date(e);return Number.isFinite(t.getTime())?t.toISOString():null}function safeURL(e){if(typeof e!=="string")return null;try{const t=new URL(e);t.username="";t.password="";t.search="";t.hash="";return t.toString().slice(0,512)}catch{return"[hidden URL]"}}function headers(e){if(!e||typeof e!=="object")return null;return Object.fromEntries(Object.entries(record(e)).slice(0,32).map(([t,r])=>[t.slice(0,80),t.toLowerCase()==="expo-channel-name"?str(r)||"":"[hidden]"]))}function safeText(e,t=[]){if(typeof e!=="string")return null;let r=e;for(const n of t)if(n)r=r.split(n).join("[hidden]");return r.replace(/https?:\/\/[^\s"']+/g,n=>safeURL(n)||"[hidden URL]").replace(/(bearer\s+)[^\s,;]+/gi,"$1[hidden]").replace(/((?:token|secret|password|authorization|api[-_]?key)\s*[:=]\s*)[^\s,;}]+/gi,"$1[hidden]").slice(0,512)}function error(e,t=[]){if(!e)return null;const r=record(e);return{name:safeText(r.name,t)||"Error",message:safeText(typeof e==="string"?e:r.message,t)||"The call failed."}}function manifest(e){if(!e||!Object.keys(record(e)).length)return null;const t=record(e);return{id:str(t.id),createdAt:iso(t.createdAt),runtimeVersion:str(t.runtimeVersion),assetCount:Array.isArray(t.assets)?t.assets.length:null,launchAsset:safeURL(record(t.launchAsset).url)}}function candidate(e){const t=record(e);if(t.type==="rollback")return{type:"rollback",createdAt:iso(t.createdAt)};const r=manifest(t.manifest??e);return r?{type:"new",updateId:str(t.updateId)||r.id,createdAt:iso(t.createdAt)||r.createdAt,runtimeVersion:r.runtimeVersion,manifest:r}:null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _exportNames={OtaInspectorRoot:true,configureOtaInspector:true,getOtaSnapshot:true,subscribeOta:true,otaInspectorSyncAdapter:true,OtaToolView:true,otaInspectorToolPreset:true,createOtaInspectorTool:true,OtaInspectorIcon:true,OTA_INSPECTOR_ICON_COLOR:true};Object.defineProperty(exports,"OTA_INSPECTOR_ICON_COLOR",{enumerable:true,get:function(){return _sharedUi.OTA_INSPECTOR_ICON_COLOR}});Object.defineProperty(exports,"OtaInspectorIcon",{enumerable:true,get:function(){return _sharedUi.OtaInspectorIcon}});Object.defineProperty(exports,"OtaInspectorRoot",{enumerable:true,get:function(){return _OtaInspectorRoot.OtaInspectorRoot}});Object.defineProperty(exports,"OtaToolView",{enumerable:true,get:function(){return _OtaToolView.OtaToolView}});Object.defineProperty(exports,"configureOtaInspector",{enumerable:true,get:function(){return _otaStore.configureOtaInspector}});Object.defineProperty(exports,"createOtaInspectorTool",{enumerable:true,get:function(){return _preset.createOtaInspectorTool}});Object.defineProperty(exports,"getOtaSnapshot",{enumerable:true,get:function(){return _otaStore.getOtaSnapshot}});Object.defineProperty(exports,"otaInspectorSyncAdapter",{enumerable:true,get:function(){return _otaInspectorSyncAdapter.otaInspectorSyncAdapter}});Object.defineProperty(exports,"otaInspectorToolPreset",{enumerable:true,get:function(){return _preset.otaInspectorToolPreset}});Object.defineProperty(exports,"subscribeOta",{enumerable:true,get:function(){return _otaStore.subscribeOta}});var _types=require("./types");Object.keys(_types).forEach(function(e){if(e==="default"||e==="__esModule")return;if(Object.prototype.hasOwnProperty.call(_exportNames,e))return;if(e in exports&&exports[e]===_types[e])return;Object.defineProperty(exports,e,{enumerable:true,get:function(){return _types[e]}})});var _OtaInspectorRoot=require("./OtaInspectorRoot");var _otaStore=require("./engine/otaStore");var _otaInspectorSyncAdapter=require("./sync/otaInspectorSyncAdapter");var _OtaToolView=require("./components/OtaToolView");var _preset=require("./preset");var _sharedUi=require("@buoy-gg/shared-ui");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _exportNames={OtaToolView:true,OtaInspectorIcon:true,OTA_INSPECTOR_ICON_COLOR:true};Object.defineProperty(exports,"OTA_INSPECTOR_ICON_COLOR",{enumerable:true,get:function(){return _sharedUi.OTA_INSPECTOR_ICON_COLOR}});Object.defineProperty(exports,"OtaInspectorIcon",{enumerable:true,get:function(){return _sharedUi.OtaInspectorIcon}});Object.defineProperty(exports,"OtaToolView",{enumerable:true,get:function(){return _OtaToolView.OtaToolView}});var _types=require("./types");Object.keys(_types).forEach(function(e){if(e==="default"||e==="__esModule")return;if(Object.prototype.hasOwnProperty.call(_exportNames,e))return;if(e in exports&&exports[e]===_types[e])return;Object.defineProperty(exports,e,{enumerable:true,get:function(){return _types[e]}})});var _OtaToolView=require("./components/OtaToolView");var _sharedUi=require("@buoy-gg/shared-ui");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.otaInspectorToolPreset=exports.createOtaInspectorTool=void 0;var _react=_interopRequireDefault(require("react"));var _sharedUi=require("@buoy-gg/shared-ui");var _OtaBody=require("./components/OtaBody");var _jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const otaInspectorToolPreset=exports.otaInspectorToolPreset=(0,_sharedUi.defineToolPreset)({id:"ota-update-inspector",name:"OTA UPDATES",description:"See which Expo update runs and apply a new one",slot:"both",color:_sharedUi.OTA_INSPECTOR_ICON_COLOR,icon:({size:e,color:o})=>(0,_jsxRuntime.jsx)(_sharedUi.OtaInspectorIcon,{size:e,color:o}),component:_OtaBody.OtaBody,modal:{subtitle:"which update runs on this app"}});const createOtaInspectorTool=exports.createOtaInspectorTool=(0,_sharedUi.createToolFactory)(otaInspectorToolPreset);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.otaInspectorSyncAdapter=void 0;var _license=require("@buoy-gg/license");var _types=require("../types");var _otaStore=require("../engine/otaStore");const otaInspectorSyncAdapter=exports.otaInspectorSyncAdapter={version:1,getSnapshot:_otaStore.otaStore.getSnapshot,subscribe:_otaStore.otaStore.subscribe,actions:Object.fromEntries(_types.OTA_ACTIONS.map(e=>[e,r=>{if(!(0,_license.isPro)())throw new Error("OTA Inspector needs Buoy Pro.");return _otaStore.otaStore.act(e,r)}]))};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.OTA_ACTIONS=void 0;const OTA_ACTIONS=exports.OTA_ACTIONS=["getState","check","fetch","reload","setHeaders","setURL","setExpected"];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import l,{useEffect as o,useState as a,memo as n}from"react";import{loadExpoSDK as u}from"./engine/expoSDK";import{otaStore as r}from"./engine/otaStore";import{jsx as i}from"react/jsx-runtime";const d=n(function t({sdk:e}){const s=e.useUpdates();o(()=>{r.attach(e);return()=>r.attach(null,"waiting")},[e]);o(()=>{r.ingest(s)},[s]);return null});export function OtaInspectorRoot(){const[t,e]=a(null);o(()=>{e(u())},[]);o(()=>{if(!t||t.sdk?.useUpdates)return;r.attach(t.sdk,t.status||"load-error");return()=>r.attach(null,"waiting")},[t]);return t?.sdk?.useUpdates?i(d,{sdk:t.sdk}):null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import m,{useSyncExternalStore as s}from"react";import{FeatureGate as n}from"@buoy-gg/shared-ui";import{otaStore as t}from"../engine/otaStore";import{otaInspectorSyncAdapter as p}from"../sync/otaInspectorSyncAdapter";import{OtaToolView as c}from"./OtaToolView";import{jsx as o}from"react/jsx-runtime";export function OtaBody(){const r=s(t.subscribe,t.getSnapshot,t.getSnapshot);return o(n,{featureName:"OTA Update Inspector",children:o(c,{snapshot:r,onAction:async(e,a)=>p.actions[e](a)})})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import $,{useState as u}from"react";import{Platform as J,ScrollView as V,StyleSheet as q,Text as i,TextInput as z,View as c}from"react-native";import{NightButton as b,NightCard as E,NightFootnote as r,NightSectionLabel as f,night as h}from"@buoy-gg/shared-ui";import{jsx as e,jsxs as s}from"react/jsx-runtime";const H=t=>t==null?"Unknown":typeof t==="object"?JSON.stringify(t,null,2):String(t);export function OtaToolView({snapshot:t,onAction:m,offline:o=false}){const[w,C]=u(null);const[y,x]=u(null);const[k,N]=u(false);const[S,P]=u("");const[R,O]=u("");const[I,F]=u("");const[L,A]=u("{}");const T=async(l,d)=>{x(null);C(null);try{if(o)throw new Error("The app is offline. Connect it first.");await m(l,d)}catch(v){C(v instanceof Error?v.message:"The call failed.")}};if(!t)return e(r,{children:"Waiting for the app\u2026"});const p=(l,d,v,W=false)=>s(c,{style:n.gap,children:[e(b,{testID:`ota-${l}${d.startsWith("Clear")?"-clear":""}`,label:d,disabled:o||!t.capabilities[l].enabled,onPress:()=>W?x({action:l,params:v}):void T(l,v)}),t.capabilities[l].reason?e(r,{children:t.capabilities[l].reason}):null]},d);const g=t.updates.downloadedUpdate;const j=()=>{const l=JSON.parse(L);if(!l||typeof l!=="object"||Array.isArray(l))throw new Error("Use a JSON header map.");return l};const D=l=>{try{const d=j();C(null);x({action:l,params:l==="setHeaders"?{requestHeaders:d}:{configOverride:{updateUrl:I,requestHeaders:d}}})}catch{C("Use a JSON header map.")}};return e(V,{style:{flex:1},testID:"ota-scroll",keyboardShouldPersistTaps:"handled",children:s(c,{style:n.content,children:[e(i,{style:n.title,children:"OTA Update Inspector"}),e(i,{style:n.text,testID:"ota-status",children:t.status}),o?e(r,{tone:"warning",children:"Offline. This is the last saved view."}):null,t.statusReason?e(r,{children:t.statusReason}):null,w||t.actionError?e(i,{style:n.error,testID:"ota-error",children:w||t.actionError?.message}):null,e(f,{children:"What runs now"}),e(E,{children:s(c,{style:n.card,children:[e(a,{label:"Expo isEnabled",value:t.running.isEnabled}),e(a,{label:"Update ID",value:t.running.updateId,id:"ota-running-id"}),e(a,{label:"Built in",value:t.running.isEmbeddedLaunch,id:"ota-embedded"}),e(a,{label:"Channel",value:t.running.channel}),e(a,{label:"Runtime",value:t.running.runtimeVersion,id:"ota-runtime"}),e(a,{label:"Launch time (ms)",value:t.running.launchDuration}),e(a,{label:"Emergency launch",value:t.running.isEmergencyLaunch}),t.running.emergencyLaunchReason?e(a,{label:"Launch fault",value:t.running.emergencyLaunchReason}):null]})}),e(f,{children:"Why did it not run?"}),t.findings.length?t.findings.map(l=>s(c,{children:[e(i,{style:n.text,testID:`ota-finding-${l.code}`,children:l.message}),s(i,{style:n.hint,children:[l.kind," \xB7 ",l.source]})]},l.code)):e(r,{children:"No fault found from these facts."}),e(f,{children:"Next update"}),e(a,{label:"Found",value:t.updates.availableUpdate,id:"ota-found"}),e(a,{label:"Saved",value:g,id:"ota-pending-detail"}),e(a,{label:"Ready to apply",value:t.updates.isUpdatePending,id:"ota-pending"}),e(a,{label:"Now",value:t.busy||(t.updates.isChecking?"Checking":t.updates.isDownloading?"Fetching":"Idle")}),e(a,{label:"Fetch progress",value:t.updates.downloadProgress==null?null:`${Math.round(t.updates.downloadProgress*100)}%`}),e(a,{label:"Last check",value:t.updates.lastCheckForUpdateTimeSinceRestart}),t.lastCheck?.reason?e(a,{label:"Check result",value:t.lastCheck.reason}):null,t.updates.checkError?e(a,{label:"Check fault",value:t.updates.checkError.message}):null,t.updates.downloadError?e(a,{label:"Fetch fault",value:t.updates.downloadError.message}):null,p("check","Check now"),p("fetch","Fetch update"),p("reload",g?.type==="rollback"?"Apply server rollback":"Reload to apply",{expectedType:g?.type,expectedUpdateId:g?.type==="new"?g.updateId:void 0},true),e(r,{children:"Reload restarts the app. Unsaved work may be lost."}),y?e(E,{children:s(c,{style:n.card,testID:"ota-confirm",children:[e(i,{style:n.text,children:y.action==="reload"?"Apply this saved update and restart?":"Save this change? It lasts through app restarts."}),e(r,{children:y.action==="reload"?H(g):"This sends the full header map. Left out keys will be cleared."}),e(b,{label:"Apply",testID:"ota-confirm-apply",onPress:()=>void T(y.action,y.params)}),e(b,{label:"Cancel",testID:"ota-confirm-cancel",onPress:()=>x(null)})]})}):null,e(b,{label:k?"Hide details":"Show details",testID:"ota-details",onPress:()=>N(!k)}),k?s(c,{style:n.gap,children:[e(a,{label:"Created at",value:t.running.createdAt}),e(a,{label:"Manifest summary",value:t.running.manifest}),e(f,{children:"Config hints"}),e(r,{children:"These are app hints, not a native readback. Secrets are hidden. Prior saved changes may be unknown."}),e(a,{label:"Hint source",value:t.config.source}),e(a,{label:"Update URL",value:t.config.updateUrl}),e(a,{label:"Headers",value:t.config.requestHeaders}),e(a,{label:"Last write source",value:t.config.overrideSource}),e(a,{label:"Last write",value:t.config.override}),e(f,{children:"Compare a target"}),e(U,{label:"Target runtime",value:S,set:P,id:"ota-target-runtime"}),e(U,{label:"Target channel",value:R,set:O,id:"ota-target-channel"}),p("setExpected","Compare",{runtimeVersion:S,channel:R}),e(f,{children:"Change the source"}),e(r,{children:"Use a full header map. Keys must exist in the build. Clearing a change restores the build config."}),e(U,{label:"Headers (JSON)",value:L,set:A,id:"ota-headers"}),e(b,{label:"Set headers",testID:"ota-setHeaders",disabled:o||!t.capabilities.setHeaders.enabled,onPress:()=>D("setHeaders")}),p("setHeaders","Clear header change",{requestHeaders:null},true),e(U,{label:"Update URL",value:I,set:F,id:"ota-url"}),e(b,{label:"Set URL",testID:"ota-setURL",disabled:o||!t.capabilities.setURL.enabled,onPress:()=>D("setURL")}),p("setURL","Clear URL change",{configOverride:null},true),e(r,{children:"URL changes need an opted in test build."})]}):null]})})}function a({label:t,value:m,id:o}){return s(c,{style:n.gap,children:[e(i,{style:n.hint,children:t}),e(i,{selectable:true,style:n.text,testID:o,children:H(m)})]})}function U({label:t,value:m,set:o,id:w}){return s(c,{children:[e(i,{style:n.hint,children:t}),e(z,{style:n.input,testID:w,accessibilityLabel:t,value:m,onChangeText:o,autoCapitalize:"none",autoCorrect:false,spellCheck:false,smartInsertDelete:false,keyboardType:J.OS==="ios"?"ascii-capable":"default"})]})}const n=q.create({content:{padding:16,paddingBottom:48,gap:14},title:{color:h.color.text,fontSize:22,fontWeight:"600"},text:{color:h.color.text,fontSize:14},hint:{color:h.color.textSecondary,fontSize:12},error:{color:h.color.danger},card:{padding:14,gap:12},gap:{gap:6},input:{color:h.color.text,backgroundColor:h.color.bg,borderColor:h.color.border,borderWidth:1,borderRadius:8,padding:10}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function classifyLoadError(e){const t=e instanceof Error?e.message:String(e);if(/Cannot find native module.*ExpoUpdates|ExpoUpdates.*not.*found/i.test(t))return"native-missing";if(/Cannot find module ['"]expo-updates['"]|Unable to resolve module expo-updates|Requiring unknown module.*expo-updates/i.test(t))return"missing";return"load-error"}function n(){const e=globalThis.expo?.modules;return!!e?.ExpoUpdates}export function loadExpoSDK(){if(!n())return{sdk:null,status:"native-missing"};try{const e=require("expo-updates");return{sdk:{...e,isDevelopmentLaunch:typeof __DEV__!=="undefined"&&__DEV__&&!e.updateId}}}catch(e){return{sdk:null,status:classifyLoadError(e)}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function loadExpoSDK(){return{sdk:null,status:"unsupported"}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function findings(e){const a=[];const n=(i,o,c,s)=>a.push({code:i,kind:o,source:c,message:s});if(e.status!=="ready")n(e.status,"observed","expo",e.statusReason||"Waiting for the app.");if(e.updates.isUpdatePending)n("pending","observed","expo","The update is fetched. Reload lets Expo choose what runs.");if(e.running.isEmergencyLaunch)n("emergency","observed","expo",e.running.emergencyLaunchReason||"Expo used a safe launch. Read the app logs.");const r=e.expected.runtimeVersion||(e.updates.availableUpdate?.type==="new"?e.updates.availableUpdate.runtimeVersion:null);if(r&&e.running.runtimeVersion&&r!==e.running.runtimeVersion){n("runtime-mismatch","comparison",e.expected.runtimeVersion?"user":"expo",`This build uses ${e.running.runtimeVersion}. The target uses ${r}. They must match.`)}else if(!r)n("runtime-check","check","user","Check that the update uses this build's runtime.");const t=e.running.channel;if(e.expected.channel&&t&&t!==e.expected.channel)n("channel-mismatch","comparison","user",`The running channel is ${t}. The target is ${e.expected.channel}. Check both.`);else if(!e.expected.channel||!t)n("channel-check","check","user","Check the channel set in the build and server.");if(e.lastCheck?.reason)n("check-reason","observed","expo",`Expo reports: ${e.lastCheck.reason}`);if(e.updates.checkError)n("check-error","observed","expo",e.updates.checkError.message);if(e.updates.downloadError)n("download-error","observed","expo",e.updates.downloadError.message);return a}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{OTA_ACTIONS as H}from"../types";import{record as w,str as m,bool as v,num as L,iso as q,safeURL as P,headers as A,safeText as D,error as b,manifest as F,candidate as y}from"./sanitize";import{findings as K}from"./findings";const I={waiting:"Waiting for the app.",missing:"expo-updates is not installed.","native-missing":"Expo native code is missing. Build the app again.",disabled:"Updates are off in this build. Debug often loads Metro.",ready:null,unsupported:"Expo updates run on iOS and Android.","load-error":"The Expo SDK could not load."};export function createOtaStore(x=u=>{const c=setTimeout(u,1e3);return()=>clearTimeout(c)}){let u=null;let c=0;let g;const E=()=>typeof __DEV__!=="undefined"&&__DEV__||l.allowActionsInRelease===true;let l={};let p=[];const k=new Set;let e={schemaVersion:1,capturedAt:new Date().toISOString(),status:"waiting",statusReason:I.waiting,running:{isEnabled:null,channel:null,runtimeVersion:null,updateId:null,createdAt:null,isEmbeddedLaunch:null,isEmergencyLaunch:null,emergencyLaunchReason:null,launchDuration:null,manifest:null},updates:{availableUpdate:null,downloadedUpdate:null,isUpdateAvailable:false,isUpdatePending:false,isChecking:false,isDownloading:false,isRestarting:false,isStartupProcedureRunning:false,downloadProgress:null,checkError:null,downloadError:null,lastCheckForUpdateTimeSinceRestart:null},config:{source:"unknown",updateUrl:null,requestHeaders:null,overrideSource:"unknown",override:null},expected:{},lastCheck:null,busy:null,actionError:null,findings:[],capabilities:{}};const R=t=>{for(const[n,s]of Object.entries(t||{}))if(n.toLowerCase()!=="expo-channel-name"&&s)p.push(s);p=[...new Set(p)].slice(-128)};function h(){const t={check:u?.checkForUpdateAsync,fetch:u?.fetchUpdateAsync,reload:u?.reloadAsync,setHeaders:u?.setUpdateRequestHeadersOverride,setURL:u?.setUpdateURLAndRequestHeadersOverride};const n=e.busy||e.updates.isChecking||e.updates.isDownloading||e.updates.isRestarting||e.updates.isStartupProcedureRunning;const s=Object.fromEntries(H.map(o=>{let d=null;if(o!=="getState"&&o!=="setExpected"){if(!E())d="This app has not opted in to release actions.";else if(e.status!=="ready")d=e.statusReason;else if(n)d="Wait for the current step to end.";else if(typeof t[o]!=="function")d="This SDK has no such action.";else if(o==="reload"&&!e.updates.isUpdatePending)d="Fetch an update first.";else if(o==="setURL"&&(!l.allowURLOverride||l.config?.disableAntiBrickingMeasures!==true))d="This build has not opted in to URL changes."}return[o,{enabled:!d,reason:d}]}));e={...e,capturedAt:new Date().toISOString(),capabilities:s};e.findings=K(e);for(const o of k)o()}function S(t){l={...l,...t};if(!E()&&e.busy==="reload"){c++;g?.();g=void 0;e={...e,busy:null,actionError:{name:"Error",message:"Reload was stopped."}}}R(l.config?.requestHeaders);e={...e,expected:{runtimeVersion:m(l.expected?.runtimeVersion)||void 0,channel:m(l.expected?.channel)||void 0},config:{...e.config,source:l.config?"app-config":"unknown",updateUrl:P(l.config?.updateUrl),requestHeaders:A(l.config?.requestHeaders)}};h()}const C=e.updates;function j(t,n){c++;g?.();g=void 0;u=t;const s=n||(t?t.isEnabled&&!t.isDevelopmentLaunch?"ready":"disabled":"missing");e={...e,busy:null,actionError:null,lastCheck:null,updates:C,status:s,statusReason:I[s],running:{isEnabled:v(t?.isEnabled),channel:m(t?.channel),runtimeVersion:m(t?.runtimeVersion),updateId:m(t?.updateId),createdAt:q(t?.createdAt),isEmbeddedLaunch:v(t?.isEmbeddedLaunch),isEmergencyLaunch:v(t?.isEmergencyLaunch),emergencyLaunchReason:D(t?.emergencyLaunchReason,p),launchDuration:L(t?.launchDuration),manifest:F(t?.manifest)}};h()}function V(t){const n=w(t);e={...e,updates:{availableUpdate:y(n.availableUpdate),downloadedUpdate:y(n.downloadedUpdate),isUpdateAvailable:n.isUpdateAvailable===true,isUpdatePending:n.isUpdatePending===true,isChecking:n.isChecking===true,isDownloading:n.isDownloading===true,isRestarting:n.isRestarting===true,isStartupProcedureRunning:n.isStartupProcedureRunning===true,downloadProgress:L(n.downloadProgress),checkError:b(n.checkError,p),downloadError:b(n.downloadError,p),lastCheckForUpdateTimeSinceRestart:q(n.lastCheckForUpdateTimeSinceRestart)}};h()}function T(t){if(t===null)return null;if(!t||typeof t!=="object"||Array.isArray(t))throw new Error("Pass a full header map or null.");const n=Object.entries(t);if(n.length>32)throw new Error("Use at most 32 headers.");for(const[s,o]of n){if(!/^[A-Za-z0-9-]{1,80}$/.test(s)||typeof o!=="string"||o.length>4096||/[\r\n]/.test(o))throw new Error("Use valid header names and text values.")}if(n.reduce((s,[o,d])=>s+o.length+d.length,0)>16384)throw new Error("Keep the full header map under 16K chars.");return Object.fromEntries(n)}async function _(t,n){if(!H.includes(t))throw new Error("Unknown OTA action.");if(n!==void 0&&(!n||typeof n!=="object"||Array.isArray(n)))throw new Error("Pass an object for action params.");const s=w(n);const o={getState:[],check:[],fetch:[],reload:["expectedType","expectedUpdateId"],setHeaders:["requestHeaders"],setURL:["configOverride"],setExpected:["channel","runtimeVersion"]};if(Object.keys(s).some(r=>!o[t].includes(r)))throw new Error("Unknown action param.");if(t==="getState")return e;if(!e.capabilities[t]?.enabled)throw new Error(e.capabilities[t]?.reason||"This action is off.");if(t==="setExpected"){for(const r of Object.keys(s))if(!["channel","runtimeVersion"].includes(r))throw new Error("Use channel or runtimeVersion.");for(const r of Object.values(s))if(typeof r!=="string"||r.length>128)throw new Error("Use target text under 129 chars.");S({expected:s});return e}const d=u;const U=c;const O=()=>{if(U!==c)throw new Error("The tool stopped. Try again.")};e={...e,busy:t,actionError:null};h();try{if(t==="check"){const r=w(await d.checkForUpdateAsync());O();e={...e,lastCheck:{isAvailable:r.isAvailable===true,isRollBackToEmbedded:r.isRollBackToEmbedded===true,reason:D(r.reason,p)},updates:{...e.updates,checkError:null,lastCheckForUpdateTimeSinceRestart:new Date().toISOString(),isUpdateAvailable:r.isAvailable===true||r.isRollBackToEmbedded===true,availableUpdate:r.isRollBackToEmbedded===true?{type:"rollback",createdAt:null}:y(r.manifest)}}}else if(t==="fetch"){const r=w(await d.fetchUpdateAsync());O();const a=r.isNew===true||r.isRollBackToEmbedded===true;e={...e,updates:{...e.updates,downloadError:null,isUpdatePending:a||e.updates.isUpdatePending,downloadedUpdate:r.isRollBackToEmbedded===true?{type:"rollback",createdAt:null}:y(r.manifest)||e.updates.downloadedUpdate}}}else if(t==="reload"){const r=e.updates.downloadedUpdate;if(!e.updates.isUpdatePending||!r||s.expectedType!==r.type||r.type==="new"&&(!r.updateId||s.expectedUpdateId!==r.updateId))throw new Error("The pending update changed. Read it and try again.");g=x(()=>{g=void 0;if(U!==c)return;const a=f=>{if(U!==c)return;e={...e,busy:null,actionError:b(f,p)};h()};const i=e.updates.downloadedUpdate;if(!E()||!e.updates.isUpdatePending||i?.type!==r.type||i.type==="new"&&r.type==="new"&&i.updateId!==r.updateId){a(new Error("The pending update or app opt-in changed. Try again."));return}try{void d.reloadAsync().catch(a)}catch(f){a(f)}});return{accepted:true,expectedType:r.type,expectedUpdateId:r.type==="new"?r.updateId:null}}else if(t==="setHeaders"){const r=T(s.requestHeaders);if(r&&l.config?.requestHeaders){const a=new Set(Object.keys(l.config.requestHeaders).map(i=>i.toLowerCase()));if(Object.keys(r).some(i=>!a.has(i.toLowerCase())))throw new Error("Each header key must exist in the native build.")}R(r);d.setUpdateRequestHeadersOverride(r);e={...e,config:{...e.config,overrideSource:"session-write",override:{...e.config.override,requestHeaders:r?A(r):void 0}}}}else if(t==="setURL"){const r=s.configOverride;let a=null;if(r!==null){const i=w(r);if(Object.keys(i).some(B=>!["updateUrl","requestHeaders"].includes(B)))throw new Error("Use updateUrl and requestHeaders.");if(typeof i.updateUrl!=="string"||i.updateUrl.length>2048)throw new Error("Pass an update URL or null.");const f=new URL(i.updateUrl);if(!["https:","http:"].includes(f.protocol)||f.username||f.password)throw new Error("Use an HTTP URL with no user or password.");if(f.protocol==="http:"&&!["127.0.0.1","localhost","[::1]"].includes(f.hostname))throw new Error("Use HTTPS outside localhost.");a={updateUrl:i.updateUrl,requestHeaders:T(i.requestHeaders)||{}}}R(a?.requestHeaders);d.setUpdateURLAndRequestHeadersOverride(a);e={...e,config:{...e.config,overrideSource:"session-write",override:a?{updateUrl:P(a.updateUrl),requestHeaders:A(a.requestHeaders)}:null}}}e={...e,busy:null};h();return e}catch(r){const a=b(r,p)||{name:"Error",message:"The call failed."};if(U!==c)throw new Error(a.message);e={...e,busy:null,actionError:a,updates:{...e.updates,...t==="check"?{checkError:a}:t==="fetch"?{downloadError:a}:{}}};h();throw new Error(a.message)}}h();return{configure:S,attach:j,ingest:V,act:_,getSnapshot:()=>e,subscribe:t=>{k.add(t);return()=>{k.delete(t)}}}}export const otaStore=createOtaStore();export const configureOtaInspector=otaStore.configure;export const getOtaSnapshot=otaStore.getSnapshot;export const subscribeOta=otaStore.subscribe;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export const record=e=>e&&typeof e==="object"&&!Array.isArray(e)?e:{};export const str=e=>typeof e==="string"?e.slice(0,512):null;export const bool=e=>typeof e==="boolean"?e:null;export const num=e=>typeof e==="number"&&Number.isFinite(e)?e:null;export function iso(e){if(!(e instanceof Date)&&typeof e!=="string"&&typeof e!=="number")return null;const t=new Date(e);return Number.isFinite(t.getTime())?t.toISOString():null}export function safeURL(e){if(typeof e!=="string")return null;try{const t=new URL(e);t.username="";t.password="";t.search="";t.hash="";return t.toString().slice(0,512)}catch{return"[hidden URL]"}}export function headers(e){if(!e||typeof e!=="object")return null;return Object.fromEntries(Object.entries(record(e)).slice(0,32).map(([t,r])=>[t.slice(0,80),t.toLowerCase()==="expo-channel-name"?str(r)||"":"[hidden]"]))}export function safeText(e,t=[]){if(typeof e!=="string")return null;let r=e;for(const n of t)if(n)r=r.split(n).join("[hidden]");return r.replace(/https?:\/\/[^\s"']+/g,n=>safeURL(n)||"[hidden URL]").replace(/(bearer\s+)[^\s,;]+/gi,"$1[hidden]").replace(/((?:token|secret|password|authorization|api[-_]?key)\s*[:=]\s*)[^\s,;}]+/gi,"$1[hidden]").slice(0,512)}export function error(e,t=[]){if(!e)return null;const r=record(e);return{name:safeText(r.name,t)||"Error",message:safeText(typeof e==="string"?e:r.message,t)||"The call failed."}}export function manifest(e){if(!e||!Object.keys(record(e)).length)return null;const t=record(e);return{id:str(t.id),createdAt:iso(t.createdAt),runtimeVersion:str(t.runtimeVersion),assetCount:Array.isArray(t.assets)?t.assets.length:null,launchAsset:safeURL(record(t.launchAsset).url)}}export function candidate(e){const t=record(e);if(t.type==="rollback")return{type:"rollback",createdAt:iso(t.createdAt)};const r=manifest(t.manifest??e);return r?{type:"new",updateId:str(t.updateId)||r.id,createdAt:iso(t.createdAt)||r.createdAt,runtimeVersion:r.runtimeVersion,manifest:r}:null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export*from"./types";export{OtaInspectorRoot}from"./OtaInspectorRoot";export{configureOtaInspector,getOtaSnapshot,subscribeOta}from"./engine/otaStore";export{otaInspectorSyncAdapter}from"./sync/otaInspectorSyncAdapter";export{OtaToolView}from"./components/OtaToolView";export{otaInspectorToolPreset,createOtaInspectorTool}from"./preset";export{OtaInspectorIcon,OTA_INSPECTOR_ICON_COLOR}from"@buoy-gg/shared-ui";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export*from"./types";export{OtaToolView}from"./components/OtaToolView";export{OtaInspectorIcon,OTA_INSPECTOR_ICON_COLOR}from"@buoy-gg/shared-ui";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import i from"react";import{OtaInspectorIcon as e,OTA_INSPECTOR_ICON_COLOR as r,defineToolPreset as p,createToolFactory as s}from"@buoy-gg/shared-ui";import{OtaBody as a}from"./components/OtaBody";import{jsx as c}from"react/jsx-runtime";export const otaInspectorToolPreset=p({id:"ota-update-inspector",name:"OTA UPDATES",description:"See which Expo update runs and apply a new one",slot:"both",color:r,icon:({size:o,color:t})=>c(e,{size:o,color:t}),component:a,modal:{subtitle:"which update runs on this app"}});export const createOtaInspectorTool=s(otaInspectorToolPreset);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{isPro as e}from"@buoy-gg/license";import{OTA_ACTIONS as s}from"../types";import{otaStore as r}from"../engine/otaStore";export const otaInspectorSyncAdapter={version:1,getSnapshot:r.getSnapshot,subscribe:r.subscribe,actions:Object.fromEntries(s.map(o=>[o,t=>{if(!e())throw new Error("OTA Inspector needs Buoy Pro.");return r.act(o,t)}]))};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export const OTA_ACTIONS=["getState","check","fetch","reload","setHeaders","setURL","setExpected"];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { OtaAction, OtaSnapshot } from "../types";
|
|
3
|
+
export type OtaActionHandler = (action: OtaAction, params?: Record<string, unknown>) => Promise<unknown>;
|
|
4
|
+
export type OtaToolViewProps = {
|
|
5
|
+
snapshot: OtaSnapshot | null;
|
|
6
|
+
onAction: OtaActionHandler;
|
|
7
|
+
offline?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/** Shared phone/Desktop view. It never imports the Expo SDK. */
|
|
10
|
+
export declare function OtaToolView({ snapshot: s, onAction, offline, }: OtaToolViewProps): React.JSX.Element;
|
|
11
|
+
//# sourceMappingURL=OtaToolView.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ExpoUpdatesLike, OtaStatus } from "../types";
|
|
2
|
+
export declare function classifyLoadError(e: unknown): OtaStatus;
|
|
3
|
+
export declare function loadExpoSDK(): {
|
|
4
|
+
sdk: ExpoUpdatesLike | null;
|
|
5
|
+
status?: OtaStatus;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=expoSDK.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type OtaAction, type OtaSnapshot, type OtaOptions, type ExpoUpdatesLike, type OtaStatus } from "../types";
|
|
2
|
+
export declare function createOtaStore(schedule?: (fn: () => void) => (() => void) | void): {
|
|
3
|
+
configure: (next: OtaOptions) => void;
|
|
4
|
+
attach: (next: ExpoUpdatesLike | null, status?: OtaStatus) => void;
|
|
5
|
+
ingest: (value: unknown) => void;
|
|
6
|
+
act: (action: OtaAction, input?: unknown) => Promise<unknown>;
|
|
7
|
+
getSnapshot: () => OtaSnapshot;
|
|
8
|
+
subscribe: (fn: () => void) => () => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const otaStore: {
|
|
11
|
+
configure: (next: OtaOptions) => void;
|
|
12
|
+
attach: (next: ExpoUpdatesLike | null, status?: OtaStatus) => void;
|
|
13
|
+
ingest: (value: unknown) => void;
|
|
14
|
+
act: (action: OtaAction, input?: unknown) => Promise<unknown>;
|
|
15
|
+
getSnapshot: () => OtaSnapshot;
|
|
16
|
+
subscribe: (fn: () => void) => () => void;
|
|
17
|
+
};
|
|
18
|
+
export declare const configureOtaInspector: (next: OtaOptions) => void;
|
|
19
|
+
export declare const getOtaSnapshot: () => OtaSnapshot;
|
|
20
|
+
export declare const subscribeOta: (fn: () => void) => () => void;
|
|
21
|
+
//# sourceMappingURL=otaStore.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ManifestSummary, OtaCandidate, OtaError } from "../types";
|
|
2
|
+
export declare const record: (v: unknown) => Record<string, unknown>;
|
|
3
|
+
export declare const str: (v: unknown) => string | null;
|
|
4
|
+
export declare const bool: (v: unknown) => boolean | null;
|
|
5
|
+
export declare const num: (v: unknown) => number | null;
|
|
6
|
+
export declare function iso(v: unknown): string | null;
|
|
7
|
+
export declare function safeURL(v: unknown): string | null;
|
|
8
|
+
export declare function headers(v: unknown): Record<string, string> | null;
|
|
9
|
+
export declare function safeText(v: unknown, secrets?: string[]): string | null;
|
|
10
|
+
export declare function error(v: unknown, secrets?: string[]): OtaError | null;
|
|
11
|
+
export declare function manifest(v: unknown): ManifestSummary | null;
|
|
12
|
+
export declare function candidate(v: unknown): OtaCandidate | null;
|
|
13
|
+
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export { OtaInspectorRoot } from "./OtaInspectorRoot";
|
|
3
|
+
export { configureOtaInspector, getOtaSnapshot, subscribeOta, } from "./engine/otaStore";
|
|
4
|
+
export { otaInspectorSyncAdapter } from "./sync/otaInspectorSyncAdapter";
|
|
5
|
+
export { OtaToolView } from "./components/OtaToolView";
|
|
6
|
+
export type { OtaToolViewProps, OtaActionHandler, } from "./components/OtaToolView";
|
|
7
|
+
export { otaInspectorToolPreset, createOtaInspectorTool } from "./preset";
|
|
8
|
+
export { OtaInspectorIcon, OTA_INSPECTOR_ICON_COLOR } from "@buoy-gg/shared-ui";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export { OtaToolView } from "./components/OtaToolView";
|
|
3
|
+
export type { OtaToolViewProps, OtaActionHandler, } from "./components/OtaToolView";
|
|
4
|
+
export { OtaInspectorIcon, OTA_INSPECTOR_ICON_COLOR } from "@buoy-gg/shared-ui";
|
|
5
|
+
//# sourceMappingURL=index.web.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { OtaBody } from "./components/OtaBody";
|
|
3
|
+
export declare const otaInspectorToolPreset: {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
slot: "both";
|
|
8
|
+
color: string;
|
|
9
|
+
icon: ({ size, color }: {
|
|
10
|
+
size: number;
|
|
11
|
+
color?: string;
|
|
12
|
+
}) => React.JSX.Element;
|
|
13
|
+
component: typeof OtaBody;
|
|
14
|
+
modal: {
|
|
15
|
+
subtitle: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare const createOtaInspectorTool: (options?: (Record<never, never> & import("@buoy-gg/shared-ui").ToolPresetOverrides) | undefined) => {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
slot: "both";
|
|
23
|
+
color: string;
|
|
24
|
+
icon: ({ size, color }: {
|
|
25
|
+
size: number;
|
|
26
|
+
color?: string;
|
|
27
|
+
}) => React.JSX.Element;
|
|
28
|
+
component: typeof OtaBody;
|
|
29
|
+
modal: {
|
|
30
|
+
subtitle: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=preset.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const otaInspectorSyncAdapter: {
|
|
2
|
+
version: number;
|
|
3
|
+
getSnapshot: () => import("..").OtaSnapshot;
|
|
4
|
+
subscribe: (fn: () => void) => () => void;
|
|
5
|
+
actions: {
|
|
6
|
+
[k: string]: (params?: unknown) => Promise<unknown>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=otaInspectorSyncAdapter.d.ts.map
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type OtaStatus = "waiting" | "missing" | "native-missing" | "disabled" | "ready" | "unsupported" | "load-error";
|
|
2
|
+
export declare const OTA_ACTIONS: readonly ["getState", "check", "fetch", "reload", "setHeaders", "setURL", "setExpected"];
|
|
3
|
+
export type OtaAction = (typeof OTA_ACTIONS)[number];
|
|
4
|
+
export type OtaTarget = {
|
|
5
|
+
runtimeVersion?: string;
|
|
6
|
+
channel?: string;
|
|
7
|
+
};
|
|
8
|
+
export type OtaConfigHint = {
|
|
9
|
+
updateUrl?: string;
|
|
10
|
+
requestHeaders?: Record<string, string>;
|
|
11
|
+
disableAntiBrickingMeasures?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type OtaOptions = {
|
|
14
|
+
expected?: OtaTarget;
|
|
15
|
+
config?: OtaConfigHint;
|
|
16
|
+
allowURLOverride?: boolean;
|
|
17
|
+
allowActionsInRelease?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type ManifestSummary = {
|
|
20
|
+
id: string | null;
|
|
21
|
+
createdAt: string | null;
|
|
22
|
+
runtimeVersion: string | null;
|
|
23
|
+
assetCount: number | null;
|
|
24
|
+
launchAsset: string | null;
|
|
25
|
+
};
|
|
26
|
+
export type OtaCandidate = {
|
|
27
|
+
type: "new";
|
|
28
|
+
updateId: string | null;
|
|
29
|
+
createdAt: string | null;
|
|
30
|
+
runtimeVersion: string | null;
|
|
31
|
+
manifest: ManifestSummary;
|
|
32
|
+
} | {
|
|
33
|
+
type: "rollback";
|
|
34
|
+
createdAt: string | null;
|
|
35
|
+
};
|
|
36
|
+
export type OtaError = {
|
|
37
|
+
name: string;
|
|
38
|
+
message: string;
|
|
39
|
+
};
|
|
40
|
+
export type OtaFinding = {
|
|
41
|
+
code: string;
|
|
42
|
+
kind: "observed" | "comparison" | "check";
|
|
43
|
+
source: "expo" | "user" | "config";
|
|
44
|
+
message: string;
|
|
45
|
+
};
|
|
46
|
+
export interface OtaSnapshot {
|
|
47
|
+
schemaVersion: 1;
|
|
48
|
+
capturedAt: string;
|
|
49
|
+
status: OtaStatus;
|
|
50
|
+
statusReason: string | null;
|
|
51
|
+
running: {
|
|
52
|
+
isEnabled: boolean | null;
|
|
53
|
+
channel: string | null;
|
|
54
|
+
runtimeVersion: string | null;
|
|
55
|
+
updateId: string | null;
|
|
56
|
+
createdAt: string | null;
|
|
57
|
+
isEmbeddedLaunch: boolean | null;
|
|
58
|
+
isEmergencyLaunch: boolean | null;
|
|
59
|
+
emergencyLaunchReason: string | null;
|
|
60
|
+
launchDuration: number | null;
|
|
61
|
+
manifest: ManifestSummary | null;
|
|
62
|
+
};
|
|
63
|
+
updates: {
|
|
64
|
+
availableUpdate: OtaCandidate | null;
|
|
65
|
+
downloadedUpdate: OtaCandidate | null;
|
|
66
|
+
isUpdateAvailable: boolean;
|
|
67
|
+
isUpdatePending: boolean;
|
|
68
|
+
isChecking: boolean;
|
|
69
|
+
isDownloading: boolean;
|
|
70
|
+
isRestarting: boolean;
|
|
71
|
+
isStartupProcedureRunning: boolean;
|
|
72
|
+
downloadProgress: number | null;
|
|
73
|
+
checkError: OtaError | null;
|
|
74
|
+
downloadError: OtaError | null;
|
|
75
|
+
lastCheckForUpdateTimeSinceRestart: string | null;
|
|
76
|
+
};
|
|
77
|
+
config: {
|
|
78
|
+
source: "unknown" | "app-config";
|
|
79
|
+
updateUrl: string | null;
|
|
80
|
+
requestHeaders: Record<string, string> | null;
|
|
81
|
+
overrideSource: "unknown" | "session-write";
|
|
82
|
+
override: OtaConfigHint | null;
|
|
83
|
+
};
|
|
84
|
+
expected: OtaTarget;
|
|
85
|
+
lastCheck: {
|
|
86
|
+
isAvailable: boolean;
|
|
87
|
+
isRollBackToEmbedded: boolean;
|
|
88
|
+
reason: string | null;
|
|
89
|
+
} | null;
|
|
90
|
+
busy: OtaAction | null;
|
|
91
|
+
actionError: OtaError | null;
|
|
92
|
+
findings: OtaFinding[];
|
|
93
|
+
capabilities: Record<OtaAction, {
|
|
94
|
+
enabled: boolean;
|
|
95
|
+
reason: string | null;
|
|
96
|
+
}>;
|
|
97
|
+
}
|
|
98
|
+
/** Small SDK boundary; keeps Expo optional for the shared view and tests. */
|
|
99
|
+
export interface ExpoUpdatesLike {
|
|
100
|
+
isDevelopmentLaunch?: boolean;
|
|
101
|
+
isEnabled?: boolean;
|
|
102
|
+
channel?: string | null;
|
|
103
|
+
runtimeVersion?: string | null;
|
|
104
|
+
updateId?: string | null;
|
|
105
|
+
createdAt?: Date | null;
|
|
106
|
+
isEmbeddedLaunch?: boolean;
|
|
107
|
+
isEmergencyLaunch?: boolean;
|
|
108
|
+
emergencyLaunchReason?: string | null;
|
|
109
|
+
launchDuration?: number | null;
|
|
110
|
+
manifest?: unknown;
|
|
111
|
+
useUpdates?: () => Record<string, unknown>;
|
|
112
|
+
checkForUpdateAsync?: () => Promise<unknown>;
|
|
113
|
+
fetchUpdateAsync?: () => Promise<unknown>;
|
|
114
|
+
reloadAsync?: () => Promise<void>;
|
|
115
|
+
setUpdateRequestHeadersOverride?: (headers: Record<string, string> | null) => void;
|
|
116
|
+
setUpdateURLAndRequestHeadersOverride?: (config: {
|
|
117
|
+
updateUrl: string;
|
|
118
|
+
requestHeaders: Record<string, string>;
|
|
119
|
+
} | null) => void;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";var M=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var ie=Object.prototype.hasOwnProperty;var se=(e,a)=>{for(var r in a)M(e,r,{get:a[r],enumerable:true})},K=(e,a,r,o)=>{if(a&&typeof a=="object"||typeof a=="function")for(let l of oe(a))!ie.call(e,l)&&l!==r&&M(e,l,{get:()=>a[l],enumerable:!(o=le(a,l))||o.enumerable});return e},de=(e,a,r)=>(K(e,a,"default"),r&&K(r,a,"default"));var St=(()=>{try{let e=globalThis.Capacitor;if(e&&typeof e.isNativePlatform=="function"&&e.isNativePlatform())return e.DEBUG===true}catch{}return process.env.NODE_ENV!=="production"})();typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);var ce=["getState","check","fetch","reload","setHeaders","setURL","setExpected"];import{useState as C}from"react";var F={};se(F,{AccessibilityInfo:()=>be,ActivityIndicator:()=>mt,Alert:()=>vt,Animated:()=>dt,AppRegistry:()=>me,AppState:()=>ge,Appearance:()=>fe,BackHandler:()=>ye,Button:()=>gt,CheckBox:()=>Pe,Clipboard:()=>ve,DeviceEventEmitter:()=>Ge,Dimensions:()=>xe,Easing:()=>we,FlatList:()=>Ue,I18nManager:()=>Ee,Image:()=>De,ImageBackground:()=>$e,InteractionManager:()=>Ce,Keyboard:()=>Se,KeyboardAvoidingView:()=>Be,LayoutAnimation:()=>ke,Linking:()=>Le,LogBox:()=>qe,Modal:()=>bt,NativeEventEmitter:()=>Oe,NativeModules:()=>he,PanResponder:()=>Ie,Picker:()=>He,PixelRatio:()=>Te,Platform:()=>W,Pressable:()=>ht,ProgressBar:()=>Ve,RefreshControl:()=>je,SafeAreaView:()=>Me,ScrollView:()=>Q,SectionList:()=>Ke,Share:()=>Ae,StatusBar:()=>Fe,StyleSheet:()=>G,Switch:()=>ft,Text:()=>y,TextInput:()=>Y,Touchable:()=>We,TouchableHighlight:()=>ut,TouchableNativeFeedback:()=>ze,TouchableOpacity:()=>ct,TouchableWithoutFeedback:()=>pt,UIManager:()=>Re,Vibration:()=>Ne,View:()=>v,VirtualizedList:()=>_e,YellowBox:()=>Je,findNodeHandle:()=>yt,unstable_createElement:()=>pe,useColorScheme:()=>Ye,useLocaleContext:()=>Qe,useWindowDimensions:()=>Xe});de(F,ue);import*as ue from"react-native-web";import{unstable_createElement as pe,NativeModules as he,AccessibilityInfo as be,Appearance as fe,AppRegistry as me,AppState as ge,BackHandler as ye,Clipboard as ve,Dimensions as xe,Easing as we,I18nManager as Ee,Keyboard as Se,InteractionManager as Ce,LayoutAnimation as ke,Linking as Le,NativeEventEmitter as Oe,PanResponder as Ie,PixelRatio as Te,Platform as W,Share as Ae,UIManager as Re,Vibration as Ne,CheckBox as Pe,FlatList as Ue,Image as De,ImageBackground as $e,KeyboardAvoidingView as Be,Picker as He,ProgressBar as Ve,RefreshControl as je,SafeAreaView as Me,SectionList as Ke,StatusBar as Fe,Touchable as We,TouchableNativeFeedback as ze,VirtualizedList as _e,YellowBox as Je,LogBox as qe,DeviceEventEmitter as Ge,useColorScheme as Ye,useLocaleContext as Qe,useWindowDimensions as Xe}from"react-native-web";import*as f from"react-native-web";import{createElement as $,forwardRef as z,useCallback as Ze,useRef as et}from"react";import{useEffect as tt,useState as at}from"react";import{createPortal as nt}from"react-dom";var rt='-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';import{jsx as lt}from"react/jsx-runtime";var U=Symbol.for("@buoy-gg/portal-host"),_=e=>{if(!(e instanceof Element))return false;if(e.closest("input, textarea, select"))return true;let a=e.closest("[contenteditable]")?.getAttribute("contenteditable")?.toLowerCase();return a===""||a==="true"||a==="plaintext-only"};function J(){let e=document;if(e[U])return e[U].host;let a=document.createElement("div");a.dataset.buoyPortalHost="",Object.assign(a.style,{position:"fixed",inset:"0",zIndex:"2147483647",pointerEvents:"none",fontFamily:rt});let r=()=>{let n=document.fullscreenElement,u=n&&n.tagName!=="CANVAS"?n:document.body;a.parentElement!==u&&u.appendChild(a)},o=new Map,l=n=>{(!a.contains(n.target)||!_(n.target))&&o.set(n.code||n.key,{key:n.key,code:n.code,location:n.location,keyCode:n.keyCode,which:n.which,altKey:n.altKey,ctrlKey:n.ctrlKey,metaKey:n.metaKey,shiftKey:n.shiftKey})},i=n=>{o.delete(n.code||n.key)},h=()=>o.clear(),m=()=>{let n=[...o.values()];o.clear();for(let u of n)document.dispatchEvent(new KeyboardEvent("keyup",{...u,bubbles:true}))},s=n=>{_(n.target)&&n.stopPropagation()},p=n=>n.stopPropagation();return r(),document.addEventListener("fullscreenchange",r),document.addEventListener("keydown",l,true),document.addEventListener("keyup",i,true),window.addEventListener("blur",h),a.addEventListener("focusin",m),a.addEventListener("keydown",s),a.addEventListener("keyup",s),a.addEventListener("keypress",s),a.addEventListener("wheel",p,{passive:true}),e[U]={host:a,users:0,dispose:()=>{document.removeEventListener("fullscreenchange",r),document.removeEventListener("keydown",l,true),document.removeEventListener("keyup",i,true),window.removeEventListener("blur",h),a.remove(),delete e[U]}},a}function ot({children:e}){let[a,r]=at(null);return tt(()=>{let o=J(),l=document[U];return l.users++,r(o),()=>{--l.users===0&&l.dispose()}},[]),a?nt(lt("div",{"data-buoy-root":"",style:{display:"contents",pointerEvents:"auto"},children:e}),a):null}var I=f,it=["shadowColor","shadowOffset","shadowOpacity","shadowRadius","textShadowColor","textShadowOffset","textShadowRadius"],T=e=>typeof e=="number"?`${e}px`:e;function B(e){if(Array.isArray(e)){let u=e.map(B);return u.some((N,S)=>N!==e[S])?u:e}if(!e||typeof e!="object"||!it.some(u=>e[u]!=null))return e;let{shadowColor:a,shadowOffset:r,shadowOpacity:o,shadowRadius:l,textShadowColor:i,textShadowOffset:h,textShadowRadius:m,...s}=e;if(a!=null||r!=null||o!=null||l!=null){let u=a??"black",N=o==null?u:`color-mix(in srgb, ${u} ${Math.min(o,1)*100}%, transparent)`,S=`${T(r?.width??0)} ${T(r?.height??0)} ${T(l??0)} ${N}`;s.boxShadow=typeof s.boxShadow=="string"?`${s.boxShadow}, ${S}`:s.boxShadow??S}let{width:p=0,height:n=0}=h??{};if(i&&(p||n||m)){let u=`${T(p)} ${T(n)} ${T(m??0)} ${i}`;s.textShadow=s.textShadow?`${s.textShadow}, ${u}`:u}return s}var st=I.StyleSheet.create({auto:{pointerEvents:"auto"},none:{pointerEvents:"none"},"box-none":{pointerEvents:"box-none"},"box-only":{pointerEvents:"box-only"}});function q(e,a){if(typeof e=="function")return o=>q(e(o),a);let r=B(e);return a?[r,st[a]]:r}var G={...I.StyleSheet,create:e=>I.StyleSheet.create(Object.fromEntries(Object.entries(e).map(([a,r])=>[a,B(r)])))};function g(e){let a=z((o,l)=>{let{accessibilityState:i,accessibilityValue:h,pointerEvents:m,...s}=o;for(let n of["busy","checked","disabled","expanded","selected"])i?.[n]!==void 0&&s[`aria-${n}`]===void 0&&(s[`aria-${n}`]=i[n]);for(let[n,u]of Object.entries({min:"valuemin",max:"valuemax",now:"valuenow",text:"valuetext"}))h?.[n]!==void 0&&s[`aria-${u}`]===void 0&&(s[`aria-${u}`]=h[n]);let p=q(s.style,m);return p!==s.style&&(s.style=p),$(e,{...s,ref:l})}),r=e.State;return r&&Object.assign(a,{State:r}),a.displayName=e.displayName??e.name??"NativeWebView",a}var v=g(f.View),y=g(f.Text),dt={...I.Animated,View:I.Animated.createAnimatedComponent(v),Text:I.Animated.createAnimatedComponent(y)},Y=g(f.TextInput),ct=g(f.TouchableOpacity),ut=g(f.TouchableHighlight),pt=g(f.TouchableWithoutFeedback),ht=g(f.Pressable),Q=g(f.ScrollView),X=z((e,a)=>{let r=et(null),o=Ze(l=>{if(l){let i=l;for(;i.parentElement&&i.parentElement!==document.body;)i=i.parentElement;i.parentElement===document.body&&(r.current=i,Object.assign(i.style,{position:"relative",zIndex:"2147483647",pointerEvents:"auto"}),J().appendChild(i))}else r.current&&(document.body.appendChild(r.current),r.current=null);typeof a=="function"?a(l):a&&(a.current=l)},[a]);return $(ot,null,$(f.Modal,{...e,ref:o}))});X.displayName="Modal";var bt=g(X),ft=g(f.Switch),mt=g(f.ActivityIndicator),gt=g(f.Button),yt=f.findNodeHandle,vt={alert(e,a,r,o){if(typeof document>"u")return;let l=document.createElement("dialog");l.dataset.buoyRoot="",l.setAttribute("aria-label",e),l.style.cssText="position:fixed;inset:0;margin:auto;width:min(440px,90vw);padding:24px;border:1px solid #475569;border-radius:14px;background:#17212e;color:#f1f5f9;font:14px system-ui;box-shadow:0 20px 80px #0008;z-index:2147483647";let i=document.createElement("h2");if(i.textContent=e,i.style.cssText="font-size:18px;margin:0 0 12px",l.appendChild(i),a){let p=document.createElement("p");p.textContent=a,p.style.cssText="line-height:1.5;white-space:pre-wrap;margin:0 0 20px",l.appendChild(p)}let h=document.createElement("div");h.style.cssText="display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px";let m=r?.length?r:[{text:"OK"}],s=()=>{l.close?.(),l.remove()};for(let p of m){let n=document.createElement("button");n.type="button",n.textContent=p.text??"OK",n.style.cssText=`padding:9px 14px;border:1px solid #64748b;border-radius:7px;color:white;background:${p.style==="destructive"?"#a52b38":"#283a4d"};cursor:pointer;font:inherit`,n.onclick=()=>{s(),p.onPress?.()},h.appendChild(n)}l.addEventListener("cancel",p=>{p.preventDefault(),o?.cancelable!==false&&(s(),o?.onDismiss?.())}),l.appendChild(h),document.body.appendChild(l),l.showModal?l.showModal():l.setAttribute("open","")}};import{NightButton as A,NightCard as Z,NightFootnote as x,NightSectionLabel as R,night as k}from"@buoy-gg/shared-ui/web";import{jsx as t,jsxs as w}from"react/jsx-runtime";var ee=e=>e==null?"Unknown":typeof e=="object"?JSON.stringify(e,null,2):String(e);function xt({snapshot:e,onAction:a,offline:r=false}){let[o,l]=C(null),[i,h]=C(null),[m,s]=C(false),[p,n]=C(""),[u,N]=C(""),[S,te]=C(""),[H,ae]=C("{}"),V=async(c,E)=>{h(null),l(null);try{if(r)throw new Error("The app is offline. Connect it first.");await a(c,E)}catch(P){l(P instanceof Error?P.message:"The call failed.")}};if(!e)return t(x,{children:"Waiting for the app\u2026"});let L=(c,E,P,re=false)=>w(v,{style:b.gap,children:[t(A,{testID:`ota-${c}${E.startsWith("Clear")?"-clear":""}`,label:E,disabled:r||!e.capabilities[c].enabled,onPress:()=>re?h({action:c,params:P}):void V(c,P)}),e.capabilities[c].reason?t(x,{children:e.capabilities[c].reason}):null]},E),O=e.updates.downloadedUpdate,ne=()=>{let c=JSON.parse(H);if(!c||typeof c!="object"||Array.isArray(c))throw new Error("Use a JSON header map.");return c},j=c=>{try{let E=ne();l(null),h({action:c,params:c==="setHeaders"?{requestHeaders:E}:{configOverride:{updateUrl:S,requestHeaders:E}}})}catch{l("Use a JSON header map.")}};return t(Q,{style:{flex:1},testID:"ota-scroll",keyboardShouldPersistTaps:"handled",children:w(v,{style:b.content,children:[t(y,{style:b.title,children:"OTA Update Inspector"}),t(y,{style:b.text,testID:"ota-status",children:e.status}),r?t(x,{tone:"warning",children:"Offline. This is the last saved view."}):null,e.statusReason?t(x,{children:e.statusReason}):null,o||e.actionError?t(y,{style:b.error,testID:"ota-error",children:o||e.actionError?.message}):null,t(R,{children:"What runs now"}),t(Z,{children:w(v,{style:b.card,children:[t(d,{label:"Expo isEnabled",value:e.running.isEnabled}),t(d,{label:"Update ID",value:e.running.updateId,id:"ota-running-id"}),t(d,{label:"Built in",value:e.running.isEmbeddedLaunch,id:"ota-embedded"}),t(d,{label:"Channel",value:e.running.channel}),t(d,{label:"Runtime",value:e.running.runtimeVersion,id:"ota-runtime"}),t(d,{label:"Launch time (ms)",value:e.running.launchDuration}),t(d,{label:"Emergency launch",value:e.running.isEmergencyLaunch}),e.running.emergencyLaunchReason?t(d,{label:"Launch fault",value:e.running.emergencyLaunchReason}):null]})}),t(R,{children:"Why did it not run?"}),e.findings.length?e.findings.map(c=>w(v,{children:[t(y,{style:b.text,testID:`ota-finding-${c.code}`,children:c.message}),w(y,{style:b.hint,children:[c.kind," \xB7 ",c.source]})]},c.code)):t(x,{children:"No fault found from these facts."}),t(R,{children:"Next update"}),t(d,{label:"Found",value:e.updates.availableUpdate,id:"ota-found"}),t(d,{label:"Saved",value:O,id:"ota-pending-detail"}),t(d,{label:"Ready to apply",value:e.updates.isUpdatePending,id:"ota-pending"}),t(d,{label:"Now",value:e.busy||(e.updates.isChecking?"Checking":e.updates.isDownloading?"Fetching":"Idle")}),t(d,{label:"Fetch progress",value:e.updates.downloadProgress==null?null:`${Math.round(e.updates.downloadProgress*100)}%`}),t(d,{label:"Last check",value:e.updates.lastCheckForUpdateTimeSinceRestart}),e.lastCheck?.reason?t(d,{label:"Check result",value:e.lastCheck.reason}):null,e.updates.checkError?t(d,{label:"Check fault",value:e.updates.checkError.message}):null,e.updates.downloadError?t(d,{label:"Fetch fault",value:e.updates.downloadError.message}):null,L("check","Check now"),L("fetch","Fetch update"),L("reload",O?.type==="rollback"?"Apply server rollback":"Reload to apply",{expectedType:O?.type,expectedUpdateId:O?.type==="new"?O.updateId:void 0},true),t(x,{children:"Reload restarts the app. Unsaved work may be lost."}),i?t(Z,{children:w(v,{style:b.card,testID:"ota-confirm",children:[t(y,{style:b.text,children:i.action==="reload"?"Apply this saved update and restart?":"Save this change? It lasts through app restarts."}),t(x,{children:i.action==="reload"?ee(O):"This sends the full header map. Left out keys will be cleared."}),t(A,{label:"Apply",testID:"ota-confirm-apply",onPress:()=>void V(i.action,i.params)}),t(A,{label:"Cancel",testID:"ota-confirm-cancel",onPress:()=>h(null)})]})}):null,t(A,{label:m?"Hide details":"Show details",testID:"ota-details",onPress:()=>s(!m)}),m?w(v,{style:b.gap,children:[t(d,{label:"Created at",value:e.running.createdAt}),t(d,{label:"Manifest summary",value:e.running.manifest}),t(R,{children:"Config hints"}),t(x,{children:"These are app hints, not a native readback. Secrets are hidden. Prior saved changes may be unknown."}),t(d,{label:"Hint source",value:e.config.source}),t(d,{label:"Update URL",value:e.config.updateUrl}),t(d,{label:"Headers",value:e.config.requestHeaders}),t(d,{label:"Last write source",value:e.config.overrideSource}),t(d,{label:"Last write",value:e.config.override}),t(R,{children:"Compare a target"}),t(D,{label:"Target runtime",value:p,set:n,id:"ota-target-runtime"}),t(D,{label:"Target channel",value:u,set:N,id:"ota-target-channel"}),L("setExpected","Compare",{runtimeVersion:p,channel:u}),t(R,{children:"Change the source"}),t(x,{children:"Use a full header map. Keys must exist in the build. Clearing a change restores the build config."}),t(D,{label:"Headers (JSON)",value:H,set:ae,id:"ota-headers"}),t(A,{label:"Set headers",testID:"ota-setHeaders",disabled:r||!e.capabilities.setHeaders.enabled,onPress:()=>j("setHeaders")}),L("setHeaders","Clear header change",{requestHeaders:null},true),t(D,{label:"Update URL",value:S,set:te,id:"ota-url"}),t(A,{label:"Set URL",testID:"ota-setURL",disabled:r||!e.capabilities.setURL.enabled,onPress:()=>j("setURL")}),L("setURL","Clear URL change",{configOverride:null},true),t(x,{children:"URL changes need an opted in test build."})]}):null]})})}function d({label:e,value:a,id:r}){return w(v,{style:b.gap,children:[t(y,{style:b.hint,children:e}),t(y,{selectable:true,style:b.text,testID:r,children:ee(a)})]})}function D({label:e,value:a,set:r,id:o}){return w(v,{children:[t(y,{style:b.hint,children:e}),t(Y,{style:b.input,testID:o,accessibilityLabel:e,value:a,onChangeText:r,autoCapitalize:"none",autoCorrect:false,spellCheck:false,smartInsertDelete:false,keyboardType:W.OS==="ios"?"ascii-capable":"default"})]})}var b=G.create({content:{padding:16,paddingBottom:48,gap:14},title:{color:k.color.text,fontSize:22,fontWeight:"600"},text:{color:k.color.text,fontSize:14},hint:{color:k.color.textSecondary,fontSize:12},error:{color:k.color.danger},card:{padding:14,gap:12},gap:{gap:6},input:{color:k.color.text,backgroundColor:k.color.bg,borderColor:k.color.border,borderWidth:1,borderRadius:8,padding:10}});import{OtaInspectorIcon as wt,OTA_INSPECTOR_ICON_COLOR as Et}from"@buoy-gg/shared-ui/web";export{ce as OTA_ACTIONS,Et as OTA_INSPECTOR_ICON_COLOR,wt as OtaInspectorIcon,xt as OtaToolView};
|
package/package.json
CHANGED
|
@@ -1,6 +1,103 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/ota-inspector",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "7.0.80",
|
|
4
|
+
"description": "See which Expo update runs and apply a new one.",
|
|
5
|
+
"main": "lib/commonjs/index.js",
|
|
6
|
+
"module": "lib/module/index.js",
|
|
7
|
+
"types": "lib/typescript/index.d.ts",
|
|
8
|
+
"react-native": "lib/module/index.js",
|
|
9
|
+
"source": "src/index.tsx",
|
|
10
|
+
"files": [
|
|
11
|
+
"lib"
|
|
12
|
+
],
|
|
13
|
+
"sideEffects": false,
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@buoy-gg/shared-ui": "^7.0.80"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@buoy-gg/license": "7.0.80",
|
|
19
|
+
"react": "*"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/react": "^19.1.0",
|
|
23
|
+
"@types/react-native": "^0.73.0",
|
|
24
|
+
"typescript": "~5.8.3",
|
|
25
|
+
"@buoy-gg/license": "^7.0.80"
|
|
26
|
+
},
|
|
27
|
+
"react-native-builder-bob": {
|
|
28
|
+
"source": "src",
|
|
29
|
+
"output": "lib",
|
|
30
|
+
"targets": [
|
|
31
|
+
"commonjs",
|
|
32
|
+
"module",
|
|
33
|
+
[
|
|
34
|
+
"typescript",
|
|
35
|
+
{
|
|
36
|
+
"project": "tsconfig.build.json"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/Buoy-gg/buoy.git",
|
|
44
|
+
"directory": "packages/ota-inspector"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/LovesWorking/react-native-buoy/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://buoy.gg/buoy/latest/docs/tools/ota-update-inspector",
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public",
|
|
52
|
+
"tag": "latest"
|
|
53
|
+
},
|
|
54
|
+
"keywords": [
|
|
55
|
+
"react-native",
|
|
56
|
+
"expo",
|
|
57
|
+
"devtools",
|
|
58
|
+
"ota",
|
|
59
|
+
"expo-updates"
|
|
60
|
+
],
|
|
61
|
+
"exports": {
|
|
62
|
+
".": {
|
|
63
|
+
"browser": {
|
|
64
|
+
"types": "./lib/typescript/index.web.d.ts",
|
|
65
|
+
"default": "./lib/web/index.mjs"
|
|
66
|
+
},
|
|
67
|
+
"import": {
|
|
68
|
+
"types": "./lib/typescript/index.d.ts",
|
|
69
|
+
"default": "./lib/module/index.js"
|
|
70
|
+
},
|
|
71
|
+
"require": {
|
|
72
|
+
"types": "./lib/typescript/index.d.ts",
|
|
73
|
+
"default": "./lib/commonjs/index.js"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"./web": {
|
|
77
|
+
"types": "./lib/typescript/index.web.d.ts",
|
|
78
|
+
"default": "./lib/web/index.mjs"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"peerDependenciesMeta": {
|
|
82
|
+
"react-native": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"react-native-web": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"react-dom": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"expo-updates": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"scripts": {
|
|
96
|
+
"build": "bob build && pnpm run build:web",
|
|
97
|
+
"typecheck": "tsc --noEmit",
|
|
98
|
+
"clean": "rimraf lib",
|
|
99
|
+
"test": "pnpm run typecheck",
|
|
100
|
+
"postinstall": "echo \"Run pnpm build to compile this package\"",
|
|
101
|
+
"build:web": "node ../../scripts/build-web.mjs ota-inspector"
|
|
102
|
+
}
|
|
6
103
|
}
|