@uploadista/react-native-core 0.0.20-beta.7 → 0.0.20-beta.8
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.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/hooks/use-multi-upload.ts +10 -6
- package/src/types/platform-types.ts +7 -4
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/types.ts","../src/types/upload-input.ts","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx","../src/components/UploadProgress.tsx","../src/hooks/use-flow.ts","../src/components/flow-primitives.tsx","../src/contexts/flow-manager-context.tsx","../src/client/create-uploadista-client.ts","../src/hooks/use-uploadista-client.ts","../src/hooks/uploadista-context.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/hooks/use-uploadista-context.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts"],"sourcesContent":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/types.ts","../src/types/upload-input.ts","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx","../src/components/UploadProgress.tsx","../src/hooks/use-flow.ts","../src/components/flow-primitives.tsx","../src/contexts/flow-manager-context.tsx","../src/client/create-uploadista-client.ts","../src/hooks/use-uploadista-client.ts","../src/hooks/uploadista-context.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/hooks/use-uploadista-context.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e,{createContext as t,useCallback as n,useContext as r,useEffect as i,useRef as a,useState as o}from"react";import{ActivityIndicator as s,FlatList as c,Pressable as l,StyleSheet as u,Text as d,View as f}from"react-native";import{FlowManager as p,UploadManager as m}from"@uploadista/client-core";import{EventType as h}from"@uploadista/core/flow";import{UploadEventType as g}from"@uploadista/core/types";import{Fragment as _,jsx as v,jsxs as y}from"react/jsx-runtime";const b=t(void 0);function x(e,t){let n=e instanceof ArrayBuffer?new Uint8Array(e):e;return new Blob([n],t)}function S(){let e=r(b);if(!e)throw Error(`useUploadistaClient must be used within an UploadistaProvider`);return e}const C={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,result:null};function w(e={}){let{client:t,fileSystemProvider:r}=S(),[s,c]=o(C),l=a(null),u=a(null);return i(()=>(l.current=new m(async(e,n)=>{let i=e;if(i.status===`success`){let e=x(await r.readFile(i.data.uri),{type:i.data.mimeType||`application/octet-stream`});return t.upload(e,n)}return Promise.resolve({abort:()=>{}})},{onStateChange:c,onProgress:e.onProgress,onChunkComplete:e.onChunkComplete,onSuccess:e.onSuccess,onError:e.onError,onAbort:e.onAbort},{metadata:e.metadata,uploadLengthDeferred:e.uploadLengthDeferred,uploadSize:e.uploadSize,onShouldRetry:e.onShouldRetry}),()=>{l.current?.cleanup()}),[t,r,e]),{state:s,upload:n(async e=>{u.current=e,await l.current?.upload(e)},[]),abort:n(()=>{l.current?.abort()},[]),reset:n(()=>{l.current?.reset(),u.current=null},[]),retry:n(()=>{u.current&&l.current?.canRetry()&&l.current.retry()},[]),isUploading:s.status===`uploading`,canRetry:l.current?.canRetry()??!1,metrics:{getInsights:()=>t.getChunkingInsights(),exportMetrics:()=>t.exportMetrics(),getNetworkMetrics:()=>t.getNetworkMetrics(),getNetworkCondition:()=>t.getNetworkCondition(),resetMetrics:()=>t.resetMetrics()}}}function T(e){let{fileSystemProvider:t}=S(),r=w({metadata:e?.metadata,onSuccess:e?.onSuccess,onError:e?.onError,onProgress:e?.onProgress}),i=n(async()=>{try{let n=await t.pickCamera(e?.cameraOptions);await r.upload(n)}catch(e){console.error(`Camera capture error:`,e)}},[t,e?.cameraOptions,r]);return{...r,captureAndUpload:i}}function E(e){let{fileSystemProvider:t}=S(),r=w({metadata:e?.metadata,onSuccess:e?.onSuccess,onError:e?.onError,onProgress:e?.onProgress}),i=n(async()=>{try{let n=await t.pickDocument({allowedTypes:e?.allowedTypes});await r.upload(n)}catch(e){throw console.error(`File selection error:`,e),e}},[t,e?.allowedTypes,r]);return{...r,pickAndUpload:i}}function ee(e){let t=e;return t.eventType===h.FlowStart||t.eventType===h.FlowEnd||t.eventType===h.FlowError||t.eventType===h.NodeStart||t.eventType===h.NodeEnd||t.eventType===h.NodePause||t.eventType===h.NodeResume||t.eventType===h.NodeError}const D=t(void 0);function te({children:e}){let{client:t,subscribeToEvents:r}=S(),o=a(new Map);i(()=>r(e=>{if(ee(e)){for(let t of o.current.values())t.manager.handleFlowEvent(e);return}if(`type`in e&&e.type===g.UPLOAD_PROGRESS&&`data`in e)for(let t of o.current.values())t.manager.handleUploadProgress(e.data.id,e.data.progress,e.data.total)}),[r]);let s=n((e,n,r)=>{let i=o.current.get(e);if(i)return i.refCount++,i.manager;let a=new p(t.uploadWithFlow,n,r,t.multiInputFlowUpload);return o.current.set(e,{manager:a,refCount:1,flowId:e}),a},[t]),c=n(e=>{let t=o.current.get(e);t&&(t.refCount--,t.refCount<=0&&(t.manager.cleanup(),o.current.delete(e)))},[]);return v(D.Provider,{value:{getManager:s,releaseManager:c},children:e})}function O(){let e=r(D);if(e===void 0)throw Error(`useFlowManagerContext must be used within a FlowManagerProvider. Make sure to wrap your component tree with <FlowManagerProvider>.`);return e}const ne={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,jobId:null,flowStarted:!1,currentNodeName:null,currentNodeType:null,flowOutputs:null};function k(e){let{client:t,fileSystemProvider:r}=S(),{getManager:s,releaseManager:c}=O(),[l,u]=o(ne),[d,f]=o(null),[p,m]=o(!1),[h,g]=o({}),[_,v]=o(new Map),y=a(null),b=a(null),C=a(e);i(()=>{C.current=e}),i(()=>{(async()=>{m(!0);try{let{flow:n}=await t.getFlow(e.flowId);f(n.nodes.filter(e=>e.type===`input`).map(e=>({nodeId:e.id,nodeName:e.name,nodeDescription:e.description,inputTypeId:e.inputTypeId,required:!0})))}catch(e){console.error(`Failed to discover flow inputs:`,e)}finally{m(!1)}})()},[t,e.flowId]),i(()=>{let t=e.flowId;y.current=s(t,{onStateChange:e=>{u(e)},onProgress:(e,t,n)=>{if(C.current.onProgress){let e=n?Math.round(t/n*100):0;C.current.onProgress(e,t,n)}},onChunkComplete:(e,t,n)=>{C.current.onChunkComplete?.(e,t,n)},onFlowComplete:e=>{C.current.onFlowComplete?.(e)},onSuccess:e=>{C.current.onSuccess?.(e)},onError:e=>{C.current.onError?.(e)},onAbort:()=>{}},{flowConfig:{flowId:e.flowId,storageId:e.storageId,outputNodeId:e.outputNodeId,metadata:e.metadata},onChunkComplete:e.onChunkComplete,onSuccess:e.onSuccess,onError:e.onError});let n=setInterval(()=>{if(y.current){let e=y.current.getInputStates();e.size>0&&v(new Map(e))}},100);return()=>{clearInterval(n),c(t),y.current=null}},[e.flowId,e.storageId,e.outputNodeId,s,c]);let w=n((e,t)=>{g(n=>({...n,[e]:t}))},[]),T=n(async e=>{if(e.status===`cancelled`)return null;if(e.status===`error`)throw e.error;return x(await r.readFile(e.data.uri),{type:e.data.mimeType||`application/octet-stream`})},[r]),E=n(async()=>{if(!y.current)throw Error(`FlowManager not initialized`);if(Object.keys(h).length===0)throw Error(`No inputs provided. Use setInput() to provide inputs before calling execute()`);b.current={...h};let e={};for(let[t,n]of Object.entries(h))if(n&&typeof n==`object`&&`status`in n&&(n.status===`success`||n.status===`cancelled`||n.status===`error`)){let r=await T(n);r&&(e[t]=r)}else e[t]=n;if(Object.keys(e).length===0)throw Error(`No valid inputs after processing. All files may have been cancelled.`);await y.current.executeFlow(e)},[h,T]);return{state:l,inputMetadata:d,inputStates:_,inputs:h,setInput:w,execute:E,upload:n(async t=>{if(t.status!==`cancelled`){if(t.status===`error`){e.onError?.(t.error);return}if(!y.current)throw Error(`FlowManager not initialized`);if(d&&d.length>0){let e=d[0];e&&(b.current={[e.nodeId]:t})}try{let e=x(await r.readFile(t.data.uri),{type:t.data.mimeType||`application/octet-stream`});if(d&&d.length>0){let n=d[0];if(!n)throw Error(`No input nodes found`);g({[n.nodeId]:t}),await y.current.executeFlow({[n.nodeId]:e})}else await y.current.upload(e)}catch(t){e.onError?.(t)}}},[d,r,e]),abort:n(()=>{y.current?.abort()},[]),reset:n(()=>{y.current?.reset(),g({}),v(new Map),b.current=null},[]),retry:n(()=>{b.current&&(l.status===`error`||l.status===`aborted`)&&(g(b.current),E())},[E,l.status]),isActive:l.status===`uploading`||l.status===`processing`,isUploadingFile:l.status===`uploading`,isProcessing:l.status===`processing`,isDiscoveringInputs:p,canRetry:(l.status===`error`||l.status===`aborted`)&&b.current!==null}}const A={items:[],totalProgress:0,totalUploaded:0,totalBytes:0,activeCount:0,completedCount:0,failedCount:0};function j(e={}){let{client:t}=S(),[r,i]=o(A),s=a(new Map),c=a(0),l=a([]),u=n(()=>`upload-${Date.now()}-${c.current++}`,[]),d=n(e=>{let t=e.reduce((e,t)=>e+t.totalBytes,0),n=e.reduce((e,t)=>e+t.bytesUploaded,0),r=t>0?Math.round(n/t*100):0,a=e.filter(e=>e.status===`uploading`).length,o=e.filter(e=>e.status===`success`).length,s=e.filter(e=>e.status===`error`).length;l.current=e,i(i=>({...i,items:e,totalProgress:r,totalUploaded:n,totalBytes:t,activeCount:a,completedCount:o,failedCount:s}))},[]),f=n(e=>{let t=e.filter(e=>e.status===`success`).map(e=>({id:u(),file:e,status:`idle`,progress:0,bytesUploaded:0,totalBytes:e.data.size,error:null,result:null})),n=[...l.current,...t];return l.current=n,i(e=>{let t=n.reduce((e,t)=>e+t.totalBytes,0);return{...e,items:n,totalBytes:t}}),t.map(e=>e.id)},[u]),p=n(async n=>{try{console.log(`Uploading item:`,n.file.data.name),d(l.current.map(e=>e.id===n.id?{...e,status:`uploading`}:e));let r=await(await fetch(n.file.data.uri)).blob(),i=n.file.data.mimeType?new Blob([r],{type:n.file.data.mimeType,lastModified:Date.now()}):r;console.log(`Uploading input:`,i);let a=await t.upload(i,{metadata:e.metadata,onProgress:(e,t,r)=>{let i=r?Math.round(t/r*100):0;d(l.current.map(e=>e.id===n.id?{...e,progress:i,bytesUploaded:t,totalBytes:r||e.totalBytes}:e))},onSuccess:t=>{d(l.current.map(e=>e.id===n.id?{...e,status:`success`,progress:100,result:t,bytesUploaded:t.size||e.totalBytes}:e)),e.onSuccess?.(t),s.current.delete(n.id)},onError:t=>{d(l.current.map(e=>e.id===n.id?{...e,status:`error`,error:t}:e)),e.onError?.(t),s.current.delete(n.id)}});s.current.set(n.id,a)}catch(t){console.error(`Error uploading item:`,t),d(l.current.map(e=>e.id===n.id?{...e,status:`error`,error:t}:e)),e.onError?.(t),s.current.delete(n.id)}},[t,e,d]),m=n(async t=>{let n=e.maxConcurrent||3,r=t?l.current.filter(e=>t.includes(e.id)&&e.status===`idle`):l.current.filter(e=>e.status===`idle`);console.log(`Items to upload:`,r.length,r);for(let e=0;e<r.length;e+=n){let t=r.slice(e,e+n);await Promise.all(t.map(e=>p(e)))}},[e.maxConcurrent,p]),h=n(e=>{let t=s.current.get(e);t&&(t.abort(),s.current.delete(e)),d(l.current.filter(t=>t.id!==e))},[d]),g=n(e=>{let t=s.current.get(e);t&&(t.abort(),s.current.delete(e)),d(l.current.map(t=>t.id===e?{...t,status:`aborted`}:t))},[d]),_=n(()=>{s.current.forEach(e=>{e.abort()}),s.current.clear(),l.current=[],i(A)},[]);return{state:r,addFiles:f,startUploads:m,removeItem:h,abortItem:g,retryItem:n(async e=>{let t=l.current.find(t=>t.id===e);if(t&&(t.status===`error`||t.status===`aborted`)){d(l.current.map(t=>t.id===e?{...t,status:`idle`,progress:0,bytesUploaded:0,error:null}:t));let t=l.current.find(t=>t.id===e);t&&await p(t)}},[p,d]),clear:_}}function M(e){let{fileSystemProvider:t}=S(),r=j({maxConcurrent:3,metadata:e?.metadata,onSuccess:e?.onSuccess,onError:e?.onError}),i=n(async()=>{let n;if(n=e?.mediaType===`video`?await t.pickVideo({allowMultiple:e?.allowMultiple??!0}):(e?.mediaType,await t.pickImage({allowMultiple:e?.allowMultiple??!0})),n.status===`cancelled`)return[];if(n.status===`error`)return console.error(`Gallery selection error:`,n.error),e?.onError?.(n.error),[];let i=r.addFiles([n]);return await r.startUploads(i),i},[t,e?.allowMultiple,e?.mediaType,e?.onError,r]);return{...r,selectAndUpload:i}}function re(){let e=a(null),t=a(0),r=a(0),[i,s]=o({totalBytes:0,durationMs:0,avgSpeed:0,peakSpeed:0,retries:0});return{metrics:i,start:n(()=>{e.current=Date.now(),t.current=0,r.current=0},[]),update:n((t,n,i=0)=>{if(!e.current)return;let a=Date.now()-e.current,o=a>0?t/a*1e3:0;o>r.current&&(r.current=o),s({totalBytes:t,durationMs:a,avgSpeed:a>0?t/a*1e3:0,peakSpeed:r.current,retries:i})},[]),end:n(()=>{let t=i;return e.current=null,t},[i]),reset:n(()=>{e.current=null,t.current=0,r.current=0,s({totalBytes:0,durationMs:0,avgSpeed:0,peakSpeed:0,retries:0})},[])}}function N(e){if(e===0)return`0 Bytes`;let t=1024,n=[`Bytes`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Math.round(e/t**r*100)/100} ${n[r]}`}function P(e){return{".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".png":`image/png`,".gif":`image/gif`,".bmp":`image/bmp`,".webp":`image/webp`,".svg":`image/svg+xml`,".mp4":`video/mp4`,".avi":`video/x-msvideo`,".mov":`video/quicktime`,".wmv":`video/x-ms-wmv`,".flv":`video/x-flv`,".mkv":`video/x-matroska`,".webm":`video/webm`,".mp3":`audio/mpeg`,".wav":`audio/wav`,".aac":`audio/aac`,".flac":`audio/flac`,".m4a":`audio/mp4`,".pdf":`application/pdf`,".doc":`application/msword`,".docx":`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,".xls":`application/vnd.ms-excel`,".xlsx":`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,".ppt":`application/vnd.ms-powerpoint`,".pptx":`application/vnd.openxmlformats-officedocument.presentationml.presentation`,".txt":`text/plain`,".csv":`text/csv`,".json":`application/json`,".xml":`application/xml`,".zip":`application/zip`}[e.toLowerCase().slice(e.lastIndexOf(`.`))]||`application/octet-stream`}function ie(e,t){if(!t||t.length===0)return!0;let n=P(e);return t.some(e=>{if(e.endsWith(`/*`)){let[t]=e.split(`/`);return n.startsWith(`${t}/`)}return e===n})}function ae(e,t,n){return!(t!==void 0&&e>t||n!==void 0&&e<n)}function oe(e){let t=e.lastIndexOf(`.`);return t===-1?``:e.slice(t+1).toLowerCase()}function se(e){let t=e.lastIndexOf(`.`);return t===-1?e:e.slice(0,t)}function ce(e){let t=[`.jpg`,`.jpeg`,`.png`,`.gif`,`.bmp`,`.webp`,`.svg`],n=e.toLowerCase().slice(e.lastIndexOf(`.`));return t.includes(n)}function le(e){let t=[`.mp4`,`.avi`,`.mov`,`.wmv`,`.flv`,`.mkv`,`.webm`],n=e.toLowerCase().slice(e.lastIndexOf(`.`));return t.includes(n)}function ue(e){let t=[`.pdf`,`.doc`,`.docx`,`.xls`,`.xlsx`,`.ppt`,`.pptx`,`.txt`,`.csv`],n=e.toLowerCase().slice(e.lastIndexOf(`.`));return t.includes(n)}let F=function(e){return e.CAMERA=`CAMERA`,e.PHOTO_LIBRARY=`PHOTO_LIBRARY`,e.WRITE_STORAGE=`WRITE_STORAGE`,e.READ_STORAGE=`READ_STORAGE`,e}({}),I=function(e){return e.GRANTED=`granted`,e.DENIED=`denied`,e.NOT_DETERMINED=`not_determined`,e.RESTRICTED=`restricted`,e}({});async function L(){try{return console.log(`Camera permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request camera permission:`,e),!1}}async function R(){try{return console.log(`Photo library permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request photo library permission:`,e),!1}}async function z(){try{return console.log(`Storage read permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request storage read permission:`,e),!1}}async function B(){try{return console.log(`Storage write permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request storage write permission:`,e),!1}}async function de(e){try{return(await Promise.all(e.map(async e=>{switch(e){case F.CAMERA:return L();case F.PHOTO_LIBRARY:return R();case F.READ_STORAGE:return z();case F.WRITE_STORAGE:return B();default:return!1}}))).every(e=>e)}catch(e){return console.error(`Failed to request permissions:`,e),!1}}async function fe(e){try{return!0}catch(e){return console.error(`Failed to check permissions:`,e),!1}}async function pe(e){try{return I.GRANTED}catch(e){return console.error(`Failed to get permission status:`,e),I.DENIED}}function me(){try{console.log(`Opening app settings (requires react-native-app-settings or platform implementation)`)}catch(e){console.error(`Failed to open app settings:`,e)}}function V(e){try{if(e.startsWith(`file://`))return e.replace(`file://`,``).split(`/`).pop()||`file`;if(e.startsWith(`content://`)){let t=e.split(`/`);return t[t.length-1]||`file`}let t=e.split(`/`);return t[t.length-1]||`file`}catch{return`file`}}function he(e){return e.startsWith(`file://`)||e.startsWith(`content://`)?e:`file://${e}`}function H(e){return e.startsWith(`file://`)?e.replace(`file://`,``):(e.startsWith(`content://`),e)}function ge(e){try{let t=H(e).split(`/`);return t.pop(),t.join(`/`)}catch{return``}}function _e(e){return e.startsWith(`content://`)}function ve(e){return e.startsWith(`file://`)}function ye(e){return e.replace(/([^:]\/)\/+/g,`$1`)}function U(e){let t=V(e);return{".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".png":`image/png`,".gif":`image/gif`,".bmp":`image/bmp`,".webp":`image/webp`,".mp4":`video/mp4`,".mov":`video/quicktime`,".avi":`video/x-msvideo`,".mp3":`audio/mpeg`,".wav":`audio/wav`,".aac":`audio/aac`,".pdf":`application/pdf`,".txt":`text/plain`,".json":`application/json`}[t.toLowerCase().slice(t.lastIndexOf(`.`))]||`application/octet-stream`}function W({state:e,label:t}){let n=()=>{switch(e.status){case`uploading`:return`#007AFF`;case`success`:return`#34C759`;case`error`:case`aborted`:return`#FF3B30`;default:return`#999999`}};return y(f,{style:[G.wrapper,{borderLeftColor:n()}],children:[e.status===`uploading`&&v(s,{size:`small`,color:n(),style:G.spinner}),(()=>{switch(e.status){case`idle`:return v(f,{style:G.container,children:v(d,{style:G.label,children:t||`Ready to upload`})});case`uploading`:return y(f,{style:G.container,children:[y(f,{style:G.headerRow,children:[v(d,{style:G.label,children:t||`Uploading`}),y(d,{style:G.percentage,children:[e.progress,`%`]})]}),v(f,{style:G.progressBarContainer,children:v(f,{style:[G.progressBar,{width:`${e.progress}%`,backgroundColor:n()}]})}),v(f,{style:G.detailsRow,children:y(d,{style:G.detail,children:[N(e.bytesUploaded),` /`,` `,N(e.totalBytes||0)]})})]});case`success`:return y(f,{style:G.container,children:[y(f,{style:G.headerRow,children:[v(d,{style:[G.label,{color:n()}],children:t||`Upload complete`}),v(d,{style:[G.percentage,{color:n()}],children:`✓`})]}),v(d,{style:[G.detail,{color:n()}],children:N(e.totalBytes||0)})]});case`error`:return y(f,{style:G.container,children:[y(f,{style:G.headerRow,children:[v(d,{style:[G.label,{color:n()}],children:t||`Upload failed`}),v(d,{style:[G.percentage,{color:n()}],children:`✕`})]}),e.error&&v(d,{style:[G.detail,{color:n()}],children:e.error.message})]});case`aborted`:return v(f,{style:G.container,children:v(d,{style:[G.label,{color:n()}],children:t||`Upload cancelled`})});default:return null}})()]})}const G=u.create({wrapper:{flexDirection:`row`,alignItems:`flex-start`,paddingVertical:8,paddingHorizontal:12,borderLeftWidth:4,backgroundColor:`#f5f5f5`,borderRadius:4,gap:8},spinner:{marginTop:4},container:{flex:1,gap:4},headerRow:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`},label:{fontSize:14,fontWeight:`600`,color:`#333333`,flex:1},percentage:{fontSize:14,fontWeight:`600`,color:`#007AFF`,minWidth:36,textAlign:`right`},progressBarContainer:{height:4,backgroundColor:`#e0e0e0`,borderRadius:2,overflow:`hidden`},progressBar:{height:`100%`,borderRadius:2},detailsRow:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`},detail:{fontSize:12,color:`#666666`}});function be({options:e,label:t=`Take Photo`,children:n,onSuccess:r,onError:a,onCancel:o,showProgress:c=!0}){let{state:u,captureAndUpload:p}=T(e),m=async()=>{try{await p()}catch(e){e instanceof Error&&(e.message.includes(`cancelled`)||e.message.includes(`aborted`)?o?.():a?.(e))}},h=u.status===`uploading`,g=h||u.status===`aborted`;return i(()=>{u.status===`success`&&u.result&&r?.(u.result)},[u.status,u.result,r]),i(()=>{u.status===`error`&&u.error&&a?.(u.error)},[u.status,u.error,a]),y(f,{style:K.container,children:[y(l,{style:[K.button,g&&K.buttonDisabled],onPress:m,disabled:g,children:[h&&v(s,{size:`small`,color:`#FFFFFF`,style:K.spinner}),v(d,{style:K.buttonText,children:n||t})]}),c&&u.status!==`idle`&&v(f,{style:K.progressContainer,children:v(W,{state:u,label:`Camera upload`})})]})}const K=u.create({container:{gap:8},button:{flexDirection:`row`,alignItems:`center`,justifyContent:`center`,paddingVertical:12,paddingHorizontal:16,backgroundColor:`#007AFF`,borderRadius:8,gap:8},buttonDisabled:{opacity:.6},buttonText:{fontSize:16,fontWeight:`600`,color:`#FFFFFF`},spinner:{marginRight:4},progressContainer:{marginTop:4}});function xe({options:e,label:t=`Choose File`,children:n,onSuccess:r,onError:a,onCancel:o,showProgress:c=!0}){let{state:u,pickAndUpload:p}=E(e),m=async()=>{try{await p()}catch(e){e instanceof Error&&(e.message.includes(`cancelled`)||e.message.includes(`aborted`)?o?.():a?.(e))}},h=u.status===`uploading`,g=h||u.status===`aborted`;return i(()=>{u.status===`success`&&u.result&&r?.(u.result)},[u.status,u.result,r]),i(()=>{u.status===`error`&&u.error&&a?.(u.error)},[u.status,u.error,a]),y(f,{style:q.container,children:[y(l,{style:[q.button,g&&q.buttonDisabled],onPress:m,disabled:g,children:[h&&v(s,{size:`small`,color:`#FFFFFF`,style:q.spinner}),v(d,{style:q.buttonText,children:n||t})]}),c&&u.status!==`idle`&&v(f,{style:q.progressContainer,children:v(W,{state:u,label:`File upload`})})]})}const q=u.create({container:{gap:8},button:{flexDirection:`row`,alignItems:`center`,justifyContent:`center`,paddingVertical:12,paddingHorizontal:16,backgroundColor:`#FF9500`,borderRadius:8,gap:8},buttonDisabled:{opacity:.6},buttonText:{fontSize:16,fontWeight:`600`,color:`#FFFFFF`},spinner:{marginRight:4},progressContainer:{marginTop:4}});function Se({options:t,label:n=`Select from Gallery`,children:r,onSuccess:i,onError:a,onCancel:o,showProgress:u=!0}){let{state:p,selectAndUpload:m}=M(t),h=async()=>{try{await m()}catch(e){e instanceof Error&&(e.message.includes(`cancelled`)||e.message.includes(`aborted`)?o?.():a?.(e))}},g=p.items.some(e=>e.status===`uploading`),_=p.items.length>0,b=_&&p.items.every(e=>e.status!==`uploading`&&e.status!==`idle`);return e.useEffect(()=>{if(b){let e=p.items.filter(e=>e.status===`success`).map(e=>e.result);e.length>0&&i?.(e)}},[b,p.items,i]),e.useEffect(()=>{let e=p.items.filter(e=>e.status===`error`)[0]?.error;e&&a?.(e)},[p.items,a]),y(f,{style:J.container,children:[y(l,{style:[J.button,g&&J.buttonDisabled],onPress:h,disabled:g,children:[g&&v(s,{size:`small`,color:`#FFFFFF`,style:J.spinner}),y(d,{style:J.buttonText,children:[r||n,_&&` (${p.items.length})`]})]}),_&&y(f,{style:J.statsContainer,children:[y(d,{style:J.statsText,children:[`Progress: `,p.items.filter(e=>e.status===`success`).length,`/`,p.items.length,` uploaded`]}),y(d,{style:J.statsText,children:[`Overall: `,p.totalProgress,`%`]})]}),u&&_&&v(c,{scrollEnabled:!1,data:p.items,renderItem:({item:e})=>v(f,{style:J.itemContainer,children:v(W,{state:{status:e.status,progress:e.progress,bytesUploaded:e.bytesUploaded,totalBytes:e.totalBytes,error:e.error,result:e.result},label:e.file.data.name})},e.id),keyExtractor:e=>e.id,style:J.listContainer,contentContainerStyle:J.listContent,ItemSeparatorComponent:()=>v(f,{style:J.separator})})]})}const J=u.create({container:{gap:8},button:{flexDirection:`row`,alignItems:`center`,justifyContent:`center`,paddingVertical:12,paddingHorizontal:16,backgroundColor:`#34C759`,borderRadius:8,gap:8},buttonDisabled:{opacity:.6},buttonText:{fontSize:16,fontWeight:`600`,color:`#FFFFFF`},spinner:{marginRight:4},statsContainer:{paddingVertical:8,paddingHorizontal:12,backgroundColor:`#f5f5f5`,borderRadius:4,gap:4},statsText:{fontSize:12,color:`#666666`},listContainer:{maxHeight:400},listContent:{gap:8},itemContainer:{paddingHorizontal:0},separator:{height:4}});function Ce({items:e,onRemove:t,onItemPress:n,showRemoveButton:r=!0}){return e.length===0?v(f,{style:Y.emptyContainer,children:v(d,{style:Y.emptyText,children:`No uploads`})}):y(f,{style:Y.container,children:[y(f,{style:Y.headerRow,children:[y(d,{style:Y.headerText,children:[`Uploads (`,e.length,`)`]}),y(d,{style:Y.headerSubtext,children:[e.filter(e=>e.progress.state===`success`).length,` complete`]})]}),v(c,{scrollEnabled:!1,data:e,renderItem:({item:e})=>y(l,{style:[Y.itemContainer,{borderLeftColor:we(e.progress.state)}],onPress:()=>n?.(e),children:[y(f,{style:Y.itemContent,children:[e.file.status===`success`&&y(f,{style:Y.itemHeader,children:[v(d,{style:Y.fileName,numberOfLines:1,children:e.file.data.name}),v(d,{style:Y.fileSize,children:Te(e.file.data.size)})]}),e.file.status===`error`&&v(d,{style:Y.errorText,children:e.progress.error?.message}),v(f,{style:Y.progressWrapper,children:v(W,{state:{status:e.progress.state===`pending`?`idle`:e.progress.state===`cancelled`?`aborted`:e.progress.state,progress:e.progress.progress,bytesUploaded:e.progress.uploadedBytes,totalBytes:e.progress.totalBytes,error:e.progress.error||null,result:e.result??null}})})]}),r&&e.progress.state!==`uploading`&&e.progress.state!==`pending`&&v(l,{style:Y.removeButton,onPress:()=>t?.(e.id),hitSlop:{top:8,right:8,bottom:8,left:8},children:v(d,{style:Y.removeButtonText,children:`✕`})})]}),keyExtractor:e=>e.id,ItemSeparatorComponent:()=>v(f,{style:Y.separator}),contentContainerStyle:Y.listContent})]})}function we(e){switch(e){case`success`:return`#34C759`;case`error`:case`cancelled`:return`#FF3B30`;case`uploading`:case`pending`:return`#007AFF`;default:return`#999999`}}function Te(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Math.round(e/t**r*10)/10} ${n[r]}`}const Y=u.create({container:{gap:8},headerRow:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`,paddingHorizontal:12,paddingVertical:8,backgroundColor:`#f9f9f9`,borderRadius:4},headerText:{fontSize:16,fontWeight:`600`,color:`#333333`},errorText:{fontSize:14,color:`#FF3B30`},headerSubtext:{fontSize:14,color:`#666666`},listContent:{gap:8},itemContainer:{flexDirection:`row`,alignItems:`center`,paddingVertical:8,paddingHorizontal:12,borderLeftWidth:4,backgroundColor:`#f5f5f5`,borderRadius:4,gap:8},itemContent:{flex:1,gap:6},itemHeader:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`},fileName:{fontSize:14,fontWeight:`500`,color:`#333333`,flex:1},fileSize:{fontSize:12,color:`#999999`,marginLeft:8},progressWrapper:{marginTop:2},removeButton:{width:32,height:32,justifyContent:`center`,alignItems:`center`,borderRadius:16,backgroundColor:`#FFE5E5`},removeButtonText:{fontSize:16,fontWeight:`600`,color:`#FF3B30`},separator:{height:4},emptyContainer:{paddingVertical:24,paddingHorizontal:12,backgroundColor:`#f5f5f5`,borderRadius:4,alignItems:`center`,justifyContent:`center`},emptyText:{fontSize:14,color:`#999999`,fontStyle:`italic`}}),X=t(null);function Z(){let e=r(X);if(!e)throw Error(`useFlowContext must be used within a <Flow> component. Wrap your component tree with <Flow flowId="..." storageId="...">`);return e}const Q=t(null);function $(){let e=r(Q);if(!e)throw Error(`useFlowInputContext must be used within a <Flow.Input> component. Wrap your component with <Flow.Input nodeId="...">`);return e}function Ee({flowId:e,storageId:t,outputNodeId:r,metadata:i,onSuccess:a,onError:o,onProgress:s,onFlowComplete:c,children:l}){let{fileSystemProvider:u}=S(),d=k({flowId:e,storageId:t,outputNodeId:r,metadata:i,onSuccess:a,onError:o,onProgress:s,onFlowComplete:c}),f=n(async e=>{if(!u?.pickDocument)throw Error(`File picker not available`);let t=await u.pickDocument();t.status===`success`&&d.setInput(e,t)},[u,d]),p=n(async()=>{if(!u?.pickDocument)throw Error(`File picker not available`);let e=await u.pickDocument();e.status===`success`&&await d.upload(e)},[u,d]),m={state:d.state,inputMetadata:d.inputMetadata,inputs:d.inputs,inputStates:d.inputStates,setInput:d.setInput,execute:d.execute,upload:d.upload,abort:d.abort,reset:d.reset,isActive:d.isActive,isUploadingFile:d.isUploadingFile,isProcessing:d.isProcessing,isDiscoveringInputs:d.isDiscoveringInputs,pickFileForInput:f,pickAndUpload:p},h={...m,submit:d.execute,cancel:d.abort};return v(X.Provider,{value:m,children:typeof l==`function`?l(h):l})}function De({children:e}){let t=Z();return v(_,{children:e({inputs:t.inputMetadata??[],isLoading:t.isDiscoveringInputs})})}function Oe({nodeId:e,children:t}){let n=Z(),r=n.inputMetadata?.find(t=>t.nodeId===e);if(!r)return null;let i={nodeId:e,metadata:r,value:n.inputs[e],setValue:t=>n.setInput(e,t),state:n.inputStates.get(e),pickFile:async()=>{await n.pickFileForInput(e)}};return v(Q.Provider,{value:i,children:typeof t==`function`?t(i):t})}function ke({children:e}){let t=$(),n=t.value,r=n?.status===`success`,i=r?n?.data?.name??null:null,a=r?n?.data?.size??null:null;return v(_,{children:e({value:t.value,hasFile:r,fileName:i,fileSize:a,progress:t.state?.progress??0,status:t.state?.status??`idle`,pickFile:t.pickFile,clear:()=>t.setValue(void 0)})})}function Ae({children:e}){let t=$(),n=t.value,r=n?.status===`success`,i=typeof t.value==`string`&&t.value.length>0;return v(_,{children:e({value:t.value,hasFile:r,isUrl:i,fileName:r?n?.data?.name??null:null,fileSize:r?n?.data?.size??null:null,fileUri:r?n?.data?.uri??null:null,clear:()=>t.setValue(void 0)})})}function je({children:e}){let t=Z();return v(_,{children:e({progress:t.state.progress,bytesUploaded:t.state.bytesUploaded,totalBytes:t.state.totalBytes,status:t.state.status})})}function Me({children:e}){let t=Z();return v(_,{children:e({status:t.state.status,currentNodeName:t.state.currentNodeName,currentNodeType:t.state.currentNodeType,error:t.state.error,jobId:t.state.jobId,flowStarted:t.state.flowStarted,flowOutputs:t.state.flowOutputs})})}function Ne({children:e}){let t=Z();return v(_,{children:e({error:t.state.error,hasError:t.state.status===`error`,message:t.state.error?.message??null,reset:t.reset})})}function Pe({children:e,disabled:t}){let n=Z(),r={submit:n.execute,isDisabled:t||n.isActive||Object.keys(n.inputs).length===0,isSubmitting:n.isActive};return v(_,{children:typeof e==`function`?e(r):e})}function Fe({children:e}){let t=Z(),n={cancel:t.abort,isDisabled:!t.isActive};return v(_,{children:typeof e==`function`?e(n):e})}function Ie({children:e}){let t=Z(),n={reset:t.reset,isDisabled:t.isActive};return v(_,{children:typeof e==`function`?e(n):e})}function Le({children:e}){let t=Z();return v(_,{children:e({isUploading:t.isActive,progress:t.state.progress,status:t.state.status,pickAndUpload:t.pickAndUpload,abort:t.abort})})}const Re=Object.assign(Ee,{Inputs:De,Input:Object.assign(Oe,{FilePicker:ke,Preview:Ae}),Progress:je,Status:Me,Error:Ne,Submit:Pe,Cancel:Fe,Reset:Ie,QuickUpload:Le});export{be as CameraUploadButton,xe as FileUploadButton,Re as Flow,te as FlowManagerProvider,Se as GalleryUploadButton,I as PermissionStatus,F as PermissionType,Ce as UploadList,W as UploadProgress,b as UploadistaContext,N as formatFileSize,ge as getDirectoryFromUri,oe as getFileExtension,V as getFileNameFromUri,se as getFileNameWithoutExtension,P as getMimeTypeFromFileName,U as getMimeTypeFromUri,pe as getPermissionStatus,fe as hasPermissions,_e as isContentUri,ue as isDocumentFile,ae as isFileSizeValid,ie as isFileTypeAllowed,ve as isFileUri,ce as isImageFile,le as isVideoFile,ye as normalizeUri,me as openAppSettings,he as pathToUri,L as requestCameraPermission,de as requestPermissions,R as requestPhotoLibraryPermission,z as requestStorageReadPermission,B as requestStorageWritePermission,H as uriToPath,T as useCameraUpload,E as useFileUpload,k as useFlow,Z as useFlowContext,$ as useFlowInputContext,O as useFlowManagerContext,M as useGalleryUpload,j as useMultiUpload,re as useUploadMetrics,S as useUploadistaContext};
|
|
1
|
+
import e,{createContext as t,useCallback as n,useContext as r,useEffect as i,useRef as a,useState as o}from"react";import{ActivityIndicator as s,FlatList as c,Pressable as l,StyleSheet as u,Text as d,View as f}from"react-native";import{FlowManager as p,UploadManager as m}from"@uploadista/client-core";import{EventType as h}from"@uploadista/core/flow";import{UploadEventType as g}from"@uploadista/core/types";import{Fragment as _,jsx as v,jsxs as y}from"react/jsx-runtime";const b=t(void 0);function x(e,t){let n=e instanceof ArrayBuffer?new Uint8Array(e):e;return new Blob([n],t)}function S(){let e=r(b);if(!e)throw Error(`useUploadistaClient must be used within an UploadistaProvider`);return e}const C={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,result:null};function w(e={}){let{client:t,fileSystemProvider:r}=S(),[s,c]=o(C),l=a(null),u=a(null);return i(()=>(l.current=new m(async(e,n)=>{let i=e;if(i.status===`success`){let e=x(await r.readFile(i.data.uri),{type:i.data.mimeType||`application/octet-stream`});return t.upload(e,n)}return Promise.resolve({abort:()=>{}})},{onStateChange:c,onProgress:e.onProgress,onChunkComplete:e.onChunkComplete,onSuccess:e.onSuccess,onError:e.onError,onAbort:e.onAbort},{metadata:e.metadata,uploadLengthDeferred:e.uploadLengthDeferred,uploadSize:e.uploadSize,onShouldRetry:e.onShouldRetry}),()=>{l.current?.cleanup()}),[t,r,e]),{state:s,upload:n(async e=>{u.current=e,await l.current?.upload(e)},[]),abort:n(()=>{l.current?.abort()},[]),reset:n(()=>{l.current?.reset(),u.current=null},[]),retry:n(()=>{u.current&&l.current?.canRetry()&&l.current.retry()},[]),isUploading:s.status===`uploading`,canRetry:l.current?.canRetry()??!1,metrics:{getInsights:()=>t.getChunkingInsights(),exportMetrics:()=>t.exportMetrics(),getNetworkMetrics:()=>t.getNetworkMetrics(),getNetworkCondition:()=>t.getNetworkCondition(),resetMetrics:()=>t.resetMetrics()}}}function T(e){let{fileSystemProvider:t}=S(),r=w({metadata:e?.metadata,onSuccess:e?.onSuccess,onError:e?.onError,onProgress:e?.onProgress}),i=n(async()=>{try{let n=await t.pickCamera(e?.cameraOptions);await r.upload(n)}catch(e){console.error(`Camera capture error:`,e)}},[t,e?.cameraOptions,r]);return{...r,captureAndUpload:i}}function E(e){let{fileSystemProvider:t}=S(),r=w({metadata:e?.metadata,onSuccess:e?.onSuccess,onError:e?.onError,onProgress:e?.onProgress}),i=n(async()=>{try{let n=await t.pickDocument({allowedTypes:e?.allowedTypes});await r.upload(n)}catch(e){throw console.error(`File selection error:`,e),e}},[t,e?.allowedTypes,r]);return{...r,pickAndUpload:i}}function ee(e){let t=e;return t.eventType===h.FlowStart||t.eventType===h.FlowEnd||t.eventType===h.FlowError||t.eventType===h.NodeStart||t.eventType===h.NodeEnd||t.eventType===h.NodePause||t.eventType===h.NodeResume||t.eventType===h.NodeError}const D=t(void 0);function te({children:e}){let{client:t,subscribeToEvents:r}=S(),o=a(new Map);i(()=>r(e=>{if(ee(e)){for(let t of o.current.values())t.manager.handleFlowEvent(e);return}if(`type`in e&&e.type===g.UPLOAD_PROGRESS&&`data`in e)for(let t of o.current.values())t.manager.handleUploadProgress(e.data.id,e.data.progress,e.data.total)}),[r]);let s=n((e,n,r)=>{let i=o.current.get(e);if(i)return i.refCount++,i.manager;let a=new p(t.uploadWithFlow,n,r,t.multiInputFlowUpload);return o.current.set(e,{manager:a,refCount:1,flowId:e}),a},[t]),c=n(e=>{let t=o.current.get(e);t&&(t.refCount--,t.refCount<=0&&(t.manager.cleanup(),o.current.delete(e)))},[]);return v(D.Provider,{value:{getManager:s,releaseManager:c},children:e})}function O(){let e=r(D);if(e===void 0)throw Error(`useFlowManagerContext must be used within a FlowManagerProvider. Make sure to wrap your component tree with <FlowManagerProvider>.`);return e}const ne={status:`idle`,progress:0,bytesUploaded:0,totalBytes:null,error:null,jobId:null,flowStarted:!1,currentNodeName:null,currentNodeType:null,flowOutputs:null};function k(e){let{client:t,fileSystemProvider:r}=S(),{getManager:s,releaseManager:c}=O(),[l,u]=o(ne),[d,f]=o(null),[p,m]=o(!1),[h,g]=o({}),[_,v]=o(new Map),y=a(null),b=a(null),C=a(e);i(()=>{C.current=e}),i(()=>{(async()=>{m(!0);try{let{flow:n}=await t.getFlow(e.flowId);f(n.nodes.filter(e=>e.type===`input`).map(e=>({nodeId:e.id,nodeName:e.name,nodeDescription:e.description,inputTypeId:e.inputTypeId,required:!0})))}catch(e){console.error(`Failed to discover flow inputs:`,e)}finally{m(!1)}})()},[t,e.flowId]),i(()=>{let t=e.flowId;y.current=s(t,{onStateChange:e=>{u(e)},onProgress:(e,t,n)=>{if(C.current.onProgress){let e=n?Math.round(t/n*100):0;C.current.onProgress(e,t,n)}},onChunkComplete:(e,t,n)=>{C.current.onChunkComplete?.(e,t,n)},onFlowComplete:e=>{C.current.onFlowComplete?.(e)},onSuccess:e=>{C.current.onSuccess?.(e)},onError:e=>{C.current.onError?.(e)},onAbort:()=>{}},{flowConfig:{flowId:e.flowId,storageId:e.storageId,outputNodeId:e.outputNodeId,metadata:e.metadata},onChunkComplete:e.onChunkComplete,onSuccess:e.onSuccess,onError:e.onError});let n=setInterval(()=>{if(y.current){let e=y.current.getInputStates();e.size>0&&v(new Map(e))}},100);return()=>{clearInterval(n),c(t),y.current=null}},[e.flowId,e.storageId,e.outputNodeId,s,c]);let w=n((e,t)=>{g(n=>({...n,[e]:t}))},[]),T=n(async e=>{if(e.status===`cancelled`)return null;if(e.status===`error`)throw e.error;return x(await r.readFile(e.data.uri),{type:e.data.mimeType||`application/octet-stream`})},[r]),E=n(async()=>{if(!y.current)throw Error(`FlowManager not initialized`);if(Object.keys(h).length===0)throw Error(`No inputs provided. Use setInput() to provide inputs before calling execute()`);b.current={...h};let e={};for(let[t,n]of Object.entries(h))if(n&&typeof n==`object`&&`status`in n&&(n.status===`success`||n.status===`cancelled`||n.status===`error`)){let r=await T(n);r&&(e[t]=r)}else e[t]=n;if(Object.keys(e).length===0)throw Error(`No valid inputs after processing. All files may have been cancelled.`);await y.current.executeFlow(e)},[h,T]);return{state:l,inputMetadata:d,inputStates:_,inputs:h,setInput:w,execute:E,upload:n(async t=>{if(t.status!==`cancelled`){if(t.status===`error`){e.onError?.(t.error);return}if(!y.current)throw Error(`FlowManager not initialized`);if(d&&d.length>0){let e=d[0];e&&(b.current={[e.nodeId]:t})}try{let e=x(await r.readFile(t.data.uri),{type:t.data.mimeType||`application/octet-stream`});if(d&&d.length>0){let n=d[0];if(!n)throw Error(`No input nodes found`);g({[n.nodeId]:t}),await y.current.executeFlow({[n.nodeId]:e})}else await y.current.upload(e)}catch(t){e.onError?.(t)}}},[d,r,e]),abort:n(()=>{y.current?.abort()},[]),reset:n(()=>{y.current?.reset(),g({}),v(new Map),b.current=null},[]),retry:n(()=>{b.current&&(l.status===`error`||l.status===`aborted`)&&(g(b.current),E())},[E,l.status]),isActive:l.status===`uploading`||l.status===`processing`,isUploadingFile:l.status===`uploading`,isProcessing:l.status===`processing`,isDiscoveringInputs:p,canRetry:(l.status===`error`||l.status===`aborted`)&&b.current!==null}}const A={items:[],totalProgress:0,totalUploaded:0,totalBytes:0,activeCount:0,completedCount:0,failedCount:0};function j(e={}){let{client:t}=S(),[r,i]=o(A),s=a(new Map),c=a(0),l=a([]),u=n(()=>`upload-${Date.now()}-${c.current++}`,[]),d=n(e=>{let t=e.reduce((e,t)=>e+t.totalBytes,0),n=e.reduce((e,t)=>e+t.bytesUploaded,0),r=t>0?Math.round(n/t*100):0,a=e.filter(e=>e.status===`uploading`).length,o=e.filter(e=>e.status===`success`).length,s=e.filter(e=>e.status===`error`).length;l.current=e,i(i=>({...i,items:e,totalProgress:r,totalUploaded:n,totalBytes:t,activeCount:a,completedCount:o,failedCount:s}))},[]),f=n(e=>{let t=e.filter(e=>e.status===`success`).map(e=>({id:u(),file:e,status:`idle`,progress:0,bytesUploaded:0,totalBytes:e.data.size,error:null,result:null})),n=[...l.current,...t];return l.current=n,i(e=>{let t=n.reduce((e,t)=>e+t.totalBytes,0);return{...e,items:n,totalBytes:t}}),t.map(e=>e.id)},[u]),p=n(async n=>{try{console.log(`Uploading item:`,n.file.data.name),d(l.current.map(e=>e.id===n.id?{...e,status:`uploading`}:e));let r=await(await fetch(n.file.data.uri)).blob(),i=r;if(n.file.data.mimeType){let e={type:n.file.data.mimeType,lastModified:Date.now()};i=new Blob([r],e)}console.log(`Uploading input:`,i);let a=await t.upload(i,{metadata:e.metadata,onProgress:(e,t,r)=>{let i=r?Math.round(t/r*100):0;d(l.current.map(e=>e.id===n.id?{...e,progress:i,bytesUploaded:t,totalBytes:r||e.totalBytes}:e))},onSuccess:t=>{d(l.current.map(e=>e.id===n.id?{...e,status:`success`,progress:100,result:t,bytesUploaded:t.size||e.totalBytes}:e)),e.onSuccess?.(t),s.current.delete(n.id)},onError:t=>{d(l.current.map(e=>e.id===n.id?{...e,status:`error`,error:t}:e)),e.onError?.(t),s.current.delete(n.id)}});s.current.set(n.id,a)}catch(t){console.error(`Error uploading item:`,t),d(l.current.map(e=>e.id===n.id?{...e,status:`error`,error:t}:e)),e.onError?.(t),s.current.delete(n.id)}},[t,e,d]),m=n(async t=>{let n=e.maxConcurrent||3,r=t?l.current.filter(e=>t.includes(e.id)&&e.status===`idle`):l.current.filter(e=>e.status===`idle`);console.log(`Items to upload:`,r.length,r);for(let e=0;e<r.length;e+=n){let t=r.slice(e,e+n);await Promise.all(t.map(e=>p(e)))}},[e.maxConcurrent,p]),h=n(e=>{let t=s.current.get(e);t&&(t.abort(),s.current.delete(e)),d(l.current.filter(t=>t.id!==e))},[d]),g=n(e=>{let t=s.current.get(e);t&&(t.abort(),s.current.delete(e)),d(l.current.map(t=>t.id===e?{...t,status:`aborted`}:t))},[d]),_=n(()=>{s.current.forEach(e=>{e.abort()}),s.current.clear(),l.current=[],i(A)},[]);return{state:r,addFiles:f,startUploads:m,removeItem:h,abortItem:g,retryItem:n(async e=>{let t=l.current.find(t=>t.id===e);if(t&&(t.status===`error`||t.status===`aborted`)){d(l.current.map(t=>t.id===e?{...t,status:`idle`,progress:0,bytesUploaded:0,error:null}:t));let t=l.current.find(t=>t.id===e);t&&await p(t)}},[p,d]),clear:_}}function M(e){let{fileSystemProvider:t}=S(),r=j({maxConcurrent:3,metadata:e?.metadata,onSuccess:e?.onSuccess,onError:e?.onError}),i=n(async()=>{let n;if(n=e?.mediaType===`video`?await t.pickVideo({allowMultiple:e?.allowMultiple??!0}):(e?.mediaType,await t.pickImage({allowMultiple:e?.allowMultiple??!0})),n.status===`cancelled`)return[];if(n.status===`error`)return console.error(`Gallery selection error:`,n.error),e?.onError?.(n.error),[];let i=r.addFiles([n]);return await r.startUploads(i),i},[t,e?.allowMultiple,e?.mediaType,e?.onError,r]);return{...r,selectAndUpload:i}}function re(){let e=a(null),t=a(0),r=a(0),[i,s]=o({totalBytes:0,durationMs:0,avgSpeed:0,peakSpeed:0,retries:0});return{metrics:i,start:n(()=>{e.current=Date.now(),t.current=0,r.current=0},[]),update:n((t,n,i=0)=>{if(!e.current)return;let a=Date.now()-e.current,o=a>0?t/a*1e3:0;o>r.current&&(r.current=o),s({totalBytes:t,durationMs:a,avgSpeed:a>0?t/a*1e3:0,peakSpeed:r.current,retries:i})},[]),end:n(()=>{let t=i;return e.current=null,t},[i]),reset:n(()=>{e.current=null,t.current=0,r.current=0,s({totalBytes:0,durationMs:0,avgSpeed:0,peakSpeed:0,retries:0})},[])}}function N(e){if(e===0)return`0 Bytes`;let t=1024,n=[`Bytes`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Math.round(e/t**r*100)/100} ${n[r]}`}function P(e){return{".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".png":`image/png`,".gif":`image/gif`,".bmp":`image/bmp`,".webp":`image/webp`,".svg":`image/svg+xml`,".mp4":`video/mp4`,".avi":`video/x-msvideo`,".mov":`video/quicktime`,".wmv":`video/x-ms-wmv`,".flv":`video/x-flv`,".mkv":`video/x-matroska`,".webm":`video/webm`,".mp3":`audio/mpeg`,".wav":`audio/wav`,".aac":`audio/aac`,".flac":`audio/flac`,".m4a":`audio/mp4`,".pdf":`application/pdf`,".doc":`application/msword`,".docx":`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,".xls":`application/vnd.ms-excel`,".xlsx":`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,".ppt":`application/vnd.ms-powerpoint`,".pptx":`application/vnd.openxmlformats-officedocument.presentationml.presentation`,".txt":`text/plain`,".csv":`text/csv`,".json":`application/json`,".xml":`application/xml`,".zip":`application/zip`}[e.toLowerCase().slice(e.lastIndexOf(`.`))]||`application/octet-stream`}function ie(e,t){if(!t||t.length===0)return!0;let n=P(e);return t.some(e=>{if(e.endsWith(`/*`)){let[t]=e.split(`/`);return n.startsWith(`${t}/`)}return e===n})}function ae(e,t,n){return!(t!==void 0&&e>t||n!==void 0&&e<n)}function oe(e){let t=e.lastIndexOf(`.`);return t===-1?``:e.slice(t+1).toLowerCase()}function se(e){let t=e.lastIndexOf(`.`);return t===-1?e:e.slice(0,t)}function ce(e){let t=[`.jpg`,`.jpeg`,`.png`,`.gif`,`.bmp`,`.webp`,`.svg`],n=e.toLowerCase().slice(e.lastIndexOf(`.`));return t.includes(n)}function le(e){let t=[`.mp4`,`.avi`,`.mov`,`.wmv`,`.flv`,`.mkv`,`.webm`],n=e.toLowerCase().slice(e.lastIndexOf(`.`));return t.includes(n)}function ue(e){let t=[`.pdf`,`.doc`,`.docx`,`.xls`,`.xlsx`,`.ppt`,`.pptx`,`.txt`,`.csv`],n=e.toLowerCase().slice(e.lastIndexOf(`.`));return t.includes(n)}let F=function(e){return e.CAMERA=`CAMERA`,e.PHOTO_LIBRARY=`PHOTO_LIBRARY`,e.WRITE_STORAGE=`WRITE_STORAGE`,e.READ_STORAGE=`READ_STORAGE`,e}({}),I=function(e){return e.GRANTED=`granted`,e.DENIED=`denied`,e.NOT_DETERMINED=`not_determined`,e.RESTRICTED=`restricted`,e}({});async function L(){try{return console.log(`Camera permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request camera permission:`,e),!1}}async function R(){try{return console.log(`Photo library permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request photo library permission:`,e),!1}}async function z(){try{return console.log(`Storage read permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request storage read permission:`,e),!1}}async function B(){try{return console.log(`Storage write permission requested (handled by file system provider)`),!0}catch(e){return console.error(`Failed to request storage write permission:`,e),!1}}async function de(e){try{return(await Promise.all(e.map(async e=>{switch(e){case F.CAMERA:return L();case F.PHOTO_LIBRARY:return R();case F.READ_STORAGE:return z();case F.WRITE_STORAGE:return B();default:return!1}}))).every(e=>e)}catch(e){return console.error(`Failed to request permissions:`,e),!1}}async function fe(e){try{return!0}catch(e){return console.error(`Failed to check permissions:`,e),!1}}async function pe(e){try{return I.GRANTED}catch(e){return console.error(`Failed to get permission status:`,e),I.DENIED}}function me(){try{console.log(`Opening app settings (requires react-native-app-settings or platform implementation)`)}catch(e){console.error(`Failed to open app settings:`,e)}}function V(e){try{if(e.startsWith(`file://`))return e.replace(`file://`,``).split(`/`).pop()||`file`;if(e.startsWith(`content://`)){let t=e.split(`/`);return t[t.length-1]||`file`}let t=e.split(`/`);return t[t.length-1]||`file`}catch{return`file`}}function he(e){return e.startsWith(`file://`)||e.startsWith(`content://`)?e:`file://${e}`}function H(e){return e.startsWith(`file://`)?e.replace(`file://`,``):(e.startsWith(`content://`),e)}function ge(e){try{let t=H(e).split(`/`);return t.pop(),t.join(`/`)}catch{return``}}function _e(e){return e.startsWith(`content://`)}function ve(e){return e.startsWith(`file://`)}function ye(e){return e.replace(/([^:]\/)\/+/g,`$1`)}function U(e){let t=V(e);return{".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".png":`image/png`,".gif":`image/gif`,".bmp":`image/bmp`,".webp":`image/webp`,".mp4":`video/mp4`,".mov":`video/quicktime`,".avi":`video/x-msvideo`,".mp3":`audio/mpeg`,".wav":`audio/wav`,".aac":`audio/aac`,".pdf":`application/pdf`,".txt":`text/plain`,".json":`application/json`}[t.toLowerCase().slice(t.lastIndexOf(`.`))]||`application/octet-stream`}function W({state:e,label:t}){let n=()=>{switch(e.status){case`uploading`:return`#007AFF`;case`success`:return`#34C759`;case`error`:case`aborted`:return`#FF3B30`;default:return`#999999`}};return y(f,{style:[G.wrapper,{borderLeftColor:n()}],children:[e.status===`uploading`&&v(s,{size:`small`,color:n(),style:G.spinner}),(()=>{switch(e.status){case`idle`:return v(f,{style:G.container,children:v(d,{style:G.label,children:t||`Ready to upload`})});case`uploading`:return y(f,{style:G.container,children:[y(f,{style:G.headerRow,children:[v(d,{style:G.label,children:t||`Uploading`}),y(d,{style:G.percentage,children:[e.progress,`%`]})]}),v(f,{style:G.progressBarContainer,children:v(f,{style:[G.progressBar,{width:`${e.progress}%`,backgroundColor:n()}]})}),v(f,{style:G.detailsRow,children:y(d,{style:G.detail,children:[N(e.bytesUploaded),` /`,` `,N(e.totalBytes||0)]})})]});case`success`:return y(f,{style:G.container,children:[y(f,{style:G.headerRow,children:[v(d,{style:[G.label,{color:n()}],children:t||`Upload complete`}),v(d,{style:[G.percentage,{color:n()}],children:`✓`})]}),v(d,{style:[G.detail,{color:n()}],children:N(e.totalBytes||0)})]});case`error`:return y(f,{style:G.container,children:[y(f,{style:G.headerRow,children:[v(d,{style:[G.label,{color:n()}],children:t||`Upload failed`}),v(d,{style:[G.percentage,{color:n()}],children:`✕`})]}),e.error&&v(d,{style:[G.detail,{color:n()}],children:e.error.message})]});case`aborted`:return v(f,{style:G.container,children:v(d,{style:[G.label,{color:n()}],children:t||`Upload cancelled`})});default:return null}})()]})}const G=u.create({wrapper:{flexDirection:`row`,alignItems:`flex-start`,paddingVertical:8,paddingHorizontal:12,borderLeftWidth:4,backgroundColor:`#f5f5f5`,borderRadius:4,gap:8},spinner:{marginTop:4},container:{flex:1,gap:4},headerRow:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`},label:{fontSize:14,fontWeight:`600`,color:`#333333`,flex:1},percentage:{fontSize:14,fontWeight:`600`,color:`#007AFF`,minWidth:36,textAlign:`right`},progressBarContainer:{height:4,backgroundColor:`#e0e0e0`,borderRadius:2,overflow:`hidden`},progressBar:{height:`100%`,borderRadius:2},detailsRow:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`},detail:{fontSize:12,color:`#666666`}});function be({options:e,label:t=`Take Photo`,children:n,onSuccess:r,onError:a,onCancel:o,showProgress:c=!0}){let{state:u,captureAndUpload:p}=T(e),m=async()=>{try{await p()}catch(e){e instanceof Error&&(e.message.includes(`cancelled`)||e.message.includes(`aborted`)?o?.():a?.(e))}},h=u.status===`uploading`,g=h||u.status===`aborted`;return i(()=>{u.status===`success`&&u.result&&r?.(u.result)},[u.status,u.result,r]),i(()=>{u.status===`error`&&u.error&&a?.(u.error)},[u.status,u.error,a]),y(f,{style:K.container,children:[y(l,{style:[K.button,g&&K.buttonDisabled],onPress:m,disabled:g,children:[h&&v(s,{size:`small`,color:`#FFFFFF`,style:K.spinner}),v(d,{style:K.buttonText,children:n||t})]}),c&&u.status!==`idle`&&v(f,{style:K.progressContainer,children:v(W,{state:u,label:`Camera upload`})})]})}const K=u.create({container:{gap:8},button:{flexDirection:`row`,alignItems:`center`,justifyContent:`center`,paddingVertical:12,paddingHorizontal:16,backgroundColor:`#007AFF`,borderRadius:8,gap:8},buttonDisabled:{opacity:.6},buttonText:{fontSize:16,fontWeight:`600`,color:`#FFFFFF`},spinner:{marginRight:4},progressContainer:{marginTop:4}});function xe({options:e,label:t=`Choose File`,children:n,onSuccess:r,onError:a,onCancel:o,showProgress:c=!0}){let{state:u,pickAndUpload:p}=E(e),m=async()=>{try{await p()}catch(e){e instanceof Error&&(e.message.includes(`cancelled`)||e.message.includes(`aborted`)?o?.():a?.(e))}},h=u.status===`uploading`,g=h||u.status===`aborted`;return i(()=>{u.status===`success`&&u.result&&r?.(u.result)},[u.status,u.result,r]),i(()=>{u.status===`error`&&u.error&&a?.(u.error)},[u.status,u.error,a]),y(f,{style:q.container,children:[y(l,{style:[q.button,g&&q.buttonDisabled],onPress:m,disabled:g,children:[h&&v(s,{size:`small`,color:`#FFFFFF`,style:q.spinner}),v(d,{style:q.buttonText,children:n||t})]}),c&&u.status!==`idle`&&v(f,{style:q.progressContainer,children:v(W,{state:u,label:`File upload`})})]})}const q=u.create({container:{gap:8},button:{flexDirection:`row`,alignItems:`center`,justifyContent:`center`,paddingVertical:12,paddingHorizontal:16,backgroundColor:`#FF9500`,borderRadius:8,gap:8},buttonDisabled:{opacity:.6},buttonText:{fontSize:16,fontWeight:`600`,color:`#FFFFFF`},spinner:{marginRight:4},progressContainer:{marginTop:4}});function Se({options:t,label:n=`Select from Gallery`,children:r,onSuccess:i,onError:a,onCancel:o,showProgress:u=!0}){let{state:p,selectAndUpload:m}=M(t),h=async()=>{try{await m()}catch(e){e instanceof Error&&(e.message.includes(`cancelled`)||e.message.includes(`aborted`)?o?.():a?.(e))}},g=p.items.some(e=>e.status===`uploading`),_=p.items.length>0,b=_&&p.items.every(e=>e.status!==`uploading`&&e.status!==`idle`);return e.useEffect(()=>{if(b){let e=p.items.filter(e=>e.status===`success`).map(e=>e.result);e.length>0&&i?.(e)}},[b,p.items,i]),e.useEffect(()=>{let e=p.items.filter(e=>e.status===`error`)[0]?.error;e&&a?.(e)},[p.items,a]),y(f,{style:J.container,children:[y(l,{style:[J.button,g&&J.buttonDisabled],onPress:h,disabled:g,children:[g&&v(s,{size:`small`,color:`#FFFFFF`,style:J.spinner}),y(d,{style:J.buttonText,children:[r||n,_&&` (${p.items.length})`]})]}),_&&y(f,{style:J.statsContainer,children:[y(d,{style:J.statsText,children:[`Progress: `,p.items.filter(e=>e.status===`success`).length,`/`,p.items.length,` uploaded`]}),y(d,{style:J.statsText,children:[`Overall: `,p.totalProgress,`%`]})]}),u&&_&&v(c,{scrollEnabled:!1,data:p.items,renderItem:({item:e})=>v(f,{style:J.itemContainer,children:v(W,{state:{status:e.status,progress:e.progress,bytesUploaded:e.bytesUploaded,totalBytes:e.totalBytes,error:e.error,result:e.result},label:e.file.data.name})},e.id),keyExtractor:e=>e.id,style:J.listContainer,contentContainerStyle:J.listContent,ItemSeparatorComponent:()=>v(f,{style:J.separator})})]})}const J=u.create({container:{gap:8},button:{flexDirection:`row`,alignItems:`center`,justifyContent:`center`,paddingVertical:12,paddingHorizontal:16,backgroundColor:`#34C759`,borderRadius:8,gap:8},buttonDisabled:{opacity:.6},buttonText:{fontSize:16,fontWeight:`600`,color:`#FFFFFF`},spinner:{marginRight:4},statsContainer:{paddingVertical:8,paddingHorizontal:12,backgroundColor:`#f5f5f5`,borderRadius:4,gap:4},statsText:{fontSize:12,color:`#666666`},listContainer:{maxHeight:400},listContent:{gap:8},itemContainer:{paddingHorizontal:0},separator:{height:4}});function Ce({items:e,onRemove:t,onItemPress:n,showRemoveButton:r=!0}){return e.length===0?v(f,{style:Y.emptyContainer,children:v(d,{style:Y.emptyText,children:`No uploads`})}):y(f,{style:Y.container,children:[y(f,{style:Y.headerRow,children:[y(d,{style:Y.headerText,children:[`Uploads (`,e.length,`)`]}),y(d,{style:Y.headerSubtext,children:[e.filter(e=>e.progress.state===`success`).length,` complete`]})]}),v(c,{scrollEnabled:!1,data:e,renderItem:({item:e})=>y(l,{style:[Y.itemContainer,{borderLeftColor:we(e.progress.state)}],onPress:()=>n?.(e),children:[y(f,{style:Y.itemContent,children:[e.file.status===`success`&&y(f,{style:Y.itemHeader,children:[v(d,{style:Y.fileName,numberOfLines:1,children:e.file.data.name}),v(d,{style:Y.fileSize,children:Te(e.file.data.size)})]}),e.file.status===`error`&&v(d,{style:Y.errorText,children:e.progress.error?.message}),v(f,{style:Y.progressWrapper,children:v(W,{state:{status:e.progress.state===`pending`?`idle`:e.progress.state===`cancelled`?`aborted`:e.progress.state,progress:e.progress.progress,bytesUploaded:e.progress.uploadedBytes,totalBytes:e.progress.totalBytes,error:e.progress.error||null,result:e.result??null}})})]}),r&&e.progress.state!==`uploading`&&e.progress.state!==`pending`&&v(l,{style:Y.removeButton,onPress:()=>t?.(e.id),hitSlop:{top:8,right:8,bottom:8,left:8},children:v(d,{style:Y.removeButtonText,children:`✕`})})]}),keyExtractor:e=>e.id,ItemSeparatorComponent:()=>v(f,{style:Y.separator}),contentContainerStyle:Y.listContent})]})}function we(e){switch(e){case`success`:return`#34C759`;case`error`:case`cancelled`:return`#FF3B30`;case`uploading`:case`pending`:return`#007AFF`;default:return`#999999`}}function Te(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Math.round(e/t**r*10)/10} ${n[r]}`}const Y=u.create({container:{gap:8},headerRow:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`,paddingHorizontal:12,paddingVertical:8,backgroundColor:`#f9f9f9`,borderRadius:4},headerText:{fontSize:16,fontWeight:`600`,color:`#333333`},errorText:{fontSize:14,color:`#FF3B30`},headerSubtext:{fontSize:14,color:`#666666`},listContent:{gap:8},itemContainer:{flexDirection:`row`,alignItems:`center`,paddingVertical:8,paddingHorizontal:12,borderLeftWidth:4,backgroundColor:`#f5f5f5`,borderRadius:4,gap:8},itemContent:{flex:1,gap:6},itemHeader:{flexDirection:`row`,justifyContent:`space-between`,alignItems:`center`},fileName:{fontSize:14,fontWeight:`500`,color:`#333333`,flex:1},fileSize:{fontSize:12,color:`#999999`,marginLeft:8},progressWrapper:{marginTop:2},removeButton:{width:32,height:32,justifyContent:`center`,alignItems:`center`,borderRadius:16,backgroundColor:`#FFE5E5`},removeButtonText:{fontSize:16,fontWeight:`600`,color:`#FF3B30`},separator:{height:4},emptyContainer:{paddingVertical:24,paddingHorizontal:12,backgroundColor:`#f5f5f5`,borderRadius:4,alignItems:`center`,justifyContent:`center`},emptyText:{fontSize:14,color:`#999999`,fontStyle:`italic`}}),X=t(null);function Z(){let e=r(X);if(!e)throw Error(`useFlowContext must be used within a <Flow> component. Wrap your component tree with <Flow flowId="..." storageId="...">`);return e}const Q=t(null);function $(){let e=r(Q);if(!e)throw Error(`useFlowInputContext must be used within a <Flow.Input> component. Wrap your component with <Flow.Input nodeId="...">`);return e}function Ee({flowId:e,storageId:t,outputNodeId:r,metadata:i,onSuccess:a,onError:o,onProgress:s,onFlowComplete:c,children:l}){let{fileSystemProvider:u}=S(),d=k({flowId:e,storageId:t,outputNodeId:r,metadata:i,onSuccess:a,onError:o,onProgress:s,onFlowComplete:c}),f=n(async e=>{if(!u?.pickDocument)throw Error(`File picker not available`);let t=await u.pickDocument();t.status===`success`&&d.setInput(e,t)},[u,d]),p=n(async()=>{if(!u?.pickDocument)throw Error(`File picker not available`);let e=await u.pickDocument();e.status===`success`&&await d.upload(e)},[u,d]),m={state:d.state,inputMetadata:d.inputMetadata,inputs:d.inputs,inputStates:d.inputStates,setInput:d.setInput,execute:d.execute,upload:d.upload,abort:d.abort,reset:d.reset,isActive:d.isActive,isUploadingFile:d.isUploadingFile,isProcessing:d.isProcessing,isDiscoveringInputs:d.isDiscoveringInputs,pickFileForInput:f,pickAndUpload:p},h={...m,submit:d.execute,cancel:d.abort};return v(X.Provider,{value:m,children:typeof l==`function`?l(h):l})}function De({children:e}){let t=Z();return v(_,{children:e({inputs:t.inputMetadata??[],isLoading:t.isDiscoveringInputs})})}function Oe({nodeId:e,children:t}){let n=Z(),r=n.inputMetadata?.find(t=>t.nodeId===e);if(!r)return null;let i={nodeId:e,metadata:r,value:n.inputs[e],setValue:t=>n.setInput(e,t),state:n.inputStates.get(e),pickFile:async()=>{await n.pickFileForInput(e)}};return v(Q.Provider,{value:i,children:typeof t==`function`?t(i):t})}function ke({children:e}){let t=$(),n=t.value,r=n?.status===`success`,i=r?n?.data?.name??null:null,a=r?n?.data?.size??null:null;return v(_,{children:e({value:t.value,hasFile:r,fileName:i,fileSize:a,progress:t.state?.progress??0,status:t.state?.status??`idle`,pickFile:t.pickFile,clear:()=>t.setValue(void 0)})})}function Ae({children:e}){let t=$(),n=t.value,r=n?.status===`success`,i=typeof t.value==`string`&&t.value.length>0;return v(_,{children:e({value:t.value,hasFile:r,isUrl:i,fileName:r?n?.data?.name??null:null,fileSize:r?n?.data?.size??null:null,fileUri:r?n?.data?.uri??null:null,clear:()=>t.setValue(void 0)})})}function je({children:e}){let t=Z();return v(_,{children:e({progress:t.state.progress,bytesUploaded:t.state.bytesUploaded,totalBytes:t.state.totalBytes,status:t.state.status})})}function Me({children:e}){let t=Z();return v(_,{children:e({status:t.state.status,currentNodeName:t.state.currentNodeName,currentNodeType:t.state.currentNodeType,error:t.state.error,jobId:t.state.jobId,flowStarted:t.state.flowStarted,flowOutputs:t.state.flowOutputs})})}function Ne({children:e}){let t=Z();return v(_,{children:e({error:t.state.error,hasError:t.state.status===`error`,message:t.state.error?.message??null,reset:t.reset})})}function Pe({children:e,disabled:t}){let n=Z(),r={submit:n.execute,isDisabled:t||n.isActive||Object.keys(n.inputs).length===0,isSubmitting:n.isActive};return v(_,{children:typeof e==`function`?e(r):e})}function Fe({children:e}){let t=Z(),n={cancel:t.abort,isDisabled:!t.isActive};return v(_,{children:typeof e==`function`?e(n):e})}function Ie({children:e}){let t=Z(),n={reset:t.reset,isDisabled:t.isActive};return v(_,{children:typeof e==`function`?e(n):e})}function Le({children:e}){let t=Z();return v(_,{children:e({isUploading:t.isActive,progress:t.state.progress,status:t.state.status,pickAndUpload:t.pickAndUpload,abort:t.abort})})}const Re=Object.assign(Ee,{Inputs:De,Input:Object.assign(Oe,{FilePicker:ke,Preview:Ae}),Progress:je,Status:Me,Error:Ne,Submit:Pe,Cancel:Fe,Reset:Ie,QuickUpload:Le});export{be as CameraUploadButton,xe as FileUploadButton,Re as Flow,te as FlowManagerProvider,Se as GalleryUploadButton,I as PermissionStatus,F as PermissionType,Ce as UploadList,W as UploadProgress,b as UploadistaContext,N as formatFileSize,ge as getDirectoryFromUri,oe as getFileExtension,V as getFileNameFromUri,se as getFileNameWithoutExtension,P as getMimeTypeFromFileName,U as getMimeTypeFromUri,pe as getPermissionStatus,fe as hasPermissions,_e as isContentUri,ue as isDocumentFile,ae as isFileSizeValid,ie as isFileTypeAllowed,ve as isFileUri,ce as isImageFile,le as isVideoFile,ye as normalizeUri,me as openAppSettings,he as pathToUri,L as requestCameraPermission,de as requestPermissions,R as requestPhotoLibraryPermission,z as requestStorageReadPermission,B as requestStorageWritePermission,H as uriToPath,T as useCameraUpload,E as useFileUpload,k as useFlow,Z as useFlowContext,$ as useFlowInputContext,O as useFlowManagerContext,M as useGalleryUpload,j as useMultiUpload,re as useUploadMetrics,S as useUploadistaContext};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["initialState: UploadState","initialState","initialState: FlowUploadState","initialState","processedInputs: Record<string, unknown>","initialState: MultiUploadState","newItems: UploadItemState[]","result: FilePickResult","parts","getStatusColor","styles","styles","styles","styles","contextValue: FlowContextValue","renderProps: FlowRenderProps","contextValue: FlowInputContextValue","renderProps: FlowSubmitRenderProps","renderProps: FlowCancelRenderProps","renderProps: FlowResetRenderProps"],"sources":["../src/hooks/uploadista-context.ts","../src/types/platform-types.ts","../src/hooks/use-uploadista-context.ts","../src/hooks/use-upload.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/contexts/flow-manager-context.tsx","../src/hooks/use-flow.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts","../src/components/UploadProgress.tsx","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx","../src/components/flow-primitives.tsx"],"sourcesContent":["import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport { createContext } from \"react\";\nimport type { FileSystemProvider } from \"../types\";\nimport type { UseUploadistaClientReturn } from \"./use-uploadista-client\";\n\nexport interface UploadistaContextType extends UseUploadistaClientReturn {\n fileSystemProvider: FileSystemProvider;\n /**\n * Subscribe to events (used internally by hooks)\n * @internal\n */\n subscribeToEvents: (handler: (event: UploadistaEvent) => void) => () => void;\n}\n\nexport const UploadistaContext = createContext<\n UploadistaContextType | undefined\n>(undefined);\n","/**\n * Platform-specific type definitions for React Native\n *\n * React Native's Blob implementation differs from the browser's Blob API.\n * This file provides proper type definitions and guards for platform-specific behavior.\n */\n\n/**\n * BufferSource represents data that can be passed to Blob constructor\n * Includes both ArrayBuffer and typed arrays (Uint8Array, etc.)\n */\nexport type BufferSource = ArrayBuffer | ArrayBufferView;\n\n/**\n * React Native Blob constructor options\n * Extends standard BlobPropertyBag with platform-specific properties\n */\nexport interface ReactNativeBlobOptions {\n /** MIME type of the blob */\n type?: string;\n /** Platform-specific: file path for optimization (React Native only) */\n path?: string;\n}\n\n/**\n * React Native Blob constructor type\n * Unlike browser Blob, accepts BufferSource in the parts array\n */\nexport interface ReactNativeBlobConstructor {\n new (\n parts?: Array<BufferSource | Blob | string>,\n options?: ReactNativeBlobOptions,\n ): Blob;\n prototype: Blob;\n}\n\n/**\n * Type guard to check if a value is ArrayBuffer\n */\nexport function isArrayBuffer(value: unknown): value is ArrayBuffer {\n return value instanceof ArrayBuffer;\n}\n\n/**\n * Type guard to check if a value is ArrayBufferView (typed array)\n */\nexport function isArrayBufferView(value: unknown): value is ArrayBufferView {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"buffer\" in value &&\n value.buffer instanceof ArrayBuffer\n );\n}\n\n/**\n * Type guard to check if a value is BufferSource\n */\nexport function isBufferSource(value: unknown): value is BufferSource {\n return isArrayBuffer(value) || isArrayBufferView(value);\n}\n\n/**\n * Type guard to check if we're in React Native environment\n * (checks for global.navigator.product === 'ReactNative')\n */\nexport function isReactNativeEnvironment(): boolean {\n return (\n typeof global !== \"undefined\" &&\n typeof global.navigator !== \"undefined\" &&\n global.navigator.product === \"ReactNative\"\n );\n}\n\n/**\n * Create a Blob from BufferSource with proper typing for React Native\n *\n * This function handles the platform differences between browser and React Native Blob APIs.\n * React Native's Blob constructor accepts BufferSource directly, while browser Blob requires\n * conversion to Uint8Array first in some cases.\n *\n * @param data - ArrayBuffer or typed array to convert to Blob\n * @param options - Blob options including MIME type\n * @returns Platform-appropriate Blob instance\n *\n * @example\n * ```typescript\n * const arrayBuffer = await fileSystemProvider.readFile(uri);\n * const blob = createBlobFromBuffer(arrayBuffer, {\n * type: 'image/jpeg'\n * });\n * ```\n */\nexport function createBlobFromBuffer(\n data: BufferSource,\n options?: ReactNativeBlobOptions,\n): Blob {\n // Convert ArrayBuffer to Uint8Array for consistent handling\n const uint8Array = data instanceof ArrayBuffer ? new Uint8Array(data) : data;\n\n // In React Native, Blob constructor accepts BufferSource\n // Cast to ReactNativeBlobConstructor to use the correct signature\n const BlobConstructor = Blob as unknown as ReactNativeBlobConstructor;\n return new BlobConstructor([uint8Array], options);\n}\n","import { useContext } from \"react\";\nimport { UploadistaContext } from \"./uploadista-context\";\n\n/**\n * Hook to access the Uploadista client instance\n * Must be used within an UploadistaProvider\n * @throws Error if used outside of UploadistaProvider\n * @returns The Uploadista client and file system provider\n */\nexport function useUploadistaContext() {\n const context = useContext(UploadistaContext);\n\n if (!context) {\n throw new Error(\n \"useUploadistaClient must be used within an UploadistaProvider\",\n );\n }\n\n return context;\n}\n","import type {\n UploadistaUploadOptions,\n UploadMetrics,\n} from \"@uploadista/client-core\";\nimport {\n UploadManager,\n type UploadState,\n type UploadStatus,\n} from \"@uploadista/client-core\";\nimport type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { FilePickResult } from \"../types\";\nimport { createBlobFromBuffer } from \"../types/platform-types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n// Re-export types from core for convenience\nexport type { UploadState, UploadStatus };\n\nexport interface UseUploadOptions {\n /**\n * Upload metadata to attach to the file\n */\n metadata?: Record<string, string>;\n\n /**\n * Whether to defer the upload size calculation\n */\n uploadLengthDeferred?: boolean;\n\n /**\n * Manual upload size override\n */\n uploadSize?: number;\n\n /**\n * Called when upload progress updates\n */\n onProgress?: (\n uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n\n /**\n * Called when a chunk completes\n */\n onChunkComplete?: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => void;\n\n /**\n * Called when upload succeeds\n */\n onSuccess?: (result: UploadFile) => void;\n\n /**\n * Called when upload fails\n */\n onError?: (error: Error) => void;\n\n /**\n * Called when upload is aborted\n */\n onAbort?: () => void;\n\n /**\n * Custom retry logic\n */\n onShouldRetry?: (error: Error, retryAttempt: number) => boolean;\n}\n\nexport interface UseUploadReturn {\n /**\n * Current upload state\n */\n state: UploadState;\n\n /**\n * Start uploading a file from a file pick result\n */\n upload: (file: FilePickResult) => Promise<void>;\n\n /**\n * Abort the current upload\n */\n abort: () => void;\n\n /**\n * Reset the upload state to idle\n */\n reset: () => void;\n\n /**\n * Retry the last failed upload\n */\n retry: () => void;\n\n /**\n * Whether an upload is currently active\n */\n isUploading: boolean;\n\n /**\n * Whether the upload can be retried\n */\n canRetry: boolean;\n\n /**\n * Upload metrics and performance insights from the client\n */\n metrics: UploadMetrics;\n}\n\nconst initialState: UploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n error: null,\n result: null,\n};\n\n/**\n * React Native hook for managing individual file uploads with full state management.\n * Provides upload progress tracking, error handling, abort functionality, and retry logic.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Upload configuration and event handlers\n * @returns Upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const upload = useUpload({\n * onSuccess: (result) => console.log('Upload complete:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * onProgress: (progress) => console.log('Progress:', progress + '%'),\n * });\n *\n * const handleFilePick = async () => {\n * const file = await pickFile();\n * if (file) await upload.upload(file);\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handleFilePick} />\n * {upload.isUploading && <Text>Progress: {upload.state.progress}%</Text>}\n * {upload.state.error && <Text>Error: {upload.state.error.message}</Text>}\n * {upload.canRetry && <Button title=\"Retry\" onPress={upload.retry} />}\n * <Button title=\"Abort\" onPress={upload.abort} disabled={!upload.isUploading} />\n * </View>\n * );\n * }\n * ```\n */\nexport function useUpload(options: UseUploadOptions = {}): UseUploadReturn {\n const { client, fileSystemProvider } = useUploadistaContext();\n const [state, setState] = useState<UploadState>(initialState);\n const managerRef = useRef<UploadManager | null>(null);\n const lastFileRef = useRef<FilePickResult | null>(null);\n\n // Create UploadManager instance\n useEffect(() => {\n // Create upload function that handles React Native file reading\n const uploadFn = async (input: unknown, opts: UploadistaUploadOptions) => {\n const file = input as FilePickResult;\n\n if (file.status === \"success\") {\n // Read file content from React Native file system\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n\n // Create a Blob from the file content using platform-aware utility\n const blob = createBlobFromBuffer(fileContent, {\n type: file.data.mimeType || \"application/octet-stream\",\n });\n\n // Upload the Blob\n return client.upload(blob, opts);\n }\n\n return Promise.resolve({ abort: () => {} });\n };\n\n managerRef.current = new UploadManager(\n uploadFn,\n {\n onStateChange: setState,\n onProgress: options.onProgress,\n onChunkComplete: options.onChunkComplete,\n onSuccess: options.onSuccess,\n onError: options.onError,\n onAbort: options.onAbort,\n },\n {\n metadata: options.metadata,\n uploadLengthDeferred: options.uploadLengthDeferred,\n uploadSize: options.uploadSize,\n onShouldRetry: options.onShouldRetry,\n },\n );\n\n return () => {\n managerRef.current?.cleanup();\n };\n }, [client, fileSystemProvider, options]);\n\n // Upload function - stores file reference for retry\n const upload = useCallback(async (file: FilePickResult) => {\n lastFileRef.current = file;\n await managerRef.current?.upload(file);\n }, []);\n\n // Abort function\n const abort = useCallback(() => {\n managerRef.current?.abort();\n }, []);\n\n // Reset function\n const reset = useCallback(() => {\n managerRef.current?.reset();\n lastFileRef.current = null;\n }, []);\n\n // Retry function\n const retry = useCallback(() => {\n if (lastFileRef.current && managerRef.current?.canRetry()) {\n managerRef.current.retry();\n }\n }, []);\n\n // Derive computed values from state\n const isUploading = state.status === \"uploading\";\n const canRetry = managerRef.current?.canRetry() ?? false;\n\n // Create metrics object that delegates to the upload client\n const metrics: UploadMetrics = {\n getInsights: () => client.getChunkingInsights(),\n exportMetrics: () => client.exportMetrics(),\n getNetworkMetrics: () => client.getNetworkMetrics(),\n getNetworkCondition: () => client.getNetworkCondition(),\n resetMetrics: () => client.resetMetrics(),\n };\n\n return {\n state,\n upload,\n abort,\n reset,\n retry,\n isUploading,\n canRetry,\n metrics,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for capturing photos and uploading them\n * Handles camera permissions and capture flow\n * @param options - Camera upload configuration\n * @returns Upload state and camera capture/upload function\n */\nexport function useCameraUpload(options?: UseCameraUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Capture and upload photo\n const captureAndUpload = useCallback(async () => {\n try {\n // Capture photo with camera\n const photo = await fileSystemProvider.pickCamera(options?.cameraOptions);\n\n // Upload captured photo\n await uploadHook.upload(photo);\n } catch (error) {\n console.error(\"Camera capture error:\", error);\n }\n }, [fileSystemProvider, options?.cameraOptions, uploadHook]);\n\n return {\n ...uploadHook,\n captureAndUpload,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading generic files (documents, etc.)\n * @param options - File upload configuration\n * @returns Upload state and file picker/upload function\n */\nexport function useFileUpload(options?: UseFileUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Pick and upload file\n const pickAndUpload = useCallback(async () => {\n try {\n // Pick file\n const file = await fileSystemProvider.pickDocument({\n allowedTypes: options?.allowedTypes,\n });\n\n // Upload file\n await uploadHook.upload(file);\n } catch (error) {\n console.error(\"File selection error:\", error);\n throw error;\n }\n }, [fileSystemProvider, options?.allowedTypes, uploadHook]);\n\n return {\n ...uploadHook,\n pickAndUpload,\n };\n}\n","import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport {\n FlowManager,\n type FlowManagerCallbacks,\n type FlowUploadOptions,\n} from \"@uploadista/client-core\";\nimport { EventType, type FlowEvent } from \"@uploadista/core/flow\";\nimport { UploadEventType } from \"@uploadista/core/types\";\nimport type { ReactNode } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n} from \"react\";\nimport { useUploadistaContext } from \"../hooks/use-uploadista-context\";\nimport type { ReactNativeUploadInput } from \"../types\";\n\n/**\n * Type guard to check if an event is a flow event\n */\nfunction isFlowEvent(event: UploadistaEvent): event is FlowEvent {\n const flowEvent = event as FlowEvent;\n return (\n flowEvent.eventType === EventType.FlowStart ||\n flowEvent.eventType === EventType.FlowEnd ||\n flowEvent.eventType === EventType.FlowError ||\n flowEvent.eventType === EventType.NodeStart ||\n flowEvent.eventType === EventType.NodeEnd ||\n flowEvent.eventType === EventType.NodePause ||\n flowEvent.eventType === EventType.NodeResume ||\n flowEvent.eventType === EventType.NodeError\n );\n}\n\n/**\n * Internal manager registry entry with ref counting\n */\ninterface ManagerEntry {\n manager: FlowManager<unknown>;\n refCount: number;\n flowId: string;\n}\n\n/**\n * Context value providing access to flow managers\n */\ninterface FlowManagerContextValue {\n /**\n * Get or create a flow manager for the given flow ID.\n * Increments ref count - must call releaseManager when done.\n *\n * @param flowId - Unique identifier for the flow\n * @param callbacks - Callbacks for state changes and lifecycle events\n * @param options - Flow configuration options\n * @returns FlowManager instance\n */\n getManager: (\n flowId: string,\n callbacks: FlowManagerCallbacks,\n options: FlowUploadOptions,\n ) => FlowManager<unknown>;\n\n /**\n * Release a flow manager reference.\n * Decrements ref count and cleans up when reaching zero.\n *\n * @param flowId - Unique identifier for the flow to release\n */\n releaseManager: (flowId: string) => void;\n}\n\nconst FlowManagerContext = createContext<FlowManagerContextValue | undefined>(\n undefined,\n);\n\n/**\n * Props for FlowManagerProvider\n */\ninterface FlowManagerProviderProps {\n children: ReactNode;\n}\n\n/**\n * Provider that manages FlowManager instances with ref counting and event routing.\n * Ensures managers persist across component re-renders and are only cleaned up\n * when all consuming components unmount.\n *\n * This provider should be nested inside UploadistaProvider to access the upload client\n * and event subscription system.\n *\n * @example\n * ```tsx\n * <UploadistaProvider baseUrl=\"https://api.example.com\" storageId=\"default\">\n * <FlowManagerProvider>\n * <App />\n * </FlowManagerProvider>\n * </UploadistaProvider>\n * ```\n */\nexport function FlowManagerProvider({ children }: FlowManagerProviderProps) {\n const { client, subscribeToEvents } = useUploadistaContext();\n const managersRef = useRef(new Map<string, ManagerEntry>());\n\n // Subscribe to all events and route to appropriate managers\n useEffect(() => {\n const unsubscribe = subscribeToEvents((event: UploadistaEvent) => {\n // Route flow events to all managers (they filter by jobId internally)\n if (isFlowEvent(event)) {\n for (const entry of managersRef.current.values()) {\n entry.manager.handleFlowEvent(event);\n }\n return;\n }\n\n // Route upload progress events to all managers\n if (\n \"type\" in event &&\n event.type === UploadEventType.UPLOAD_PROGRESS &&\n \"data\" in event\n ) {\n for (const entry of managersRef.current.values()) {\n entry.manager.handleUploadProgress(\n event.data.id,\n event.data.progress,\n event.data.total,\n );\n }\n }\n });\n\n return unsubscribe;\n }, [subscribeToEvents]);\n\n const getManager = useCallback(\n (\n flowId: string,\n callbacks: FlowManagerCallbacks,\n options: FlowUploadOptions,\n ): FlowManager<unknown> => {\n const existing = managersRef.current.get(flowId);\n\n if (existing) {\n // Increment ref count for existing manager\n existing.refCount++;\n return existing.manager;\n }\n\n // Create new manager using client from hook scope\n const manager = new FlowManager<ReactNativeUploadInput>(\n client.uploadWithFlow,\n callbacks,\n options,\n client.multiInputFlowUpload,\n );\n\n managersRef.current.set(flowId, {\n manager,\n refCount: 1,\n flowId,\n });\n\n return manager;\n },\n [client],\n );\n\n const releaseManager = useCallback((flowId: string) => {\n const existing = managersRef.current.get(flowId);\n if (!existing) return;\n\n existing.refCount--;\n\n // Clean up when no more refs\n if (existing.refCount <= 0) {\n existing.manager.cleanup();\n managersRef.current.delete(flowId);\n }\n }, []);\n\n return (\n <FlowManagerContext.Provider value={{ getManager, releaseManager }}>\n {children}\n </FlowManagerContext.Provider>\n );\n}\n\n/**\n * Hook to access the FlowManager context.\n * Must be used within a FlowManagerProvider.\n *\n * @returns FlowManager context value with getManager and releaseManager functions\n * @throws Error if used outside of FlowManagerProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { getManager, releaseManager } = useFlowManagerContext();\n * // Use to create managers...\n * }\n * ```\n */\nexport function useFlowManagerContext(): FlowManagerContextValue {\n const context = useContext(FlowManagerContext);\n\n if (context === undefined) {\n throw new Error(\n \"useFlowManagerContext must be used within a FlowManagerProvider. \" +\n \"Make sure to wrap your component tree with <FlowManagerProvider>.\",\n );\n }\n\n return context;\n}\n","import type {\n FlowManager,\n FlowUploadState,\n FlowUploadStatus,\n InputExecutionState,\n} from \"@uploadista/client-core\";\nimport type { TypedOutput } from \"@uploadista/core/flow\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useFlowManagerContext } from \"../contexts/flow-manager-context\";\nimport type { FilePickResult } from \"../types\";\nimport { createBlobFromBuffer } from \"../types/platform-types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n// Re-export types from core for convenience\nexport type { FlowUploadState, FlowUploadStatus, InputExecutionState };\n\n/**\n * Input metadata discovered from the flow\n */\nexport interface FlowInputMetadata {\n /** Input node ID */\n nodeId: string;\n /** Human-readable node name */\n nodeName: string;\n /** Node description explaining what input is needed */\n nodeDescription: string;\n /** Input type ID from inputTypeRegistry - describes how clients interact with this node */\n inputTypeId?: string;\n /** Whether this input is required */\n required: boolean;\n}\n\n/**\n * Options for the useFlow hook\n */\nexport interface UseFlowOptions {\n /** Flow ID to execute */\n flowId: string;\n /** Storage ID for the upload */\n storageId: string;\n /** Output node ID for the flow */\n outputNodeId?: string;\n /** Metadata to pass to flow */\n metadata?: Record<string, unknown>;\n /** Called when upload succeeds (receives typed outputs from all output nodes) */\n onSuccess?: (outputs: TypedOutput[]) => void;\n /** Called when the flow completes successfully (receives full flow outputs) */\n onFlowComplete?: (outputs: TypedOutput[]) => void;\n /** Called when upload fails */\n onError?: (error: Error) => void;\n /** Called when upload progress updates */\n onProgress?: (\n progress: number,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n /** Called when a chunk completes */\n onChunkComplete?: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => void;\n}\n\n/**\n * Return value from the useFlow hook with upload control methods and state.\n *\n * @property state - Complete flow upload state with progress and outputs\n * @property inputMetadata - Metadata about discovered input nodes (null until discovered)\n * @property inputStates - Per-input execution state for multi-input flows\n * @property inputs - Current input values set via setInput()\n * @property setInput - Set an input value for a specific node (for progressive provision)\n * @property execute - Execute the flow with current inputs (auto-detects types)\n * @property upload - Convenience method for single-file upload (same as execute with one file input)\n * @property abort - Cancel the current upload and flow execution\n * @property reset - Reset state to idle (clears all data)\n * @property retry - Retry the last failed upload\n * @property isActive - True when upload or processing is active\n * @property isUploadingFile - True only during file upload phase\n * @property isProcessing - True only during flow processing phase\n * @property isDiscoveringInputs - True while discovering flow inputs\n * @property canRetry - True if a retry is possible\n */\nexport interface UseFlowReturn {\n /**\n * Current upload state\n */\n state: FlowUploadState;\n\n /**\n * Discovered input nodes metadata (null until discovery completes)\n */\n inputMetadata: FlowInputMetadata[] | null;\n\n /**\n * Per-input execution state for multi-input flows\n */\n inputStates: ReadonlyMap<string, InputExecutionState>;\n\n /**\n * Current inputs set via setInput()\n */\n inputs: Record<string, unknown>;\n\n /**\n * Set an input value for a specific node.\n * For progressive input provision before calling execute().\n *\n * @param nodeId - The input node ID\n * @param value - The input value (FilePickResult, URL string, or structured data)\n */\n setInput: (nodeId: string, value: FilePickResult | string | unknown) => void;\n\n /**\n * Execute the flow with current inputs.\n * Automatically detects input types and routes appropriately.\n * For single input, uses standard upload path.\n * For multiple inputs, requires multiInputUploadFn.\n */\n execute: () => Promise<void>;\n\n /**\n * Upload a single file through the flow (convenience method).\n * Equivalent to setInput(firstNodeId, file) + execute().\n *\n * @param file - FilePickResult from a picker\n */\n upload: (file: FilePickResult) => Promise<void>;\n\n /**\n * Abort the current upload\n */\n abort: () => void;\n\n /**\n * Reset the upload state and clear all inputs\n */\n reset: () => void;\n\n /**\n * Retry the last failed upload\n */\n retry: () => void;\n\n /**\n * Whether an upload or flow execution is in progress (uploading OR processing)\n */\n isActive: boolean;\n\n /**\n * Whether the file is currently being uploaded (chunks being sent)\n */\n isUploadingFile: boolean;\n\n /**\n * Whether the flow is currently processing (after upload completes)\n */\n isProcessing: boolean;\n\n /**\n * Whether the hook is discovering flow inputs\n */\n isDiscoveringInputs: boolean;\n\n /**\n * Whether a retry is possible (after error or abort with stored inputs)\n */\n canRetry: boolean;\n}\n\nconst initialState: FlowUploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n error: null,\n jobId: null,\n flowStarted: false,\n currentNodeName: null,\n currentNodeType: null,\n flowOutputs: null,\n};\n\n/**\n * React Native hook for executing flows with single or multiple inputs.\n * Automatically discovers input nodes and detects input types (File, URL, structured data).\n * Supports progressive input provision via setInput() and execute().\n *\n * This is the unified flow hook that replaces useFlowUpload for advanced use cases.\n * It provides:\n * - Auto-discovery of flow input nodes\n * - Automatic input type detection (FilePickResult -> upload, string -> URL, object -> data)\n * - Progressive input provision via setInput()\n * - Multi-input support with parallel coordination\n * - Per-input state tracking\n *\n * Must be used within FlowManagerProvider (which must be within UploadistaProvider).\n * Flow events are automatically routed by the provider to the appropriate manager.\n *\n * @param options - Flow upload configuration including flow ID and event handlers\n * @returns Flow upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const flow = useFlow({\n * flowId: 'image-processing-flow',\n * storageId: 'my-storage',\n * onSuccess: (outputs) => console.log('Flow complete:', outputs),\n * onError: (error) => console.error('Flow failed:', error),\n * });\n *\n * const handlePickFile = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file) {\n * await flow.upload(file);\n * }\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handlePickFile} />\n * {flow.isActive && <Text>Progress: {flow.state.progress}%</Text>}\n * {flow.inputMetadata && (\n * <Text>Found {flow.inputMetadata.length} input nodes</Text>\n * )}\n * <Button title=\"Abort\" onPress={flow.abort} disabled={!flow.isActive} />\n * </View>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Multi-input flow\n * function MultiInputComponent() {\n * const flow = useFlow({\n * flowId: 'multi-source-flow',\n * storageId: 'my-storage',\n * });\n *\n * const handlePickPrimary = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file.status === 'success') {\n * flow.setInput('primary-input', file);\n * }\n * };\n *\n * const handleSetUrl = (url: string) => {\n * flow.setInput('url-input', url);\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick Primary\" onPress={handlePickPrimary} />\n * <TextInput onChangeText={handleSetUrl} placeholder=\"Enter URL\" />\n * <Button title=\"Execute\" onPress={flow.execute} />\n * </View>\n * );\n * }\n * ```\n *\n * @see {@link useFlowUpload} for a simpler file-only upload hook\n */\nexport function useFlow(options: UseFlowOptions): UseFlowReturn {\n const { client, fileSystemProvider } = useUploadistaContext();\n const { getManager, releaseManager } = useFlowManagerContext();\n const [state, setState] = useState<FlowUploadState>(initialState);\n const [inputMetadata, setInputMetadata] = useState<\n FlowInputMetadata[] | null\n >(null);\n const [isDiscoveringInputs, setIsDiscoveringInputs] = useState(false);\n const [inputs, setInputs] = useState<Record<string, unknown>>({});\n const [inputStates, setInputStates] = useState<\n ReadonlyMap<string, InputExecutionState>\n >(new Map());\n const managerRef = useRef<FlowManager<unknown> | null>(null);\n const lastInputsRef = useRef<Record<string, unknown> | null>(null);\n\n // Store callbacks in refs so they can be updated without recreating the manager\n const callbacksRef = useRef(options);\n\n // Update refs on every render to capture latest callbacks\n useEffect(() => {\n callbacksRef.current = options;\n });\n\n // Auto-discover flow inputs on mount\n useEffect(() => {\n const discoverInputs = async () => {\n setIsDiscoveringInputs(true);\n try {\n const { flow } = await client.getFlow(options.flowId);\n\n // Find all input nodes\n const inputNodes = flow.nodes.filter((node) => node.type === \"input\");\n\n const metadata: FlowInputMetadata[] = inputNodes.map((node) => ({\n nodeId: node.id,\n nodeName: node.name,\n nodeDescription: node.description,\n inputTypeId: node.inputTypeId,\n required: true,\n }));\n\n setInputMetadata(metadata);\n } catch (error) {\n console.error(\"Failed to discover flow inputs:\", error);\n } finally {\n setIsDiscoveringInputs(false);\n }\n };\n\n discoverInputs();\n }, [client, options.flowId]);\n\n // Get or create manager from context when component mounts\n // biome-ignore lint/correctness/useExhaustiveDependencies: we don't want to recreate the manager on every render\n useEffect(() => {\n const flowId = options.flowId;\n\n // Create stable callback wrappers that call the latest callbacks via refs\n const stableCallbacks = {\n onStateChange: (newState: FlowUploadState) => {\n setState(newState);\n },\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n if (callbacksRef.current.onProgress) {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n callbacksRef.current.onProgress(progress, bytesUploaded, totalBytes);\n }\n },\n onChunkComplete: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => {\n callbacksRef.current.onChunkComplete?.(\n chunkSize,\n bytesAccepted,\n bytesTotal,\n );\n },\n onFlowComplete: (outputs: TypedOutput[]) => {\n callbacksRef.current.onFlowComplete?.(outputs);\n },\n onSuccess: (outputs: TypedOutput[]) => {\n callbacksRef.current.onSuccess?.(outputs);\n },\n onError: (error: Error) => {\n callbacksRef.current.onError?.(error);\n },\n onAbort: () => {\n // onAbort not exposed in public API\n },\n };\n\n // Get manager from context (creates if doesn't exist, increments ref count)\n managerRef.current = getManager(flowId, stableCallbacks, {\n flowConfig: {\n flowId: options.flowId,\n storageId: options.storageId,\n outputNodeId: options.outputNodeId,\n metadata: options.metadata as Record<string, string> | undefined,\n },\n onChunkComplete: options.onChunkComplete,\n onSuccess: options.onSuccess,\n onError: options.onError,\n });\n\n // Set up interval to poll input states for multi-input flows\n const pollInterval = setInterval(() => {\n if (managerRef.current) {\n const states = managerRef.current.getInputStates();\n if (states.size > 0) {\n setInputStates(new Map(states));\n }\n }\n }, 100); // Poll every 100ms\n\n // Release manager when component unmounts or flowId changes\n return () => {\n clearInterval(pollInterval);\n releaseManager(flowId);\n managerRef.current = null;\n };\n }, [\n options.flowId,\n options.storageId,\n options.outputNodeId,\n getManager,\n releaseManager,\n ]);\n\n // Set an input value\n const setInput = useCallback(\n (nodeId: string, value: FilePickResult | string | unknown) => {\n setInputs((prev) => ({ ...prev, [nodeId]: value }));\n },\n [],\n );\n\n // Helper to convert FilePickResult to Blob\n const filePickToBlob = useCallback(\n async (file: FilePickResult): Promise<Blob | null> => {\n if (file.status === \"cancelled\") {\n return null;\n }\n if (file.status === \"error\") {\n throw file.error;\n }\n\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n return createBlobFromBuffer(fileContent, {\n type: file.data.mimeType || \"application/octet-stream\",\n });\n },\n [fileSystemProvider],\n );\n\n // Execute flow with current inputs\n const execute = useCallback(async () => {\n if (!managerRef.current) {\n throw new Error(\"FlowManager not initialized\");\n }\n\n if (Object.keys(inputs).length === 0) {\n throw new Error(\n \"No inputs provided. Use setInput() to provide inputs before calling execute()\",\n );\n }\n\n // Store inputs for retry\n lastInputsRef.current = { ...inputs };\n\n // Convert FilePickResults to Blobs\n const processedInputs: Record<string, unknown> = {};\n\n for (const [nodeId, value] of Object.entries(inputs)) {\n // Check if value is a FilePickResult\n if (\n value &&\n typeof value === \"object\" &&\n \"status\" in value &&\n (value.status === \"success\" ||\n value.status === \"cancelled\" ||\n value.status === \"error\")\n ) {\n const blob = await filePickToBlob(value as FilePickResult);\n if (blob) {\n processedInputs[nodeId] = blob;\n }\n // If blob is null (cancelled), skip this input\n } else {\n // Pass through strings (URLs) and other values as-is\n processedInputs[nodeId] = value;\n }\n }\n\n if (Object.keys(processedInputs).length === 0) {\n throw new Error(\n \"No valid inputs after processing. All files may have been cancelled.\",\n );\n }\n\n await managerRef.current.executeFlow(processedInputs);\n }, [inputs, filePickToBlob]);\n\n // Convenience method for single file upload\n const upload = useCallback(\n async (file: FilePickResult) => {\n // Handle cancelled picker\n if (file.status === \"cancelled\") {\n return;\n }\n\n // Handle picker error\n if (file.status === \"error\") {\n options.onError?.(file.error);\n return;\n }\n\n if (!managerRef.current) {\n throw new Error(\"FlowManager not initialized\");\n }\n\n // Store for retry\n if (inputMetadata && inputMetadata.length > 0) {\n const firstInputNode = inputMetadata[0];\n if (firstInputNode) {\n lastInputsRef.current = { [firstInputNode.nodeId]: file };\n }\n }\n\n try {\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n const blob = createBlobFromBuffer(fileContent, {\n type: file.data.mimeType || \"application/octet-stream\",\n });\n\n // If we have input metadata, use the first input node\n if (inputMetadata && inputMetadata.length > 0) {\n const firstInputNode = inputMetadata[0];\n if (!firstInputNode) {\n throw new Error(\"No input nodes found\");\n }\n setInputs({ [firstInputNode.nodeId]: file });\n await managerRef.current.executeFlow({\n [firstInputNode.nodeId]: blob,\n });\n } else {\n // Fall back to direct upload (manager will handle discovery)\n await managerRef.current.upload(blob);\n }\n } catch (error) {\n options.onError?.(error as Error);\n }\n },\n [inputMetadata, fileSystemProvider, options],\n );\n\n const abort = useCallback(() => {\n managerRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n managerRef.current?.reset();\n setInputs({});\n setInputStates(new Map());\n lastInputsRef.current = null;\n }, []);\n\n const retry = useCallback(() => {\n if (\n lastInputsRef.current &&\n (state.status === \"error\" || state.status === \"aborted\")\n ) {\n // Restore inputs and re-execute\n setInputs(lastInputsRef.current);\n execute();\n }\n }, [execute, state.status]);\n\n // Derive computed values from state (reactive to state changes)\n const isActive =\n state.status === \"uploading\" || state.status === \"processing\";\n const isUploadingFile = state.status === \"uploading\";\n const isProcessing = state.status === \"processing\";\n const canRetry =\n (state.status === \"error\" || state.status === \"aborted\") &&\n lastInputsRef.current !== null;\n\n return {\n state,\n inputMetadata,\n inputStates,\n inputs,\n setInput,\n execute,\n upload,\n abort,\n reset,\n retry,\n isActive,\n isUploadingFile,\n isProcessing,\n isDiscoveringInputs,\n canRetry,\n };\n}\n","import type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { FilePickResult, UseMultiUploadOptions } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport interface UploadItemState {\n id: string;\n file: Extract<FilePickResult, { status: \"success\" }>;\n status: \"idle\" | \"uploading\" | \"success\" | \"error\" | \"aborted\";\n progress: number;\n bytesUploaded: number;\n totalBytes: number;\n error: Error | null;\n result: UploadFile | null;\n}\n\nexport interface MultiUploadState {\n items: UploadItemState[];\n totalProgress: number;\n totalUploaded: number;\n totalBytes: number;\n activeCount: number;\n completedCount: number;\n failedCount: number;\n}\n\nconst initialState: MultiUploadState = {\n items: [],\n totalProgress: 0,\n totalUploaded: 0,\n totalBytes: 0,\n activeCount: 0,\n completedCount: 0,\n failedCount: 0,\n};\n\n/**\n * Hook for managing multiple concurrent file uploads with progress tracking.\n * Each file is uploaded independently using the core upload client.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Multi-upload configuration options\n * @returns Multi-upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const multiUpload = useMultiUpload({\n * maxConcurrent: 3,\n * onSuccess: (result) => console.log('File uploaded:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * });\n *\n * const handlePickFiles = async () => {\n * const files = await fileSystemProvider.pickImage({ allowMultiple: true });\n * multiUpload.addFiles(files);\n * await multiUpload.startUploads();\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick Files\" onPress={handlePickFiles} />\n * <Text>Progress: {multiUpload.state.totalProgress}%</Text>\n * <Text>Active: {multiUpload.state.activeCount}</Text>\n * <Text>Completed: {multiUpload.state.completedCount}/{multiUpload.state.items.length}</Text>\n * </View>\n * );\n * }\n * ```\n */\nexport function useMultiUpload(options: UseMultiUploadOptions = {}) {\n const { client } = useUploadistaContext();\n const [state, setState] = useState<MultiUploadState>(initialState);\n const abortControllersRef = useRef<Map<string, { abort: () => void }>>(\n new Map(),\n );\n const nextIdRef = useRef(0);\n // Use ref to track items synchronously\n const itemsRef = useRef<UploadItemState[]>([]);\n\n const generateId = useCallback(() => {\n return `upload-${Date.now()}-${nextIdRef.current++}`;\n }, []);\n\n const updateAggregateStats = useCallback((items: UploadItemState[]) => {\n const totalBytes = items.reduce((sum, item) => sum + item.totalBytes, 0);\n const totalUploaded = items.reduce(\n (sum, item) => sum + item.bytesUploaded,\n 0,\n );\n const totalProgress =\n totalBytes > 0 ? Math.round((totalUploaded / totalBytes) * 100) : 0;\n const activeCount = items.filter(\n (item) => item.status === \"uploading\",\n ).length;\n const completedCount = items.filter(\n (item) => item.status === \"success\",\n ).length;\n const failedCount = items.filter((item) => item.status === \"error\").length;\n\n // Update ref synchronously\n itemsRef.current = items;\n\n setState((prev) => ({\n ...prev,\n items,\n totalProgress,\n totalUploaded,\n totalBytes,\n activeCount,\n completedCount,\n failedCount,\n }));\n }, []);\n\n const addFiles = useCallback(\n (files: FilePickResult[]) => {\n // Filter out cancelled and error results, only keep successful picks\n const successfulFiles = files.filter(\n (file): file is Extract<FilePickResult, { status: \"success\" }> =>\n file.status === \"success\",\n );\n\n const newItems: UploadItemState[] = successfulFiles.map((file) => ({\n id: generateId(),\n file,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n totalBytes: file.data.size,\n error: null,\n result: null,\n }));\n\n // Update ref synchronously\n const updatedItems = [...itemsRef.current, ...newItems];\n itemsRef.current = updatedItems;\n\n setState((prev) => {\n const totalBytes = updatedItems.reduce(\n (sum, item) => sum + item.totalBytes,\n 0,\n );\n return {\n ...prev,\n items: updatedItems,\n totalBytes,\n };\n });\n\n return newItems.map((item) => item.id);\n },\n [generateId],\n );\n\n const uploadSingleItem = useCallback(\n async (item: UploadItemState) => {\n try {\n console.log(\"Uploading item:\", item.file.data.name);\n // Update status to uploading\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id ? { ...i, status: \"uploading\" as const } : i,\n );\n updateAggregateStats(updatedItems);\n\n // Convert file URI to Blob using fetch (React Native compatible)\n // React Native's Blob doesn't support ArrayBuffer/Uint8Array constructor\n const response = await fetch(item.file.data.uri);\n const blob = await response.blob();\n\n // Override blob type if we have mimeType from picker\n const uploadInput = item.file.data.mimeType\n ? new Blob([blob], {\n type: item.file.data.mimeType,\n lastModified: Date.now(),\n })\n : blob;\n\n // Start upload using the client\n console.log(\"Uploading input:\", uploadInput);\n const uploadPromise = client.upload(uploadInput, {\n metadata: options.metadata,\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n progress,\n bytesUploaded,\n totalBytes: totalBytes || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n },\n\n onSuccess: (result: UploadFile) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"success\" as const,\n progress: 100,\n result,\n bytesUploaded: result.size || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onSuccess?.(result);\n abortControllersRef.current.delete(item.id);\n },\n\n onError: (error: Error) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id ? { ...i, status: \"error\" as const, error } : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error);\n abortControllersRef.current.delete(item.id);\n },\n });\n\n // Store abort controller\n const controller = await uploadPromise;\n abortControllersRef.current.set(item.id, controller);\n } catch (error) {\n console.error(\"Error uploading item:\", error);\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"error\" as const,\n error: error as Error,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error as Error);\n abortControllersRef.current.delete(item.id);\n }\n },\n [client, options, updateAggregateStats],\n );\n\n const startUploads = useCallback(\n async (itemIds?: string[]) => {\n const maxConcurrent = options.maxConcurrent || 3;\n\n // Get items from ref (synchronous access to latest items)\n const itemsToUpload = itemIds\n ? itemsRef.current.filter(\n (item) => itemIds.includes(item.id) && item.status === \"idle\",\n )\n : itemsRef.current.filter((item) => item.status === \"idle\");\n\n console.log(\"Items to upload:\", itemsToUpload.length, itemsToUpload);\n\n // Process items in batches\n for (let i = 0; i < itemsToUpload.length; i += maxConcurrent) {\n const batch = itemsToUpload.slice(i, i + maxConcurrent);\n await Promise.all(batch.map((item) => uploadSingleItem(item)));\n }\n },\n [options.maxConcurrent, uploadSingleItem],\n );\n\n const removeItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.filter((item) => item.id !== id);\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const abortItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.map((item) =>\n item.id === id ? { ...item, status: \"aborted\" as const } : item,\n );\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const clear = useCallback(() => {\n // Abort all active uploads\n abortControllersRef.current.forEach((controller) => {\n controller.abort();\n });\n abortControllersRef.current.clear();\n\n // Clear ref\n itemsRef.current = [];\n\n setState(initialState);\n }, []);\n\n const retryItem = useCallback(\n async (id: string) => {\n const item = itemsRef.current.find((i) => i.id === id);\n if (item && (item.status === \"error\" || item.status === \"aborted\")) {\n // Reset item status to idle\n const updatedItems = itemsRef.current.map((i) =>\n i.id === id\n ? {\n ...i,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n error: null,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n // Upload it (get the reset item from the updated items)\n const resetItem = itemsRef.current.find((i) => i.id === id);\n if (resetItem) {\n await uploadSingleItem(resetItem);\n }\n }\n },\n [uploadSingleItem, updateAggregateStats],\n );\n\n return {\n state,\n addFiles,\n startUploads,\n removeItem,\n abortItem,\n retryItem,\n clear,\n };\n}\n","import { useCallback } from \"react\";\nimport type { FilePickResult, UseGalleryUploadOptions } from \"../types\";\nimport { useMultiUpload } from \"./use-multi-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading photos/videos from gallery\n * Handles batch selection and concurrent uploads\n * @param options - Gallery upload configuration\n * @returns Upload state and gallery selection/upload function\n */\nexport function useGalleryUpload(options?: UseGalleryUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useMultiUpload({\n maxConcurrent: 3,\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n });\n\n // Select and upload media from gallery\n const selectAndUpload = useCallback(async () => {\n let result: FilePickResult;\n\n // Select appropriate media type\n if (options?.mediaType === \"video\") {\n result = await fileSystemProvider.pickVideo({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else if (options?.mediaType === \"photo\") {\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else {\n // For 'mixed' or default, use pickImage first (can be extended to support both)\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n }\n\n // Handle cancelled picker\n if (result.status === \"cancelled\") {\n return [];\n }\n\n // Handle picker error\n if (result.status === \"error\") {\n console.error(\"Gallery selection error:\", result.error);\n options?.onError?.(result.error);\n return [];\n }\n\n // Success - add file and start upload\n const itemIds = uploadHook.addFiles([result]);\n await uploadHook.startUploads(itemIds);\n\n return itemIds;\n }, [\n fileSystemProvider,\n options?.allowMultiple,\n options?.mediaType,\n options?.onError,\n uploadHook,\n ]);\n\n return {\n ...uploadHook,\n selectAndUpload,\n };\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { UploadMetrics } from \"../types\";\n\n/**\n * Hook for tracking upload performance metrics\n * @returns Metrics object and methods to track uploads\n */\nexport function useUploadMetrics() {\n const startTimeRef = useRef<number | null>(null);\n const startBytesRef = useRef<number>(0);\n const peakSpeedRef = useRef<number>(0);\n\n const [metrics, setMetrics] = useState<UploadMetrics>({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n\n // Start tracking\n const start = useCallback(() => {\n startTimeRef.current = Date.now();\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n }, []);\n\n // Update metrics based on current progress\n const update = useCallback(\n (uploadedBytes: number, _totalBytes: number, currentRetries = 0) => {\n if (!startTimeRef.current) {\n return;\n }\n\n const now = Date.now();\n const durationMs = now - startTimeRef.current;\n const speed = durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0;\n\n if (speed > peakSpeedRef.current) {\n peakSpeedRef.current = speed;\n }\n\n setMetrics({\n totalBytes: uploadedBytes,\n durationMs,\n avgSpeed: durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0,\n peakSpeed: peakSpeedRef.current,\n retries: currentRetries,\n });\n },\n [],\n );\n\n // End tracking and return final metrics\n const end = useCallback(() => {\n const finalMetrics = metrics;\n startTimeRef.current = null;\n return finalMetrics;\n }, [metrics]);\n\n // Reset metrics\n const reset = useCallback(() => {\n startTimeRef.current = null;\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n setMetrics({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n }, []);\n\n return {\n metrics,\n start,\n update,\n end,\n reset,\n };\n}\n","/**\n * File utility functions for React Native uploads\n */\n\n/**\n * Format file size to human readable string\n * @param bytes - Size in bytes\n * @returns Formatted size string (e.g., \"1.5 MB\")\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return \"0 Bytes\";\n\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${Math.round((bytes / k ** i) * 100) / 100} ${sizes[i]}`;\n}\n\n/**\n * Get MIME type from file name\n * @param fileName - File name with extension\n * @returns MIME type or 'application/octet-stream' as fallback\n */\nexport function getMimeTypeFromFileName(fileName: string): string {\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".avi\": \"video/x-msvideo\",\n \".mov\": \"video/quicktime\",\n \".wmv\": \"video/x-ms-wmv\",\n \".flv\": \"video/x-flv\",\n \".mkv\": \"video/x-matroska\",\n \".webm\": \"video/webm\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n \".flac\": \"audio/flac\",\n \".m4a\": \"audio/mp4\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".doc\": \"application/msword\",\n \".docx\":\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \".xls\": \"application/vnd.ms-excel\",\n \".xlsx\":\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \".ppt\": \"application/vnd.ms-powerpoint\",\n \".pptx\":\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \".txt\": \"text/plain\",\n \".csv\": \"text/csv\",\n \".json\": \"application/json\",\n \".xml\": \"application/xml\",\n \".zip\": \"application/zip\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n\n/**\n * Check if file type is allowed\n * @param fileName - File name to check\n * @param allowedTypes - Array of allowed MIME types (e.g., ['image/jpeg', 'image/png'])\n * @returns True if file type is allowed\n */\nexport function isFileTypeAllowed(\n fileName: string,\n allowedTypes: string[],\n): boolean {\n if (!allowedTypes || allowedTypes.length === 0) {\n return true;\n }\n\n const mimeType = getMimeTypeFromFileName(fileName);\n return allowedTypes.some((allowed) => {\n if (allowed.endsWith(\"/*\")) {\n // Handle wildcard patterns like 'image/*'\n const [type] = allowed.split(\"/\");\n return mimeType.startsWith(`${type}/`);\n }\n return allowed === mimeType;\n });\n}\n\n/**\n * Check if file size is within limits\n * @param fileSize - File size in bytes\n * @param maxSize - Maximum allowed size in bytes (optional)\n * @param minSize - Minimum allowed size in bytes (optional)\n * @returns True if file size is within limits\n */\nexport function isFileSizeValid(\n fileSize: number,\n maxSize?: number,\n minSize?: number,\n): boolean {\n if (maxSize !== undefined && fileSize > maxSize) {\n return false;\n }\n\n if (minSize !== undefined && fileSize < minSize) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get file extension\n * @param fileName - File name\n * @returns File extension without dot (e.g., 'pdf' for 'document.pdf')\n */\nexport function getFileExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n return fileName.slice(lastDot + 1).toLowerCase();\n}\n\n/**\n * Get file name without extension\n * @param fileName - File name\n * @returns File name without extension\n */\nexport function getFileNameWithoutExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return fileName;\n return fileName.slice(0, lastDot);\n}\n\n/**\n * Check if file is an image\n * @param fileName - File name\n * @returns True if file is an image\n */\nexport function isImageFile(fileName: string): boolean {\n const imageExtensions = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".bmp\",\n \".webp\",\n \".svg\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return imageExtensions.includes(ext);\n}\n\n/**\n * Check if file is a video\n * @param fileName - File name\n * @returns True if file is a video\n */\nexport function isVideoFile(fileName: string): boolean {\n const videoExtensions = [\n \".mp4\",\n \".avi\",\n \".mov\",\n \".wmv\",\n \".flv\",\n \".mkv\",\n \".webm\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return videoExtensions.includes(ext);\n}\n\n/**\n * Check if file is a document\n * @param fileName - File name\n * @returns True if file is a document\n */\nexport function isDocumentFile(fileName: string): boolean {\n const docExtensions = [\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".txt\",\n \".csv\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return docExtensions.includes(ext);\n}\n","/**\n * Permission utility functions for React Native uploads\n * Handles camera, gallery, and file access permissions\n */\n\n/**\n * Permission types\n */\nexport enum PermissionType {\n CAMERA = \"CAMERA\",\n PHOTO_LIBRARY = \"PHOTO_LIBRARY\",\n WRITE_STORAGE = \"WRITE_STORAGE\",\n READ_STORAGE = \"READ_STORAGE\",\n}\n\n/**\n * Permission status\n */\nexport enum PermissionStatus {\n GRANTED = \"granted\",\n DENIED = \"denied\",\n NOT_DETERMINED = \"not_determined\",\n RESTRICTED = \"restricted\",\n}\n\n/**\n * Request camera permission\n * This is primarily used to check if we should attempt camera operations\n * Actual permission requests are handled by the file system providers\n *\n * @returns Promise resolving to true if permission is granted or already granted\n */\nexport async function requestCameraPermission(): Promise<boolean> {\n try {\n // Permission requests are handled by the file system provider implementations\n // This function serves as a placeholder for app-level permission handling\n console.log(\n \"Camera permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request camera permission:\", error);\n return false;\n }\n}\n\n/**\n * Request photo library permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestPhotoLibraryPermission(): Promise<boolean> {\n try {\n console.log(\n \"Photo library permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request photo library permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage read permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageReadPermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage read permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage read permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage write permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageWritePermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage write permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage write permission:\", error);\n return false;\n }\n}\n\n/**\n * Request multiple permissions at once\n * @param permissions - Array of permission types to request\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function requestPermissions(\n permissions: PermissionType[],\n): Promise<boolean> {\n try {\n const results = await Promise.all(\n permissions.map(async (permission) => {\n switch (permission) {\n case PermissionType.CAMERA:\n return requestCameraPermission();\n case PermissionType.PHOTO_LIBRARY:\n return requestPhotoLibraryPermission();\n case PermissionType.READ_STORAGE:\n return requestStorageReadPermission();\n case PermissionType.WRITE_STORAGE:\n return requestStorageWritePermission();\n default:\n return false;\n }\n }),\n );\n\n return results.every((result) => result);\n } catch (error) {\n console.error(\"Failed to request permissions:\", error);\n return false;\n }\n}\n\n/**\n * Check if all required permissions are granted\n * @param permissions - Array of permission types to check\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function hasPermissions(\n _permissions: PermissionType[],\n): Promise<boolean> {\n try {\n // In React Native, permission checking is typically handled by the platform\n // This is a placeholder that assumes permissions will be handled by the file system provider\n return true;\n } catch (error) {\n console.error(\"Failed to check permissions:\", error);\n return false;\n }\n}\n\n/**\n * Get permission status\n * @param permission - Permission type to check\n * @returns Promise resolving to permission status\n */\nexport async function getPermissionStatus(\n _permission: PermissionType,\n): Promise<PermissionStatus> {\n try {\n // This is a placeholder implementation\n // Real implementation would use platform-specific APIs\n return PermissionStatus.GRANTED;\n } catch (error) {\n console.error(\"Failed to get permission status:\", error);\n return PermissionStatus.DENIED;\n }\n}\n\n/**\n * Open app settings to request permissions\n * Guides user to app settings where they can manually enable permissions\n */\nexport function openAppSettings(): void {\n try {\n // This would typically use react-native-app-settings or similar\n console.log(\n \"Opening app settings (requires react-native-app-settings or platform implementation)\",\n );\n } catch (error) {\n console.error(\"Failed to open app settings:\", error);\n }\n}\n","/**\n * URI utility functions for React Native file handling\n */\n\n/**\n * Extract file name from URI\n * @param uri - File URI\n * @returns File name extracted from URI\n */\nexport function getFileNameFromUri(uri: string): string {\n try {\n // Handle different URI formats\n if (uri.startsWith(\"file://\")) {\n // File URI format\n const path = uri.replace(\"file://\", \"\");\n return path.split(\"/\").pop() || \"file\";\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URI format (Android)\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n }\n\n // Assume it's a path or other format\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n } catch {\n return \"file\";\n }\n}\n\n/**\n * Convert file path to file URI\n * @param filePath - File path\n * @returns File URI\n */\nexport function pathToUri(filePath: string): string {\n if (filePath.startsWith(\"file://\")) {\n return filePath;\n }\n\n if (filePath.startsWith(\"content://\")) {\n return filePath;\n }\n\n // Convert to file URI\n return `file://${filePath}`;\n}\n\n/**\n * Convert file URI to file path\n * @param uri - File URI\n * @returns File path\n */\nexport function uriToPath(uri: string): string {\n if (uri.startsWith(\"file://\")) {\n return uri.replace(\"file://\", \"\");\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URIs cannot be converted to paths directly\n return uri;\n }\n\n return uri;\n}\n\n/**\n * Get directory from URI\n * @param uri - File URI\n * @returns Directory path\n */\nexport function getDirectoryFromUri(uri: string): string {\n try {\n const path = uriToPath(uri);\n const parts = path.split(\"/\");\n parts.pop(); // Remove file name\n return parts.join(\"/\");\n } catch {\n return \"\";\n }\n}\n\n/**\n * Check if URI is a content URI (Android specific)\n * @param uri - URI to check\n * @returns True if URI is a content URI\n */\nexport function isContentUri(uri: string): boolean {\n return uri.startsWith(\"content://\");\n}\n\n/**\n * Check if URI is a file URI\n * @param uri - URI to check\n * @returns True if URI is a file URI\n */\nexport function isFileUri(uri: string): boolean {\n return uri.startsWith(\"file://\");\n}\n\n/**\n * Normalize URI for cross-platform compatibility\n * @param uri - URI to normalize\n * @returns Normalized URI\n */\nexport function normalizeUri(uri: string): string {\n // Remove duplicate slashes (but keep protocol slashes)\n return uri.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Get MIME type hint from URI\n * @param uri - File URI\n * @returns MIME type hint based on file extension\n */\nexport function getMimeTypeFromUri(uri: string): string {\n const fileName = getFileNameFromUri(uri);\n\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".mov\": \"video/quicktime\",\n \".avi\": \"video/x-msvideo\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".txt\": \"text/plain\",\n \".json\": \"application/json\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n","import { ActivityIndicator, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadState } from \"../hooks/use-upload\";\nimport { formatFileSize } from \"../utils\";\n\nexport interface UploadProgressProps {\n /** Upload state information */\n state: UploadState;\n /** Optional custom label */\n label?: string;\n}\n\n/**\n * Component to display upload progress with percentage, size, and speed\n */\nexport function UploadProgress({ state, label }: UploadProgressProps) {\n const getStatusColor = () => {\n switch (state.status) {\n case \"uploading\":\n return \"#007AFF\";\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"aborted\":\n return \"#FF3B30\";\n default:\n return \"#999999\";\n }\n };\n\n const renderContent = () => {\n switch (state.status) {\n case \"idle\":\n return (\n <View style={styles.container}>\n <Text style={styles.label}>{label || \"Ready to upload\"}</Text>\n </View>\n );\n\n case \"uploading\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.label}>{label || \"Uploading\"}</Text>\n <Text style={styles.percentage}>{state.progress}%</Text>\n </View>\n\n {/* Progress bar */}\n <View style={styles.progressBarContainer}>\n <View\n style={[\n styles.progressBar,\n {\n width: `${state.progress}%`,\n backgroundColor: getStatusColor(),\n },\n ]}\n />\n </View>\n\n {/* Details row */}\n <View style={styles.detailsRow}>\n <Text style={styles.detail}>\n {formatFileSize(state.bytesUploaded)} /{\" \"}\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n </View>\n );\n\n case \"success\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload complete\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✓\n </Text>\n </View>\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n );\n\n case \"error\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload failed\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✕\n </Text>\n </View>\n {state.error && (\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {state.error.message}\n </Text>\n )}\n </View>\n );\n\n case \"aborted\":\n return (\n <View style={styles.container}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload cancelled\"}\n </Text>\n </View>\n );\n\n default:\n return null;\n }\n };\n\n return (\n <View\n style={[\n styles.wrapper,\n {\n borderLeftColor: getStatusColor(),\n },\n ]}\n >\n {state.status === \"uploading\" && (\n <ActivityIndicator\n size=\"small\"\n color={getStatusColor()}\n style={styles.spinner}\n />\n )}\n {renderContent()}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrapper: {\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n spinner: {\n marginTop: 4,\n },\n container: {\n flex: 1,\n gap: 4,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n label: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#333333\",\n flex: 1,\n },\n percentage: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#007AFF\",\n minWidth: 36,\n textAlign: \"right\",\n },\n progressBarContainer: {\n height: 4,\n backgroundColor: \"#e0e0e0\",\n borderRadius: 2,\n overflow: \"hidden\",\n },\n progressBar: {\n height: \"100%\",\n borderRadius: 2,\n },\n detailsRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n detail: {\n fontSize: 12,\n color: \"#666666\",\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useCameraUpload } from \"../hooks\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface CameraUploadButtonProps {\n /** Options for camera upload */\n options?: UseCameraUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for camera capture and upload\n * Triggers camera on press and handles upload with progress display\n */\nexport function CameraUploadButton({\n options,\n label = \"Take Photo\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: CameraUploadButtonProps) {\n const { state, captureAndUpload } = useCameraUpload(options);\n\n const handlePress = async () => {\n try {\n await captureAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"Camera upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#007AFF\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useFileUpload } from \"../hooks\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface FileUploadButtonProps {\n /** Options for file upload */\n options?: UseFileUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for document/file selection and upload\n * Generic file picker with progress display\n */\nexport function FileUploadButton({\n options,\n label = \"Choose File\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: FileUploadButtonProps) {\n const { state, pickAndUpload } = useFileUpload(options);\n\n const handlePress = async () => {\n try {\n await pickAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"File upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#FF9500\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import React, { type ReactNode } from \"react\";\nimport {\n ActivityIndicator,\n FlatList,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useGalleryUpload } from \"../hooks\";\nimport type { UseGalleryUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface GalleryUploadButtonProps {\n /** Options for gallery upload */\n options?: UseGalleryUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when all uploads complete successfully */\n onSuccess?: (results: unknown[]) => void;\n /** Callback when any upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show individual progress for each file */\n showProgress?: boolean;\n}\n\n/**\n * Button component for gallery selection and batch upload\n * Triggers gallery picker on press and handles concurrent uploads\n */\nexport function GalleryUploadButton({\n options,\n label = \"Select from Gallery\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: GalleryUploadButtonProps) {\n const { state, selectAndUpload } = useGalleryUpload(options);\n\n const handlePress = async () => {\n try {\n await selectAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.items.some((item) => item.status === \"uploading\");\n const hasItems = state.items.length > 0;\n const allComplete =\n hasItems &&\n state.items.every(\n (item) => item.status !== \"uploading\" && item.status !== \"idle\",\n );\n\n React.useEffect(() => {\n if (allComplete) {\n const results = state.items\n .filter((item) => item.status === \"success\")\n .map((item) => item.result);\n if (results.length > 0) {\n onSuccess?.(results);\n }\n }\n }, [allComplete, state.items, onSuccess]);\n\n React.useEffect(() => {\n const errors = state.items.filter((item) => item.status === \"error\");\n const firstError = errors[0]?.error;\n if (firstError) {\n onError?.(firstError);\n }\n }, [state.items, onError]);\n\n const renderItem = ({ item }: { item: (typeof state.items)[0] }) => (\n <View key={item.id} style={styles.itemContainer}>\n <UploadProgress\n state={{\n status: item.status,\n progress: item.progress,\n bytesUploaded: item.bytesUploaded,\n totalBytes: item.totalBytes,\n error: item.error,\n result: item.result,\n }}\n label={item.file.data.name}\n />\n </View>\n );\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isLoading && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isLoading}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>\n {children || label}\n {hasItems && ` (${state.items.length})`}\n </Text>\n </Pressable>\n\n {hasItems && (\n <View style={styles.statsContainer}>\n <Text style={styles.statsText}>\n Progress: {state.items.filter((i) => i.status === \"success\").length}\n /{state.items.length} uploaded\n </Text>\n <Text style={styles.statsText}>Overall: {state.totalProgress}%</Text>\n </View>\n )}\n\n {showProgress && hasItems && (\n <FlatList\n scrollEnabled={false}\n data={state.items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n style={styles.listContainer}\n contentContainerStyle={styles.listContent}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#34C759\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n statsContainer: {\n paddingVertical: 8,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 4,\n },\n statsText: {\n fontSize: 12,\n color: \"#666666\",\n },\n listContainer: {\n maxHeight: 400,\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n paddingHorizontal: 0,\n },\n separator: {\n height: 4,\n },\n});\n","import { FlatList, Pressable, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadItem } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface UploadListProps {\n /** List of upload items to display */\n items: UploadItem[];\n /** Callback when remove item is pressed */\n onRemove?: (id: string) => void;\n /** Callback when item is pressed */\n onItemPress?: (item: UploadItem) => void;\n /** Whether to show remove button */\n showRemoveButton?: boolean;\n}\n\n/**\n * Component to display a list of upload items with individual progress\n * Shows status indicators and allows removal of items\n */\nexport function UploadList({\n items,\n onRemove,\n onItemPress,\n showRemoveButton = true,\n}: UploadListProps) {\n const renderItem = ({ item }: { item: UploadItem }) => (\n <Pressable\n style={[\n styles.itemContainer,\n { borderLeftColor: getStatusColor(item.progress.state) },\n ]}\n onPress={() => onItemPress?.(item)}\n >\n <View style={styles.itemContent}>\n {item.file.status === \"success\" && (\n <View style={styles.itemHeader}>\n <Text style={styles.fileName} numberOfLines={1}>\n {item.file.data.name}\n </Text>\n <Text style={styles.fileSize}>\n {getFileSizeDisplay(item.file.data.size)}\n </Text>\n </View>\n )}\n {item.file.status === \"error\" && (\n <Text style={styles.errorText}>{item.progress.error?.message}</Text>\n )}\n <View style={styles.progressWrapper}>\n <UploadProgress\n state={{\n status:\n item.progress.state === \"pending\"\n ? \"idle\"\n : item.progress.state === \"cancelled\"\n ? \"aborted\"\n : item.progress.state,\n progress: item.progress.progress,\n bytesUploaded: item.progress.uploadedBytes,\n totalBytes: item.progress.totalBytes,\n error: item.progress.error || null,\n result: item.result ?? null,\n }}\n />\n </View>\n </View>\n {showRemoveButton &&\n item.progress.state !== \"uploading\" &&\n item.progress.state !== \"pending\" && (\n <Pressable\n style={styles.removeButton}\n onPress={() => onRemove?.(item.id)}\n hitSlop={{ top: 8, right: 8, bottom: 8, left: 8 }}\n >\n <Text style={styles.removeButtonText}>✕</Text>\n </Pressable>\n )}\n </Pressable>\n );\n\n if (items.length === 0) {\n return (\n <View style={styles.emptyContainer}>\n <Text style={styles.emptyText}>No uploads</Text>\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.headerText}>Uploads ({items.length})</Text>\n <Text style={styles.headerSubtext}>\n {items.filter((i) => i.progress.state === \"success\").length} complete\n </Text>\n </View>\n <FlatList\n scrollEnabled={false}\n data={items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n contentContainerStyle={styles.listContent}\n />\n </View>\n );\n}\n\n// Helper functions\nfunction getStatusColor(state: string): string {\n switch (state) {\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"cancelled\":\n return \"#FF3B30\";\n case \"uploading\":\n case \"pending\":\n return \"#007AFF\";\n default:\n return \"#999999\";\n }\n}\n\nfunction getFileSizeDisplay(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${Math.round((bytes / k ** i) * 10) / 10} ${sizes[i]}`;\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: \"#f9f9f9\",\n borderRadius: 4,\n },\n headerText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#333333\",\n },\n errorText: {\n fontSize: 14,\n color: \"#FF3B30\",\n },\n headerSubtext: {\n fontSize: 14,\n color: \"#666666\",\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n itemContent: {\n flex: 1,\n gap: 6,\n },\n itemHeader: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n fileName: {\n fontSize: 14,\n fontWeight: \"500\",\n color: \"#333333\",\n flex: 1,\n },\n fileSize: {\n fontSize: 12,\n color: \"#999999\",\n marginLeft: 8,\n },\n progressWrapper: {\n marginTop: 2,\n },\n removeButton: {\n width: 32,\n height: 32,\n justifyContent: \"center\",\n alignItems: \"center\",\n borderRadius: 16,\n backgroundColor: \"#FFE5E5\",\n },\n removeButtonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FF3B30\",\n },\n separator: {\n height: 4,\n },\n emptyContainer: {\n paddingVertical: 24,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n emptyText: {\n fontSize: 14,\n color: \"#999999\",\n fontStyle: \"italic\",\n },\n});\n","import type {\n FlowUploadState,\n FlowUploadStatus,\n InputExecutionState,\n} from \"@uploadista/client-core\";\nimport type { TypedOutput } from \"@uploadista/core/flow\";\nimport { createContext, type ReactNode, useCallback, useContext } from \"react\";\nimport {\n type FlowInputMetadata,\n type UseFlowOptions,\n useFlow,\n} from \"../hooks/use-flow\";\nimport { useUploadistaContext } from \"../hooks/use-uploadista-context\";\nimport type { FilePickResult } from \"../types\";\n\n// Re-export types for convenience\nexport type {\n FlowUploadState,\n FlowUploadStatus,\n InputExecutionState,\n FlowInputMetadata,\n};\n\n// ============ FLOW CONTEXT ============\n\n/**\n * Context value provided by the Flow component root.\n * Contains all flow state and actions.\n */\nexport interface FlowContextValue {\n /** Current upload state */\n state: FlowUploadState;\n /** Discovered input nodes metadata (null until discovery completes) */\n inputMetadata: FlowInputMetadata[] | null;\n /** Current input values set via setInput() */\n inputs: Record<string, unknown>;\n /** Per-input execution state for multi-input flows */\n inputStates: ReadonlyMap<string, InputExecutionState>;\n\n /** Set an input value for a specific node */\n setInput: (nodeId: string, value: unknown) => void;\n /** Execute the flow with current inputs */\n execute: () => Promise<void>;\n /** Upload a single file through the flow */\n upload: (file: FilePickResult) => Promise<void>;\n /** Abort the current upload */\n abort: () => void;\n /** Reset the upload state and clear all inputs */\n reset: () => void;\n\n /** Whether an upload or flow execution is in progress */\n isActive: boolean;\n /** Whether the file is currently being uploaded */\n isUploadingFile: boolean;\n /** Whether the flow is currently processing */\n isProcessing: boolean;\n /** Whether the hook is discovering flow inputs */\n isDiscoveringInputs: boolean;\n\n /** Pick a file and set it for a specific input node */\n pickFileForInput: (nodeId: string) => Promise<void>;\n /** Pick a file and start upload immediately (single-file flows) */\n pickAndUpload: () => Promise<void>;\n}\n\nconst FlowContext = createContext<FlowContextValue | null>(null);\n\n/**\n * Hook to access flow context from within a Flow component.\n * @throws Error if used outside of a Flow component\n */\nexport function useFlowContext(): FlowContextValue {\n const context = useContext(FlowContext);\n if (!context) {\n throw new Error(\n \"useFlowContext must be used within a <Flow> component. \" +\n 'Wrap your component tree with <Flow flowId=\"...\" storageId=\"...\">',\n );\n }\n return context;\n}\n\n// ============ FLOW INPUT CONTEXT ============\n\n/**\n * Context value for a specific input node within a Flow.\n */\nexport interface FlowInputContextValue {\n /** Input node ID */\n nodeId: string;\n /** Input metadata from flow discovery */\n metadata: FlowInputMetadata;\n /** Current value for this input */\n value: unknown;\n /** Set the value for this input */\n setValue: (value: unknown) => void;\n /** Per-input execution state (if available) */\n state: InputExecutionState | undefined;\n /** Pick a file for this input */\n pickFile: () => Promise<void>;\n}\n\nconst FlowInputContext = createContext<FlowInputContextValue | null>(null);\n\n/**\n * Hook to access flow input context from within a Flow.Input component.\n * @throws Error if used outside of a Flow.Input component\n */\nexport function useFlowInputContext(): FlowInputContextValue {\n const context = useContext(FlowInputContext);\n if (!context) {\n throw new Error(\n \"useFlowInputContext must be used within a <Flow.Input> component. \" +\n 'Wrap your component with <Flow.Input nodeId=\"...\">',\n );\n }\n return context;\n}\n\n// ============ FLOW ROOT COMPONENT ============\n\n/**\n * Render props for the Flow root component.\n */\nexport interface FlowRenderProps extends FlowContextValue {\n /** Alias for execute() */\n submit: () => Promise<void>;\n /** Alias for abort() */\n cancel: () => void;\n}\n\n/**\n * Props for the Flow root component.\n */\nexport interface FlowProps {\n /** Flow ID to execute */\n flowId: string;\n /** Storage ID for file uploads */\n storageId: string;\n /** Optional output node ID to wait for */\n outputNodeId?: string;\n /** Optional metadata to include with the flow execution */\n metadata?: Record<string, string>;\n /** Called when flow completes successfully */\n onSuccess?: (outputs: TypedOutput[]) => void;\n /** Called when flow fails */\n onError?: (error: Error) => void;\n /** Called on upload progress */\n onProgress?: (\n progress: number,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n /** Called when flow completes with all outputs */\n onFlowComplete?: (outputs: TypedOutput[]) => void;\n /** Children to render (can be render function or ReactNode) */\n children: ReactNode | ((props: FlowRenderProps) => ReactNode);\n}\n\n/**\n * Root component for flow-based uploads on React Native.\n * Provides context for all Flow sub-components.\n *\n * @example\n * ```tsx\n * <Flow flowId=\"image-optimizer\" storageId=\"s3\" onSuccess={handleSuccess}>\n * <Flow.Inputs>\n * {({ inputs, isLoading }) => (\n * inputs.map(input => (\n * <Flow.Input key={input.nodeId} nodeId={input.nodeId}>\n * {({ metadata, pickFile }) => (\n * <Button onPress={pickFile} title={metadata.nodeName} />\n * )}\n * </Flow.Input>\n * ))\n * )}\n * </Flow.Inputs>\n * <Flow.Submit>\n * <Text>Process</Text>\n * </Flow.Submit>\n * </Flow>\n * ```\n */\nfunction FlowRoot({\n flowId,\n storageId,\n outputNodeId,\n metadata,\n onSuccess,\n onError,\n onProgress,\n onFlowComplete,\n children,\n}: FlowProps) {\n const { fileSystemProvider } = useUploadistaContext();\n\n const options: UseFlowOptions = {\n flowId,\n storageId,\n outputNodeId,\n metadata,\n onSuccess,\n onError,\n onProgress,\n onFlowComplete,\n };\n\n const flow = useFlow(options);\n\n // Pick a file for a specific input node\n const pickFileForInput = useCallback(\n async (nodeId: string) => {\n if (!fileSystemProvider?.pickDocument) {\n throw new Error(\"File picker not available\");\n }\n const result = await fileSystemProvider.pickDocument();\n if (result.status === \"success\") {\n flow.setInput(nodeId, result);\n }\n },\n [fileSystemProvider, flow],\n );\n\n // Pick a file and start upload immediately\n const pickAndUpload = useCallback(async () => {\n if (!fileSystemProvider?.pickDocument) {\n throw new Error(\"File picker not available\");\n }\n const result = await fileSystemProvider.pickDocument();\n if (result.status === \"success\") {\n await flow.upload(result);\n }\n }, [fileSystemProvider, flow]);\n\n const contextValue: FlowContextValue = {\n state: flow.state,\n inputMetadata: flow.inputMetadata,\n inputs: flow.inputs,\n inputStates: flow.inputStates,\n setInput: flow.setInput,\n execute: flow.execute,\n upload: flow.upload,\n abort: flow.abort,\n reset: flow.reset,\n isActive: flow.isActive,\n isUploadingFile: flow.isUploadingFile,\n isProcessing: flow.isProcessing,\n isDiscoveringInputs: flow.isDiscoveringInputs,\n pickFileForInput,\n pickAndUpload,\n };\n\n const renderProps: FlowRenderProps = {\n ...contextValue,\n submit: flow.execute,\n cancel: flow.abort,\n };\n\n return (\n <FlowContext.Provider value={contextValue}>\n {typeof children === \"function\" ? children(renderProps) : children}\n </FlowContext.Provider>\n );\n}\n\n// ============ INPUTS DISCOVERY PRIMITIVE ============\n\n/**\n * Render props for Flow.Inputs component.\n */\nexport interface FlowInputsRenderProps {\n /** Discovered input metadata */\n inputs: FlowInputMetadata[];\n /** Whether inputs are still being discovered */\n isLoading: boolean;\n}\n\n/**\n * Props for Flow.Inputs component.\n */\nexport interface FlowInputsProps {\n /** Render function receiving discovered inputs */\n children: (props: FlowInputsRenderProps) => ReactNode;\n}\n\n/**\n * Auto-discovers flow input nodes and provides them via render props.\n *\n * @example\n * ```tsx\n * <Flow.Inputs>\n * {({ inputs, isLoading }) => (\n * isLoading ? <ActivityIndicator /> : (\n * inputs.map(input => (\n * <Flow.Input key={input.nodeId} nodeId={input.nodeId}>\n * ...\n * </Flow.Input>\n * ))\n * )\n * )}\n * </Flow.Inputs>\n * ```\n */\nfunction FlowInputs({ children }: FlowInputsProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowInputsRenderProps = {\n inputs: flow.inputMetadata ?? [],\n isLoading: flow.isDiscoveringInputs,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ INPUT PRIMITIVE ============\n\n/**\n * Props for Flow.Input component.\n */\nexport interface FlowInputProps {\n /** Input node ID */\n nodeId: string;\n /** Children (can be render function or regular children) */\n children: ReactNode | ((props: FlowInputContextValue) => ReactNode);\n}\n\n/**\n * Scoped input context provider for a specific input node.\n * Children can access input-specific state via useFlowInputContext().\n *\n * @example\n * ```tsx\n * <Flow.Input nodeId=\"video-input\">\n * {({ metadata, value, pickFile }) => (\n * <View>\n * <Text>{metadata.nodeName}</Text>\n * <Button onPress={pickFile} title=\"Select File\" />\n * {value && <Text>Selected: {value.data?.name}</Text>}\n * </View>\n * )}\n * </Flow.Input>\n * ```\n */\nfunction FlowInput({ nodeId, children }: FlowInputProps) {\n const flow = useFlowContext();\n\n const metadata = flow.inputMetadata?.find((m) => m.nodeId === nodeId);\n\n if (!metadata) {\n // Input not yet discovered or doesn't exist\n return null;\n }\n\n const pickFile = async () => {\n await flow.pickFileForInput(nodeId);\n };\n\n const contextValue: FlowInputContextValue = {\n nodeId,\n metadata,\n value: flow.inputs[nodeId],\n setValue: (value) => flow.setInput(nodeId, value),\n state: flow.inputStates.get(nodeId),\n pickFile,\n };\n\n return (\n <FlowInputContext.Provider value={contextValue}>\n {typeof children === \"function\" ? children(contextValue) : children}\n </FlowInputContext.Provider>\n );\n}\n\n// ============ INPUT FILE PICKER PRIMITIVE ============\n\n/**\n * Render props for Flow.Input.FilePicker component.\n */\nexport interface FlowInputFilePickerRenderProps {\n /** Current value for this input */\n value: unknown;\n /** Whether a file is selected */\n hasFile: boolean;\n /** File name (if value is FilePickResult) */\n fileName: string | null;\n /** File size in bytes (if value is FilePickResult) */\n fileSize: number | null;\n /** Per-input progress (if available) */\n progress: number;\n /** Per-input status (if available) */\n status: string;\n /** Open file picker */\n pickFile: () => Promise<void>;\n /** Clear the input value */\n clear: () => void;\n}\n\n/**\n * Props for Flow.Input.FilePicker component.\n */\nexport interface FlowInputFilePickerProps {\n /** Render function receiving file picker state */\n children: (props: FlowInputFilePickerRenderProps) => ReactNode;\n}\n\n/**\n * File picker for a specific input within a Flow.Input.\n * Sets the input value but does NOT trigger upload until Flow.Submit is pressed.\n */\nfunction FlowInputFilePicker({ children }: FlowInputFilePickerProps) {\n const input = useFlowInputContext();\n\n // Check if value is a FilePickResult\n const fileResult = input.value as FilePickResult | undefined;\n const hasFile = fileResult?.status === \"success\";\n const fileName = hasFile ? (fileResult?.data?.name ?? null) : null;\n const fileSize = hasFile ? (fileResult?.data?.size ?? null) : null;\n\n const renderProps: FlowInputFilePickerRenderProps = {\n value: input.value,\n hasFile,\n fileName,\n fileSize,\n progress: input.state?.progress ?? 0,\n status: input.state?.status ?? \"idle\",\n pickFile: input.pickFile,\n clear: () => input.setValue(undefined),\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ INPUT PREVIEW PRIMITIVE ============\n\n/**\n * Render props for Flow.Input.Preview component.\n */\nexport interface FlowInputPreviewRenderProps {\n /** Current value */\n value: unknown;\n /** Whether a file is selected */\n hasFile: boolean;\n /** Whether value is a URL string */\n isUrl: boolean;\n /** File name (if value is FilePickResult) */\n fileName: string | null;\n /** File size in bytes (if value is FilePickResult) */\n fileSize: number | null;\n /** File URI (if value is FilePickResult) */\n fileUri: string | null;\n /** Clear the input value */\n clear: () => void;\n}\n\n/**\n * Props for Flow.Input.Preview component.\n */\nexport interface FlowInputPreviewProps {\n /** Render function receiving preview state */\n children: (props: FlowInputPreviewRenderProps) => ReactNode;\n}\n\n/**\n * Preview component for showing the selected value within a Flow.Input.\n */\nfunction FlowInputPreview({ children }: FlowInputPreviewProps) {\n const input = useFlowInputContext();\n\n // Check if value is a FilePickResult\n const fileResult = input.value as FilePickResult | undefined;\n const hasFile = fileResult?.status === \"success\";\n const isUrl =\n typeof input.value === \"string\" && (input.value as string).length > 0;\n\n const renderProps: FlowInputPreviewRenderProps = {\n value: input.value,\n hasFile,\n isUrl,\n fileName: hasFile ? (fileResult?.data?.name ?? null) : null,\n fileSize: hasFile ? (fileResult?.data?.size ?? null) : null,\n fileUri: hasFile ? (fileResult?.data?.uri ?? null) : null,\n clear: () => input.setValue(undefined),\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ PROGRESS PRIMITIVE ============\n\n/**\n * Render props for Flow.Progress component.\n */\nexport interface FlowProgressRenderProps {\n /** Progress percentage (0-100) */\n progress: number;\n /** Bytes uploaded so far */\n bytesUploaded: number;\n /** Total bytes to upload (null if unknown) */\n totalBytes: number | null;\n /** Current status */\n status: FlowUploadStatus;\n}\n\n/**\n * Props for Flow.Progress component.\n */\nexport interface FlowProgressProps {\n /** Render function receiving progress state */\n children: (props: FlowProgressRenderProps) => ReactNode;\n}\n\n/**\n * Progress display component within a Flow.\n */\nfunction FlowProgress({ children }: FlowProgressProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowProgressRenderProps = {\n progress: flow.state.progress,\n bytesUploaded: flow.state.bytesUploaded,\n totalBytes: flow.state.totalBytes,\n status: flow.state.status,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ STATUS PRIMITIVE ============\n\n/**\n * Render props for Flow.Status component.\n */\nexport interface FlowStatusRenderProps {\n /** Current status */\n status: FlowUploadStatus;\n /** Current node being processed (if any) */\n currentNodeName: string | null;\n /** Current node type (if any) */\n currentNodeType: string | null;\n /** Error (if status is error) */\n error: Error | null;\n /** Job ID (if started) */\n jobId: string | null;\n /** Whether flow has started */\n flowStarted: boolean;\n /** Flow outputs (if completed) */\n flowOutputs: TypedOutput[] | null;\n}\n\n/**\n * Props for Flow.Status component.\n */\nexport interface FlowStatusProps {\n /** Render function receiving status state */\n children: (props: FlowStatusRenderProps) => ReactNode;\n}\n\n/**\n * Status display component within a Flow.\n */\nfunction FlowStatus({ children }: FlowStatusProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowStatusRenderProps = {\n status: flow.state.status,\n currentNodeName: flow.state.currentNodeName,\n currentNodeType: flow.state.currentNodeType,\n error: flow.state.error,\n jobId: flow.state.jobId,\n flowStarted: flow.state.flowStarted,\n flowOutputs: flow.state.flowOutputs,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ ERROR PRIMITIVE ============\n\n/**\n * Render props for Flow.Error component.\n */\nexport interface FlowErrorRenderProps {\n /** Error object (null if no error) */\n error: Error | null;\n /** Whether there is an error */\n hasError: boolean;\n /** Error message */\n message: string | null;\n /** Reset the flow */\n reset: () => void;\n}\n\n/**\n * Props for Flow.Error component.\n */\nexport interface FlowErrorProps {\n /** Render function receiving error state */\n children: (props: FlowErrorRenderProps) => ReactNode;\n}\n\n/**\n * Error display component within a Flow.\n */\nfunction FlowError({ children }: FlowErrorProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowErrorRenderProps = {\n error: flow.state.error,\n hasError: flow.state.status === \"error\",\n message: flow.state.error?.message ?? null,\n reset: flow.reset,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ ACTION PRIMITIVES ============\n\n/**\n * Render props for Flow.Submit component.\n */\nexport interface FlowSubmitRenderProps {\n /** Execute the flow */\n submit: () => Promise<void>;\n /** Whether the button should be disabled */\n isDisabled: boolean;\n /** Whether currently submitting */\n isSubmitting: boolean;\n}\n\n/**\n * Props for Flow.Submit component.\n */\nexport interface FlowSubmitProps {\n /** Render function receiving submit state */\n children: ReactNode | ((props: FlowSubmitRenderProps) => ReactNode);\n /** Additional disabled state */\n disabled?: boolean;\n}\n\n/**\n * Submit primitive that executes the flow with current inputs.\n * Provides render props for building custom submit buttons.\n * Automatically disabled when uploading.\n */\nfunction FlowSubmit({ children, disabled }: FlowSubmitProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowSubmitRenderProps = {\n submit: flow.execute,\n isDisabled: disabled || flow.isActive || Object.keys(flow.inputs).length === 0,\n isSubmitting: flow.isActive,\n };\n\n return <>{typeof children === \"function\" ? children(renderProps) : children}</>;\n}\n\n/**\n * Render props for Flow.Cancel component.\n */\nexport interface FlowCancelRenderProps {\n /** Cancel the flow */\n cancel: () => void;\n /** Whether the button should be disabled */\n isDisabled: boolean;\n}\n\n/**\n * Props for Flow.Cancel component.\n */\nexport interface FlowCancelProps {\n /** Render function receiving cancel state */\n children: ReactNode | ((props: FlowCancelRenderProps) => ReactNode);\n}\n\n/**\n * Cancel primitive that aborts the current upload.\n */\nfunction FlowCancel({ children }: FlowCancelProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowCancelRenderProps = {\n cancel: flow.abort,\n isDisabled: !flow.isActive,\n };\n\n return <>{typeof children === \"function\" ? children(renderProps) : children}</>;\n}\n\n/**\n * Render props for Flow.Reset component.\n */\nexport interface FlowResetRenderProps {\n /** Reset the flow */\n reset: () => void;\n /** Whether the button should be disabled */\n isDisabled: boolean;\n}\n\n/**\n * Props for Flow.Reset component.\n */\nexport interface FlowResetProps {\n /** Render function receiving reset state */\n children: ReactNode | ((props: FlowResetRenderProps) => ReactNode);\n}\n\n/**\n * Reset primitive that clears all inputs and resets to idle state.\n */\nfunction FlowReset({ children }: FlowResetProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowResetRenderProps = {\n reset: flow.reset,\n isDisabled: flow.isActive,\n };\n\n return <>{typeof children === \"function\" ? children(renderProps) : children}</>;\n}\n\n// ============ QUICK UPLOAD PRIMITIVE ============\n\n/**\n * Render props for Flow.QuickUpload component.\n */\nexport interface FlowQuickUploadRenderProps {\n /** Whether currently uploading */\n isUploading: boolean;\n /** Progress percentage (0-100) */\n progress: number;\n /** Current status */\n status: FlowUploadStatus;\n /** Pick a file and start upload immediately */\n pickAndUpload: () => Promise<void>;\n /** Abort the current upload */\n abort: () => void;\n}\n\n/**\n * Props for Flow.QuickUpload component.\n */\nexport interface FlowQuickUploadProps {\n /** Render function receiving quick upload state */\n children: (props: FlowQuickUploadRenderProps) => ReactNode;\n}\n\n/**\n * Quick upload component for single-file flows.\n * Picks a file and starts upload immediately.\n *\n * @example\n * ```tsx\n * <Flow.QuickUpload>\n * {({ isUploading, progress, pickAndUpload, abort }) => (\n * <Button\n * onPress={isUploading ? abort : pickAndUpload}\n * title={isUploading ? `Uploading ${progress}%` : 'Upload File'}\n * />\n * )}\n * </Flow.QuickUpload>\n * ```\n */\nfunction FlowQuickUpload({ children }: FlowQuickUploadProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowQuickUploadRenderProps = {\n isUploading: flow.isActive,\n progress: flow.state.progress,\n status: flow.state.status,\n pickAndUpload: flow.pickAndUpload,\n abort: flow.abort,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ COMPOUND COMPONENT EXPORT ============\n\n/**\n * Flow compound component for flow-based file uploads on React Native.\n *\n * Provides a composable, headless API for building flow upload interfaces.\n * All sub-components use render props for complete UI control.\n *\n * @example Quick Upload (Single File)\n * ```tsx\n * <Flow flowId=\"image-optimizer\" storageId=\"s3\" onSuccess={handleSuccess}>\n * <Flow.QuickUpload>\n * {({ isUploading, progress, pickAndUpload, abort }) => (\n * <View>\n * <Button\n * onPress={isUploading ? abort : pickAndUpload}\n * title={isUploading ? 'Cancel' : 'Upload Image'}\n * />\n * {isUploading && <Text>{progress}%</Text>}\n * </View>\n * )}\n * </Flow.QuickUpload>\n * </Flow>\n * ```\n *\n * @example Multi-Input Flow\n * ```tsx\n * <Flow flowId=\"video-processor\" storageId=\"s3\">\n * <Flow.Inputs>\n * {({ inputs, isLoading }) => (\n * isLoading ? <ActivityIndicator /> : inputs.map(input => (\n * <Flow.Input key={input.nodeId} nodeId={input.nodeId}>\n * {({ metadata, pickFile, value }) => (\n * <View>\n * <Text>{metadata.nodeName}</Text>\n * <Button onPress={pickFile} title=\"Select File\" />\n * <Flow.Input.Preview>\n * {({ hasFile, fileName }) => hasFile && <Text>{fileName}</Text>}\n * </Flow.Input.Preview>\n * </View>\n * )}\n * </Flow.Input>\n * ))\n * )}\n * </Flow.Inputs>\n * <CustomSubmitButton />\n * </Flow>\n * ```\n */\nexport const Flow = Object.assign(FlowRoot, {\n Inputs: FlowInputs,\n Input: Object.assign(FlowInput, {\n FilePicker: FlowInputFilePicker,\n Preview: FlowInputPreview,\n }),\n Progress: FlowProgress,\n Status: FlowStatus,\n Error: FlowError,\n Submit: FlowSubmit,\n Cancel: FlowCancel,\n Reset: FlowReset,\n QuickUpload: FlowQuickUpload,\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["initialState: UploadState","initialState","initialState: FlowUploadState","initialState","processedInputs: Record<string, unknown>","initialState: MultiUploadState","newItems: UploadItemState[]","uploadInput: Blob","result: FilePickResult","parts","getStatusColor","styles","styles","styles","styles","contextValue: FlowContextValue","renderProps: FlowRenderProps","contextValue: FlowInputContextValue","renderProps: FlowSubmitRenderProps","renderProps: FlowCancelRenderProps","renderProps: FlowResetRenderProps"],"sources":["../src/hooks/uploadista-context.ts","../src/types/platform-types.ts","../src/hooks/use-uploadista-context.ts","../src/hooks/use-upload.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/contexts/flow-manager-context.tsx","../src/hooks/use-flow.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts","../src/components/UploadProgress.tsx","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx","../src/components/flow-primitives.tsx"],"sourcesContent":["import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport { createContext } from \"react\";\nimport type { FileSystemProvider } from \"../types\";\nimport type { UseUploadistaClientReturn } from \"./use-uploadista-client\";\n\nexport interface UploadistaContextType extends UseUploadistaClientReturn {\n fileSystemProvider: FileSystemProvider;\n /**\n * Subscribe to events (used internally by hooks)\n * @internal\n */\n subscribeToEvents: (handler: (event: UploadistaEvent) => void) => () => void;\n}\n\nexport const UploadistaContext = createContext<\n UploadistaContextType | undefined\n>(undefined);\n","/**\n * Platform-specific type definitions for React Native\n *\n * React Native's Blob implementation differs from the browser's Blob API.\n * This file provides proper type definitions and guards for platform-specific behavior.\n */\n\n/**\n * BufferSource represents data that can be passed to Blob constructor\n * Includes both ArrayBuffer and typed arrays (Uint8Array, etc.)\n */\nexport type BufferSource = ArrayBuffer | ArrayBufferView;\n\n/**\n * React Native Blob constructor options\n * Extends standard BlobPropertyBag with platform-specific properties\n */\nexport interface ReactNativeBlobOptions {\n /** MIME type of the blob */\n type?: string;\n /** Platform-specific: file path for optimization (React Native only) */\n path?: string;\n}\n\n/**\n * React Native Blob constructor type\n * Unlike browser Blob, accepts BufferSource in the parts array\n */\nexport interface ReactNativeBlobConstructor {\n new (\n parts?: Array<BufferSource | Blob | string>,\n options?: ReactNativeBlobOptions,\n ): Blob;\n prototype: Blob;\n}\n\n/**\n * Type guard to check if a value is ArrayBuffer\n */\nexport function isArrayBuffer(value: unknown): value is ArrayBuffer {\n return value instanceof ArrayBuffer;\n}\n\n/**\n * Type guard to check if a value is ArrayBufferView (typed array)\n */\nexport function isArrayBufferView(value: unknown): value is ArrayBufferView {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"buffer\" in value &&\n value.buffer instanceof ArrayBuffer\n );\n}\n\n/**\n * Type guard to check if a value is BufferSource\n */\nexport function isBufferSource(value: unknown): value is BufferSource {\n return isArrayBuffer(value) || isArrayBufferView(value);\n}\n\n/**\n * Type guard to check if we're in React Native environment\n * (checks for navigator.product === 'ReactNative')\n */\nexport function isReactNativeEnvironment(): boolean {\n const g = globalThis as typeof globalThis & {\n navigator?: { product?: string };\n };\n return (\n typeof g !== \"undefined\" &&\n typeof g.navigator !== \"undefined\" &&\n g.navigator.product === \"ReactNative\"\n );\n}\n\n/**\n * Create a Blob from BufferSource with proper typing for React Native\n *\n * This function handles the platform differences between browser and React Native Blob APIs.\n * React Native's Blob constructor accepts BufferSource directly, while browser Blob requires\n * conversion to Uint8Array first in some cases.\n *\n * @param data - ArrayBuffer or typed array to convert to Blob\n * @param options - Blob options including MIME type\n * @returns Platform-appropriate Blob instance\n *\n * @example\n * ```typescript\n * const arrayBuffer = await fileSystemProvider.readFile(uri);\n * const blob = createBlobFromBuffer(arrayBuffer, {\n * type: 'image/jpeg'\n * });\n * ```\n */\nexport function createBlobFromBuffer(\n data: BufferSource,\n options?: ReactNativeBlobOptions,\n): Blob {\n // Convert ArrayBuffer to Uint8Array for consistent handling\n const uint8Array = data instanceof ArrayBuffer ? new Uint8Array(data) : data;\n\n // In React Native, Blob constructor accepts BufferSource\n // Cast to ReactNativeBlobConstructor to use the correct signature\n const BlobConstructor = Blob as unknown as ReactNativeBlobConstructor;\n return new BlobConstructor([uint8Array], options);\n}\n","import { useContext } from \"react\";\nimport { UploadistaContext } from \"./uploadista-context\";\n\n/**\n * Hook to access the Uploadista client instance\n * Must be used within an UploadistaProvider\n * @throws Error if used outside of UploadistaProvider\n * @returns The Uploadista client and file system provider\n */\nexport function useUploadistaContext() {\n const context = useContext(UploadistaContext);\n\n if (!context) {\n throw new Error(\n \"useUploadistaClient must be used within an UploadistaProvider\",\n );\n }\n\n return context;\n}\n","import type {\n UploadistaUploadOptions,\n UploadMetrics,\n} from \"@uploadista/client-core\";\nimport {\n UploadManager,\n type UploadState,\n type UploadStatus,\n} from \"@uploadista/client-core\";\nimport type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { FilePickResult } from \"../types\";\nimport { createBlobFromBuffer } from \"../types/platform-types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n// Re-export types from core for convenience\nexport type { UploadState, UploadStatus };\n\nexport interface UseUploadOptions {\n /**\n * Upload metadata to attach to the file\n */\n metadata?: Record<string, string>;\n\n /**\n * Whether to defer the upload size calculation\n */\n uploadLengthDeferred?: boolean;\n\n /**\n * Manual upload size override\n */\n uploadSize?: number;\n\n /**\n * Called when upload progress updates\n */\n onProgress?: (\n uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n\n /**\n * Called when a chunk completes\n */\n onChunkComplete?: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => void;\n\n /**\n * Called when upload succeeds\n */\n onSuccess?: (result: UploadFile) => void;\n\n /**\n * Called when upload fails\n */\n onError?: (error: Error) => void;\n\n /**\n * Called when upload is aborted\n */\n onAbort?: () => void;\n\n /**\n * Custom retry logic\n */\n onShouldRetry?: (error: Error, retryAttempt: number) => boolean;\n}\n\nexport interface UseUploadReturn {\n /**\n * Current upload state\n */\n state: UploadState;\n\n /**\n * Start uploading a file from a file pick result\n */\n upload: (file: FilePickResult) => Promise<void>;\n\n /**\n * Abort the current upload\n */\n abort: () => void;\n\n /**\n * Reset the upload state to idle\n */\n reset: () => void;\n\n /**\n * Retry the last failed upload\n */\n retry: () => void;\n\n /**\n * Whether an upload is currently active\n */\n isUploading: boolean;\n\n /**\n * Whether the upload can be retried\n */\n canRetry: boolean;\n\n /**\n * Upload metrics and performance insights from the client\n */\n metrics: UploadMetrics;\n}\n\nconst initialState: UploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n error: null,\n result: null,\n};\n\n/**\n * React Native hook for managing individual file uploads with full state management.\n * Provides upload progress tracking, error handling, abort functionality, and retry logic.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Upload configuration and event handlers\n * @returns Upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const upload = useUpload({\n * onSuccess: (result) => console.log('Upload complete:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * onProgress: (progress) => console.log('Progress:', progress + '%'),\n * });\n *\n * const handleFilePick = async () => {\n * const file = await pickFile();\n * if (file) await upload.upload(file);\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handleFilePick} />\n * {upload.isUploading && <Text>Progress: {upload.state.progress}%</Text>}\n * {upload.state.error && <Text>Error: {upload.state.error.message}</Text>}\n * {upload.canRetry && <Button title=\"Retry\" onPress={upload.retry} />}\n * <Button title=\"Abort\" onPress={upload.abort} disabled={!upload.isUploading} />\n * </View>\n * );\n * }\n * ```\n */\nexport function useUpload(options: UseUploadOptions = {}): UseUploadReturn {\n const { client, fileSystemProvider } = useUploadistaContext();\n const [state, setState] = useState<UploadState>(initialState);\n const managerRef = useRef<UploadManager | null>(null);\n const lastFileRef = useRef<FilePickResult | null>(null);\n\n // Create UploadManager instance\n useEffect(() => {\n // Create upload function that handles React Native file reading\n const uploadFn = async (input: unknown, opts: UploadistaUploadOptions) => {\n const file = input as FilePickResult;\n\n if (file.status === \"success\") {\n // Read file content from React Native file system\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n\n // Create a Blob from the file content using platform-aware utility\n const blob = createBlobFromBuffer(fileContent, {\n type: file.data.mimeType || \"application/octet-stream\",\n });\n\n // Upload the Blob\n return client.upload(blob, opts);\n }\n\n return Promise.resolve({ abort: () => {} });\n };\n\n managerRef.current = new UploadManager(\n uploadFn,\n {\n onStateChange: setState,\n onProgress: options.onProgress,\n onChunkComplete: options.onChunkComplete,\n onSuccess: options.onSuccess,\n onError: options.onError,\n onAbort: options.onAbort,\n },\n {\n metadata: options.metadata,\n uploadLengthDeferred: options.uploadLengthDeferred,\n uploadSize: options.uploadSize,\n onShouldRetry: options.onShouldRetry,\n },\n );\n\n return () => {\n managerRef.current?.cleanup();\n };\n }, [client, fileSystemProvider, options]);\n\n // Upload function - stores file reference for retry\n const upload = useCallback(async (file: FilePickResult) => {\n lastFileRef.current = file;\n await managerRef.current?.upload(file);\n }, []);\n\n // Abort function\n const abort = useCallback(() => {\n managerRef.current?.abort();\n }, []);\n\n // Reset function\n const reset = useCallback(() => {\n managerRef.current?.reset();\n lastFileRef.current = null;\n }, []);\n\n // Retry function\n const retry = useCallback(() => {\n if (lastFileRef.current && managerRef.current?.canRetry()) {\n managerRef.current.retry();\n }\n }, []);\n\n // Derive computed values from state\n const isUploading = state.status === \"uploading\";\n const canRetry = managerRef.current?.canRetry() ?? false;\n\n // Create metrics object that delegates to the upload client\n const metrics: UploadMetrics = {\n getInsights: () => client.getChunkingInsights(),\n exportMetrics: () => client.exportMetrics(),\n getNetworkMetrics: () => client.getNetworkMetrics(),\n getNetworkCondition: () => client.getNetworkCondition(),\n resetMetrics: () => client.resetMetrics(),\n };\n\n return {\n state,\n upload,\n abort,\n reset,\n retry,\n isUploading,\n canRetry,\n metrics,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for capturing photos and uploading them\n * Handles camera permissions and capture flow\n * @param options - Camera upload configuration\n * @returns Upload state and camera capture/upload function\n */\nexport function useCameraUpload(options?: UseCameraUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Capture and upload photo\n const captureAndUpload = useCallback(async () => {\n try {\n // Capture photo with camera\n const photo = await fileSystemProvider.pickCamera(options?.cameraOptions);\n\n // Upload captured photo\n await uploadHook.upload(photo);\n } catch (error) {\n console.error(\"Camera capture error:\", error);\n }\n }, [fileSystemProvider, options?.cameraOptions, uploadHook]);\n\n return {\n ...uploadHook,\n captureAndUpload,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading generic files (documents, etc.)\n * @param options - File upload configuration\n * @returns Upload state and file picker/upload function\n */\nexport function useFileUpload(options?: UseFileUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Pick and upload file\n const pickAndUpload = useCallback(async () => {\n try {\n // Pick file\n const file = await fileSystemProvider.pickDocument({\n allowedTypes: options?.allowedTypes,\n });\n\n // Upload file\n await uploadHook.upload(file);\n } catch (error) {\n console.error(\"File selection error:\", error);\n throw error;\n }\n }, [fileSystemProvider, options?.allowedTypes, uploadHook]);\n\n return {\n ...uploadHook,\n pickAndUpload,\n };\n}\n","import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport {\n FlowManager,\n type FlowManagerCallbacks,\n type FlowUploadOptions,\n} from \"@uploadista/client-core\";\nimport { EventType, type FlowEvent } from \"@uploadista/core/flow\";\nimport { UploadEventType } from \"@uploadista/core/types\";\nimport type { ReactNode } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n} from \"react\";\nimport { useUploadistaContext } from \"../hooks/use-uploadista-context\";\nimport type { ReactNativeUploadInput } from \"../types\";\n\n/**\n * Type guard to check if an event is a flow event\n */\nfunction isFlowEvent(event: UploadistaEvent): event is FlowEvent {\n const flowEvent = event as FlowEvent;\n return (\n flowEvent.eventType === EventType.FlowStart ||\n flowEvent.eventType === EventType.FlowEnd ||\n flowEvent.eventType === EventType.FlowError ||\n flowEvent.eventType === EventType.NodeStart ||\n flowEvent.eventType === EventType.NodeEnd ||\n flowEvent.eventType === EventType.NodePause ||\n flowEvent.eventType === EventType.NodeResume ||\n flowEvent.eventType === EventType.NodeError\n );\n}\n\n/**\n * Internal manager registry entry with ref counting\n */\ninterface ManagerEntry {\n manager: FlowManager<unknown>;\n refCount: number;\n flowId: string;\n}\n\n/**\n * Context value providing access to flow managers\n */\ninterface FlowManagerContextValue {\n /**\n * Get or create a flow manager for the given flow ID.\n * Increments ref count - must call releaseManager when done.\n *\n * @param flowId - Unique identifier for the flow\n * @param callbacks - Callbacks for state changes and lifecycle events\n * @param options - Flow configuration options\n * @returns FlowManager instance\n */\n getManager: (\n flowId: string,\n callbacks: FlowManagerCallbacks,\n options: FlowUploadOptions,\n ) => FlowManager<unknown>;\n\n /**\n * Release a flow manager reference.\n * Decrements ref count and cleans up when reaching zero.\n *\n * @param flowId - Unique identifier for the flow to release\n */\n releaseManager: (flowId: string) => void;\n}\n\nconst FlowManagerContext = createContext<FlowManagerContextValue | undefined>(\n undefined,\n);\n\n/**\n * Props for FlowManagerProvider\n */\ninterface FlowManagerProviderProps {\n children: ReactNode;\n}\n\n/**\n * Provider that manages FlowManager instances with ref counting and event routing.\n * Ensures managers persist across component re-renders and are only cleaned up\n * when all consuming components unmount.\n *\n * This provider should be nested inside UploadistaProvider to access the upload client\n * and event subscription system.\n *\n * @example\n * ```tsx\n * <UploadistaProvider baseUrl=\"https://api.example.com\" storageId=\"default\">\n * <FlowManagerProvider>\n * <App />\n * </FlowManagerProvider>\n * </UploadistaProvider>\n * ```\n */\nexport function FlowManagerProvider({ children }: FlowManagerProviderProps) {\n const { client, subscribeToEvents } = useUploadistaContext();\n const managersRef = useRef(new Map<string, ManagerEntry>());\n\n // Subscribe to all events and route to appropriate managers\n useEffect(() => {\n const unsubscribe = subscribeToEvents((event: UploadistaEvent) => {\n // Route flow events to all managers (they filter by jobId internally)\n if (isFlowEvent(event)) {\n for (const entry of managersRef.current.values()) {\n entry.manager.handleFlowEvent(event);\n }\n return;\n }\n\n // Route upload progress events to all managers\n if (\n \"type\" in event &&\n event.type === UploadEventType.UPLOAD_PROGRESS &&\n \"data\" in event\n ) {\n for (const entry of managersRef.current.values()) {\n entry.manager.handleUploadProgress(\n event.data.id,\n event.data.progress,\n event.data.total,\n );\n }\n }\n });\n\n return unsubscribe;\n }, [subscribeToEvents]);\n\n const getManager = useCallback(\n (\n flowId: string,\n callbacks: FlowManagerCallbacks,\n options: FlowUploadOptions,\n ): FlowManager<unknown> => {\n const existing = managersRef.current.get(flowId);\n\n if (existing) {\n // Increment ref count for existing manager\n existing.refCount++;\n return existing.manager;\n }\n\n // Create new manager using client from hook scope\n const manager = new FlowManager<ReactNativeUploadInput>(\n client.uploadWithFlow,\n callbacks,\n options,\n client.multiInputFlowUpload,\n );\n\n managersRef.current.set(flowId, {\n manager,\n refCount: 1,\n flowId,\n });\n\n return manager;\n },\n [client],\n );\n\n const releaseManager = useCallback((flowId: string) => {\n const existing = managersRef.current.get(flowId);\n if (!existing) return;\n\n existing.refCount--;\n\n // Clean up when no more refs\n if (existing.refCount <= 0) {\n existing.manager.cleanup();\n managersRef.current.delete(flowId);\n }\n }, []);\n\n return (\n <FlowManagerContext.Provider value={{ getManager, releaseManager }}>\n {children}\n </FlowManagerContext.Provider>\n );\n}\n\n/**\n * Hook to access the FlowManager context.\n * Must be used within a FlowManagerProvider.\n *\n * @returns FlowManager context value with getManager and releaseManager functions\n * @throws Error if used outside of FlowManagerProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { getManager, releaseManager } = useFlowManagerContext();\n * // Use to create managers...\n * }\n * ```\n */\nexport function useFlowManagerContext(): FlowManagerContextValue {\n const context = useContext(FlowManagerContext);\n\n if (context === undefined) {\n throw new Error(\n \"useFlowManagerContext must be used within a FlowManagerProvider. \" +\n \"Make sure to wrap your component tree with <FlowManagerProvider>.\",\n );\n }\n\n return context;\n}\n","import type {\n FlowManager,\n FlowUploadState,\n FlowUploadStatus,\n InputExecutionState,\n} from \"@uploadista/client-core\";\nimport type { TypedOutput } from \"@uploadista/core/flow\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useFlowManagerContext } from \"../contexts/flow-manager-context\";\nimport type { FilePickResult } from \"../types\";\nimport { createBlobFromBuffer } from \"../types/platform-types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n// Re-export types from core for convenience\nexport type { FlowUploadState, FlowUploadStatus, InputExecutionState };\n\n/**\n * Input metadata discovered from the flow\n */\nexport interface FlowInputMetadata {\n /** Input node ID */\n nodeId: string;\n /** Human-readable node name */\n nodeName: string;\n /** Node description explaining what input is needed */\n nodeDescription: string;\n /** Input type ID from inputTypeRegistry - describes how clients interact with this node */\n inputTypeId?: string;\n /** Whether this input is required */\n required: boolean;\n}\n\n/**\n * Options for the useFlow hook\n */\nexport interface UseFlowOptions {\n /** Flow ID to execute */\n flowId: string;\n /** Storage ID for the upload */\n storageId: string;\n /** Output node ID for the flow */\n outputNodeId?: string;\n /** Metadata to pass to flow */\n metadata?: Record<string, unknown>;\n /** Called when upload succeeds (receives typed outputs from all output nodes) */\n onSuccess?: (outputs: TypedOutput[]) => void;\n /** Called when the flow completes successfully (receives full flow outputs) */\n onFlowComplete?: (outputs: TypedOutput[]) => void;\n /** Called when upload fails */\n onError?: (error: Error) => void;\n /** Called when upload progress updates */\n onProgress?: (\n progress: number,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n /** Called when a chunk completes */\n onChunkComplete?: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => void;\n}\n\n/**\n * Return value from the useFlow hook with upload control methods and state.\n *\n * @property state - Complete flow upload state with progress and outputs\n * @property inputMetadata - Metadata about discovered input nodes (null until discovered)\n * @property inputStates - Per-input execution state for multi-input flows\n * @property inputs - Current input values set via setInput()\n * @property setInput - Set an input value for a specific node (for progressive provision)\n * @property execute - Execute the flow with current inputs (auto-detects types)\n * @property upload - Convenience method for single-file upload (same as execute with one file input)\n * @property abort - Cancel the current upload and flow execution\n * @property reset - Reset state to idle (clears all data)\n * @property retry - Retry the last failed upload\n * @property isActive - True when upload or processing is active\n * @property isUploadingFile - True only during file upload phase\n * @property isProcessing - True only during flow processing phase\n * @property isDiscoveringInputs - True while discovering flow inputs\n * @property canRetry - True if a retry is possible\n */\nexport interface UseFlowReturn {\n /**\n * Current upload state\n */\n state: FlowUploadState;\n\n /**\n * Discovered input nodes metadata (null until discovery completes)\n */\n inputMetadata: FlowInputMetadata[] | null;\n\n /**\n * Per-input execution state for multi-input flows\n */\n inputStates: ReadonlyMap<string, InputExecutionState>;\n\n /**\n * Current inputs set via setInput()\n */\n inputs: Record<string, unknown>;\n\n /**\n * Set an input value for a specific node.\n * For progressive input provision before calling execute().\n *\n * @param nodeId - The input node ID\n * @param value - The input value (FilePickResult, URL string, or structured data)\n */\n setInput: (nodeId: string, value: FilePickResult | string | unknown) => void;\n\n /**\n * Execute the flow with current inputs.\n * Automatically detects input types and routes appropriately.\n * For single input, uses standard upload path.\n * For multiple inputs, requires multiInputUploadFn.\n */\n execute: () => Promise<void>;\n\n /**\n * Upload a single file through the flow (convenience method).\n * Equivalent to setInput(firstNodeId, file) + execute().\n *\n * @param file - FilePickResult from a picker\n */\n upload: (file: FilePickResult) => Promise<void>;\n\n /**\n * Abort the current upload\n */\n abort: () => void;\n\n /**\n * Reset the upload state and clear all inputs\n */\n reset: () => void;\n\n /**\n * Retry the last failed upload\n */\n retry: () => void;\n\n /**\n * Whether an upload or flow execution is in progress (uploading OR processing)\n */\n isActive: boolean;\n\n /**\n * Whether the file is currently being uploaded (chunks being sent)\n */\n isUploadingFile: boolean;\n\n /**\n * Whether the flow is currently processing (after upload completes)\n */\n isProcessing: boolean;\n\n /**\n * Whether the hook is discovering flow inputs\n */\n isDiscoveringInputs: boolean;\n\n /**\n * Whether a retry is possible (after error or abort with stored inputs)\n */\n canRetry: boolean;\n}\n\nconst initialState: FlowUploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n error: null,\n jobId: null,\n flowStarted: false,\n currentNodeName: null,\n currentNodeType: null,\n flowOutputs: null,\n};\n\n/**\n * React Native hook for executing flows with single or multiple inputs.\n * Automatically discovers input nodes and detects input types (File, URL, structured data).\n * Supports progressive input provision via setInput() and execute().\n *\n * This is the unified flow hook that replaces useFlowUpload for advanced use cases.\n * It provides:\n * - Auto-discovery of flow input nodes\n * - Automatic input type detection (FilePickResult -> upload, string -> URL, object -> data)\n * - Progressive input provision via setInput()\n * - Multi-input support with parallel coordination\n * - Per-input state tracking\n *\n * Must be used within FlowManagerProvider (which must be within UploadistaProvider).\n * Flow events are automatically routed by the provider to the appropriate manager.\n *\n * @param options - Flow upload configuration including flow ID and event handlers\n * @returns Flow upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const flow = useFlow({\n * flowId: 'image-processing-flow',\n * storageId: 'my-storage',\n * onSuccess: (outputs) => console.log('Flow complete:', outputs),\n * onError: (error) => console.error('Flow failed:', error),\n * });\n *\n * const handlePickFile = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file) {\n * await flow.upload(file);\n * }\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handlePickFile} />\n * {flow.isActive && <Text>Progress: {flow.state.progress}%</Text>}\n * {flow.inputMetadata && (\n * <Text>Found {flow.inputMetadata.length} input nodes</Text>\n * )}\n * <Button title=\"Abort\" onPress={flow.abort} disabled={!flow.isActive} />\n * </View>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Multi-input flow\n * function MultiInputComponent() {\n * const flow = useFlow({\n * flowId: 'multi-source-flow',\n * storageId: 'my-storage',\n * });\n *\n * const handlePickPrimary = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file.status === 'success') {\n * flow.setInput('primary-input', file);\n * }\n * };\n *\n * const handleSetUrl = (url: string) => {\n * flow.setInput('url-input', url);\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick Primary\" onPress={handlePickPrimary} />\n * <TextInput onChangeText={handleSetUrl} placeholder=\"Enter URL\" />\n * <Button title=\"Execute\" onPress={flow.execute} />\n * </View>\n * );\n * }\n * ```\n *\n * @see {@link useFlowUpload} for a simpler file-only upload hook\n */\nexport function useFlow(options: UseFlowOptions): UseFlowReturn {\n const { client, fileSystemProvider } = useUploadistaContext();\n const { getManager, releaseManager } = useFlowManagerContext();\n const [state, setState] = useState<FlowUploadState>(initialState);\n const [inputMetadata, setInputMetadata] = useState<\n FlowInputMetadata[] | null\n >(null);\n const [isDiscoveringInputs, setIsDiscoveringInputs] = useState(false);\n const [inputs, setInputs] = useState<Record<string, unknown>>({});\n const [inputStates, setInputStates] = useState<\n ReadonlyMap<string, InputExecutionState>\n >(new Map());\n const managerRef = useRef<FlowManager<unknown> | null>(null);\n const lastInputsRef = useRef<Record<string, unknown> | null>(null);\n\n // Store callbacks in refs so they can be updated without recreating the manager\n const callbacksRef = useRef(options);\n\n // Update refs on every render to capture latest callbacks\n useEffect(() => {\n callbacksRef.current = options;\n });\n\n // Auto-discover flow inputs on mount\n useEffect(() => {\n const discoverInputs = async () => {\n setIsDiscoveringInputs(true);\n try {\n const { flow } = await client.getFlow(options.flowId);\n\n // Find all input nodes\n const inputNodes = flow.nodes.filter((node) => node.type === \"input\");\n\n const metadata: FlowInputMetadata[] = inputNodes.map((node) => ({\n nodeId: node.id,\n nodeName: node.name,\n nodeDescription: node.description,\n inputTypeId: node.inputTypeId,\n required: true,\n }));\n\n setInputMetadata(metadata);\n } catch (error) {\n console.error(\"Failed to discover flow inputs:\", error);\n } finally {\n setIsDiscoveringInputs(false);\n }\n };\n\n discoverInputs();\n }, [client, options.flowId]);\n\n // Get or create manager from context when component mounts\n // biome-ignore lint/correctness/useExhaustiveDependencies: we don't want to recreate the manager on every render\n useEffect(() => {\n const flowId = options.flowId;\n\n // Create stable callback wrappers that call the latest callbacks via refs\n const stableCallbacks = {\n onStateChange: (newState: FlowUploadState) => {\n setState(newState);\n },\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n if (callbacksRef.current.onProgress) {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n callbacksRef.current.onProgress(progress, bytesUploaded, totalBytes);\n }\n },\n onChunkComplete: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => {\n callbacksRef.current.onChunkComplete?.(\n chunkSize,\n bytesAccepted,\n bytesTotal,\n );\n },\n onFlowComplete: (outputs: TypedOutput[]) => {\n callbacksRef.current.onFlowComplete?.(outputs);\n },\n onSuccess: (outputs: TypedOutput[]) => {\n callbacksRef.current.onSuccess?.(outputs);\n },\n onError: (error: Error) => {\n callbacksRef.current.onError?.(error);\n },\n onAbort: () => {\n // onAbort not exposed in public API\n },\n };\n\n // Get manager from context (creates if doesn't exist, increments ref count)\n managerRef.current = getManager(flowId, stableCallbacks, {\n flowConfig: {\n flowId: options.flowId,\n storageId: options.storageId,\n outputNodeId: options.outputNodeId,\n metadata: options.metadata as Record<string, string> | undefined,\n },\n onChunkComplete: options.onChunkComplete,\n onSuccess: options.onSuccess,\n onError: options.onError,\n });\n\n // Set up interval to poll input states for multi-input flows\n const pollInterval = setInterval(() => {\n if (managerRef.current) {\n const states = managerRef.current.getInputStates();\n if (states.size > 0) {\n setInputStates(new Map(states));\n }\n }\n }, 100); // Poll every 100ms\n\n // Release manager when component unmounts or flowId changes\n return () => {\n clearInterval(pollInterval);\n releaseManager(flowId);\n managerRef.current = null;\n };\n }, [\n options.flowId,\n options.storageId,\n options.outputNodeId,\n getManager,\n releaseManager,\n ]);\n\n // Set an input value\n const setInput = useCallback(\n (nodeId: string, value: FilePickResult | string | unknown) => {\n setInputs((prev) => ({ ...prev, [nodeId]: value }));\n },\n [],\n );\n\n // Helper to convert FilePickResult to Blob\n const filePickToBlob = useCallback(\n async (file: FilePickResult): Promise<Blob | null> => {\n if (file.status === \"cancelled\") {\n return null;\n }\n if (file.status === \"error\") {\n throw file.error;\n }\n\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n return createBlobFromBuffer(fileContent, {\n type: file.data.mimeType || \"application/octet-stream\",\n });\n },\n [fileSystemProvider],\n );\n\n // Execute flow with current inputs\n const execute = useCallback(async () => {\n if (!managerRef.current) {\n throw new Error(\"FlowManager not initialized\");\n }\n\n if (Object.keys(inputs).length === 0) {\n throw new Error(\n \"No inputs provided. Use setInput() to provide inputs before calling execute()\",\n );\n }\n\n // Store inputs for retry\n lastInputsRef.current = { ...inputs };\n\n // Convert FilePickResults to Blobs\n const processedInputs: Record<string, unknown> = {};\n\n for (const [nodeId, value] of Object.entries(inputs)) {\n // Check if value is a FilePickResult\n if (\n value &&\n typeof value === \"object\" &&\n \"status\" in value &&\n (value.status === \"success\" ||\n value.status === \"cancelled\" ||\n value.status === \"error\")\n ) {\n const blob = await filePickToBlob(value as FilePickResult);\n if (blob) {\n processedInputs[nodeId] = blob;\n }\n // If blob is null (cancelled), skip this input\n } else {\n // Pass through strings (URLs) and other values as-is\n processedInputs[nodeId] = value;\n }\n }\n\n if (Object.keys(processedInputs).length === 0) {\n throw new Error(\n \"No valid inputs after processing. All files may have been cancelled.\",\n );\n }\n\n await managerRef.current.executeFlow(processedInputs);\n }, [inputs, filePickToBlob]);\n\n // Convenience method for single file upload\n const upload = useCallback(\n async (file: FilePickResult) => {\n // Handle cancelled picker\n if (file.status === \"cancelled\") {\n return;\n }\n\n // Handle picker error\n if (file.status === \"error\") {\n options.onError?.(file.error);\n return;\n }\n\n if (!managerRef.current) {\n throw new Error(\"FlowManager not initialized\");\n }\n\n // Store for retry\n if (inputMetadata && inputMetadata.length > 0) {\n const firstInputNode = inputMetadata[0];\n if (firstInputNode) {\n lastInputsRef.current = { [firstInputNode.nodeId]: file };\n }\n }\n\n try {\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n const blob = createBlobFromBuffer(fileContent, {\n type: file.data.mimeType || \"application/octet-stream\",\n });\n\n // If we have input metadata, use the first input node\n if (inputMetadata && inputMetadata.length > 0) {\n const firstInputNode = inputMetadata[0];\n if (!firstInputNode) {\n throw new Error(\"No input nodes found\");\n }\n setInputs({ [firstInputNode.nodeId]: file });\n await managerRef.current.executeFlow({\n [firstInputNode.nodeId]: blob,\n });\n } else {\n // Fall back to direct upload (manager will handle discovery)\n await managerRef.current.upload(blob);\n }\n } catch (error) {\n options.onError?.(error as Error);\n }\n },\n [inputMetadata, fileSystemProvider, options],\n );\n\n const abort = useCallback(() => {\n managerRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n managerRef.current?.reset();\n setInputs({});\n setInputStates(new Map());\n lastInputsRef.current = null;\n }, []);\n\n const retry = useCallback(() => {\n if (\n lastInputsRef.current &&\n (state.status === \"error\" || state.status === \"aborted\")\n ) {\n // Restore inputs and re-execute\n setInputs(lastInputsRef.current);\n execute();\n }\n }, [execute, state.status]);\n\n // Derive computed values from state (reactive to state changes)\n const isActive =\n state.status === \"uploading\" || state.status === \"processing\";\n const isUploadingFile = state.status === \"uploading\";\n const isProcessing = state.status === \"processing\";\n const canRetry =\n (state.status === \"error\" || state.status === \"aborted\") &&\n lastInputsRef.current !== null;\n\n return {\n state,\n inputMetadata,\n inputStates,\n inputs,\n setInput,\n execute,\n upload,\n abort,\n reset,\n retry,\n isActive,\n isUploadingFile,\n isProcessing,\n isDiscoveringInputs,\n canRetry,\n };\n}\n","import type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { FilePickResult, UseMultiUploadOptions } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport interface UploadItemState {\n id: string;\n file: Extract<FilePickResult, { status: \"success\" }>;\n status: \"idle\" | \"uploading\" | \"success\" | \"error\" | \"aborted\";\n progress: number;\n bytesUploaded: number;\n totalBytes: number;\n error: Error | null;\n result: UploadFile | null;\n}\n\nexport interface MultiUploadState {\n items: UploadItemState[];\n totalProgress: number;\n totalUploaded: number;\n totalBytes: number;\n activeCount: number;\n completedCount: number;\n failedCount: number;\n}\n\nconst initialState: MultiUploadState = {\n items: [],\n totalProgress: 0,\n totalUploaded: 0,\n totalBytes: 0,\n activeCount: 0,\n completedCount: 0,\n failedCount: 0,\n};\n\n/**\n * Hook for managing multiple concurrent file uploads with progress tracking.\n * Each file is uploaded independently using the core upload client.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Multi-upload configuration options\n * @returns Multi-upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const multiUpload = useMultiUpload({\n * maxConcurrent: 3,\n * onSuccess: (result) => console.log('File uploaded:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * });\n *\n * const handlePickFiles = async () => {\n * const files = await fileSystemProvider.pickImage({ allowMultiple: true });\n * multiUpload.addFiles(files);\n * await multiUpload.startUploads();\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick Files\" onPress={handlePickFiles} />\n * <Text>Progress: {multiUpload.state.totalProgress}%</Text>\n * <Text>Active: {multiUpload.state.activeCount}</Text>\n * <Text>Completed: {multiUpload.state.completedCount}/{multiUpload.state.items.length}</Text>\n * </View>\n * );\n * }\n * ```\n */\nexport function useMultiUpload(options: UseMultiUploadOptions = {}) {\n const { client } = useUploadistaContext();\n const [state, setState] = useState<MultiUploadState>(initialState);\n const abortControllersRef = useRef<Map<string, { abort: () => void }>>(\n new Map(),\n );\n const nextIdRef = useRef(0);\n // Use ref to track items synchronously\n const itemsRef = useRef<UploadItemState[]>([]);\n\n const generateId = useCallback(() => {\n return `upload-${Date.now()}-${nextIdRef.current++}`;\n }, []);\n\n const updateAggregateStats = useCallback((items: UploadItemState[]) => {\n const totalBytes = items.reduce((sum, item) => sum + item.totalBytes, 0);\n const totalUploaded = items.reduce(\n (sum, item) => sum + item.bytesUploaded,\n 0,\n );\n const totalProgress =\n totalBytes > 0 ? Math.round((totalUploaded / totalBytes) * 100) : 0;\n const activeCount = items.filter(\n (item) => item.status === \"uploading\",\n ).length;\n const completedCount = items.filter(\n (item) => item.status === \"success\",\n ).length;\n const failedCount = items.filter((item) => item.status === \"error\").length;\n\n // Update ref synchronously\n itemsRef.current = items;\n\n setState((prev) => ({\n ...prev,\n items,\n totalProgress,\n totalUploaded,\n totalBytes,\n activeCount,\n completedCount,\n failedCount,\n }));\n }, []);\n\n const addFiles = useCallback(\n (files: FilePickResult[]) => {\n // Filter out cancelled and error results, only keep successful picks\n const successfulFiles = files.filter(\n (file): file is Extract<FilePickResult, { status: \"success\" }> =>\n file.status === \"success\",\n );\n\n const newItems: UploadItemState[] = successfulFiles.map((file) => ({\n id: generateId(),\n file,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n totalBytes: file.data.size,\n error: null,\n result: null,\n }));\n\n // Update ref synchronously\n const updatedItems = [...itemsRef.current, ...newItems];\n itemsRef.current = updatedItems;\n\n setState((prev) => {\n const totalBytes = updatedItems.reduce(\n (sum, item) => sum + item.totalBytes,\n 0,\n );\n return {\n ...prev,\n items: updatedItems,\n totalBytes,\n };\n });\n\n return newItems.map((item) => item.id);\n },\n [generateId],\n );\n\n const uploadSingleItem = useCallback(\n async (item: UploadItemState) => {\n try {\n console.log(\"Uploading item:\", item.file.data.name);\n // Update status to uploading\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id ? { ...i, status: \"uploading\" as const } : i,\n );\n updateAggregateStats(updatedItems);\n\n // Convert file URI to Blob using fetch (React Native compatible)\n // React Native's Blob doesn't support ArrayBuffer/Uint8Array constructor\n const response = await fetch(item.file.data.uri);\n const blob = await response.blob();\n\n // Override blob type if we have mimeType from picker\n // Use type assertion to handle differences between Expo's BlobOptions and standard BlobPropertyBag\n let uploadInput: Blob = blob;\n if (item.file.data.mimeType) {\n const blobOptions = {\n type: item.file.data.mimeType,\n lastModified: Date.now(),\n };\n // biome-ignore lint/suspicious/noExplicitAny: Expo and bare RN have incompatible Blob types\n uploadInput = new Blob([blob], blobOptions as any);\n }\n\n // Start upload using the client\n console.log(\"Uploading input:\", uploadInput);\n const uploadPromise = client.upload(uploadInput, {\n metadata: options.metadata,\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n progress,\n bytesUploaded,\n totalBytes: totalBytes || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n },\n\n onSuccess: (result: UploadFile) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"success\" as const,\n progress: 100,\n result,\n bytesUploaded: result.size || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onSuccess?.(result);\n abortControllersRef.current.delete(item.id);\n },\n\n onError: (error: Error) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id ? { ...i, status: \"error\" as const, error } : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error);\n abortControllersRef.current.delete(item.id);\n },\n });\n\n // Store abort controller\n const controller = await uploadPromise;\n abortControllersRef.current.set(item.id, controller);\n } catch (error) {\n console.error(\"Error uploading item:\", error);\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"error\" as const,\n error: error as Error,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error as Error);\n abortControllersRef.current.delete(item.id);\n }\n },\n [client, options, updateAggregateStats],\n );\n\n const startUploads = useCallback(\n async (itemIds?: string[]) => {\n const maxConcurrent = options.maxConcurrent || 3;\n\n // Get items from ref (synchronous access to latest items)\n const itemsToUpload = itemIds\n ? itemsRef.current.filter(\n (item) => itemIds.includes(item.id) && item.status === \"idle\",\n )\n : itemsRef.current.filter((item) => item.status === \"idle\");\n\n console.log(\"Items to upload:\", itemsToUpload.length, itemsToUpload);\n\n // Process items in batches\n for (let i = 0; i < itemsToUpload.length; i += maxConcurrent) {\n const batch = itemsToUpload.slice(i, i + maxConcurrent);\n await Promise.all(batch.map((item) => uploadSingleItem(item)));\n }\n },\n [options.maxConcurrent, uploadSingleItem],\n );\n\n const removeItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.filter((item) => item.id !== id);\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const abortItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.map((item) =>\n item.id === id ? { ...item, status: \"aborted\" as const } : item,\n );\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const clear = useCallback(() => {\n // Abort all active uploads\n abortControllersRef.current.forEach((controller) => {\n controller.abort();\n });\n abortControllersRef.current.clear();\n\n // Clear ref\n itemsRef.current = [];\n\n setState(initialState);\n }, []);\n\n const retryItem = useCallback(\n async (id: string) => {\n const item = itemsRef.current.find((i) => i.id === id);\n if (item && (item.status === \"error\" || item.status === \"aborted\")) {\n // Reset item status to idle\n const updatedItems = itemsRef.current.map((i) =>\n i.id === id\n ? {\n ...i,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n error: null,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n // Upload it (get the reset item from the updated items)\n const resetItem = itemsRef.current.find((i) => i.id === id);\n if (resetItem) {\n await uploadSingleItem(resetItem);\n }\n }\n },\n [uploadSingleItem, updateAggregateStats],\n );\n\n return {\n state,\n addFiles,\n startUploads,\n removeItem,\n abortItem,\n retryItem,\n clear,\n };\n}\n","import { useCallback } from \"react\";\nimport type { FilePickResult, UseGalleryUploadOptions } from \"../types\";\nimport { useMultiUpload } from \"./use-multi-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading photos/videos from gallery\n * Handles batch selection and concurrent uploads\n * @param options - Gallery upload configuration\n * @returns Upload state and gallery selection/upload function\n */\nexport function useGalleryUpload(options?: UseGalleryUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useMultiUpload({\n maxConcurrent: 3,\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n });\n\n // Select and upload media from gallery\n const selectAndUpload = useCallback(async () => {\n let result: FilePickResult;\n\n // Select appropriate media type\n if (options?.mediaType === \"video\") {\n result = await fileSystemProvider.pickVideo({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else if (options?.mediaType === \"photo\") {\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else {\n // For 'mixed' or default, use pickImage first (can be extended to support both)\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n }\n\n // Handle cancelled picker\n if (result.status === \"cancelled\") {\n return [];\n }\n\n // Handle picker error\n if (result.status === \"error\") {\n console.error(\"Gallery selection error:\", result.error);\n options?.onError?.(result.error);\n return [];\n }\n\n // Success - add file and start upload\n const itemIds = uploadHook.addFiles([result]);\n await uploadHook.startUploads(itemIds);\n\n return itemIds;\n }, [\n fileSystemProvider,\n options?.allowMultiple,\n options?.mediaType,\n options?.onError,\n uploadHook,\n ]);\n\n return {\n ...uploadHook,\n selectAndUpload,\n };\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { UploadMetrics } from \"../types\";\n\n/**\n * Hook for tracking upload performance metrics\n * @returns Metrics object and methods to track uploads\n */\nexport function useUploadMetrics() {\n const startTimeRef = useRef<number | null>(null);\n const startBytesRef = useRef<number>(0);\n const peakSpeedRef = useRef<number>(0);\n\n const [metrics, setMetrics] = useState<UploadMetrics>({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n\n // Start tracking\n const start = useCallback(() => {\n startTimeRef.current = Date.now();\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n }, []);\n\n // Update metrics based on current progress\n const update = useCallback(\n (uploadedBytes: number, _totalBytes: number, currentRetries = 0) => {\n if (!startTimeRef.current) {\n return;\n }\n\n const now = Date.now();\n const durationMs = now - startTimeRef.current;\n const speed = durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0;\n\n if (speed > peakSpeedRef.current) {\n peakSpeedRef.current = speed;\n }\n\n setMetrics({\n totalBytes: uploadedBytes,\n durationMs,\n avgSpeed: durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0,\n peakSpeed: peakSpeedRef.current,\n retries: currentRetries,\n });\n },\n [],\n );\n\n // End tracking and return final metrics\n const end = useCallback(() => {\n const finalMetrics = metrics;\n startTimeRef.current = null;\n return finalMetrics;\n }, [metrics]);\n\n // Reset metrics\n const reset = useCallback(() => {\n startTimeRef.current = null;\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n setMetrics({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n }, []);\n\n return {\n metrics,\n start,\n update,\n end,\n reset,\n };\n}\n","/**\n * File utility functions for React Native uploads\n */\n\n/**\n * Format file size to human readable string\n * @param bytes - Size in bytes\n * @returns Formatted size string (e.g., \"1.5 MB\")\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return \"0 Bytes\";\n\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${Math.round((bytes / k ** i) * 100) / 100} ${sizes[i]}`;\n}\n\n/**\n * Get MIME type from file name\n * @param fileName - File name with extension\n * @returns MIME type or 'application/octet-stream' as fallback\n */\nexport function getMimeTypeFromFileName(fileName: string): string {\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".avi\": \"video/x-msvideo\",\n \".mov\": \"video/quicktime\",\n \".wmv\": \"video/x-ms-wmv\",\n \".flv\": \"video/x-flv\",\n \".mkv\": \"video/x-matroska\",\n \".webm\": \"video/webm\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n \".flac\": \"audio/flac\",\n \".m4a\": \"audio/mp4\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".doc\": \"application/msword\",\n \".docx\":\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \".xls\": \"application/vnd.ms-excel\",\n \".xlsx\":\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \".ppt\": \"application/vnd.ms-powerpoint\",\n \".pptx\":\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \".txt\": \"text/plain\",\n \".csv\": \"text/csv\",\n \".json\": \"application/json\",\n \".xml\": \"application/xml\",\n \".zip\": \"application/zip\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n\n/**\n * Check if file type is allowed\n * @param fileName - File name to check\n * @param allowedTypes - Array of allowed MIME types (e.g., ['image/jpeg', 'image/png'])\n * @returns True if file type is allowed\n */\nexport function isFileTypeAllowed(\n fileName: string,\n allowedTypes: string[],\n): boolean {\n if (!allowedTypes || allowedTypes.length === 0) {\n return true;\n }\n\n const mimeType = getMimeTypeFromFileName(fileName);\n return allowedTypes.some((allowed) => {\n if (allowed.endsWith(\"/*\")) {\n // Handle wildcard patterns like 'image/*'\n const [type] = allowed.split(\"/\");\n return mimeType.startsWith(`${type}/`);\n }\n return allowed === mimeType;\n });\n}\n\n/**\n * Check if file size is within limits\n * @param fileSize - File size in bytes\n * @param maxSize - Maximum allowed size in bytes (optional)\n * @param minSize - Minimum allowed size in bytes (optional)\n * @returns True if file size is within limits\n */\nexport function isFileSizeValid(\n fileSize: number,\n maxSize?: number,\n minSize?: number,\n): boolean {\n if (maxSize !== undefined && fileSize > maxSize) {\n return false;\n }\n\n if (minSize !== undefined && fileSize < minSize) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get file extension\n * @param fileName - File name\n * @returns File extension without dot (e.g., 'pdf' for 'document.pdf')\n */\nexport function getFileExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n return fileName.slice(lastDot + 1).toLowerCase();\n}\n\n/**\n * Get file name without extension\n * @param fileName - File name\n * @returns File name without extension\n */\nexport function getFileNameWithoutExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return fileName;\n return fileName.slice(0, lastDot);\n}\n\n/**\n * Check if file is an image\n * @param fileName - File name\n * @returns True if file is an image\n */\nexport function isImageFile(fileName: string): boolean {\n const imageExtensions = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".bmp\",\n \".webp\",\n \".svg\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return imageExtensions.includes(ext);\n}\n\n/**\n * Check if file is a video\n * @param fileName - File name\n * @returns True if file is a video\n */\nexport function isVideoFile(fileName: string): boolean {\n const videoExtensions = [\n \".mp4\",\n \".avi\",\n \".mov\",\n \".wmv\",\n \".flv\",\n \".mkv\",\n \".webm\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return videoExtensions.includes(ext);\n}\n\n/**\n * Check if file is a document\n * @param fileName - File name\n * @returns True if file is a document\n */\nexport function isDocumentFile(fileName: string): boolean {\n const docExtensions = [\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".txt\",\n \".csv\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return docExtensions.includes(ext);\n}\n","/**\n * Permission utility functions for React Native uploads\n * Handles camera, gallery, and file access permissions\n */\n\n/**\n * Permission types\n */\nexport enum PermissionType {\n CAMERA = \"CAMERA\",\n PHOTO_LIBRARY = \"PHOTO_LIBRARY\",\n WRITE_STORAGE = \"WRITE_STORAGE\",\n READ_STORAGE = \"READ_STORAGE\",\n}\n\n/**\n * Permission status\n */\nexport enum PermissionStatus {\n GRANTED = \"granted\",\n DENIED = \"denied\",\n NOT_DETERMINED = \"not_determined\",\n RESTRICTED = \"restricted\",\n}\n\n/**\n * Request camera permission\n * This is primarily used to check if we should attempt camera operations\n * Actual permission requests are handled by the file system providers\n *\n * @returns Promise resolving to true if permission is granted or already granted\n */\nexport async function requestCameraPermission(): Promise<boolean> {\n try {\n // Permission requests are handled by the file system provider implementations\n // This function serves as a placeholder for app-level permission handling\n console.log(\n \"Camera permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request camera permission:\", error);\n return false;\n }\n}\n\n/**\n * Request photo library permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestPhotoLibraryPermission(): Promise<boolean> {\n try {\n console.log(\n \"Photo library permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request photo library permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage read permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageReadPermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage read permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage read permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage write permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageWritePermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage write permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage write permission:\", error);\n return false;\n }\n}\n\n/**\n * Request multiple permissions at once\n * @param permissions - Array of permission types to request\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function requestPermissions(\n permissions: PermissionType[],\n): Promise<boolean> {\n try {\n const results = await Promise.all(\n permissions.map(async (permission) => {\n switch (permission) {\n case PermissionType.CAMERA:\n return requestCameraPermission();\n case PermissionType.PHOTO_LIBRARY:\n return requestPhotoLibraryPermission();\n case PermissionType.READ_STORAGE:\n return requestStorageReadPermission();\n case PermissionType.WRITE_STORAGE:\n return requestStorageWritePermission();\n default:\n return false;\n }\n }),\n );\n\n return results.every((result) => result);\n } catch (error) {\n console.error(\"Failed to request permissions:\", error);\n return false;\n }\n}\n\n/**\n * Check if all required permissions are granted\n * @param permissions - Array of permission types to check\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function hasPermissions(\n _permissions: PermissionType[],\n): Promise<boolean> {\n try {\n // In React Native, permission checking is typically handled by the platform\n // This is a placeholder that assumes permissions will be handled by the file system provider\n return true;\n } catch (error) {\n console.error(\"Failed to check permissions:\", error);\n return false;\n }\n}\n\n/**\n * Get permission status\n * @param permission - Permission type to check\n * @returns Promise resolving to permission status\n */\nexport async function getPermissionStatus(\n _permission: PermissionType,\n): Promise<PermissionStatus> {\n try {\n // This is a placeholder implementation\n // Real implementation would use platform-specific APIs\n return PermissionStatus.GRANTED;\n } catch (error) {\n console.error(\"Failed to get permission status:\", error);\n return PermissionStatus.DENIED;\n }\n}\n\n/**\n * Open app settings to request permissions\n * Guides user to app settings where they can manually enable permissions\n */\nexport function openAppSettings(): void {\n try {\n // This would typically use react-native-app-settings or similar\n console.log(\n \"Opening app settings (requires react-native-app-settings or platform implementation)\",\n );\n } catch (error) {\n console.error(\"Failed to open app settings:\", error);\n }\n}\n","/**\n * URI utility functions for React Native file handling\n */\n\n/**\n * Extract file name from URI\n * @param uri - File URI\n * @returns File name extracted from URI\n */\nexport function getFileNameFromUri(uri: string): string {\n try {\n // Handle different URI formats\n if (uri.startsWith(\"file://\")) {\n // File URI format\n const path = uri.replace(\"file://\", \"\");\n return path.split(\"/\").pop() || \"file\";\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URI format (Android)\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n }\n\n // Assume it's a path or other format\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n } catch {\n return \"file\";\n }\n}\n\n/**\n * Convert file path to file URI\n * @param filePath - File path\n * @returns File URI\n */\nexport function pathToUri(filePath: string): string {\n if (filePath.startsWith(\"file://\")) {\n return filePath;\n }\n\n if (filePath.startsWith(\"content://\")) {\n return filePath;\n }\n\n // Convert to file URI\n return `file://${filePath}`;\n}\n\n/**\n * Convert file URI to file path\n * @param uri - File URI\n * @returns File path\n */\nexport function uriToPath(uri: string): string {\n if (uri.startsWith(\"file://\")) {\n return uri.replace(\"file://\", \"\");\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URIs cannot be converted to paths directly\n return uri;\n }\n\n return uri;\n}\n\n/**\n * Get directory from URI\n * @param uri - File URI\n * @returns Directory path\n */\nexport function getDirectoryFromUri(uri: string): string {\n try {\n const path = uriToPath(uri);\n const parts = path.split(\"/\");\n parts.pop(); // Remove file name\n return parts.join(\"/\");\n } catch {\n return \"\";\n }\n}\n\n/**\n * Check if URI is a content URI (Android specific)\n * @param uri - URI to check\n * @returns True if URI is a content URI\n */\nexport function isContentUri(uri: string): boolean {\n return uri.startsWith(\"content://\");\n}\n\n/**\n * Check if URI is a file URI\n * @param uri - URI to check\n * @returns True if URI is a file URI\n */\nexport function isFileUri(uri: string): boolean {\n return uri.startsWith(\"file://\");\n}\n\n/**\n * Normalize URI for cross-platform compatibility\n * @param uri - URI to normalize\n * @returns Normalized URI\n */\nexport function normalizeUri(uri: string): string {\n // Remove duplicate slashes (but keep protocol slashes)\n return uri.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Get MIME type hint from URI\n * @param uri - File URI\n * @returns MIME type hint based on file extension\n */\nexport function getMimeTypeFromUri(uri: string): string {\n const fileName = getFileNameFromUri(uri);\n\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".mov\": \"video/quicktime\",\n \".avi\": \"video/x-msvideo\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".txt\": \"text/plain\",\n \".json\": \"application/json\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n","import { ActivityIndicator, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadState } from \"../hooks/use-upload\";\nimport { formatFileSize } from \"../utils\";\n\nexport interface UploadProgressProps {\n /** Upload state information */\n state: UploadState;\n /** Optional custom label */\n label?: string;\n}\n\n/**\n * Component to display upload progress with percentage, size, and speed\n */\nexport function UploadProgress({ state, label }: UploadProgressProps) {\n const getStatusColor = () => {\n switch (state.status) {\n case \"uploading\":\n return \"#007AFF\";\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"aborted\":\n return \"#FF3B30\";\n default:\n return \"#999999\";\n }\n };\n\n const renderContent = () => {\n switch (state.status) {\n case \"idle\":\n return (\n <View style={styles.container}>\n <Text style={styles.label}>{label || \"Ready to upload\"}</Text>\n </View>\n );\n\n case \"uploading\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.label}>{label || \"Uploading\"}</Text>\n <Text style={styles.percentage}>{state.progress}%</Text>\n </View>\n\n {/* Progress bar */}\n <View style={styles.progressBarContainer}>\n <View\n style={[\n styles.progressBar,\n {\n width: `${state.progress}%`,\n backgroundColor: getStatusColor(),\n },\n ]}\n />\n </View>\n\n {/* Details row */}\n <View style={styles.detailsRow}>\n <Text style={styles.detail}>\n {formatFileSize(state.bytesUploaded)} /{\" \"}\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n </View>\n );\n\n case \"success\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload complete\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✓\n </Text>\n </View>\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n );\n\n case \"error\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload failed\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✕\n </Text>\n </View>\n {state.error && (\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {state.error.message}\n </Text>\n )}\n </View>\n );\n\n case \"aborted\":\n return (\n <View style={styles.container}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload cancelled\"}\n </Text>\n </View>\n );\n\n default:\n return null;\n }\n };\n\n return (\n <View\n style={[\n styles.wrapper,\n {\n borderLeftColor: getStatusColor(),\n },\n ]}\n >\n {state.status === \"uploading\" && (\n <ActivityIndicator\n size=\"small\"\n color={getStatusColor()}\n style={styles.spinner}\n />\n )}\n {renderContent()}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrapper: {\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n spinner: {\n marginTop: 4,\n },\n container: {\n flex: 1,\n gap: 4,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n label: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#333333\",\n flex: 1,\n },\n percentage: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#007AFF\",\n minWidth: 36,\n textAlign: \"right\",\n },\n progressBarContainer: {\n height: 4,\n backgroundColor: \"#e0e0e0\",\n borderRadius: 2,\n overflow: \"hidden\",\n },\n progressBar: {\n height: \"100%\",\n borderRadius: 2,\n },\n detailsRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n detail: {\n fontSize: 12,\n color: \"#666666\",\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useCameraUpload } from \"../hooks\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface CameraUploadButtonProps {\n /** Options for camera upload */\n options?: UseCameraUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for camera capture and upload\n * Triggers camera on press and handles upload with progress display\n */\nexport function CameraUploadButton({\n options,\n label = \"Take Photo\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: CameraUploadButtonProps) {\n const { state, captureAndUpload } = useCameraUpload(options);\n\n const handlePress = async () => {\n try {\n await captureAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"Camera upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#007AFF\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useFileUpload } from \"../hooks\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface FileUploadButtonProps {\n /** Options for file upload */\n options?: UseFileUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for document/file selection and upload\n * Generic file picker with progress display\n */\nexport function FileUploadButton({\n options,\n label = \"Choose File\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: FileUploadButtonProps) {\n const { state, pickAndUpload } = useFileUpload(options);\n\n const handlePress = async () => {\n try {\n await pickAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"File upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#FF9500\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import React, { type ReactNode } from \"react\";\nimport {\n ActivityIndicator,\n FlatList,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useGalleryUpload } from \"../hooks\";\nimport type { UseGalleryUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface GalleryUploadButtonProps {\n /** Options for gallery upload */\n options?: UseGalleryUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when all uploads complete successfully */\n onSuccess?: (results: unknown[]) => void;\n /** Callback when any upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show individual progress for each file */\n showProgress?: boolean;\n}\n\n/**\n * Button component for gallery selection and batch upload\n * Triggers gallery picker on press and handles concurrent uploads\n */\nexport function GalleryUploadButton({\n options,\n label = \"Select from Gallery\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: GalleryUploadButtonProps) {\n const { state, selectAndUpload } = useGalleryUpload(options);\n\n const handlePress = async () => {\n try {\n await selectAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.items.some((item) => item.status === \"uploading\");\n const hasItems = state.items.length > 0;\n const allComplete =\n hasItems &&\n state.items.every(\n (item) => item.status !== \"uploading\" && item.status !== \"idle\",\n );\n\n React.useEffect(() => {\n if (allComplete) {\n const results = state.items\n .filter((item) => item.status === \"success\")\n .map((item) => item.result);\n if (results.length > 0) {\n onSuccess?.(results);\n }\n }\n }, [allComplete, state.items, onSuccess]);\n\n React.useEffect(() => {\n const errors = state.items.filter((item) => item.status === \"error\");\n const firstError = errors[0]?.error;\n if (firstError) {\n onError?.(firstError);\n }\n }, [state.items, onError]);\n\n const renderItem = ({ item }: { item: (typeof state.items)[0] }) => (\n <View key={item.id} style={styles.itemContainer}>\n <UploadProgress\n state={{\n status: item.status,\n progress: item.progress,\n bytesUploaded: item.bytesUploaded,\n totalBytes: item.totalBytes,\n error: item.error,\n result: item.result,\n }}\n label={item.file.data.name}\n />\n </View>\n );\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isLoading && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isLoading}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>\n {children || label}\n {hasItems && ` (${state.items.length})`}\n </Text>\n </Pressable>\n\n {hasItems && (\n <View style={styles.statsContainer}>\n <Text style={styles.statsText}>\n Progress: {state.items.filter((i) => i.status === \"success\").length}\n /{state.items.length} uploaded\n </Text>\n <Text style={styles.statsText}>Overall: {state.totalProgress}%</Text>\n </View>\n )}\n\n {showProgress && hasItems && (\n <FlatList\n scrollEnabled={false}\n data={state.items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n style={styles.listContainer}\n contentContainerStyle={styles.listContent}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#34C759\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n statsContainer: {\n paddingVertical: 8,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 4,\n },\n statsText: {\n fontSize: 12,\n color: \"#666666\",\n },\n listContainer: {\n maxHeight: 400,\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n paddingHorizontal: 0,\n },\n separator: {\n height: 4,\n },\n});\n","import { FlatList, Pressable, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadItem } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface UploadListProps {\n /** List of upload items to display */\n items: UploadItem[];\n /** Callback when remove item is pressed */\n onRemove?: (id: string) => void;\n /** Callback when item is pressed */\n onItemPress?: (item: UploadItem) => void;\n /** Whether to show remove button */\n showRemoveButton?: boolean;\n}\n\n/**\n * Component to display a list of upload items with individual progress\n * Shows status indicators and allows removal of items\n */\nexport function UploadList({\n items,\n onRemove,\n onItemPress,\n showRemoveButton = true,\n}: UploadListProps) {\n const renderItem = ({ item }: { item: UploadItem }) => (\n <Pressable\n style={[\n styles.itemContainer,\n { borderLeftColor: getStatusColor(item.progress.state) },\n ]}\n onPress={() => onItemPress?.(item)}\n >\n <View style={styles.itemContent}>\n {item.file.status === \"success\" && (\n <View style={styles.itemHeader}>\n <Text style={styles.fileName} numberOfLines={1}>\n {item.file.data.name}\n </Text>\n <Text style={styles.fileSize}>\n {getFileSizeDisplay(item.file.data.size)}\n </Text>\n </View>\n )}\n {item.file.status === \"error\" && (\n <Text style={styles.errorText}>{item.progress.error?.message}</Text>\n )}\n <View style={styles.progressWrapper}>\n <UploadProgress\n state={{\n status:\n item.progress.state === \"pending\"\n ? \"idle\"\n : item.progress.state === \"cancelled\"\n ? \"aborted\"\n : item.progress.state,\n progress: item.progress.progress,\n bytesUploaded: item.progress.uploadedBytes,\n totalBytes: item.progress.totalBytes,\n error: item.progress.error || null,\n result: item.result ?? null,\n }}\n />\n </View>\n </View>\n {showRemoveButton &&\n item.progress.state !== \"uploading\" &&\n item.progress.state !== \"pending\" && (\n <Pressable\n style={styles.removeButton}\n onPress={() => onRemove?.(item.id)}\n hitSlop={{ top: 8, right: 8, bottom: 8, left: 8 }}\n >\n <Text style={styles.removeButtonText}>✕</Text>\n </Pressable>\n )}\n </Pressable>\n );\n\n if (items.length === 0) {\n return (\n <View style={styles.emptyContainer}>\n <Text style={styles.emptyText}>No uploads</Text>\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.headerText}>Uploads ({items.length})</Text>\n <Text style={styles.headerSubtext}>\n {items.filter((i) => i.progress.state === \"success\").length} complete\n </Text>\n </View>\n <FlatList\n scrollEnabled={false}\n data={items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n contentContainerStyle={styles.listContent}\n />\n </View>\n );\n}\n\n// Helper functions\nfunction getStatusColor(state: string): string {\n switch (state) {\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"cancelled\":\n return \"#FF3B30\";\n case \"uploading\":\n case \"pending\":\n return \"#007AFF\";\n default:\n return \"#999999\";\n }\n}\n\nfunction getFileSizeDisplay(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${Math.round((bytes / k ** i) * 10) / 10} ${sizes[i]}`;\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: \"#f9f9f9\",\n borderRadius: 4,\n },\n headerText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#333333\",\n },\n errorText: {\n fontSize: 14,\n color: \"#FF3B30\",\n },\n headerSubtext: {\n fontSize: 14,\n color: \"#666666\",\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n itemContent: {\n flex: 1,\n gap: 6,\n },\n itemHeader: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n fileName: {\n fontSize: 14,\n fontWeight: \"500\",\n color: \"#333333\",\n flex: 1,\n },\n fileSize: {\n fontSize: 12,\n color: \"#999999\",\n marginLeft: 8,\n },\n progressWrapper: {\n marginTop: 2,\n },\n removeButton: {\n width: 32,\n height: 32,\n justifyContent: \"center\",\n alignItems: \"center\",\n borderRadius: 16,\n backgroundColor: \"#FFE5E5\",\n },\n removeButtonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FF3B30\",\n },\n separator: {\n height: 4,\n },\n emptyContainer: {\n paddingVertical: 24,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n emptyText: {\n fontSize: 14,\n color: \"#999999\",\n fontStyle: \"italic\",\n },\n});\n","import type {\n FlowUploadState,\n FlowUploadStatus,\n InputExecutionState,\n} from \"@uploadista/client-core\";\nimport type { TypedOutput } from \"@uploadista/core/flow\";\nimport { createContext, type ReactNode, useCallback, useContext } from \"react\";\nimport {\n type FlowInputMetadata,\n type UseFlowOptions,\n useFlow,\n} from \"../hooks/use-flow\";\nimport { useUploadistaContext } from \"../hooks/use-uploadista-context\";\nimport type { FilePickResult } from \"../types\";\n\n// Re-export types for convenience\nexport type {\n FlowUploadState,\n FlowUploadStatus,\n InputExecutionState,\n FlowInputMetadata,\n};\n\n// ============ FLOW CONTEXT ============\n\n/**\n * Context value provided by the Flow component root.\n * Contains all flow state and actions.\n */\nexport interface FlowContextValue {\n /** Current upload state */\n state: FlowUploadState;\n /** Discovered input nodes metadata (null until discovery completes) */\n inputMetadata: FlowInputMetadata[] | null;\n /** Current input values set via setInput() */\n inputs: Record<string, unknown>;\n /** Per-input execution state for multi-input flows */\n inputStates: ReadonlyMap<string, InputExecutionState>;\n\n /** Set an input value for a specific node */\n setInput: (nodeId: string, value: unknown) => void;\n /** Execute the flow with current inputs */\n execute: () => Promise<void>;\n /** Upload a single file through the flow */\n upload: (file: FilePickResult) => Promise<void>;\n /** Abort the current upload */\n abort: () => void;\n /** Reset the upload state and clear all inputs */\n reset: () => void;\n\n /** Whether an upload or flow execution is in progress */\n isActive: boolean;\n /** Whether the file is currently being uploaded */\n isUploadingFile: boolean;\n /** Whether the flow is currently processing */\n isProcessing: boolean;\n /** Whether the hook is discovering flow inputs */\n isDiscoveringInputs: boolean;\n\n /** Pick a file and set it for a specific input node */\n pickFileForInput: (nodeId: string) => Promise<void>;\n /** Pick a file and start upload immediately (single-file flows) */\n pickAndUpload: () => Promise<void>;\n}\n\nconst FlowContext = createContext<FlowContextValue | null>(null);\n\n/**\n * Hook to access flow context from within a Flow component.\n * @throws Error if used outside of a Flow component\n */\nexport function useFlowContext(): FlowContextValue {\n const context = useContext(FlowContext);\n if (!context) {\n throw new Error(\n \"useFlowContext must be used within a <Flow> component. \" +\n 'Wrap your component tree with <Flow flowId=\"...\" storageId=\"...\">',\n );\n }\n return context;\n}\n\n// ============ FLOW INPUT CONTEXT ============\n\n/**\n * Context value for a specific input node within a Flow.\n */\nexport interface FlowInputContextValue {\n /** Input node ID */\n nodeId: string;\n /** Input metadata from flow discovery */\n metadata: FlowInputMetadata;\n /** Current value for this input */\n value: unknown;\n /** Set the value for this input */\n setValue: (value: unknown) => void;\n /** Per-input execution state (if available) */\n state: InputExecutionState | undefined;\n /** Pick a file for this input */\n pickFile: () => Promise<void>;\n}\n\nconst FlowInputContext = createContext<FlowInputContextValue | null>(null);\n\n/**\n * Hook to access flow input context from within a Flow.Input component.\n * @throws Error if used outside of a Flow.Input component\n */\nexport function useFlowInputContext(): FlowInputContextValue {\n const context = useContext(FlowInputContext);\n if (!context) {\n throw new Error(\n \"useFlowInputContext must be used within a <Flow.Input> component. \" +\n 'Wrap your component with <Flow.Input nodeId=\"...\">',\n );\n }\n return context;\n}\n\n// ============ FLOW ROOT COMPONENT ============\n\n/**\n * Render props for the Flow root component.\n */\nexport interface FlowRenderProps extends FlowContextValue {\n /** Alias for execute() */\n submit: () => Promise<void>;\n /** Alias for abort() */\n cancel: () => void;\n}\n\n/**\n * Props for the Flow root component.\n */\nexport interface FlowProps {\n /** Flow ID to execute */\n flowId: string;\n /** Storage ID for file uploads */\n storageId: string;\n /** Optional output node ID to wait for */\n outputNodeId?: string;\n /** Optional metadata to include with the flow execution */\n metadata?: Record<string, string>;\n /** Called when flow completes successfully */\n onSuccess?: (outputs: TypedOutput[]) => void;\n /** Called when flow fails */\n onError?: (error: Error) => void;\n /** Called on upload progress */\n onProgress?: (\n progress: number,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n /** Called when flow completes with all outputs */\n onFlowComplete?: (outputs: TypedOutput[]) => void;\n /** Children to render (can be render function or ReactNode) */\n children: ReactNode | ((props: FlowRenderProps) => ReactNode);\n}\n\n/**\n * Root component for flow-based uploads on React Native.\n * Provides context for all Flow sub-components.\n *\n * @example\n * ```tsx\n * <Flow flowId=\"image-optimizer\" storageId=\"s3\" onSuccess={handleSuccess}>\n * <Flow.Inputs>\n * {({ inputs, isLoading }) => (\n * inputs.map(input => (\n * <Flow.Input key={input.nodeId} nodeId={input.nodeId}>\n * {({ metadata, pickFile }) => (\n * <Button onPress={pickFile} title={metadata.nodeName} />\n * )}\n * </Flow.Input>\n * ))\n * )}\n * </Flow.Inputs>\n * <Flow.Submit>\n * <Text>Process</Text>\n * </Flow.Submit>\n * </Flow>\n * ```\n */\nfunction FlowRoot({\n flowId,\n storageId,\n outputNodeId,\n metadata,\n onSuccess,\n onError,\n onProgress,\n onFlowComplete,\n children,\n}: FlowProps) {\n const { fileSystemProvider } = useUploadistaContext();\n\n const options: UseFlowOptions = {\n flowId,\n storageId,\n outputNodeId,\n metadata,\n onSuccess,\n onError,\n onProgress,\n onFlowComplete,\n };\n\n const flow = useFlow(options);\n\n // Pick a file for a specific input node\n const pickFileForInput = useCallback(\n async (nodeId: string) => {\n if (!fileSystemProvider?.pickDocument) {\n throw new Error(\"File picker not available\");\n }\n const result = await fileSystemProvider.pickDocument();\n if (result.status === \"success\") {\n flow.setInput(nodeId, result);\n }\n },\n [fileSystemProvider, flow],\n );\n\n // Pick a file and start upload immediately\n const pickAndUpload = useCallback(async () => {\n if (!fileSystemProvider?.pickDocument) {\n throw new Error(\"File picker not available\");\n }\n const result = await fileSystemProvider.pickDocument();\n if (result.status === \"success\") {\n await flow.upload(result);\n }\n }, [fileSystemProvider, flow]);\n\n const contextValue: FlowContextValue = {\n state: flow.state,\n inputMetadata: flow.inputMetadata,\n inputs: flow.inputs,\n inputStates: flow.inputStates,\n setInput: flow.setInput,\n execute: flow.execute,\n upload: flow.upload,\n abort: flow.abort,\n reset: flow.reset,\n isActive: flow.isActive,\n isUploadingFile: flow.isUploadingFile,\n isProcessing: flow.isProcessing,\n isDiscoveringInputs: flow.isDiscoveringInputs,\n pickFileForInput,\n pickAndUpload,\n };\n\n const renderProps: FlowRenderProps = {\n ...contextValue,\n submit: flow.execute,\n cancel: flow.abort,\n };\n\n return (\n <FlowContext.Provider value={contextValue}>\n {typeof children === \"function\" ? children(renderProps) : children}\n </FlowContext.Provider>\n );\n}\n\n// ============ INPUTS DISCOVERY PRIMITIVE ============\n\n/**\n * Render props for Flow.Inputs component.\n */\nexport interface FlowInputsRenderProps {\n /** Discovered input metadata */\n inputs: FlowInputMetadata[];\n /** Whether inputs are still being discovered */\n isLoading: boolean;\n}\n\n/**\n * Props for Flow.Inputs component.\n */\nexport interface FlowInputsProps {\n /** Render function receiving discovered inputs */\n children: (props: FlowInputsRenderProps) => ReactNode;\n}\n\n/**\n * Auto-discovers flow input nodes and provides them via render props.\n *\n * @example\n * ```tsx\n * <Flow.Inputs>\n * {({ inputs, isLoading }) => (\n * isLoading ? <ActivityIndicator /> : (\n * inputs.map(input => (\n * <Flow.Input key={input.nodeId} nodeId={input.nodeId}>\n * ...\n * </Flow.Input>\n * ))\n * )\n * )}\n * </Flow.Inputs>\n * ```\n */\nfunction FlowInputs({ children }: FlowInputsProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowInputsRenderProps = {\n inputs: flow.inputMetadata ?? [],\n isLoading: flow.isDiscoveringInputs,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ INPUT PRIMITIVE ============\n\n/**\n * Props for Flow.Input component.\n */\nexport interface FlowInputProps {\n /** Input node ID */\n nodeId: string;\n /** Children (can be render function or regular children) */\n children: ReactNode | ((props: FlowInputContextValue) => ReactNode);\n}\n\n/**\n * Scoped input context provider for a specific input node.\n * Children can access input-specific state via useFlowInputContext().\n *\n * @example\n * ```tsx\n * <Flow.Input nodeId=\"video-input\">\n * {({ metadata, value, pickFile }) => (\n * <View>\n * <Text>{metadata.nodeName}</Text>\n * <Button onPress={pickFile} title=\"Select File\" />\n * {value && <Text>Selected: {value.data?.name}</Text>}\n * </View>\n * )}\n * </Flow.Input>\n * ```\n */\nfunction FlowInput({ nodeId, children }: FlowInputProps) {\n const flow = useFlowContext();\n\n const metadata = flow.inputMetadata?.find((m) => m.nodeId === nodeId);\n\n if (!metadata) {\n // Input not yet discovered or doesn't exist\n return null;\n }\n\n const pickFile = async () => {\n await flow.pickFileForInput(nodeId);\n };\n\n const contextValue: FlowInputContextValue = {\n nodeId,\n metadata,\n value: flow.inputs[nodeId],\n setValue: (value) => flow.setInput(nodeId, value),\n state: flow.inputStates.get(nodeId),\n pickFile,\n };\n\n return (\n <FlowInputContext.Provider value={contextValue}>\n {typeof children === \"function\" ? children(contextValue) : children}\n </FlowInputContext.Provider>\n );\n}\n\n// ============ INPUT FILE PICKER PRIMITIVE ============\n\n/**\n * Render props for Flow.Input.FilePicker component.\n */\nexport interface FlowInputFilePickerRenderProps {\n /** Current value for this input */\n value: unknown;\n /** Whether a file is selected */\n hasFile: boolean;\n /** File name (if value is FilePickResult) */\n fileName: string | null;\n /** File size in bytes (if value is FilePickResult) */\n fileSize: number | null;\n /** Per-input progress (if available) */\n progress: number;\n /** Per-input status (if available) */\n status: string;\n /** Open file picker */\n pickFile: () => Promise<void>;\n /** Clear the input value */\n clear: () => void;\n}\n\n/**\n * Props for Flow.Input.FilePicker component.\n */\nexport interface FlowInputFilePickerProps {\n /** Render function receiving file picker state */\n children: (props: FlowInputFilePickerRenderProps) => ReactNode;\n}\n\n/**\n * File picker for a specific input within a Flow.Input.\n * Sets the input value but does NOT trigger upload until Flow.Submit is pressed.\n */\nfunction FlowInputFilePicker({ children }: FlowInputFilePickerProps) {\n const input = useFlowInputContext();\n\n // Check if value is a FilePickResult\n const fileResult = input.value as FilePickResult | undefined;\n const hasFile = fileResult?.status === \"success\";\n const fileName = hasFile ? (fileResult?.data?.name ?? null) : null;\n const fileSize = hasFile ? (fileResult?.data?.size ?? null) : null;\n\n const renderProps: FlowInputFilePickerRenderProps = {\n value: input.value,\n hasFile,\n fileName,\n fileSize,\n progress: input.state?.progress ?? 0,\n status: input.state?.status ?? \"idle\",\n pickFile: input.pickFile,\n clear: () => input.setValue(undefined),\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ INPUT PREVIEW PRIMITIVE ============\n\n/**\n * Render props for Flow.Input.Preview component.\n */\nexport interface FlowInputPreviewRenderProps {\n /** Current value */\n value: unknown;\n /** Whether a file is selected */\n hasFile: boolean;\n /** Whether value is a URL string */\n isUrl: boolean;\n /** File name (if value is FilePickResult) */\n fileName: string | null;\n /** File size in bytes (if value is FilePickResult) */\n fileSize: number | null;\n /** File URI (if value is FilePickResult) */\n fileUri: string | null;\n /** Clear the input value */\n clear: () => void;\n}\n\n/**\n * Props for Flow.Input.Preview component.\n */\nexport interface FlowInputPreviewProps {\n /** Render function receiving preview state */\n children: (props: FlowInputPreviewRenderProps) => ReactNode;\n}\n\n/**\n * Preview component for showing the selected value within a Flow.Input.\n */\nfunction FlowInputPreview({ children }: FlowInputPreviewProps) {\n const input = useFlowInputContext();\n\n // Check if value is a FilePickResult\n const fileResult = input.value as FilePickResult | undefined;\n const hasFile = fileResult?.status === \"success\";\n const isUrl =\n typeof input.value === \"string\" && (input.value as string).length > 0;\n\n const renderProps: FlowInputPreviewRenderProps = {\n value: input.value,\n hasFile,\n isUrl,\n fileName: hasFile ? (fileResult?.data?.name ?? null) : null,\n fileSize: hasFile ? (fileResult?.data?.size ?? null) : null,\n fileUri: hasFile ? (fileResult?.data?.uri ?? null) : null,\n clear: () => input.setValue(undefined),\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ PROGRESS PRIMITIVE ============\n\n/**\n * Render props for Flow.Progress component.\n */\nexport interface FlowProgressRenderProps {\n /** Progress percentage (0-100) */\n progress: number;\n /** Bytes uploaded so far */\n bytesUploaded: number;\n /** Total bytes to upload (null if unknown) */\n totalBytes: number | null;\n /** Current status */\n status: FlowUploadStatus;\n}\n\n/**\n * Props for Flow.Progress component.\n */\nexport interface FlowProgressProps {\n /** Render function receiving progress state */\n children: (props: FlowProgressRenderProps) => ReactNode;\n}\n\n/**\n * Progress display component within a Flow.\n */\nfunction FlowProgress({ children }: FlowProgressProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowProgressRenderProps = {\n progress: flow.state.progress,\n bytesUploaded: flow.state.bytesUploaded,\n totalBytes: flow.state.totalBytes,\n status: flow.state.status,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ STATUS PRIMITIVE ============\n\n/**\n * Render props for Flow.Status component.\n */\nexport interface FlowStatusRenderProps {\n /** Current status */\n status: FlowUploadStatus;\n /** Current node being processed (if any) */\n currentNodeName: string | null;\n /** Current node type (if any) */\n currentNodeType: string | null;\n /** Error (if status is error) */\n error: Error | null;\n /** Job ID (if started) */\n jobId: string | null;\n /** Whether flow has started */\n flowStarted: boolean;\n /** Flow outputs (if completed) */\n flowOutputs: TypedOutput[] | null;\n}\n\n/**\n * Props for Flow.Status component.\n */\nexport interface FlowStatusProps {\n /** Render function receiving status state */\n children: (props: FlowStatusRenderProps) => ReactNode;\n}\n\n/**\n * Status display component within a Flow.\n */\nfunction FlowStatus({ children }: FlowStatusProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowStatusRenderProps = {\n status: flow.state.status,\n currentNodeName: flow.state.currentNodeName,\n currentNodeType: flow.state.currentNodeType,\n error: flow.state.error,\n jobId: flow.state.jobId,\n flowStarted: flow.state.flowStarted,\n flowOutputs: flow.state.flowOutputs,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ ERROR PRIMITIVE ============\n\n/**\n * Render props for Flow.Error component.\n */\nexport interface FlowErrorRenderProps {\n /** Error object (null if no error) */\n error: Error | null;\n /** Whether there is an error */\n hasError: boolean;\n /** Error message */\n message: string | null;\n /** Reset the flow */\n reset: () => void;\n}\n\n/**\n * Props for Flow.Error component.\n */\nexport interface FlowErrorProps {\n /** Render function receiving error state */\n children: (props: FlowErrorRenderProps) => ReactNode;\n}\n\n/**\n * Error display component within a Flow.\n */\nfunction FlowError({ children }: FlowErrorProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowErrorRenderProps = {\n error: flow.state.error,\n hasError: flow.state.status === \"error\",\n message: flow.state.error?.message ?? null,\n reset: flow.reset,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ ACTION PRIMITIVES ============\n\n/**\n * Render props for Flow.Submit component.\n */\nexport interface FlowSubmitRenderProps {\n /** Execute the flow */\n submit: () => Promise<void>;\n /** Whether the button should be disabled */\n isDisabled: boolean;\n /** Whether currently submitting */\n isSubmitting: boolean;\n}\n\n/**\n * Props for Flow.Submit component.\n */\nexport interface FlowSubmitProps {\n /** Render function receiving submit state */\n children: ReactNode | ((props: FlowSubmitRenderProps) => ReactNode);\n /** Additional disabled state */\n disabled?: boolean;\n}\n\n/**\n * Submit primitive that executes the flow with current inputs.\n * Provides render props for building custom submit buttons.\n * Automatically disabled when uploading.\n */\nfunction FlowSubmit({ children, disabled }: FlowSubmitProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowSubmitRenderProps = {\n submit: flow.execute,\n isDisabled: disabled || flow.isActive || Object.keys(flow.inputs).length === 0,\n isSubmitting: flow.isActive,\n };\n\n return <>{typeof children === \"function\" ? children(renderProps) : children}</>;\n}\n\n/**\n * Render props for Flow.Cancel component.\n */\nexport interface FlowCancelRenderProps {\n /** Cancel the flow */\n cancel: () => void;\n /** Whether the button should be disabled */\n isDisabled: boolean;\n}\n\n/**\n * Props for Flow.Cancel component.\n */\nexport interface FlowCancelProps {\n /** Render function receiving cancel state */\n children: ReactNode | ((props: FlowCancelRenderProps) => ReactNode);\n}\n\n/**\n * Cancel primitive that aborts the current upload.\n */\nfunction FlowCancel({ children }: FlowCancelProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowCancelRenderProps = {\n cancel: flow.abort,\n isDisabled: !flow.isActive,\n };\n\n return <>{typeof children === \"function\" ? children(renderProps) : children}</>;\n}\n\n/**\n * Render props for Flow.Reset component.\n */\nexport interface FlowResetRenderProps {\n /** Reset the flow */\n reset: () => void;\n /** Whether the button should be disabled */\n isDisabled: boolean;\n}\n\n/**\n * Props for Flow.Reset component.\n */\nexport interface FlowResetProps {\n /** Render function receiving reset state */\n children: ReactNode | ((props: FlowResetRenderProps) => ReactNode);\n}\n\n/**\n * Reset primitive that clears all inputs and resets to idle state.\n */\nfunction FlowReset({ children }: FlowResetProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowResetRenderProps = {\n reset: flow.reset,\n isDisabled: flow.isActive,\n };\n\n return <>{typeof children === \"function\" ? children(renderProps) : children}</>;\n}\n\n// ============ QUICK UPLOAD PRIMITIVE ============\n\n/**\n * Render props for Flow.QuickUpload component.\n */\nexport interface FlowQuickUploadRenderProps {\n /** Whether currently uploading */\n isUploading: boolean;\n /** Progress percentage (0-100) */\n progress: number;\n /** Current status */\n status: FlowUploadStatus;\n /** Pick a file and start upload immediately */\n pickAndUpload: () => Promise<void>;\n /** Abort the current upload */\n abort: () => void;\n}\n\n/**\n * Props for Flow.QuickUpload component.\n */\nexport interface FlowQuickUploadProps {\n /** Render function receiving quick upload state */\n children: (props: FlowQuickUploadRenderProps) => ReactNode;\n}\n\n/**\n * Quick upload component for single-file flows.\n * Picks a file and starts upload immediately.\n *\n * @example\n * ```tsx\n * <Flow.QuickUpload>\n * {({ isUploading, progress, pickAndUpload, abort }) => (\n * <Button\n * onPress={isUploading ? abort : pickAndUpload}\n * title={isUploading ? `Uploading ${progress}%` : 'Upload File'}\n * />\n * )}\n * </Flow.QuickUpload>\n * ```\n */\nfunction FlowQuickUpload({ children }: FlowQuickUploadProps) {\n const flow = useFlowContext();\n\n const renderProps: FlowQuickUploadRenderProps = {\n isUploading: flow.isActive,\n progress: flow.state.progress,\n status: flow.state.status,\n pickAndUpload: flow.pickAndUpload,\n abort: flow.abort,\n };\n\n return <>{children(renderProps)}</>;\n}\n\n// ============ COMPOUND COMPONENT EXPORT ============\n\n/**\n * Flow compound component for flow-based file uploads on React Native.\n *\n * Provides a composable, headless API for building flow upload interfaces.\n * All sub-components use render props for complete UI control.\n *\n * @example Quick Upload (Single File)\n * ```tsx\n * <Flow flowId=\"image-optimizer\" storageId=\"s3\" onSuccess={handleSuccess}>\n * <Flow.QuickUpload>\n * {({ isUploading, progress, pickAndUpload, abort }) => (\n * <View>\n * <Button\n * onPress={isUploading ? abort : pickAndUpload}\n * title={isUploading ? 'Cancel' : 'Upload Image'}\n * />\n * {isUploading && <Text>{progress}%</Text>}\n * </View>\n * )}\n * </Flow.QuickUpload>\n * </Flow>\n * ```\n *\n * @example Multi-Input Flow\n * ```tsx\n * <Flow flowId=\"video-processor\" storageId=\"s3\">\n * <Flow.Inputs>\n * {({ inputs, isLoading }) => (\n * isLoading ? <ActivityIndicator /> : inputs.map(input => (\n * <Flow.Input key={input.nodeId} nodeId={input.nodeId}>\n * {({ metadata, pickFile, value }) => (\n * <View>\n * <Text>{metadata.nodeName}</Text>\n * <Button onPress={pickFile} title=\"Select File\" />\n * <Flow.Input.Preview>\n * {({ hasFile, fileName }) => hasFile && <Text>{fileName}</Text>}\n * </Flow.Input.Preview>\n * </View>\n * )}\n * </Flow.Input>\n * ))\n * )}\n * </Flow.Inputs>\n * <CustomSubmitButton />\n * </Flow>\n * ```\n */\nexport const Flow = Object.assign(FlowRoot, {\n Inputs: FlowInputs,\n Input: Object.assign(FlowInput, {\n FilePicker: FlowInputFilePicker,\n Preview: FlowInputPreview,\n }),\n Progress: FlowProgress,\n Status: FlowStatus,\n Error: FlowError,\n Submit: FlowSubmit,\n Cancel: FlowCancel,\n Reset: FlowReset,\n QuickUpload: FlowQuickUpload,\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uploadista/react-native-core",
|
|
3
|
-
"version": "0.0.20-beta.
|
|
3
|
+
"version": "0.0.20-beta.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core React Native client for Uploadista",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"uuid": "^13.0.0",
|
|
17
17
|
"js-base64": "^3.7.7",
|
|
18
|
-
"@uploadista/core": "0.0.20-beta.
|
|
19
|
-
"@uploadista/client-core": "0.0.20-beta.
|
|
18
|
+
"@uploadista/core": "0.0.20-beta.8",
|
|
19
|
+
"@uploadista/client-core": "0.0.20-beta.8"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"react": ">=16.8.0",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/react": ">=18.0.0",
|
|
33
|
-
"tsdown": "0.
|
|
34
|
-
"@uploadista/typescript-config": "0.0.20-beta.
|
|
33
|
+
"tsdown": "0.18.0",
|
|
34
|
+
"@uploadista/typescript-config": "0.0.20-beta.8"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
|
-
"build": "tsdown",
|
|
37
|
+
"build": "tsc --noEmit && tsdown",
|
|
38
38
|
"format": "biome format --write ./src",
|
|
39
39
|
"lint": "biome lint --write ./src",
|
|
40
40
|
"check": "biome check --write ./src"
|
|
@@ -170,12 +170,16 @@ export function useMultiUpload(options: UseMultiUploadOptions = {}) {
|
|
|
170
170
|
const blob = await response.blob();
|
|
171
171
|
|
|
172
172
|
// Override blob type if we have mimeType from picker
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
173
|
+
// Use type assertion to handle differences between Expo's BlobOptions and standard BlobPropertyBag
|
|
174
|
+
let uploadInput: Blob = blob;
|
|
175
|
+
if (item.file.data.mimeType) {
|
|
176
|
+
const blobOptions = {
|
|
177
|
+
type: item.file.data.mimeType,
|
|
178
|
+
lastModified: Date.now(),
|
|
179
|
+
};
|
|
180
|
+
// biome-ignore lint/suspicious/noExplicitAny: Expo and bare RN have incompatible Blob types
|
|
181
|
+
uploadInput = new Blob([blob], blobOptions as any);
|
|
182
|
+
}
|
|
179
183
|
|
|
180
184
|
// Start upload using the client
|
|
181
185
|
console.log("Uploading input:", uploadInput);
|
|
@@ -62,13 +62,16 @@ export function isBufferSource(value: unknown): value is BufferSource {
|
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Type guard to check if we're in React Native environment
|
|
65
|
-
* (checks for
|
|
65
|
+
* (checks for navigator.product === 'ReactNative')
|
|
66
66
|
*/
|
|
67
67
|
export function isReactNativeEnvironment(): boolean {
|
|
68
|
+
const g = globalThis as typeof globalThis & {
|
|
69
|
+
navigator?: { product?: string };
|
|
70
|
+
};
|
|
68
71
|
return (
|
|
69
|
-
typeof
|
|
70
|
-
typeof
|
|
71
|
-
|
|
72
|
+
typeof g !== "undefined" &&
|
|
73
|
+
typeof g.navigator !== "undefined" &&
|
|
74
|
+
g.navigator.product === "ReactNative"
|
|
72
75
|
);
|
|
73
76
|
}
|
|
74
77
|
|