aspect-sync 0.1.15 → 0.1.17

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.
Files changed (3) hide show
  1. package/README.md +135 -67
  2. package/dist/index.js +6 -6
  3. package/package.json +4 -3
package/README.md CHANGED
@@ -4,15 +4,14 @@ A CLI tool to sync files from external services (via rclone) to the Aspect platf
4
4
 
5
5
  ## Features
6
6
 
7
- - **Rclone Integration**: Sync files from any rclone-supported remote (Dropbox, Google Drive, S3, etc.)
8
- - **Directory Structure Preservation**: Maintains folder hierarchy from source to destination
9
- - **Idempotent Syncs**: Safe to re-run - automatically skips already-uploaded files and reuses existing directories
10
- - **Upload-Core Uploads**: Efficient chunked uploads through Aspect's edge worker with retry logic
11
- - **Dynamic CLI Progress**: Real-time upload progress display with in-place updates
12
- - **Concurrent Uploads**: Configurable parallel chunk uploads for optimal performance
13
- - **Session Isolation**: Auto-generated nanosecond-precision sessions for safe concurrent syncs
14
- - **Automatic Cleanup**: Removes local files after successful upload
15
- - **Retry Logic**: Automatic retry for failed uploads (part-level and file-level)
7
+ - **Rclone integration**: Lists and downloads from any rclone-supported remote.
8
+ - **Aspect-compatible path planning**: Preserves source hierarchy while sanitizing names that Aspect rejects.
9
+ - **Duplicate preservation when supported**: Preserves duplicate file and folder names when the rclone provider exposes stable IDs.
10
+ - **Idempotent reruns**: Reuses existing directories and skips assets that are already uploaded.
11
+ - **Batched migrations**: Downloads and uploads large remotes in size-limited batches.
12
+ - **Progress display**: Shows download, upload, skip, and failure progress in the terminal.
13
+ - **Session isolation**: Uses unique session directories so concurrent syncs do not collide.
14
+ - **Automatic cleanup**: Removes local staged files after successful upload unless `--keep-local` is set.
16
15
 
17
16
  ## Prerequisites
18
17
 
@@ -61,19 +60,19 @@ my-s3:
61
60
  **Important:** The remote names are shown **with a colon** (`:`) but you use them **without the colon** in the `--remote` parameter.
62
61
 
63
62
  Examples:
64
- - If you see `dropbox:` use `--remote dropbox`
65
- - If you see `my-dropbox:` use `--remote my-dropbox`
66
- - If you see `gdrive:` use `--remote gdrive`
63
+ - If you see `dropbox:`, use `--remote dropbox`
64
+ - If you see `my-dropbox:`, use `--remote my-dropbox`
65
+ - If you see `gdrive:`, use `--remote gdrive`
67
66
 
68
67
  ### Test Your Remote
69
68
 
70
69
  Before syncing, test that your remote works:
71
70
  ```bash
72
71
  # List files in the root of your remote
73
- rclone ls dropbox:
72
+ rclone lsjson dropbox: --recursive
74
73
 
75
74
  # List files in a specific folder
76
- rclone ls dropbox:my-folder
75
+ rclone lsjson dropbox:my-folder --recursive
77
76
  ```
78
77
 
79
78
  This should list files in your cloud storage. If you see files listed, your remote is configured correctly!
@@ -112,24 +111,58 @@ npx aspect-sync \
112
111
 
113
112
  ### Command Options
114
113
 
115
- | Option | Description | Required | Default |
116
- |--------|-------------|----------|---------|
117
- | `--remote <name>` | rclone remote name from your rclone config (without colon). Use `rclone listremotes` to see your configured remotes. | Yes | - |
118
- | `--path <path>` | Remote path to sync from | Yes | - |
119
- | `--directory-id <id>` | Aspect directory ID to upload to | Yes | - |
120
- | `--project-id <id>` | Aspect project ID | Yes | - |
121
- | `--api-key <key>` | Aspect API key (or set `ASPECT_API_KEY` env var) | Yes | - |
122
- | `--api-url <url>` | Aspect API URL (or set `ASPECT_API_URL` env var) | No | `https://api.aspect.inc` |
123
- | `--edge-worker-url <url>` | Aspect edge worker URL (or set `ASPECT_EDGE_WORKER_URL` env var) | No | `https://mackinac.aspect.inc` |
124
- | `--upload-concurrent <number>` | Max concurrent chunk uploads | No | `16` |
125
- | `--batch-size <size>` | Run the migration in download/upload batches (e.g., `500GB`, `1TB`) so data is uploaded as soon as each batch finishes downloading. | No | Disabled |
126
- | `--keep-local` | Keep local files after upload (for debugging) | No | `false` |
127
- | `--check` | Run in check-only mode (list remote files and compare with Aspect without downloading/uploading) | No | `false` |
128
- | `--temp-dir <path>` | Base temporary directory for synced files | No | `~/.aspect/sync` |
129
- | `--session <name>` | Session name for isolation. If not provided, auto-generates timestamp with nanosecond precision (YYYY-MM-DD_HHh-MMm-SSs-NNNNNNNNNns). Creates subdirectory in temp-dir. | No | Auto-generated |
130
- | `--rclone-extra <arg>` | Additional rclone argument appended to the sync command. Repeat the flag to pass multiple values. | No | Not set |
131
-
132
- Repeat `--rclone-extra` for each passthrough flag you need. Example: `--rclone-extra --drive-shared-with-me`.
114
+ Required:
115
+
116
+ | Option | Description |
117
+ |--------|-------------|
118
+ | `--remote <name>` | rclone remote name from your rclone config, without the trailing colon. |
119
+ | `--path <path>` | Remote path to sync from. |
120
+ | `--directory-id <id>` | Aspect directory ID to upload into. |
121
+ | `--project-id <id>` | Aspect project ID. |
122
+ | `--api-key <key>` | Aspect API key. Can also be set with `ASPECT_API_KEY`. |
123
+
124
+ Aspect API options:
125
+
126
+ | Option | Description | Default |
127
+ |--------|-------------|---------|
128
+ | `--api-url <url>` | Aspect API URL. Can also be set with `ASPECT_API_URL`. | `https://api.aspect.inc` |
129
+ | `--edge-worker-url <url>` | Aspect edge worker URL. Can also be set with `ASPECT_EDGE_WORKER_URL`. | `https://mackinac.aspect.inc` |
130
+
131
+ Sync behavior:
132
+
133
+ | Option | Description | Default |
134
+ |--------|-------------|---------|
135
+ | `--upload-concurrent <number>` | Maximum concurrent chunk uploads to Aspect. | `16` |
136
+ | `--batch-size <size>` | Enables batched mode with a maximum batch size, for example `500GB` or `1TB`. | Disabled |
137
+ | `--keep-local` | Keep local staged files after upload for debugging. | `false` |
138
+ | `--check` | Check remote files against Aspect without downloading or uploading. | `false` |
139
+ | `--temp-dir <path>` | Base temporary directory for sync sessions. | `~/.aspect/sync` |
140
+ | `--session <name>` | Session name. If omitted, a nanosecond-precision timestamp is generated. | Auto-generated |
141
+
142
+ rclone tuning:
143
+
144
+ | Option | Description | Default |
145
+ |--------|-------------|---------|
146
+ | `--rclone-transfers <number>` | Parallel file transfers for bulk rclone sync. Also controls rclone checkers. | `4` |
147
+ | `--rclone-multi-thread-streams <number>` | Streams per large file for rclone transfers. | `4` |
148
+ | `--rclone-multi-thread-chunk-size <size>` | rclone multi-thread chunk size. | `64MiB` |
149
+ | `--rclone-multi-thread-cutoff <size>` | Minimum file size for rclone multi-threading. | `64MiB` |
150
+ | `--rclone-buffer-size <size>` | rclone buffer size per transfer. | `64M` |
151
+ | `--rclone-no-mmap` | Disable rclone memory-mapped I/O. | `false` |
152
+ | `--rclone-extra <arg>` | Extra rclone argument. Repeat for multiple args. | Not set |
153
+
154
+ Repeat `--rclone-extra` for each passthrough value. Example:
155
+
156
+ ```bash
157
+ aspect-sync \
158
+ --remote gdrive \
159
+ --path /Videos \
160
+ --directory-id <directory-id> \
161
+ --project-id <project-id> \
162
+ --api-key <api-key> \
163
+ --rclone-extra --drive-root-folder-id \
164
+ --rclone-extra <folder-id>
165
+ ```
133
166
 
134
167
  ### Environment Variables
135
168
 
@@ -147,6 +180,8 @@ aspect-sync \
147
180
  --project-id <project-id>
148
181
  ```
149
182
 
183
+ Analytics is enabled only when a PostHog key is available at build time or runtime. Runtime values can be supplied with `ASPECT_POSTHOG_KEY`/`ASPECT_POSTHOG_HOST` or `POSTHOG_KEY`/`POSTHOG_HOST`. Set `ASPECT_DISABLE_POSTHOG=true` or `POSTHOG_DISABLED=true` to disable analytics.
184
+
150
185
  ## Examples
151
186
 
152
187
  ### Sync from Dropbox
@@ -173,6 +208,19 @@ aspect-sync \
173
208
  --rclone-extra --drive-shared-with-me
174
209
  ```
175
210
 
211
+ ### Sync a Specific Google Drive Folder by ID
212
+
213
+ ```bash
214
+ aspect-sync \
215
+ --remote gdrive \
216
+ --path / \
217
+ --directory-id abc-123-def \
218
+ --project-id xyz-789-uvw \
219
+ --api-key your-api-key \
220
+ --rclone-extra --drive-root-folder-id \
221
+ --rclone-extra 1truv6wvzgXM3CkGMzuC8c-hrpMk5RAAs
222
+ ```
223
+
176
224
  ### Sync from S3 Bucket
177
225
 
178
226
  ```bash
@@ -223,41 +271,67 @@ Sessions are stored in `~/.aspect/sync/{session-name}` by default. The full path
223
271
 
224
272
  ## How It Works
225
273
 
226
- 1. **Session Creation**: Creates isolated session directory with nanosecond-precision timestamp
227
- 2. **Rclone Sync**: Downloads files from the remote to the session directory
228
- 3. **Directory Discovery**: Fetches existing directory tree from Aspect to avoid duplicates
229
- 4. **Directory Creation**: Creates only missing directories, reuses existing ones
230
- 5. **Asset Deduplication**: Checks if each asset already exists before uploading
231
- 6. **File Upload**: Uploads new assets using multipart upload (20MB chunks)
232
- 7. **Progress Display**: Shows real-time upload progress in the CLI
233
- 8. **Cleanup**: Deletes local files after successful upload (unless `--keep-local` is set)
274
+ 1. **Session creation**: Creates an isolated local session directory.
275
+ 2. **Remote listing**: Uses `rclone lsjson` to list files and directories with IDs when the remote exposes them.
276
+ 3. **Path planning**: Sanitizes names for Aspect and assigns unique targets for duplicate files and folders.
277
+ 4. **Directory planning**: Fetches the existing Aspect directory tree and creates only missing directories.
278
+ 5. **Asset existence check**: Skips assets that already exist and are fully uploaded.
279
+ 6. **Download**: Downloads unchanged files with bulk `rclone sync --files-from`; downloads renamed or duplicate files by ID when needed.
280
+ 7. **Upload**: Uploads staged files through `@aspect/upload-core` and the Aspect edge worker.
281
+ 8. **Cleanup**: Deletes local staged files after successful upload unless `--keep-local` is set.
282
+
283
+ Aspect upload chunk size is controlled by the server. There is no CLI flag for upload chunk size.
284
+
285
+ ## Name Sanitization And Duplicates
286
+
287
+ Aspect enforces cross-platform file and folder names. Sanitization works for all rclone providers because it happens inside `aspect-sync` after remote listing. During planning, each path segment is sanitized before upload:
288
+
289
+ - forbidden characters such as `:`, `*`, `?`, `"`, `<`, `>`, and `|` are replaced with `_`
290
+ - trailing dots/spaces are trimmed
291
+ - reserved Windows names such as `CON`, `AUX`, and `COM1` are prefixed with `_`
292
+ - names are truncated to the backend byte limit
293
+
294
+ Some providers, especially Google Drive, allow duplicate names in the same folder. `aspect-sync` preserves those without changing the source when rclone exposes stable IDs:
295
+
296
+ - duplicate files use parenthesized suffixes, for example `IMG_1891.MOV`, `IMG_1891 (2).MOV`
297
+ - duplicate folders use numeric suffixes, for example `Shoot`, `Shoot 2`
298
+
299
+ Provider behavior:
300
+
301
+ - Providers without duplicate folder ambiguity work normally.
302
+ - Duplicate files are preserved when rclone exposes stable file IDs. If identity is required but no file ID is available, the sync fails instead of guessing.
303
+ - Duplicate folders are preserved when rclone exposes stable folder IDs and supports querying children by folder ID. Google Drive is the primary supported provider for this flow.
304
+ - Duplicate folders without stable folder IDs fail with a clear error instead of silently merging folders.
305
+
306
+ When a duplicate Google Drive folder is detected, `aspect-sync` queries each folder by its Drive ID and downloads descendants by file ID so the source folder identity is preserved.
234
307
 
235
308
  ## Idempotent Behavior
236
309
 
237
310
  The syncer is **fully idempotent** - you can safely re-run the same sync multiple times:
238
311
 
239
- **Existing directories are reused** - The tool fetches the directory tree first and only creates missing directories
312
+ **Existing directories are reused** - The tool fetches the directory tree first and only creates missing directories.
240
313
 
241
- **Existing assets are skipped** - Before uploading, checks if an asset with the same name, size, and location already exists
314
+ **Existing assets are skipped** - Before uploading, checks if an asset with the same name, size, and location already exists.
242
315
  - If found and fully uploaded: Skips upload
243
316
  - If found but incomplete: Deletes incomplete asset and re-uploads
244
317
  - If not found: Proceeds with upload
245
318
 
246
- **Clean re-runs** - If a sync fails halfway:
247
- ```bash
248
- # First run - uploads 50 of 100 files then crashes
249
- aspect-sync --remote dropbox --path /videos --directory-id abc --project-id xyz --api-key key
319
+ **Clean re-runs** - If a sync fails halfway:
250
320
 
251
- # Re-run - skips the 50 uploaded files, uploads remaining 50
252
- aspect-sync --remote dropbox --path /videos --directory-id abc --project-id xyz --api-key key
253
- ```
321
+ ```bash
322
+ # First run - uploads 50 of 100 files then crashes
323
+ aspect-sync --remote dropbox --path /videos --directory-id abc --project-id xyz --api-key key
324
+
325
+ # Re-run - skips the 50 uploaded files, uploads remaining 50
326
+ aspect-sync --remote dropbox --path /videos --directory-id abc --project-id xyz --api-key key
327
+ ```
254
328
 
255
329
  **Output on re-run:**
256
330
  ```
257
- video1.mp4 (100%)
258
- video2.mp4 (Skipped - already uploaded) ← Already uploaded
259
- video3.mp4 (Skipped - already uploaded) ← Already uploaded
260
- video4.mp4 (45%) ← Uploading now
331
+ video1.mp4 (100%)
332
+ video2.mp4 (Skipped - already uploaded)
333
+ video3.mp4 (Skipped - already uploaded)
334
+ video4.mp4 (45%)
261
335
 
262
336
  Total: 100 | Success: 1 | Failed: 0 | Skipped: 98 | In Progress: 1 | Queued: 0
263
337
  ```
@@ -267,29 +341,23 @@ Total: 100 | Success: 1 | Failed: 0 | Skipped: 98 | In Progress: 1 | Queued: 0
267
341
  The tool shows dynamic, in-place progress updates:
268
342
 
269
343
  ```
270
- video1.mp4 (100%)
271
- video2.mp4 (100%)
272
- video3.mp4 (Skipped - already uploaded)
273
- video4.mp4 (47%)
274
- video5.mp4 (23%)
344
+ video1.mp4 (100%)
345
+ video2.mp4 (100%)
346
+ video3.mp4 (Skipped - already uploaded)
347
+ video4.mp4 (47%)
348
+ video5.mp4 (23%)
275
349
 
276
350
  Total: 10 | Success: 2 | Failed: 0 | Skipped: 1 | In Progress: 2 | Queued: 5 | Speed: 45.3 Mbps | Time remaining: 2m 15s
277
351
  ```
278
352
 
279
- **Status Indicators:**
280
- - `✓` = Successfully uploaded
281
- - `✗` = Failed upload
282
- - `⊘` = Skipped (already exists on server)
283
- - `↑` = Currently uploading
284
-
285
353
  Only files that are actively uploading are shown (not the entire queue).
286
354
 
287
355
  ## Error Handling
288
356
 
289
357
  ### Retry Logic
290
358
 
291
- - **Part-level retries**: Each 20MB chunk is retried up to 3 times on failure
292
- - **File-level retries**: Each file upload is retried up to 3 times on failure
359
+ - **Chunk retries**: Upload chunks are retried on transient failures.
360
+ - **File retries**: Failed files can be retried by rerunning the sync.
293
361
  - **Exponential backoff**: Delays increase exponentially between retries
294
362
 
295
363
  ### Common Errors
@@ -348,7 +416,7 @@ Verify your rclone remote is configured:
348
416
 
349
417
  ```bash
350
418
  rclone listremotes
351
- rclone ls dropbox:
419
+ rclone lsjson dropbox: --recursive
352
420
  ```
353
421
 
354
422
  ## License
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import{Command as Pt}from"commander";import Le from"node:path";import{readFileSync as Ft}from"node:fs";import{fileURLToPath as kt}from"node:url";import Oe from"node:os";import be from"node:path";function Me(n){let e=n.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)$/i);if(!e)return null;let t=parseFloat(e[1]),s=e[2].toUpperCase(),r={B:1,KB:1024,MB:1024*1024,GB:1024*1024*1024,TB:1024*1024*1024*1024};return t*(r[s]||1)}function Ce(n){let e=n.options.apiKey||n.environment.ASPECT_API_KEY||"";if(!e)throw new Error("Error: --api-key is required (or set ASPECT_API_KEY env variable)");let t=ne({value:n.options.rcloneTransfers,optionName:"--rclone-transfers"}),s=ne({value:n.options.rcloneMultiThreadStreams,optionName:"--rclone-multi-thread-streams"}),r=ne({value:n.options.uploadConcurrent,optionName:"--upload-concurrent"}),i=parseFloat(n.options.uploadChunkSize);if(Number.isNaN(i)||i<=0)throw new Error("Error: --upload-chunk-size must be a positive number");let o=Ne(n.options.batchSize),a=n.options.session??Ge({now:n.now??new Date,highResolutionTime:n.highResolutionTime??process.hrtime.bigint()}),l=n.options.tempDir||be.join(Oe.homedir(),".aspect","sync");return{remote:n.options.remote,remotePath:n.options.path,directoryId:n.options.directoryId,projectId:n.options.projectId,apiUrl:n.options.apiUrl||n.environment.ASPECT_API_URL||"https://api.aspect.inc",edgeWorkerUrl:n.options.edgeWorkerUrl||n.environment.ASPECT_EDGE_WORKER_URL||"https://mackinac.aspect.inc",apiKey:e,maxConcurrent:r,keepLocal:n.options.keepLocal,localTempDir:be.join(l,a),sessionName:a,rcloneOptions:{transfers:t,checkers:t>=16?Math.floor(t/4):t,multiThreadStreams:s,multiThreadChunkSize:n.options.rcloneMultiThreadChunkSize,multiThreadCutoff:n.options.rcloneMultiThreadCutoff,bufferSize:n.options.rcloneBufferSize,useMmap:!n.options.rcloneNoMmap,extraRcloneArgs:n.options.rcloneExtra},batchSizeBytes:o,chunkSizeBytes:Math.round(i*1024*1024)}}function ne(n){let e=parseInt(n.value,10);if(Number.isNaN(e)||e<1)throw new Error(`Error: ${n.optionName} must be a positive integer`);return e}function Ne(n){if(!n)return;let e=Me(n);if(e===null)throw new Error(`Error: Invalid batch size format: ${n}`);return e}function Ge(n){let e=n.now.getFullYear(),t=String(n.now.getMonth()+1).padStart(2,"0"),s=String(n.now.getDate()).padStart(2,"0"),r=String(n.now.getHours()).padStart(2,"0"),i=String(n.now.getMinutes()).padStart(2,"0"),o=String(n.now.getSeconds()).padStart(2,"0"),a=n.highResolutionTime%1000000000n,l=String(a).padStart(9,"0");return`${e}-${t}-${s}_${r}h-${i}m-${o}s-${l}ns`}import $ from"node:fs/promises";import se from"node:path";import{spawn as Y}from"child_process";import*as N from"fs";import*as R from"path";import T from"node:path";function H(n,e){if(e.length===0)return"queued";if(n.isCreatingFolders)return"creating-folders";let t={queued:0,paused:0,inProgress:0,success:0,failed:0,cancelled:0};for(let r of e)switch(r.status){case"queued":t.queued++;break;case"paused":t.paused++;break;case"in-progress":t.inProgress++;break;case"success":t.success++;break;case"failed":t.failed++;break;case"cancelled":t.cancelled++;break}let s=e.length;return t.failed===s?"all-failed":t.failed>0?"some-failed":t.success===s?"success":t.paused>0&&t.queued===0&&t.inProgress===0?"paused":t.queued>0||t.inProgress>0?t.queued+t.paused===s?"queued":"in-progress":"cancelled"}function ie(n,e){let t=H(n,e);return t==="creating-folders"||t==="in-progress"||t==="queued"||t==="paused"?"cancelled":t}function oe(n){let e=[];for(let t of Object.values(n))t.chunkedState&&(t.status==="queued"||t.status==="in-progress"||t.status==="paused")&&e.push(t.chunkedState.assetId);return e}function ae(n){for(let e of Object.values(n))if(e.status==="queued"||e.status==="in-progress"||e.status==="paused")return!0;return!1}function w(n){let t=Object.values(n).reduce((s,r)=>{switch(r.status!=="failed"&&r.status!=="cancelled"&&(s.totalBytesToUpload+=r.totalBytesToUpload,s.totalBytesUploaded+=r.bytesUploaded),s.totalAssetCount+=1,r.status){case"queued":s.queuedAssetCount+=1;break;case"paused":s.pausedAssetCount+=1;break;case"in-progress":s.inProgressAssetCount+=1;break;case"success":s.successAssetCount+=1;break;case"failed":s.failedAssetCount+=1;break;case"cancelled":s.cancelledAssetCount+=1;break}return s},{totalBytesToUpload:0,totalBytesUploaded:0,totalAssetCount:0,queuedAssetCount:0,pausedAssetCount:0,inProgressAssetCount:0,successAssetCount:0,failedAssetCount:0,cancelledAssetCount:0,hasActiveUploads:!1,progress:0});return t.hasActiveUploads=t.totalAssetCount-t.successAssetCount-t.failedAssetCount-t.cancelledAssetCount>0,t.progress=t.hasActiveUploads?t.totalBytesUploaded/t.totalBytesToUpload:0,t}function le(n,e){if(e.length===0)return null;let t=e.reduce((s,r)=>(r.status!=="failed"&&r.status!=="cancelled"&&(s.totalBytes+=r.totalBytesToUpload,s.uploadedBytes+=r.bytesUploaded),r.status==="success"?s.filesSucceeded++:r.status==="failed"&&s.filesFailed++,(r.status==="success"||r.status==="failed"||r.status==="cancelled")&&s.filesCompleted++,s),{totalBytes:0,uploadedBytes:0,filesCompleted:0,filesSucceeded:0,filesTotal:e.length,filesFailed:0,percentage:0});return t.percentage=t.totalBytes>0?t.uploadedBytes/t.totalBytes*100:0,t}function ue(n){let e=Object.values(n).filter(t=>t.status==="queued"||t.status==="in-progress"||t.status==="paused");return e.length===0?!1:e.every(t=>t.status==="paused")}function ce(n){return Object.values(n).some(e=>e.status==="paused")}import Gt from"axios";var x=class{#t;#s;#e;#i;#o;#n=0;#a=0;#l=0;#r=0;#u=0;#A=0;constructor(e){this.#t=e?.alphaFast??.1,this.#s=e?.alphaMax??.5,this.#e=e?.consecutiveForBoost??3,this.#i=e?.minSamples??3,this.#o=e?.maxGapSeconds??2}sample(e){let t=Date.now();if(this.#r===0){this.#r=t,this.#u=e;return}let r=(t-this.#r)/1e3,i=e-this.#u;if(r<=0||i<0)return;if(r>this.#o){this.#r=t,this.#u=e;return}let o=i/r;if(this.#A===0)this.#n=o;else{let l=o-this.#n>=0?1:-1;this.#l!==0&&l===this.#l?this.#a++:this.#a=0,this.#l=l;let u=Math.min(1,this.#a/this.#e),c=this.#t+(this.#s-this.#t)*u;this.#n=c*o+(1-c)*this.#n}this.#r=t,this.#u=e,this.#A++}etaSeconds(e){return!this.isWarmedUp||this.#n<=0?0:e/this.#n}adjustTotalBytes(e){this.#u+=e}reset(){this.#n=0,this.#a=0,this.#l=0,this.#r=0,this.#u=0,this.#A=0}serialize(){return{displaySpeedBps:this.#n,lastSampleTimestamp:this.#r,lastSampleTotalBytes:this.#u,sampleCount:this.#A}}get speedBps(){return this.#n}get speedMbps(){return this.#n*8/1e6}get isWarmedUp(){return this.#A>=this.#i}};function P(n){let e={"X-Aspect-Share-Id":n.shareId};return n.shareAuthentication&&(e["X-Aspect-Share-Authentication"]=n.shareAuthentication),e}var _=class{#t;#s;#e;#i;#o;#n;#a;#l;#r;#u;#A;#g;#I;#h;#B;#U;#C;#P;#f;#m;#R;#c;#v;#x;#d;#w;#S;#y;#k;#_;#F;#p;#E;constructor(e){this.#s=e?.minConcurrency??1,this.#e=e?.maxConcurrency??8,this.#t=e?.initialConcurrency??this.#s,this.#i=e?.errorThreshold??1,this.#o=(e?.cooldownSeconds??10)*1e3,this.#n=e?.plateauThreshold??.05,this.#a=e?.onChange,this.#l=e?.now??Date.now,this.#r=this.#t,this.#u="probing",this.#A=0,this.#g=0,this.#I=0,this.#h=0,this.#B=!1,this.#U=0,this.#C=0,this.#P=1/0,this.#_=0,this.#F=0,this.#p=0,this.#E=0,this.#f=1/0,this.#m=0,this.#R=3e4,this.#c=0,this.#v=0,this.#x=0,this.#d=0,this.#w=0,this.#S=0,this.#y=0,this.#k=0}recordSuccess(e,t){if(e<=0)return;if(this.#U>0){this.#U--;return}this.#h++,this.#_+=e;let s=this.#l();if(this.#F===0){this.#F=s;return}let r=s-this.#F;if(r>=200){let c=this.#_/r*1e3;this.#E===0?this.#p=c:this.#p=.3*c+(1-.3)*this.#p,this.#E++,this.#E>=5&&(this.#x=Math.max(this.#x,this.#p)),this.#_=0,this.#F=s}if(t!==void 0&&t>0&&e>0){let c=t/(e/1048576);this.#w===0?this.#d=c:this.#d=.3*c+(1-.3)*this.#d,this.#w++}if(this.#u==="cooldown"&&s>=this.#A&&(this.#u="probing"),this.#u!=="probing")return;if(this.#g>0){let c;if(this.#E>=25?c=.03:this.#E>=15?c=.04:this.#E>=5&&(c=.07),c!==void 0&&(this.#p-this.#g)/this.#g<=-c){this.#y=0,this.#k=0,this.#L();return}}let i=this.#B?this.#r*2:this.#r;if(this.#h<i)return;if(this.#I=0,this.#E<5){this.#h=0;return}let o=this.#f<1/0&&this.#l()<this.#m?this.#f-1:this.#e,a=Math.min(this.#e,this.#P-1,o);if(this.#r>=a){if(this.#f<1/0&&this.#p>0&&this.#c>0){let c=(this.#p-this.#c)/this.#c;if(c>.2){this.#f=1/0,this.#m=0,this.#R=3e4,this.#c=0,this.#v=0,this.#h=0;return}if(c<=-.07){this.#h=0;return}}if(this.#x>0&&this.#p>0&&this.#E>=5&&(this.#x-this.#p)/this.#x>.07){this.#f=1/0,this.#m=0,this.#R=3e4,this.#c=0,this.#v=0,this.#x=this.#p,this.#h=0;return}if(this.#v>0&&this.#d>0&&this.#w>=2&&(this.#v-this.#d)/this.#v>.2){this.#f=1/0,this.#m=0,this.#R=3e4,this.#c=0,this.#v=0,this.#h=0;return}this.#h=0;return}let l=this.#p;if(this.#g>0){let c=Math.max(.02,this.#n*3/this.#r),d=(l-this.#g)/this.#g;if(d<=-.07){this.#y=0,this.#k=0,this.#L();return}else if(d<c){if(this.#w>=2&&this.#S>0){let h=this.#d/this.#S,p=this.#r/(this.#r-1);if(h<p*.9){this.#h=0;return}}if(this.#y++,this.#y<3){this.#h=0;return}this.#y=0,this.#k=0,this.#L();return}else if(d<c*2){if(this.#k++,this.#k<2){this.#h=0;return}this.#y=0,this.#k=0}else this.#y=0,this.#k=0;this.#f<1/0&&(this.#f=1/0,this.#m=0,this.#R=3e4,this.#c=0,this.#v=0)}this.#S=this.#d,this.#y=0,this.#k=0;let u=this.#r;this.#r++,this.#g=l,this.#h=0,this.#U=Math.max(0,u-1),this.#_=0,this.#F=0,this.#p=0,this.#E=0,this.#d=0,this.#w=0,this.#a?.(this.#r)}#L(){let e=Math.max(this.#s,this.#r-1);e<this.#r&&(this.#f=Math.min(this.#f,this.#r),this.#m=this.#l()+this.#R,this.#R=Math.min(this.#R*2,12e4),this.#c=this.#g,this.#v=this.#S,this.#r=e,this.#g=0,this.#_=0,this.#F=0,this.#p=0,this.#E=0,this.#d=0,this.#w=0,this.#a?.(this.#r)),this.#h=0}recordError(){if(this.#U>0&&this.#U--,this.#I++,this.#I<this.#i)return;this.#r===this.#C&&(this.#P=Math.min(this.#P,this.#r)),this.#C=this.#r;let e=this.#r;this.#r=Math.max(this.#s,Math.floor(this.#r/2)),this.#u="cooldown",this.#A=this.#l()+this.#o,this.#B=!0,this.#I=0,this.#h=0,this.#U=0,this.#g=0,this.#_=0,this.#F=0,this.#p=0,this.#E=0,this.#d=0,this.#w=0,this.#S=0,this.#y=0,this.#k=0,this.#r!==e&&this.#a?.(this.#r)}get concurrency(){return this.#r}get speedBps(){return this.#p}get latencyMsPerMB(){return this.#d}reset(){this.#r=this.#t,this.#u="probing",this.#A=0,this.#g=0,this.#I=0,this.#h=0,this.#B=!1,this.#U=0,this.#C=0,this.#P=1/0,this.#f=1/0,this.#m=0,this.#R=3e4,this.#c=0,this.#v=0,this.#x=0,this.#d=0,this.#w=0,this.#S=0,this.#y=0,this.#k=0,this.#_=0,this.#F=0,this.#p=0,this.#E=0,this.#a?.(this.#r)}};function Re(n){let e=`[${n}]`;return{info:(...t)=>console.info(e,...t),warn:(...t)=>console.warn(e,...t),error:(...t)=>console.error(e,...t)}}var de=Re("transfer");var j=class{uploadAssets={};uploadGroups={};#t=new x;get uploadSpeedState(){return this.#t.serialize()}uploadStats={uploadSpeedMbps:0,timeRemainingSeconds:0,formattedSpeed:"Calculating...",formattedTime:"Calculating..."};dirtyAssetIds=new Set;dirtyGroupIds=new Set;dirtyHistoryGroupIds=new Set;#s(e){e!==0&&this.#t.adjustTotalBytes(-e)}adjustSpeedBaselineForSkippedBytes(e){e!==0&&this.#t.adjustTotalBytes(e)}#e(){Object.values(this.uploadAssets).some(t=>t.status==="queued"||t.status==="in-progress")||this.#t.reset()}#i(e){this.dirtyAssetIds.add(e)}#o(e){this.dirtyGroupIds.add(e)}addUploadAsset({assetId:e,fileReader:t,abortController:s,parentId:r,projectId:i,groupId:o,chunkSize:a,shareContext:l}){this.uploadAssets[e]={assetId:e,totalBytesToUpload:t.size,bytesUploaded:0,status:"queued",fileName:t.name,createdAt:new Date().toISOString(),i:Object.keys(this.uploadAssets).length,parentId:r,projectId:i,groupId:o,retryCount:0,chunkSize:a??0,fileReader:t,abortController:s,shareContext:l},this.#i(e)}updateUploadProgress(e,t){let s=this.uploadAssets[e];if(!s||s.status==="paused"||s.status==="cancelled"||s.status==="success"||s.status==="failed")return;let r=t>0&&s.status==="queued"?"in-progress":s.status,i=Math.min(t,s.totalBytesToUpload);s.bytesUploaded=i,s.status=r,this.#i(e)}markUploadInProgress(e){let t=this.uploadAssets[e];t&&(t.status="in-progress",this.#i(e))}markUploadSuccess(e){let t=this.uploadAssets[e];t&&(t.status="success",t.bytesUploaded=t.totalBytesToUpload,this.#i(e),this.#e(),this.cleanupOnCompletion(e))}markUploadFailed(e,t){let s=this.uploadAssets[e];if(!s)return;let r=s.bytesUploaded;s.status="failed",s.errorMessage=t,s.bytesUploaded=0,this.#i(e),this.#s(r),this.#e(),this.cleanupOnCompletion(e)}removeUploadAsset(e){let s=this.uploadAssets[e]?.bytesUploaded??0;delete this.uploadAssets[e],this.#i(e),this.#s(s),this.#e()}clearAllUploads(){this.uploadAssets={},this.#t.reset()}clearTerminalState(){if(!Object.values(this.uploadAssets).some(t=>t.status==="queued"||t.status==="in-progress"||t.status==="paused")){for(let t of Object.keys(this.uploadAssets))delete this.uploadAssets[t];for(let t of Object.keys(this.uploadGroups))delete this.uploadGroups[t];this.#t.reset()}}resetAssetForRetryQueue(e){let t=this.uploadAssets[e];t&&(t.status="queued",t.bytesUploaded=0,t.errorMessage=void 0,t.retryCount=t.retryCount+1,this.#i(e))}resetAssetForRetrying(e){let t=this.uploadAssets[e];t&&(t.status="queued",t.bytesUploaded=0,t.retryCount=0,this.#i(e))}pauseUpload(e){let t=this.uploadAssets[e];if(!t||t.status!=="queued"&&t.status!=="in-progress")return;let s=0;if(t.chunkedState){let{completedChunkIndices:i,chunkSize:o}=t.chunkedState;for(let a of i){let l=a*o,u=Math.min(l+o,t.totalBytesToUpload);s+=u-l}}let r=t.bytesUploaded-s;t.status="paused",t.bytesUploaded=s,this.#i(e),this.#s(r),this.#e(),t.abortController.abort()}unpauseUpload(e){let t=this.uploadAssets[e];t&&t.status==="paused"&&(t.status="queued",this.#i(e))}pauseUploadGroup(e){let t=this.uploadGroups[e];if(t&&!t.isCreatingFolders){t.isPaused=!0,this.#o(e);for(let s of t.assetIds)this.pauseUpload(s)}}unpauseUploadGroup(e){let t=this.uploadGroups[e];t&&(t.isPaused=!1,this.#o(e))}pauseAllUploads(){for(let e of Object.values(this.uploadGroups))e.isCreatingFolders||this.pauseUploadGroup(e.id)}resumeAllUploads(){for(let e of Object.values(this.uploadGroups))e.isPaused&&this.unpauseUploadGroup(e.id)}markUploadCancelled(e){let t=this.uploadAssets[e];if(!t||t.status==="success"||t.status==="failed"||t.status==="cancelled")return;let s=t.bytesUploaded;t.status="cancelled",this.#i(e),this.#s(s),this.#e(),this.cleanupOnCompletion(e)}setChunkedState(e,t){let s=this.uploadAssets[e];s&&(s.chunkedState=t,this.#i(e))}addCompletedChunkIndex(e,t){let s=this.uploadAssets[e];!s||!s.chunkedState||(s.chunkedState={...s.chunkedState,completedChunkIndices:[...s.chunkedState.completedChunkIndices,t]},this.#i(e))}clearChunkedState(e){let t=this.uploadAssets[e];t&&(t.chunkedState=void 0,this.#i(e))}hasGroupsCreatingFolders(){return Object.values(this.uploadGroups).some(e=>e.isCreatingFolders===!0)}areAllUploadsPaused(){return ue(this.uploadAssets)}hasPausedUploads(){return ce(this.uploadAssets)}getUploadAsset(e){return this.uploadAssets[e]}getSerializableAsset(e){let t=this.uploadAssets[e];if(t)return this.#l(t)}getUploadSummary(){return w(this.#u())}getAllUploadAssetsSortedByRecent(){return Object.values(this.uploadAssets).map(e=>this.#l(e)).sort((e,t)=>t.i-e.i)}getGroupAssets(e){let t=this.uploadGroups[e];return!t||!t.assetIds?[]:t.assetIds.map(s=>this.uploadAssets[s]).filter(Boolean).map(s=>this.#l(s))}getGroupAssetsInternal(e){let t=this.uploadGroups[e];return!t||!t.assetIds?[]:t.assetIds.map(s=>this.uploadAssets[s]).filter(Boolean)}addUploadGroup(e){let t=crypto.randomUUID();return this.uploadGroups[t]={...e,id:t,fileReaders:new Map},this.#o(t),t}updateUploadGroup(e,t){let s=this.uploadGroups[e];s&&(Object.assign(s,t),this.#o(e))}addAssetToGroup(e,t){let s=this.uploadGroups[e];s&&(s.assetIds.push(t),this.#o(e))}removeUploadGroup(e){let t=this.uploadGroups[e];if(t)for(let s of t.assetIds)delete this.uploadAssets[s],this.#i(s);delete this.uploadGroups[e],this.#o(e)}getUploadGroup(e){let t=this.uploadGroups[e];if(t)return this.#r(t)}getAllUploadGroups(){return Object.values(this.uploadGroups).map(e=>this.#r(e)).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}getUploadGroupProgress(e){let t=this.uploadGroups[e];if(!t)return null;let s=this.getGroupAssets(e);return le(this.#r(t),s)}getUploadGroupStatus(e){let t=this.uploadGroups[e];if(!t)return null;let s=this.getGroupAssets(e);return s.length>0?H(this.#r(t),s):null}getAssetsByParentId(e){return Object.values(this.uploadAssets).filter(t=>t.parentId===e).map(t=>this.#l(t))}getActiveUploadGroups(){return Object.values(this.uploadGroups).filter(e=>{let t=this.getUploadGroupStatus(e.id);return t&&["queued","creating-folders","in-progress"].includes(t)}).map(e=>this.#r(e))}cleanupOnCompletion(e){let t=this.uploadAssets[e];if(!t)return;let s=t.groupId;if(s){let i=this.uploadGroups[s];if(i){let o=this.getGroupAssets(s),a=this.#r(i);this.dirtyHistoryGroupIds.add(s),!o.some(u=>u.status==="queued"||u.status==="in-progress")&&!i.completedAt&&(i.completedAt=new Date().toISOString(),this.#o(s))}}let r=this.getUploadSummary();if(r.cancelledAssetCount+r.failedAssetCount+r.successAssetCount===r.totalAssetCount)for(let i of Object.keys(this.uploadAssets)){let o=this.uploadAssets[i];o&&(o.bytesUploaded=0,this.#i(i))}}updateUploadStats(){let e=this.getUploadSummary(),t=e.queuedAssetCount>0||e.inProgressAssetCount>0;t&&this.#t.sample(e.totalBytesUploaded);let s=this.#t.isWarmedUp?this.#t.speedMbps:0,r=t&&this.#t.isWarmedUp?this.#t.etaSeconds(e.totalBytesToUpload-e.totalBytesUploaded):0;this.uploadStats={uploadSpeedMbps:s,timeRemainingSeconds:r,formattedSpeed:this.#n(s),formattedTime:this.#a(r)}}#n(e){return!Number.isFinite(e)||e<=0?"Calculating...":e<1?`${(e*1e3).toFixed(0)} Kbps`:`${e.toFixed(1)} Mbps`}#a(e){if(!Number.isFinite(e)||e<=0)return"Calculating...";let t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60);return t>0?`${t}h ${s}m left`:s>0?`${s}m ${r}s left`:`${r}s left`}buildHistoryItem(e){let t=this.uploadGroups[e];if(!t)return null;let s=this.getGroupAssets(e),r=this.#r(t);return{groupId:t.id,name:t.name,type:t.type,fileCount:t.fileCount,folderCount:t.folderCount,topLevelFileCount:t.topLevelFileCount,topLevelFolderCount:t.topLevelFolderCount,status:ie(r,s),createdAt:t.createdAt,completedAt:t.completedAt,rootDirectoryId:t.rootDirectoryId,projectId:t.projectId,errorMessage:t.errorMessage,conflictResolution:t.conflictResolution}}#l({fileReader:e,abortController:t,shareContext:s,...r}){return r}#r({fileReaders:e,...t}){return t}#u(){let e={};for(let[t,s]of Object.entries(this.uploadAssets))e[t]=this.#l(s);return e}#A(){let e={};for(let[t,s]of Object.entries(this.uploadGroups))e[t]=this.#r(s);return e}getSerializableSnapshot(){return{uploadAssets:this.#u(),uploadGroups:this.#A(),uploadStats:{...this.uploadStats},uploadSpeedState:this.uploadSpeedState}}getDirtyDelta(){let e={};for(let s of this.dirtyAssetIds){let r=this.uploadAssets[s];r&&(e[s]=this.#l(r))}let t={};for(let s of this.dirtyGroupIds){let r=this.uploadGroups[s];r&&(t[s]=this.#r(r))}return{assets:e,groups:t}}clearDirtyFlags(){this.dirtyAssetIds.clear(),this.dirtyGroupIds.clear(),this.dirtyHistoryGroupIds.clear()}};function He(n,e){let t=new Date(n).getTime(),s=Date.now();return t-s<=e}var q=class{#t;#s=new Map;#e=new Map;constructor(e){this.#t=e}seedToken(e,t,s){this.#s.set(e,{token:t,expiresAt:s})}async getToken(e,t){let s=this.#s.get(e);if(s&&!He(s.expiresAt,3e5))return s.token;let r=this.#e.get(e);if(r)return r;let i=t?P(t):void 0,o=this.#t.post(`/assets/${e}/token`,{},i).then(a=>{if(!a.token)throw new Error("Token refresh failed: no token in response");return this.#s.set(e,{token:a.token,expiresAt:a.token_expires_at}),this.#e.delete(e),a.token}).catch(a=>{throw this.#e.delete(e),a});return this.#e.set(e,o),o}clearCache(e){e?this.#s.delete(e):this.#s.clear()}};var W=class{#t=[];registerAsset(e){this.#t.push({assetId:e.assetId,totalChunks:e.totalChunks,nextChunkToClaim:0,completedChunkIndices:new Set(e.completedChunkIndices),isPaused:!1})}claimNextChunk(){for(let e of this.#t)if(!e.isPaused)for(;e.nextChunkToClaim<e.totalChunks;){let t=e.nextChunkToClaim;if(e.nextChunkToClaim++,!e.completedChunkIndices.has(t))return{assetId:e.assetId,chunkIndex:t}}return null}markChunkCompleted(e,t){let s=this.#s(e);return s?(s.completedChunkIndices.add(t),s.completedChunkIndices.size>=s.totalChunks):!1}pauseAsset(e){let t=this.#s(e);t&&(t.isPaused=!0)}unpauseAsset(e){let t=this.#s(e);t&&(t.isPaused=!1,this.#e(t))}removeAsset(e){this.#t=this.#t.filter(t=>t.assetId!==e)}hasAsset(e){return this.#t.some(t=>t.assetId===e)}clear(){this.#t=[]}#s(e){return this.#t.find(t=>t.assetId===e)}#e(e){for(let t=0;t<e.totalChunks;t++)if(!e.completedChunkIndices.has(t)){e.nextChunkToClaim=t;return}e.nextChunkToClaim=e.totalChunks}};var je=/[/\\:*?"<>|\x00-\x1F]/g,qe=["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"];function B(n){let e=n.replace(je,"_");e=e.replace(/[. ]+$/,""),(!e||e==="."||e==="..")&&(e="unnamed");let t=e.includes(".")?e.substring(0,e.lastIndexOf(".")):e;qe.includes(t.toUpperCase())&&(e=`_${e}`);let s=new TextEncoder;if(s.encode(e).length>255){let r=e.lastIndexOf("."),i=r>0?e.substring(r):"",o=r>0?e.substring(0,r):e,l=255-s.encode(i).length;for(;s.encode(o).length>l&&o.length>0;)o=o.slice(0,-1);e=o+i}return e}var E=class extends Error{constructor(){super("Upload cancelled"),this.name="CancelledError"}};function D(n){return n instanceof E||n instanceof Error&&n.name==="CancelledError"||n instanceof Error&&n.name==="CanceledError"||n instanceof Error&&n.name==="AbortError"}function Je(n){return D(n)||n instanceof Error&&n.name==="NoAuthError"}function Ze(n){return new Promise(e=>setTimeout(e,n))}function et(n){return n instanceof Blob?n.size:n.byteLength}var L=class{#t;#s;#e;#i;#o;#n;#a;#l;#r;#u;#A;#g;#I;#h=null;#B=0;#U=!1;#C=[];#P=new Set;#f=!1;#m=!1;#R=!1;#c=[];#v=!1;#x=!1;#d=new W;#w=0;#S=new Map;#y=new Map;#k=[];#_=!1;#F=null;#p="keep_both";#E=new Map;#L=null;#b=!1;#D=null;#N=!1;constructor(e){this.#t=e.httpClient,this.#s=new q(e.httpClient),this.#e=new j,this.#i=e.historyStore??null,this.#o=e.settingsStore??null,this.#n=e.analytics??null,this.#a=e.logger??de,this.#l=e.onChange??null,this.#r=e.onClear??null,this.#u=e.onSummary??null,this.#A=e.onConcurrencyAdjusted??null,this.#I=e.deltaIntervalMs??333;let t=e.maxConcurrency??4;if(e.adaptiveConcurrency!==!1){let s=e.adaptiveConcurrencyConfig;this.#D=new _({initialConcurrency:s?.initialConcurrency??Math.min(2,t),minConcurrency:s?.minConcurrency??1,maxConcurrency:s?.maxConcurrency??t,errorThreshold:s?.errorThreshold,cooldownSeconds:s?.cooldownSeconds??10,plateauThreshold:s?.plateauThreshold,onChange:r=>{let i=this.#g;if(this.setMaxConcurrency(r),i===r)return;let o=this.#N?"reset":r>i?"probe_increase":"error_decrease",a=Math.round(this.#D.speedBps/(1024*1024)*100)/100,l=Math.round(this.#D.latencyMsPerMB*100)/100;this.#a.info(`Adaptive concurrency: ${i} \u2192 ${r} (${o}), speed=${a}MB/s, latency=${l}ms/MB`),this.#A?.({previousConcurrency:i,newConcurrency:r,reason:o,speedMbps:a,latencyMsPerMB:l})},now:s?.now}),this.#g=this.#D.concurrency}else this.#g=t;this.#i&&(this.#C=this.#i.load()),this.#o&&(this.#F=this.#o.getBandwidthLimitBps(),this.#p=this.#o.getConflictResolution()),(this.#l||this.#u)&&(this.#h=setInterval(()=>{this.#le()},this.#I)),this.#n&&(this.#L=setInterval(()=>{this.#ce()},6e4))}startUpload(e){let t=e.assetId||crypto.randomUUID(),s=!!e.assetId,r;if(s){let o=this.#e.getUploadAsset(t);if(!o)throw new Error(`Cannot retry: asset ${t} not found`);r=o.chunkSize}else{if(e.chunkSize===void 0||e.chunkSize===null)throw new Error("chunkSize is required for new uploads");r=e.chunkSize}let i=new AbortController;if(s){if(this.#e.getUploadAsset(t).status==="cancelled")return t;e.resetRetryCount&&this.#e.resetAssetForRetrying(t);let a=this.#e.getUploadAsset(t);a.abortController=i,a.fileReader=e.fileReader,e.shareContext&&(a.shareContext=e.shareContext)}else this.#e.addUploadAsset({assetId:t,fileReader:e.fileReader,abortController:i,parentId:e.directoryId,projectId:e.projectId,groupId:e.groupId,chunkSize:r,shareContext:e.shareContext});return this.#c.push(t),this.#G(),this.#T(),t}startGroupUpload(e){this.#e.clearTerminalState();let t=this.#e.addUploadGroup({type:e.type,name:e.name,assetIds:[],fileCount:e.fileCount,folderCount:e.folderCount,topLevelFileCount:e.topLevelFileCount,topLevelFolderCount:e.topLevelFolderCount,isCreatingFolders:!1,isPaused:!1,createdAt:new Date().toISOString(),rootDirectoryId:e.rootDirectoryId,projectId:e.projectId,retryCount:0,conflictResolution:e.conflictResolutionOverride??this.#p});return this.#E.set(t,Date.now()),this.#n?.("upload:started",{file_count:e.fileCount,total_bytes:e.totalBytes??0,has_folders:e.folderCount>0,project_id:e.projectId}),this.#e.dirtyHistoryGroupIds.add(t),this.#$(),this.#T(),t}pauseUpload(e){let t=this.#e.getUploadAsset(e);this.#e.pauseUpload(e),this.#c=this.#c.filter(s=>s!==e),this.#d.pauseAsset(e),!this.#b&&t&&this.#n&&this.#n("upload:file_paused",{file_name:t.fileName,file_size:t.totalBytesToUpload,bytes_uploaded:t.bytesUploaded,project_id:t.projectId??""}),this.#T()}unpauseUpload(e){this.#e.unpauseUpload(e),this.#T()}cancelUpload(e){let t=this.#e.getUploadAsset(e);if(!t||t.status==="success"||t.status==="failed"||t.status==="cancelled")return;let s=t.fileName,r=t.totalBytesToUpload,i=t.bytesUploaded,o=t.projectId,a=t.chunkedState?.assetId;(t.status==="queued"||t.status==="in-progress")&&t.abortController.abort(),this.#c=this.#c.filter(l=>l!==e),this.#d.removeAsset(e),this.#S.delete(e),this.#y.delete(e),this.#e.markUploadCancelled(e),this.#e.clearChunkedState(e),t.fileReader.close?.(),!this.#b&&this.#n&&this.#n("upload:file_cancelled",{file_name:s,file_size:r,bytes_uploaded:i,project_id:o??""}),this.#T(),this.#O(),this.#G(),this.#q(),a&&(this.#k.push(a),this.#K())}cancelAllUploads(){let e=this.#W();this.#b=!0;try{let s=Object.values(this.#e.uploadAssets).filter(r=>r.status==="queued"||r.status==="in-progress"||r.status==="paused");for(let r of s)this.cancelUpload(r.assetId)}finally{this.#b=!1}this.#n?.("upload:all_cancelled",e)}retryUpload(e){let t=this.#e.getUploadAsset(e);t&&t.status==="failed"&&this.startUpload({fileReader:t.fileReader,directoryId:t.parentId??"",projectId:t.projectId,groupId:t.groupId,assetId:e,resumeChunked:t.chunkedState,resetRetryCount:!0,shareContext:t.shareContext})}resumeUpload(e){let t=this.#e.getUploadAsset(e);if(!t||t.status!=="paused")return;!this.#b&&this.#n&&this.#n("upload:file_resumed",{file_name:t.fileName,file_size:t.totalBytesToUpload,bytes_uploaded:t.bytesUploaded,project_id:t.projectId??""});let s=new AbortController;t.abortController=s,this.#e.unpauseUpload(e),this.#d.hasAsset(e)?(this.#d.unpauseAsset(e),this.#T(),this.#O()):this.startUpload({fileReader:t.fileReader,directoryId:t.parentId??"",projectId:t.projectId,groupId:t.groupId,assetId:e,resumeChunked:t.chunkedState,shareContext:t.shareContext})}pauseUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;let s=this.#b;this.#b=!0,this.#e.pauseUploadGroup(e);for(let r of t.assetIds)this.#c=this.#c.filter(i=>i!==r),this.#d.pauseAsset(r);this.#b=s,this.#b||this.#X(e,t,"upload:group_paused"),this.#T()}unpauseUploadGroup(e){this.#e.unpauseUploadGroup(e),this.#T()}cancelUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;let{totalBytes:s,bytesUploaded:r,filesRemaining:i}=this.#Y(t),o=this.#b;this.#b=!0;for(let a of t.assetIds)this.cancelUpload(a);this.#b=o,this.#b||this.#n?.("upload:group_cancelled",{file_count:t.assetIds.length,files_remaining:i,total_bytes:s,bytes_uploaded:r,project_id:t.projectId}),this.#E.delete(e)}resumeUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;this.#b||this.#X(e,t,"upload:group_resumed");let s=this.#b;this.#b=!0,this.#e.unpauseUploadGroup(e);for(let r of t.assetIds){let i=this.#e.getUploadAsset(r);i&&i.status==="paused"&&this.resumeUpload(r)}this.#b=s}retryUploadGroup(e){let t=this.#e.uploadGroups[e];if(t)for(let s of t.assetIds){let r=this.#e.getUploadAsset(s);r&&r.status==="failed"&&this.retryUpload(s)}}setGroupCreatingFolders(e,t){this.#e.updateUploadGroup(e,{isCreatingFolders:t}),this.#T()}addAssetToGroup(e,t){this.#e.addAssetToGroup(e,t)}pauseAllUploads(){let e=this.#W();this.#b=!0;try{for(let t of Object.values(this.#e.uploadAssets))t.groupId||this.pauseUpload(t.assetId);for(let t of Object.values(this.#e.uploadGroups))t.isCreatingFolders||this.pauseUploadGroup(t.id)}finally{this.#b=!1}this.#n?.("upload:all_paused",e),this.#T()}resumeAllUploads(){let e=this.#W();this.#b=!0;try{for(let t of Object.values(this.#e.uploadAssets))!t.groupId&&t.status==="paused"&&this.resumeUpload(t.assetId);for(let t of Object.values(this.#e.uploadGroups))t.isPaused&&this.resumeUploadGroup(t.id)}finally{this.#b=!1}this.#n?.("upload:all_resumed",e),this.#T()}clearAllUploads(){this.#c=[],this.#d.clear(),this.#S.clear(),this.#y.clear(),this.#e.clearAllUploads(),this.#e.uploadGroups={},this.#D&&(this.#N=!0,this.#D.reset(),this.#N=!1),this.#r?.({all:!0}),this.#u?.(this.#z())}clearHistory(){this.#C=[],this.#i?.clear(),this.#f=!0,this.#P.clear(),this.#R=!0,this.#T()}removeHistoryItem(e){this.#C=this.#C.filter(t=>t.groupId!==e),this.#i?.remove(e),this.#P.add(e),this.#R=!0,this.#T()}removeGroup(e){this.#e.removeUploadGroup(e),this.#C=this.#C.filter(t=>t.groupId!==e),this.#i?.remove(e),this.#P.add(e),this.#R=!0,this.#r?.({groupId:e}),this.#u?.(this.#z()),this.#T()}getHttpClient(){return this.#t}setBandwidthLimit(e){this.#F=e,this.#o?.setBandwidthLimitBps(e),this.#R=!0,this.#T()}getBandwidthLimit(){return this.#F}setConflictResolution(e){this.#p=e,this.#o?.setConflictResolution(e),this.#R=!0,this.#T()}getConflictResolution(){return this.#p}getGroupConflictResolution(e){return this.#e.getUploadGroup(e)?.conflictResolution??this.#p}setMaxConcurrency(e){this.#g=e,this.#O()}#J(){return this.#F===null?null:Math.floor(this.#F/Math.max(1,this.#g))}getSnapshot(){return this.#e.updateUploadStats(),{...this.#e.getSerializableSnapshot(),uploadHistory:[...this.#C??[]],uploadSummary:this.#z(),bandwidthLimitBps:this.#F,conflictResolution:this.#p}}getUploadAsset(e){return this.#e.getSerializableAsset(e)}getUploadSummary(){return this.#z()}getGroupAssets(e){return this.#e.getGroupAssets(e)}getUploadGroupStatus(e){return this.#e.getUploadGroupStatus(e)}getUploadGroupProgress(e){return this.#e.getUploadGroupProgress(e)}hasGroupsCreatingFolders(){return this.#e.hasGroupsCreatingFolders()}areAllUploadsPaused(){return this.#e.areAllUploadsPaused()}hasPausedUploads(){return this.#e.hasPausedUploads()}hasActiveUploads(){return ae(this.#e.getSerializableSnapshot().uploadAssets)}getServerAssetIdsToCancel(){return oe(this.#e.getSerializableSnapshot().uploadAssets)}async cancelActiveServerUploads(){let e=this.getServerAssetIdsToCancel();if(e.length!==0)try{await this.#t.post("/assets/cancel-uploads",{asset_ids:e})}catch{await this.#t.post("/assets/cancel-uploads",{asset_ids:e})}}destroy(){this.#m=!0,this.#h&&(clearInterval(this.#h),this.#h=null),this.#L&&(clearInterval(this.#L),this.#L=null),this.#c=[],this.#d.clear();for(let e of Object.values(this.#e.uploadAssets))e.abortController.abort(),e.fileReader.close?.()}#G(){this.#x||(this.#x=!0,queueMicrotask(()=>{this.#x=!1,this.#Z()}))}async#Z(){if(!this.#v){for(this.#v=!0;this.#c.length>0&&!(this.#S.size>5);){let e=Math.min(this.#c.length,20-this.#S.size);if(e<=0)break;let t=[],s=[];for(let r=0;r<e&&this.#c.length>0;r++){let i=this.#c[0],o=this.#e.getUploadAsset(i);if(!o||o.status==="cancelled"){this.#c.shift(),r--;continue}if(this.#c.shift(),s.push(i),o.chunkedState)try{this.#ee(i,o),this.#O()}catch(a){D(a)||this.#M(i,a)}else t.push(i)}if(t.length>0){let r=new Map;for(let i of t){let a=this.#e.getUploadAsset(i)?.shareContext?.shareId??"",l=r.get(a);l||(l=[],r.set(a,l)),l.push(i)}for(let i of r.values())try{await this.#te(i)}catch(o){for(let a of i)this.#M(a,o instanceof Error?o:new Error(String(o)))}this.#O()}}this.#v=!1}}#ee(e,t){let s=t.chunkedState,r={serverAssetId:s.assetId,chunkIds:s.chunkIds,chunkSize:s.chunkSize,totalChunks:s.totalChunks,sizeBytes:s.sizeBytes},i=s.completedChunkIndices;this.#S.set(e,r);let o=new Array(r.totalChunks).fill(0);if(i.length>0){for(let l of i){let u=l*r.chunkSize,c=Math.min(u+r.chunkSize,t.totalBytesToUpload);o[l]=c-u}let a=o.reduce((l,u)=>l+u,0);this.#e.updateUploadProgress(e,a)}if(this.#y.set(e,o),r.totalChunks===0||i.length>=r.totalChunks){this.#j(e).catch(a=>{this.#M(e,a)});return}this.#d.registerAsset({assetId:e,totalChunks:r.totalChunks,completedChunkIndices:i})}async#te(e){let t=[],s=[];for(let a of e){let l=this.#e.getUploadAsset(a);if(!l||l.status==="cancelled")continue;let u=B(l.fileName),c=l.groupId?this.#e.getUploadGroup(l.groupId)?.conflictResolution??this.#p:this.#p,d=(()=>{switch(c){case"keep_both":return{auto_rename:"parenthesized"};case"replace":return{conflict_resolution:"replace"};case"skip":return{conflict_resolution:"skip"}}})();t.push({directory_id:l.parentId,id:a,name:u,size_bytes:l.totalBytesToUpload,...d}),s.push(a)}if(t.length===0)return;let r=this.#e.getUploadAsset(s[0]),i=r?.shareContext?P(r.shareContext):void 0,o=await this.#t.post("/assets/chunked/initiate",t,i);for(let a=0;a<s.length;a++){let l=s[a],u=o[a];if(!u||u.error){this.#M(l,new Error(u?.error??"Unknown batch initiation error"));continue}if(u.skipped){let y=this.#e.getUploadAsset(l);y&&(this.#e.adjustSpeedBaselineForSkippedBytes(y.totalBytesToUpload),this.#e.markUploadSuccess(l),this.#e.dirtyHistoryGroupIds.add(y.groupId??""),this.#$(),y.fileReader.close?.());continue}let c=u.result,d=this.#e.getUploadAsset(l);if(!d||d.status==="cancelled"||d.status==="paused"){(!d||d.status==="cancelled")&&(this.#k.push(c.asset_id),this.#K());continue}let h=Math.ceil(d.totalBytesToUpload/c.chunk_size),p=Array.from({length:h},()=>crypto.randomUUID());this.#s.seedToken(c.asset_id,c.token,c.token_expires_at);let g={serverAssetId:c.asset_id,chunkIds:p,chunkSize:c.chunk_size,totalChunks:h,sizeBytes:d.totalBytesToUpload};this.#e.setChunkedState(l,{assetId:g.serverAssetId,chunkIds:g.chunkIds,completedChunkIndices:[],chunkSize:g.chunkSize,totalChunks:g.totalChunks,sizeBytes:g.sizeBytes}),this.#S.set(l,g);let b=new Array(g.totalChunks).fill(0);if(this.#y.set(l,b),g.totalChunks===0){this.#j(l).catch(y=>{this.#M(l,y)});continue}this.#d.registerAsset({assetId:l,totalChunks:g.totalChunks,completedChunkIndices:[]})}}#O(){if(!this.#m)for(;this.#w<this.#g;){let e=this.#d.claimNextChunk();if(!e)break;this.#w++;let{assetId:t,chunkIndex:s}=e;this.#se(t,s).then(r=>{this.#w--,this.#ne(t,s,r),this.#O()}).catch(r=>{if(this.#w--,D(r)){this.#O();return}this.#ie(t,s,r),this.#O()})}}async#se(e,t){let s;for(let r=0;r<3;r++)try{let i=this.#y.get(e);return i&&(i[t]=0,this.#H(e)),await this.#re(e,t)}catch(i){if(D(i))throw i;if(s=i instanceof Error?i:new Error(String(i)),this.#D?.recordError(),this.#oe(e,t,s,r),r===2)throw s;let o=this.#y.get(e);o&&(o[t]=0,this.#H(e));let a=1e3*Math.pow(2,r);await Ze(a)}throw s||new Error("Unknown error during chunk upload")}async#re(e,t){let s=this.#e.getUploadAsset(e);if(!s)throw new E;if(s.abortController.signal.aborted)throw new E;let r=this.#S.get(e);if(!r)throw new Error(`No chunk metadata for asset ${e}`);let i=t*r.chunkSize,o=Math.min(i+r.chunkSize,s.totalBytesToUpload),a=await s.fileReader.readChunk(i,o),l=et(a);if(s.abortController.signal.aborted)throw new E;let u=r.chunkIds[t],c=await this.#s.getToken(r.serverAssetId,s.shareContext),d=`/uploads/chunks/${u}`,h=Date.now(),p=await this.#t.putWithToken(d,a,c,{signal:s.abortController.signal,onProgress:y=>{let U=this.#y.get(e);U&&(U[t]=y,this.#H(e))},contentType:"application/octet-stream",getMaxUploadRate:()=>this.#J()}),g=Date.now()-h;if(!p.status||p.status<200||p.status>=300)throw this.#a.error("Chunk upload returned unexpected status",{chunkIndex:t,chunkId:u,assetId:e,serverAssetId:r.serverAssetId,chunkSizeBytes:l,durationMs:g,httpStatus:p.status,statusText:p.statusText,responseBody:p.data,responseHeaders:p.headers}),new Error(`Chunk ${t} upload failed: unexpected status ${p.status}`);let b=this.#y.get(e);return b&&(b[t]=l,this.#H(e)),g}#H(e){let t=this.#y.get(e);if(!t)return;let s=t.reduce((r,i)=>r+i,0);this.#e.updateUploadProgress(e,s)}#ne(e,t,s){if(this.#D){let i=this.#S.get(e);if(i){let o=t*i.chunkSize,l=Math.min(o+i.chunkSize,i.sizeBytes)-o;this.#D.recordSuccess(l,s)}}this.#e.addCompletedChunkIndex(e,t),this.#d.markChunkCompleted(e,t)&&this.#j(e).catch(i=>{this.#M(e,i)})}#ie(e,t,s){this.#M(e,s)}#oe(e,t,s,r){if(!this.#n)return;let i=this.#e.getUploadAsset(e);if(!i)return;let o=this.#S.get(e);if(!o)return;let a=t*o.chunkSize,u=Math.min(a+o.chunkSize,o.sizeBytes)-a,c=s,d=typeof c.code=="string"?c.code:null,h=c.response?.status,p=typeof h=="number"?h:null,g=s.cause?s.cause instanceof Error?s.cause.message:String(s.cause):null;this.#n("upload:chunk_error",{file_name:i.fileName,file_size:i.totalBytesToUpload,chunk_index:t,chunk_size:u,chunks_total:o.totalChunks,attempt:r+1,max_attempts:3,is_final_attempt:r===2,error_type:s.name,error_message:s.message,error_code:d,http_status:p,error_stack:s.stack??null,error_cause:g,project_id:i.projectId??""})}#ae(e,t,s,r){if(!this.#n||D(t))return;let i=t instanceof Error?t.message:"Unknown error",o=t,a=t instanceof Error&&t.cause?t.cause instanceof Error?t.cause.message:String(t.cause):null,l=typeof o.code=="string"?o.code:null,u=o.response?.status,c=typeof u=="number"?u:null,d=this.#S.get(e.assetId);this.#n("upload:file_error",{file_name:e.fileName,file_size:e.totalBytesToUpload,bytes_uploaded:e.bytesUploaded,chunks_completed:e.chunkedState?.completedChunkIndices.length??0,chunks_total:d?.totalChunks??0,attempt:s+1,max_attempts:4,is_final_attempt:r,error_type:t instanceof Error?t.name:"Unknown",error_message:i,error_code:l,http_status:c,error_stack:t instanceof Error?t.stack??null:null,error_cause:a,project_id:e.projectId??""})}async#j(e){let t=this.#e.getUploadAsset(e);if(!t)return;let s=this.#S.get(e);if(!s)return;if(t.abortController.signal.aborted)throw new E;let r=crypto.randomUUID(),i=JSON.stringify(s.chunkIds),o=new TextEncoder().encode(i),a=await this.#s.getToken(s.serverAssetId,t.shareContext),l=`/uploads/manifests/${r}`;try{await this.#t.putWithToken(l,o,a,{signal:t.abortController.signal,contentType:"application/json"})}catch(u){throw this.#a.error("Manifest upload failed",{assetId:e,serverAssetId:s.serverAssetId,manifestId:r},u),u}if(t.abortController.signal.aborted)throw new E;try{let u=t.shareContext?P(t.shareContext):void 0;await this.#t.post(`/assets/${s.serverAssetId}/revisions/commit`,{manifest_id:r,size_bytes:s.sizeBytes,is_initial_upload:!0,client_performed_at:new Date().toISOString()},u)}catch(u){throw this.#a.error("Commit revision failed",{assetId:e,serverAssetId:s.serverAssetId,manifestId:r,sizeBytes:s.sizeBytes},u),u}this.#e.markUploadSuccess(e),this.#e.clearChunkedState(e),this.#$(),this.#T(),this.#S.delete(e),this.#y.delete(e),this.#d.removeAsset(e),await t.fileReader.close?.(),this.#V(e),this.#G(),this.#q()}#M(e,t){let s=this.#e.getUploadAsset(e);if(!s||s.status==="paused"||s.status==="cancelled")return;let r=s.retryCount,i=r>=3||Je(t);if(this.#ae(s,t,r,i),i){let o=t instanceof Error?t.message:"Unknown error";this.#a.error("Asset upload permanently failed",{assetId:e,fileName:s.fileName,totalRetries:r,bytesUploaded:s.bytesUploaded,totalBytes:s.totalBytesToUpload,chunksCompleted:s.chunkedState?.completedChunkIndices.length??0},t),s.abortController.abort(),this.#e.markUploadFailed(e,o),this.#d.removeAsset(e),this.#S.delete(e),this.#y.delete(e),this.#$(),this.#T(),this.#V(e),this.#G(),this.#q()}else{this.#a.warn("Asset upload failed, scheduling retry",{assetId:e,fileName:s.fileName,retryAttempt:r+1,maxRetries:3},t);let o=s.chunkedState;s.abortController.abort(),this.#d.removeAsset(e),this.#S.delete(e),this.#y.delete(e),this.#e.resetAssetForRetryQueue(e),this.#T(),this.#G();let a=2e3*Math.pow(2,r);setTimeout(()=>{if(this.#m)return;let l=this.#e.getUploadAsset(e);!l||l.status!=="queued"||this.startUpload({fileReader:l.fileReader,directoryId:l.parentId??"",projectId:l.projectId,groupId:l.groupId,assetId:e,resumeChunked:o,shareContext:l.shareContext})},a)}}#q(){this.#D&&(this.hasActiveUploads()||(this.#N=!0,this.#D.reset(),this.#N=!1))}#K(){this.#_||(this.#_=!0,queueMicrotask(()=>{this.#_=!1;let e=this.#k.splice(0);e.length!==0&&this.#t.post("/assets/cancel-uploads",{asset_ids:e}).catch(t=>{this.#a.error("Failed to batch abort uploads",{assetIds:e},t)})}))}#z(){return w(this.#e.getSerializableSnapshot().uploadAssets)}#T(){this.#U||(this.#U=!0,queueMicrotask(()=>{this.#U=!1,this.#ue()}))}#le(){this.#Q(!0)}#ue(){this.#Q(!1)}#Q(e){if(this.#m||!this.#l&&!this.#u)return;e?this.#e.updateUploadStats():(this.#B++,this.#B%3===0&&this.#e.updateUploadStats());let t=this.#e.getDirtyDelta();if(!this.#R&&Object.keys(t.assets).length===0&&Object.keys(t.groups).length===0&&this.#e.dirtyHistoryGroupIds.size===0)return;this.#R=!1,this.#e.dirtyHistoryGroupIds.size>0&&this.#$();let r=this.#e.dirtyHistoryGroupIds.size>0?this.#de():void 0,i=this.#f?!0:void 0,o=this.#P.size>0?[...this.#P]:void 0;this.#f=!1,this.#P.clear();let a=this.#z(),l={assets:t.assets,groups:t.groups,uploadStats:{...this.#e.uploadStats},uploadSpeedState:this.#e.uploadSpeedState,historyItems:r,removedHistoryGroupIds:o,historyCleared:i,uploadSummary:a,bandwidthLimitBps:this.#F,conflictResolution:this.#p};this.#e.clearDirtyFlags(),this.#l?.(l),this.#u?.(a)}#Y(e){let t=0,s=0,r=0;for(let i of e.assetIds){let o=this.#e.getUploadAsset(i);o&&(t+=o.totalBytesToUpload,s+=o.bytesUploaded,o.status!=="success"&&o.status!=="failed"&&o.status!=="cancelled"&&r++)}return{totalBytes:t,bytesUploaded:s,filesRemaining:r}}#W(){let e=0,t=0,s=0,r=0;for(let i of Object.values(this.#e.uploadGroups)){e++;for(let o of i.assetIds){let a=this.#e.getUploadAsset(o);a&&(a.status==="success"||a.status==="failed"||a.status==="cancelled"||(t++,s+=a.totalBytesToUpload,r+=a.bytesUploaded))}}return{group_count:e,file_count:t,total_bytes:s,bytes_uploaded:r}}#ce(){if(!(!this.#n||this.#m))for(let e of Object.values(this.#e.uploadGroups)){let t=!1,s=0,r=0,i=0,o=0,a=0,l=0,u=0,c=0,d=0,h=0;for(let b of e.assetIds){let y=this.#e.getUploadAsset(b);if(!y)continue;let U=y.totalBytesToUpload;switch(s+=U,r+=y.bytesUploaded,y.status){case"success":i++,o+=U;break;case"failed":a++,l+=U;break;case"cancelled":u++,c+=U;break;case"in-progress":d++,t=!0;break;case"queued":h++,t=!0;break;case"paused":t=!0;break}}if(!t)continue;let p=this.#E.get(e.id),g=p?Date.now()-p:0;this.#n("upload:group_progress",{group_id:e.id,file_count:e.assetIds.length,total_bytes:s,bytes_uploaded:r,duration_ms:g,project_id:e.projectId,succeeded_count:i,succeeded_bytes:o,failed_count:a,failed_bytes:l,cancelled_count:u,cancelled_bytes:c,in_progress_count:d,queued_count:h,progress:s>0?r/s:0,concurrency:this.#g,upload_speed_mbps:this.#e.uploadStats.uploadSpeedMbps})}}#X(e,t,s){if(!this.#n)return;let{totalBytes:r,bytesUploaded:i}=this.#Y(t);this.#n(s,{file_count:t.fileCount,total_bytes:r,bytes_uploaded:i,project_id:t.projectId})}#V(e){if(!this.#n)return;let t=this.#e.getUploadAsset(e);if(!t?.groupId)return;let s=this.#e.uploadGroups[t.groupId];if(!s)return;let r=!0,i=0,o=0,a=0,l=0,u=0,c=0,d=0;for(let g of s.assetIds){let b=this.#e.getUploadAsset(g);if(!b)continue;let y=b.totalBytesToUpload;if(d+=y,b.status==="success")i++,o+=y;else if(b.status==="failed")a++,l+=y;else if(b.status==="cancelled")u++,c+=y;else{r=!1;break}}if(!r)return;let h=this.#E.get(s.id),p=h?Date.now()-h:0;this.#n("upload:group_completed",{file_count:s.assetIds.length,total_bytes:d,duration_ms:p,project_id:s.projectId,succeeded_count:i,succeeded_bytes:o,failed_count:a,failed_bytes:l,cancelled_count:u,cancelled_bytes:c}),this.#E.delete(s.id)}#de(){let e={};for(let t of this.#e.dirtyHistoryGroupIds){let s=this.#e.buildHistoryItem(t);s&&(e[t]=s)}return e}#$(){if(!this.#i)return;let e={};for(let t of this.#e.dirtyHistoryGroupIds){let s=this.#e.buildHistoryItem(t);if(s){e[t]=s;let r=this.#C.findIndex(i=>i.groupId===t);r>=0?this.#C[r]=s:this.#C.unshift(s)}}Object.keys(e).length>0&&this.#i.merge(e)}};var O=class{#t=65536;#s=0;async*createIterator(e,t,s){let r=0,i=Math.max(65536,Math.min(e.byteLength,this.#t)),o=this.#s;for(;r<e.byteLength;){if(s?.aborted)return;let a=Math.min(r+i,e.byteLength),l=e.subarray(r,a),u=l.byteLength,c=performance.now();yield l;let d=performance.now()-c;r=a;let h=t();if(h!==null&&h>0){let p=Math.round(h*50/1e3);if(i=Math.max(65536,Math.min(e.byteLength,p)),r<e.byteLength){let b=u/h*1e3-d;b>1&&await new Promise(y=>setTimeout(y,b))}}else{if(d>=.5){let p=u/d*1e3;o=o===0?p:o*(1-.3)+p*.3}else o===0&&(i=Math.min(e.byteLength,i*2));if(o>0){let p=Math.round(o*50/1e3);i=Math.max(65536,Math.min(e.byteLength,p))}}this.#t=i,this.#s=o}}};function C(n){let e=n.replace(/\\/g,"/");if(e.split("/").some(i=>i===".."))throw new Error(`Remote path cannot contain parent directory segments: ${n}`);let r=T.posix.normalize(e).replace(/^\/+/,"");if(r===""||r===".")throw new Error(`Remote path must resolve to a file path: ${n}`);return r}function Ee(n){let e=new Map;for(let i of n){let o=C(i.targetPath??i.path);e.set(o,(e.get(o)??0)+1)}let t=new Set,s=[],r=[];for(let i of n){let o=C(i.path),a=C(i.targetPath??i.path),l=M(a),u=pe(l,t),c=(e.get(a)??0)>1,d=u!==o;t.add(u),s.push({...i,targetPath:u,requiresIdentityDownload:i.requiresIdentityDownload===!0||c}),(d||c)&&r.push({sourcePath:i.path,targetPath:u,reason:c||u!==l?"duplicate":"sanitized"})}return{files:s,changes:r}}function F(n){return C(n.targetPath??n.path)}function Te(n,e){let t=F(n);return{relativePath:t,absolutePath:T.join(e,t),fileName:T.posix.basename(t),size:n.size}}function M(n){return n.split("/").map(t=>B(t)).join("/")}function pe(n,e){if(!e.has(n))return n;let t=T.posix.dirname(n),s=T.posix.basename(n),r=T.posix.extname(s),i=r.length>0?s.slice(0,-r.length):s,o=2;for(;;){let a=`${i} (${o})${r}`,l=t==="."?a:`${t}/${a}`;if(!e.has(l))return l;o+=1}}function me(n,e){if(!e.has(n))return n;let t=T.posix.dirname(n),s=T.posix.basename(n),r=2;for(;;){let i=`${s} ${r}`,o=t==="."?i:`${t}/${i}`;if(!e.has(o))return o;r+=1}}var A=class extends Error{constructor(t,s){super(t);this.stderr=s;this.name="RcloneError"}stderr};function tt(n){let e=["sync",n.remoteSource,n.localPath];return n.batchFilePath&&e.push("--files-from",n.batchFilePath),e.push("--progress","--stats","1s","--stats-one-line","-v","--transfers",String(n.rcloneOptions.transfers),"--checkers",String(n.rcloneOptions.checkers),"--multi-thread-streams",String(n.rcloneOptions.multiThreadStreams),"--multi-thread-chunk-size",n.rcloneOptions.multiThreadChunkSize,"--multi-thread-cutoff",n.rcloneOptions.multiThreadCutoff,"--fast-list","--buffer-size",n.rcloneOptions.bufferSize),n.rcloneOptions.useMmap&&e.push("--use-mmap"),n.rcloneOptions.extraRcloneArgs?.length&&e.push(...n.rcloneOptions.extraRcloneArgs),e}function st(n){let e=["lsjson",n.remoteSource,"--recursive","--fast-list"];return n.extraArgs?.length&&e.push(...n.extraArgs),e}function rt(n){let e=["backend","query",`${n.remote}:`,n.query];return n.extraArgs?.length&&e.push(...n.extraArgs),e}function nt(n){let e=["copyto",n.remoteFileSource,n.localTargetPath,"--progress","--stats","1s","--stats-one-line","-v","--multi-thread-streams",String(n.rcloneOptions.multiThreadStreams),"--multi-thread-chunk-size",n.rcloneOptions.multiThreadChunkSize,"--multi-thread-cutoff",n.rcloneOptions.multiThreadCutoff,"--buffer-size",n.rcloneOptions.bufferSize];return n.rcloneOptions.useMmap&&e.push("--use-mmap"),n.rcloneOptions.extraRcloneArgs?.length&&e.push(...n.rcloneOptions.extraRcloneArgs),e}function it(n){let e=["backend","copyid",`${n.remote}:`,n.fileId,n.localTargetPath];return n.rcloneOptions.extraRcloneArgs?.length&&e.push(...n.rcloneOptions.extraRcloneArgs),e}function k(n,e){let t=e.trim(),s={B:1,k:1024,Ki:1024,KiB:1024,kB:1e3,M:1024*1024,Mi:1024*1024,MiB:1024*1024,MB:1e3*1e3,G:1024*1024*1024,Gi:1024*1024*1024,GiB:1024*1024*1024,GB:1e3*1e3*1e3,T:1024*1024*1024*1024,Ti:1024*1024*1024*1024,TiB:1024*1024*1024*1024,TB:1e3*1e3*1e3*1e3};return n*(s[t]||1)}function Ue(n){let e=0,t=n.match(/(\d+)h/),s=n.match(/(\d+)m/),r=n.match(/(\d+)s/);return t&&(e+=parseInt(t[1],10)*3600),s&&(e+=parseInt(s[1],10)*60),r&&(e+=parseInt(r[1],10)),e}function ot(n){let e=n.trim(),t=/^([\d.]+)\s*([A-Za-z]+)\s*\/\s*([\d.]+)\s*([A-Za-z]+),\s*([\d.]+)%?,\s*([\d.]+)\s*([A-Za-z]+)\/s,\s*ETA\s+(.+)$/,s=e.match(t);if(s){let a=s[8].trim();return{bytesTransferred:k(parseFloat(s[1]),s[2]),totalBytes:k(parseFloat(s[3]),s[4]),percentComplete:parseFloat(s[5]),speed:k(parseFloat(s[6]),s[7]),eta:a==="-"?0:Ue(a)}}let r=e.match(/Transferred:\s+([\d.]+)\s*([A-Za-z]+)\s*\/\s*([\d.]+)\s*([A-Za-z]+),\s*([\d.]+)%/);if(!r)return null;let i=e.match(/([\d.]+)\s*([A-Za-z]+)\/s/),o=e.match(/ETA\s+([^\s]+)$/);return{bytesTransferred:k(parseFloat(r[1]),r[2]),totalBytes:k(parseFloat(r[3]),r[4]),percentComplete:parseFloat(r[5]),speed:i?k(parseFloat(i[1]),i[2]):0,eta:o&&o[1]!=="-"?Ue(o[1]):0}}function ge(n){return new Promise((e,t)=>{let s=Y("rclone",n.args,{stdio:["ignore","pipe","pipe"]}),r="",i=0,o=a=>{for(let l of a.split(`
3
- `)){if(l.trim().length===0)continue;let u=ot(l);if(!u)continue;let c=Date.now();!(u.percentComplete>=100)&&c-i<500||(i=c,n.onProgress?.(u))}};s.stdout.on("data",a=>{o(a.toString())}),s.stderr.on("data",a=>{let l=a.toString();r+=l,o(l)}),s.on("close",async a=>{a===0?e():t(new A(`rclone exited with code ${a}`,r))}),s.on("error",a=>{t(new A(`Failed to start rclone: ${a.message}`,""))})})}async function fe(){return new Promise((n,e)=>{let t=Y("rclone",["version"]);t.on("error",()=>{e(new Error("rclone is not installed or not in PATH. Please install rclone first: https://rclone.org/install/"))}),t.on("close",s=>{s===0?n():e(new Error("rclone is not installed or not in PATH. Please install rclone first: https://rclone.org/install/"))})})}async function at(n,e,t,s,r,i){let o=`${n}:${e}`;return ge({args:tt({remoteSource:o,localPath:t,rcloneOptions:r,batchFilePath:s}),remoteSource:o,onProgress:i})}async function X(n,e,t=[]){let s=`${n}:${e}`;return new Promise((r,i)=>{let o=Y("rclone",st({remoteSource:s,extraArgs:t})),a="",l="";o.stdout.on("data",u=>{a+=u.toString()}),o.stderr.on("data",u=>{l+=u.toString()}),o.on("close",async u=>{if(u===0)try{let c=JSON.parse(a||"[]");if(!Array.isArray(c))throw new Error("rclone lsjson did not return an array");let d=lt(c),h=await ut({remote:n,files:d.files,directories:d.directories,extraArgs:t});r(h)}catch(c){i(new A(`Failed to parse file listing from ${s}: ${c instanceof Error?c.message:String(c)}`,l))}else i(new A(`Failed to list files from ${s}`,l))}),o.on("error",u=>{i(new A(`Failed to start rclone: ${u.message}`,""))})})}async function Pe(n){let e=[],t=[];for(let s of n.files)gt(s)?t.push(s):e.push(s);e.length>0&&(await N.promises.writeFile(n.batchFilePath,`${e.map(s=>s.path).join(`
2
+ import{Command as Ht}from"commander";import $e from"node:path";import{readFileSync as zt}from"node:fs";import{fileURLToPath as $t}from"node:url";import qe from"node:os";import be from"node:path";var We="phc_rDzmwduU3NzHyELgLEg7nMjqpTgaSpC2a6tMKL8VyjN",Ke="https://t.aspect.inc",Ye="https://t.aspect.inc";function Qe(n){let e=n.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)$/i);if(!e)return null;let t=parseFloat(e[1]),s=e[2].toUpperCase(),r={B:1,KB:1024,MB:1024*1024,GB:1024*1024*1024,TB:1024*1024*1024*1024};return t*(r[s]||1)}function Ee(n){let e=n.options.apiKey||n.environment.ASPECT_API_KEY||"";if(!e)throw new Error("Error: --api-key is required (or set ASPECT_API_KEY env variable)");let t=ie({value:n.options.rcloneTransfers,optionName:"--rclone-transfers"}),s=ie({value:n.options.rcloneMultiThreadStreams,optionName:"--rclone-multi-thread-streams"}),r=ie({value:n.options.uploadConcurrent,optionName:"--upload-concurrent"}),i=Xe(n.options.batchSize),o=n.options.session??Ve({now:n.now??new Date,highResolutionTime:n.highResolutionTime??process.hrtime.bigint()}),a=n.options.tempDir||be.join(qe.homedir(),".aspect","sync");return{remote:n.options.remote,remotePath:n.options.path,directoryId:n.options.directoryId,projectId:n.options.projectId,apiUrl:n.options.apiUrl||n.environment.ASPECT_API_URL||"https://api.aspect.inc",edgeWorkerUrl:n.options.edgeWorkerUrl||n.environment.ASPECT_EDGE_WORKER_URL||"https://mackinac.aspect.inc",apiKey:e,maxConcurrent:r,keepLocal:n.options.keepLocal,localTempDir:be.join(a,o),sessionName:o,rcloneOptions:{transfers:t,checkers:t>=16?Math.floor(t/4):t,multiThreadStreams:s,multiThreadChunkSize:n.options.rcloneMultiThreadChunkSize,multiThreadCutoff:n.options.rcloneMultiThreadCutoff,bufferSize:n.options.rcloneBufferSize,useMmap:!n.options.rcloneNoMmap,extraRcloneArgs:n.options.rcloneExtra},batchSizeBytes:i,analytics:{posthogKey:n.environment.ASPECT_POSTHOG_KEY||n.environment.POSTHOG_KEY||n.environment.POSTHOG_API_KEY||We,posthogHost:n.environment.ASPECT_POSTHOG_HOST||n.environment.POSTHOG_HOST||Ke||Ye,disabled:Ae(n.environment.ASPECT_DISABLE_POSTHOG)||Ae(n.environment.POSTHOG_DISABLED)}}}function ie(n){let e=parseInt(n.value,10);if(Number.isNaN(e)||e<1)throw new Error(`Error: ${n.optionName} must be a positive integer`);return e}function Xe(n){if(!n)return;let e=Qe(n);if(e===null)throw new Error(`Error: Invalid batch size format: ${n}`);return e}function Ae(n){return n?["1","true","yes"].includes(n.toLowerCase()):!1}function Ve(n){let e=n.now.getFullYear(),t=String(n.now.getMonth()+1).padStart(2,"0"),s=String(n.now.getDate()).padStart(2,"0"),r=String(n.now.getHours()).padStart(2,"0"),i=String(n.now.getMinutes()).padStart(2,"0"),o=String(n.now.getSeconds()).padStart(2,"0"),a=n.highResolutionTime%1000000000n,l=String(a).padStart(9,"0");return`${e}-${t}-${s}_${r}h-${i}m-${o}s-${l}ns`}import $ from"node:fs/promises";import re from"node:path";import{spawn as X}from"child_process";import*as G from"fs";import*as E from"path";import R from"node:path";function j(n,e){if(e.length===0)return"queued";if(n.isCreatingFolders)return"creating-folders";let t={queued:0,paused:0,inProgress:0,success:0,failed:0,cancelled:0};for(let r of e)switch(r.status){case"queued":t.queued++;break;case"paused":t.paused++;break;case"in-progress":t.inProgress++;break;case"success":t.success++;break;case"failed":t.failed++;break;case"cancelled":t.cancelled++;break}let s=e.length;return t.failed===s?"all-failed":t.failed>0?"some-failed":t.success===s?"success":t.paused>0&&t.queued===0&&t.inProgress===0?"paused":t.queued>0||t.inProgress>0?t.queued+t.paused===s?"queued":"in-progress":"cancelled"}function oe(n,e){let t=j(n,e);return t==="creating-folders"||t==="in-progress"||t==="queued"||t==="paused"?"cancelled":t}function ae(n){let e=[];for(let t of Object.values(n))t.chunkedState&&(t.status==="queued"||t.status==="in-progress"||t.status==="paused")&&e.push(t.chunkedState.assetId);return e}function le(n){for(let e of Object.values(n))if(e.status==="queued"||e.status==="in-progress"||e.status==="paused")return!0;return!1}function w(n){let t=Object.values(n).reduce((s,r)=>{switch(r.status!=="failed"&&r.status!=="cancelled"&&(s.totalBytesToUpload+=r.totalBytesToUpload,s.totalBytesUploaded+=r.bytesUploaded),s.totalAssetCount+=1,r.status){case"queued":s.queuedAssetCount+=1;break;case"paused":s.pausedAssetCount+=1;break;case"in-progress":s.inProgressAssetCount+=1;break;case"success":s.successAssetCount+=1;break;case"failed":s.failedAssetCount+=1;break;case"cancelled":s.cancelledAssetCount+=1;break}return s},{totalBytesToUpload:0,totalBytesUploaded:0,totalAssetCount:0,queuedAssetCount:0,pausedAssetCount:0,inProgressAssetCount:0,successAssetCount:0,failedAssetCount:0,cancelledAssetCount:0,hasActiveUploads:!1,progress:0});return t.hasActiveUploads=t.totalAssetCount-t.successAssetCount-t.failedAssetCount-t.cancelledAssetCount>0,t.progress=t.hasActiveUploads?t.totalBytesUploaded/t.totalBytesToUpload:0,t}function ue(n,e){if(e.length===0)return null;let t=e.reduce((s,r)=>(r.status!=="failed"&&r.status!=="cancelled"&&(s.totalBytes+=r.totalBytesToUpload,s.uploadedBytes+=r.bytesUploaded),r.status==="success"?s.filesSucceeded++:r.status==="failed"&&s.filesFailed++,(r.status==="success"||r.status==="failed"||r.status==="cancelled")&&s.filesCompleted++,s),{totalBytes:0,uploadedBytes:0,filesCompleted:0,filesSucceeded:0,filesTotal:e.length,filesFailed:0,percentage:0});return t.percentage=t.totalBytes>0?t.uploadedBytes/t.totalBytes*100:0,t}function ce(n){let e=Object.values(n).filter(t=>t.status==="queued"||t.status==="in-progress"||t.status==="paused");return e.length===0?!1:e.every(t=>t.status==="paused")}function de(n){return Object.values(n).some(e=>e.status==="paused")}import es from"axios";var x=class{#t;#s;#e;#i;#o;#n=0;#a=0;#l=0;#r=0;#u=0;#A=0;constructor(e){this.#t=e?.alphaFast??.1,this.#s=e?.alphaMax??.5,this.#e=e?.consecutiveForBoost??3,this.#i=e?.minSamples??3,this.#o=e?.maxGapSeconds??2}sample(e){let t=Date.now();if(this.#r===0){this.#r=t,this.#u=e;return}let r=(t-this.#r)/1e3,i=e-this.#u;if(r<=0||i<0)return;if(r>this.#o){this.#r=t,this.#u=e;return}let o=i/r;if(this.#A===0)this.#n=o;else{let l=o-this.#n>=0?1:-1;this.#l!==0&&l===this.#l?this.#a++:this.#a=0,this.#l=l;let u=Math.min(1,this.#a/this.#e),c=this.#t+(this.#s-this.#t)*u;this.#n=c*o+(1-c)*this.#n}this.#r=t,this.#u=e,this.#A++}etaSeconds(e){return!this.isWarmedUp||this.#n<=0?0:e/this.#n}adjustTotalBytes(e){this.#u+=e}reset(){this.#n=0,this.#a=0,this.#l=0,this.#r=0,this.#u=0,this.#A=0}serialize(){return{displaySpeedBps:this.#n,lastSampleTimestamp:this.#r,lastSampleTotalBytes:this.#u,sampleCount:this.#A}}get speedBps(){return this.#n}get speedMbps(){return this.#n*8/1e6}get isWarmedUp(){return this.#A>=this.#i}};function P(n){let e={"X-Aspect-Share-Id":n.shareId};return n.shareAuthentication&&(e["X-Aspect-Share-Authentication"]=n.shareAuthentication),e}var D=class{#t;#s;#e;#i;#o;#n;#a;#l;#r;#u;#A;#g;#k;#h;#D;#U;#b;#P;#f;#m;#E;#c;#v;#w;#d;#_;#S;#y;#F;#x;#I;#p;#T;constructor(e){this.#s=e?.minConcurrency??1,this.#e=e?.maxConcurrency??8,this.#t=e?.initialConcurrency??this.#s,this.#i=e?.errorThreshold??1,this.#o=(e?.cooldownSeconds??10)*1e3,this.#n=e?.plateauThreshold??.05,this.#a=e?.onChange,this.#l=e?.now??Date.now,this.#r=this.#t,this.#u="probing",this.#A=0,this.#g=0,this.#k=0,this.#h=0,this.#D=!1,this.#U=0,this.#b=0,this.#P=1/0,this.#x=0,this.#I=0,this.#p=0,this.#T=0,this.#f=1/0,this.#m=0,this.#E=3e4,this.#c=0,this.#v=0,this.#w=0,this.#d=0,this.#_=0,this.#S=0,this.#y=0,this.#F=0}recordSuccess(e,t){if(e<=0)return;if(this.#U>0){this.#U--;return}this.#h++,this.#x+=e;let s=this.#l();if(this.#I===0){this.#I=s;return}let r=s-this.#I;if(r>=200){let c=this.#x/r*1e3;this.#T===0?this.#p=c:this.#p=.3*c+(1-.3)*this.#p,this.#T++,this.#T>=5&&(this.#w=Math.max(this.#w,this.#p)),this.#x=0,this.#I=s}if(t!==void 0&&t>0&&e>0){let c=t/(e/1048576);this.#_===0?this.#d=c:this.#d=.3*c+(1-.3)*this.#d,this.#_++}if(this.#u==="cooldown"&&s>=this.#A&&(this.#u="probing"),this.#u!=="probing")return;if(this.#g>0){let c;if(this.#T>=25?c=.03:this.#T>=15?c=.04:this.#T>=5&&(c=.07),c!==void 0&&(this.#p-this.#g)/this.#g<=-c){this.#y=0,this.#F=0,this.#O();return}}let i=this.#D?this.#r*2:this.#r;if(this.#h<i)return;if(this.#k=0,this.#T<5){this.#h=0;return}let o=this.#f<1/0&&this.#l()<this.#m?this.#f-1:this.#e,a=Math.min(this.#e,this.#P-1,o);if(this.#r>=a){if(this.#f<1/0&&this.#p>0&&this.#c>0){let c=(this.#p-this.#c)/this.#c;if(c>.2){this.#f=1/0,this.#m=0,this.#E=3e4,this.#c=0,this.#v=0,this.#h=0;return}if(c<=-.07){this.#h=0;return}}if(this.#w>0&&this.#p>0&&this.#T>=5&&(this.#w-this.#p)/this.#w>.07){this.#f=1/0,this.#m=0,this.#E=3e4,this.#c=0,this.#v=0,this.#w=this.#p,this.#h=0;return}if(this.#v>0&&this.#d>0&&this.#_>=2&&(this.#v-this.#d)/this.#v>.2){this.#f=1/0,this.#m=0,this.#E=3e4,this.#c=0,this.#v=0,this.#h=0;return}this.#h=0;return}let l=this.#p;if(this.#g>0){let c=Math.max(.02,this.#n*3/this.#r),d=(l-this.#g)/this.#g;if(d<=-.07){this.#y=0,this.#F=0,this.#O();return}else if(d<c){if(this.#_>=2&&this.#S>0){let h=this.#d/this.#S,p=this.#r/(this.#r-1);if(h<p*.9){this.#h=0;return}}if(this.#y++,this.#y<3){this.#h=0;return}this.#y=0,this.#F=0,this.#O();return}else if(d<c*2){if(this.#F++,this.#F<2){this.#h=0;return}this.#y=0,this.#F=0}else this.#y=0,this.#F=0;this.#f<1/0&&(this.#f=1/0,this.#m=0,this.#E=3e4,this.#c=0,this.#v=0)}this.#S=this.#d,this.#y=0,this.#F=0;let u=this.#r;this.#r++,this.#g=l,this.#h=0,this.#U=Math.max(0,u-1),this.#x=0,this.#I=0,this.#p=0,this.#T=0,this.#d=0,this.#_=0,this.#a?.(this.#r)}#O(){let e=Math.max(this.#s,this.#r-1);e<this.#r&&(this.#f=Math.min(this.#f,this.#r),this.#m=this.#l()+this.#E,this.#E=Math.min(this.#E*2,12e4),this.#c=this.#g,this.#v=this.#S,this.#r=e,this.#g=0,this.#x=0,this.#I=0,this.#p=0,this.#T=0,this.#d=0,this.#_=0,this.#a?.(this.#r)),this.#h=0}recordError(){if(this.#U>0&&this.#U--,this.#k++,this.#k<this.#i)return;this.#r===this.#b&&(this.#P=Math.min(this.#P,this.#r)),this.#b=this.#r;let e=this.#r;this.#r=Math.max(this.#s,Math.floor(this.#r/2)),this.#u="cooldown",this.#A=this.#l()+this.#o,this.#D=!0,this.#k=0,this.#h=0,this.#U=0,this.#g=0,this.#x=0,this.#I=0,this.#p=0,this.#T=0,this.#d=0,this.#_=0,this.#S=0,this.#y=0,this.#F=0,this.#r!==e&&this.#a?.(this.#r)}get concurrency(){return this.#r}get speedBps(){return this.#p}get latencyMsPerMB(){return this.#d}reset(){this.#r=this.#t,this.#u="probing",this.#A=0,this.#g=0,this.#k=0,this.#h=0,this.#D=!1,this.#U=0,this.#b=0,this.#P=1/0,this.#f=1/0,this.#m=0,this.#E=3e4,this.#c=0,this.#v=0,this.#w=0,this.#d=0,this.#_=0,this.#S=0,this.#y=0,this.#F=0,this.#x=0,this.#I=0,this.#p=0,this.#T=0,this.#a?.(this.#r)}};function Re(n){let e=`[${n}]`;return{info:(...t)=>console.info(e,...t),warn:(...t)=>console.warn(e,...t),error:(...t)=>console.error(e,...t)}}var he=Re("transfer");var q=class{uploadAssets={};uploadGroups={};#t=new x;get uploadSpeedState(){return this.#t.serialize()}uploadStats={uploadSpeedMbps:0,timeRemainingSeconds:0,formattedSpeed:"Calculating...",formattedTime:"Calculating..."};dirtyAssetIds=new Set;dirtyGroupIds=new Set;dirtyHistoryGroupIds=new Set;#s(e){e!==0&&this.#t.adjustTotalBytes(-e)}adjustSpeedBaselineForSkippedBytes(e){e!==0&&this.#t.adjustTotalBytes(e)}#e(){Object.values(this.uploadAssets).some(t=>t.status==="queued"||t.status==="in-progress")||this.#t.reset()}#i(e){this.dirtyAssetIds.add(e)}#o(e){this.dirtyGroupIds.add(e)}addUploadAsset({assetId:e,fileReader:t,abortController:s,parentId:r,projectId:i,groupId:o,chunkSize:a,shareContext:l}){this.uploadAssets[e]={assetId:e,totalBytesToUpload:t.size,bytesUploaded:0,status:"queued",fileName:t.name,createdAt:new Date().toISOString(),i:Object.keys(this.uploadAssets).length,parentId:r,projectId:i,groupId:o,retryCount:0,chunkSize:a??0,fileReader:t,abortController:s,shareContext:l},this.#i(e)}updateUploadProgress(e,t){let s=this.uploadAssets[e];if(!s||s.status==="paused"||s.status==="cancelled"||s.status==="success"||s.status==="failed")return;let r=t>0&&s.status==="queued"?"in-progress":s.status,i=Math.min(t,s.totalBytesToUpload);s.bytesUploaded=i,s.status=r,this.#i(e)}markUploadInProgress(e){let t=this.uploadAssets[e];t&&(t.status="in-progress",this.#i(e))}markUploadSuccess(e){let t=this.uploadAssets[e];t&&(t.status="success",t.bytesUploaded=t.totalBytesToUpload,this.#i(e),this.#e(),this.cleanupOnCompletion(e))}markUploadFailed(e,t){let s=this.uploadAssets[e];if(!s)return;let r=s.bytesUploaded;s.status="failed",s.errorMessage=t,s.bytesUploaded=0,this.#i(e),this.#s(r),this.#e(),this.cleanupOnCompletion(e)}removeUploadAsset(e){let s=this.uploadAssets[e]?.bytesUploaded??0;delete this.uploadAssets[e],this.#i(e),this.#s(s),this.#e()}clearAllUploads(){this.uploadAssets={},this.#t.reset()}clearTerminalState(){if(!Object.values(this.uploadAssets).some(t=>t.status==="queued"||t.status==="in-progress"||t.status==="paused")){for(let t of Object.keys(this.uploadAssets))delete this.uploadAssets[t];for(let t of Object.keys(this.uploadGroups))delete this.uploadGroups[t];this.#t.reset()}}resetAssetForRetryQueue(e){let t=this.uploadAssets[e];t&&(t.status="queued",t.bytesUploaded=0,t.errorMessage=void 0,t.retryCount=t.retryCount+1,this.#i(e))}resetAssetForRetrying(e){let t=this.uploadAssets[e];t&&(t.status="queued",t.bytesUploaded=0,t.retryCount=0,this.#i(e))}pauseUpload(e){let t=this.uploadAssets[e];if(!t||t.status!=="queued"&&t.status!=="in-progress")return;let s=0;if(t.chunkedState){let{completedChunkIndices:i,chunkSize:o}=t.chunkedState;for(let a of i){let l=a*o,u=Math.min(l+o,t.totalBytesToUpload);s+=u-l}}let r=t.bytesUploaded-s;t.status="paused",t.bytesUploaded=s,this.#i(e),this.#s(r),this.#e(),t.abortController.abort()}unpauseUpload(e){let t=this.uploadAssets[e];t&&t.status==="paused"&&(t.status="queued",this.#i(e))}pauseUploadGroup(e){let t=this.uploadGroups[e];if(t&&!t.isCreatingFolders){t.isPaused=!0,this.#o(e);for(let s of t.assetIds)this.pauseUpload(s)}}unpauseUploadGroup(e){let t=this.uploadGroups[e];t&&(t.isPaused=!1,this.#o(e))}pauseAllUploads(){for(let e of Object.values(this.uploadGroups))e.isCreatingFolders||this.pauseUploadGroup(e.id)}resumeAllUploads(){for(let e of Object.values(this.uploadGroups))e.isPaused&&this.unpauseUploadGroup(e.id)}markUploadCancelled(e){let t=this.uploadAssets[e];if(!t||t.status==="success"||t.status==="failed"||t.status==="cancelled")return;let s=t.bytesUploaded;t.status="cancelled",this.#i(e),this.#s(s),this.#e(),this.cleanupOnCompletion(e)}setChunkedState(e,t){let s=this.uploadAssets[e];s&&(s.chunkedState=t,this.#i(e))}addCompletedChunkIndex(e,t){let s=this.uploadAssets[e];!s||!s.chunkedState||(s.chunkedState={...s.chunkedState,completedChunkIndices:[...s.chunkedState.completedChunkIndices,t]},this.#i(e))}clearChunkedState(e){let t=this.uploadAssets[e];t&&(t.chunkedState=void 0,this.#i(e))}hasGroupsCreatingFolders(){return Object.values(this.uploadGroups).some(e=>e.isCreatingFolders===!0)}areAllUploadsPaused(){return ce(this.uploadAssets)}hasPausedUploads(){return de(this.uploadAssets)}getUploadAsset(e){return this.uploadAssets[e]}getSerializableAsset(e){let t=this.uploadAssets[e];if(t)return this.#l(t)}getUploadSummary(){return w(this.#u())}getAllUploadAssetsSortedByRecent(){return Object.values(this.uploadAssets).map(e=>this.#l(e)).sort((e,t)=>t.i-e.i)}getGroupAssets(e){let t=this.uploadGroups[e];return!t||!t.assetIds?[]:t.assetIds.map(s=>this.uploadAssets[s]).filter(Boolean).map(s=>this.#l(s))}getGroupAssetsInternal(e){let t=this.uploadGroups[e];return!t||!t.assetIds?[]:t.assetIds.map(s=>this.uploadAssets[s]).filter(Boolean)}addUploadGroup(e){let t=crypto.randomUUID();return this.uploadGroups[t]={...e,id:t,fileReaders:new Map},this.#o(t),t}updateUploadGroup(e,t){let s=this.uploadGroups[e];s&&(Object.assign(s,t),this.#o(e))}addAssetToGroup(e,t){let s=this.uploadGroups[e];s&&(s.assetIds.push(t),this.#o(e))}removeUploadGroup(e){let t=this.uploadGroups[e];if(t)for(let s of t.assetIds)delete this.uploadAssets[s],this.#i(s);delete this.uploadGroups[e],this.#o(e)}getUploadGroup(e){let t=this.uploadGroups[e];if(t)return this.#r(t)}getAllUploadGroups(){return Object.values(this.uploadGroups).map(e=>this.#r(e)).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}getUploadGroupProgress(e){let t=this.uploadGroups[e];if(!t)return null;let s=this.getGroupAssets(e);return ue(this.#r(t),s)}getUploadGroupStatus(e){let t=this.uploadGroups[e];if(!t)return null;let s=this.getGroupAssets(e);return s.length>0?j(this.#r(t),s):null}getAssetsByParentId(e){return Object.values(this.uploadAssets).filter(t=>t.parentId===e).map(t=>this.#l(t))}getActiveUploadGroups(){return Object.values(this.uploadGroups).filter(e=>{let t=this.getUploadGroupStatus(e.id);return t&&["queued","creating-folders","in-progress"].includes(t)}).map(e=>this.#r(e))}cleanupOnCompletion(e){let t=this.uploadAssets[e];if(!t)return;let s=t.groupId;if(s){let i=this.uploadGroups[s];if(i){let o=this.getGroupAssets(s),a=this.#r(i);this.dirtyHistoryGroupIds.add(s),!o.some(u=>u.status==="queued"||u.status==="in-progress")&&!i.completedAt&&(i.completedAt=new Date().toISOString(),this.#o(s))}}let r=this.getUploadSummary();if(r.cancelledAssetCount+r.failedAssetCount+r.successAssetCount===r.totalAssetCount)for(let i of Object.keys(this.uploadAssets)){let o=this.uploadAssets[i];o&&(o.bytesUploaded=0,this.#i(i))}}updateUploadStats(){let e=this.getUploadSummary(),t=e.queuedAssetCount>0||e.inProgressAssetCount>0;t&&this.#t.sample(e.totalBytesUploaded);let s=this.#t.isWarmedUp?this.#t.speedMbps:0,r=t&&this.#t.isWarmedUp?this.#t.etaSeconds(e.totalBytesToUpload-e.totalBytesUploaded):0;this.uploadStats={uploadSpeedMbps:s,timeRemainingSeconds:r,formattedSpeed:this.#n(s),formattedTime:this.#a(r)}}#n(e){return!Number.isFinite(e)||e<=0?"Calculating...":e<1?`${(e*1e3).toFixed(0)} Kbps`:`${e.toFixed(1)} Mbps`}#a(e){if(!Number.isFinite(e)||e<=0)return"Calculating...";let t=Math.floor(e/3600),s=Math.floor(e%3600/60),r=Math.floor(e%60);return t>0?`${t}h ${s}m left`:s>0?`${s}m ${r}s left`:`${r}s left`}buildHistoryItem(e){let t=this.uploadGroups[e];if(!t)return null;let s=this.getGroupAssets(e),r=this.#r(t);return{groupId:t.id,name:t.name,type:t.type,fileCount:t.fileCount,folderCount:t.folderCount,topLevelFileCount:t.topLevelFileCount,topLevelFolderCount:t.topLevelFolderCount,status:oe(r,s),createdAt:t.createdAt,completedAt:t.completedAt,rootDirectoryId:t.rootDirectoryId,projectId:t.projectId,errorMessage:t.errorMessage,conflictResolution:t.conflictResolution}}#l({fileReader:e,abortController:t,shareContext:s,...r}){return r}#r({fileReaders:e,...t}){return t}#u(){let e={};for(let[t,s]of Object.entries(this.uploadAssets))e[t]=this.#l(s);return e}#A(){let e={};for(let[t,s]of Object.entries(this.uploadGroups))e[t]=this.#r(s);return e}getSerializableSnapshot(){return{uploadAssets:this.#u(),uploadGroups:this.#A(),uploadStats:{...this.uploadStats},uploadSpeedState:this.uploadSpeedState}}getDirtyDelta(){let e={};for(let s of this.dirtyAssetIds){let r=this.uploadAssets[s];r&&(e[s]=this.#l(r))}let t={};for(let s of this.dirtyGroupIds){let r=this.uploadGroups[s];r&&(t[s]=this.#r(r))}return{assets:e,groups:t}}clearDirtyFlags(){this.dirtyAssetIds.clear(),this.dirtyGroupIds.clear(),this.dirtyHistoryGroupIds.clear()}};function et(n,e){let t=new Date(n).getTime(),s=Date.now();return t-s<=e}var W=class{#t;#s=new Map;#e=new Map;constructor(e){this.#t=e}seedToken(e,t,s){this.#s.set(e,{token:t,expiresAt:s})}async getToken(e,t){let s=this.#s.get(e);if(s&&!et(s.expiresAt,3e5))return s.token;let r=this.#e.get(e);if(r)return r;let i=t?P(t):void 0,o=this.#t.post(`/assets/${e}/token`,{},i).then(a=>{if(!a.token)throw new Error("Token refresh failed: no token in response");return this.#s.set(e,{token:a.token,expiresAt:a.token_expires_at}),this.#e.delete(e),a.token}).catch(a=>{throw this.#e.delete(e),a});return this.#e.set(e,o),o}clearCache(e){e?this.#s.delete(e):this.#s.clear()}};var K=class{#t=[];registerAsset(e){this.#t.push({assetId:e.assetId,totalChunks:e.totalChunks,nextChunkToClaim:0,completedChunkIndices:new Set(e.completedChunkIndices),isPaused:!1})}claimNextChunk(){for(let e of this.#t)if(!e.isPaused)for(;e.nextChunkToClaim<e.totalChunks;){let t=e.nextChunkToClaim;if(e.nextChunkToClaim++,!e.completedChunkIndices.has(t))return{assetId:e.assetId,chunkIndex:t}}return null}markChunkCompleted(e,t){let s=this.#s(e);return s?(s.completedChunkIndices.add(t),s.completedChunkIndices.size>=s.totalChunks):!1}pauseAsset(e){let t=this.#s(e);t&&(t.isPaused=!0)}unpauseAsset(e){let t=this.#s(e);t&&(t.isPaused=!1,this.#e(t))}removeAsset(e){this.#t=this.#t.filter(t=>t.assetId!==e)}hasAsset(e){return this.#t.some(t=>t.assetId===e)}clear(){this.#t=[]}#s(e){return this.#t.find(t=>t.assetId===e)}#e(e){for(let t=0;t<e.totalChunks;t++)if(!e.completedChunkIndices.has(t)){e.nextChunkToClaim=t;return}e.nextChunkToClaim=e.totalChunks}};var tt=/[/\\:*?"<>|\x00-\x1F]/g,st=["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"];function B(n){let e=n.replace(tt,"_");e=e.replace(/[. ]+$/,""),(!e||e==="."||e==="..")&&(e="unnamed");let t=e.includes(".")?e.substring(0,e.lastIndexOf(".")):e;st.includes(t.toUpperCase())&&(e=`_${e}`);let s=new TextEncoder;if(s.encode(e).length>255){let r=e.lastIndexOf("."),i=r>0?e.substring(r):"",o=r>0?e.substring(0,r):e,l=255-s.encode(i).length;for(;s.encode(o).length>l&&o.length>0;)o=o.slice(0,-1);e=o+i}return e}var T=class extends Error{constructor(){super("Upload cancelled"),this.name="CancelledError"}};function O(n){return n instanceof T||n instanceof Error&&n.name==="CancelledError"||n instanceof Error&&n.name==="CanceledError"||n instanceof Error&&n.name==="AbortError"}function ut(n){return O(n)||n instanceof Error&&n.name==="NoAuthError"}function ct(n){return new Promise(e=>setTimeout(e,n))}function dt(n){return n instanceof Blob?n.size:n.byteLength}var L=class{#t;#s;#e;#i;#o;#n;#a;#l;#r;#u;#A;#g;#k;#h=null;#D=0;#U=!1;#b=[];#P=new Set;#f=!1;#m=!1;#E=!1;#c=[];#v=!1;#w=!1;#d=new K;#_=0;#S=new Map;#y=new Map;#F=[];#x=!1;#I=null;#p="keep_both";#T=new Map;#O=null;#C=!1;#B=null;#N=!1;constructor(e){this.#t=e.httpClient,this.#s=new W(e.httpClient),this.#e=new q,this.#i=e.historyStore??null,this.#o=e.settingsStore??null,this.#n=e.analytics??null,this.#a=e.logger??he,this.#l=e.onChange??null,this.#r=e.onClear??null,this.#u=e.onSummary??null,this.#A=e.onConcurrencyAdjusted??null,this.#k=e.deltaIntervalMs??333;let t=e.maxConcurrency??4;if(e.adaptiveConcurrency!==!1){let s=e.adaptiveConcurrencyConfig;this.#B=new D({initialConcurrency:s?.initialConcurrency??Math.min(2,t),minConcurrency:s?.minConcurrency??1,maxConcurrency:s?.maxConcurrency??t,errorThreshold:s?.errorThreshold,cooldownSeconds:s?.cooldownSeconds??10,plateauThreshold:s?.plateauThreshold,onChange:r=>{let i=this.#g;if(this.setMaxConcurrency(r),i===r)return;let o=this.#N?"reset":r>i?"probe_increase":"error_decrease",a=Math.round(this.#B.speedBps/(1024*1024)*100)/100,l=Math.round(this.#B.latencyMsPerMB*100)/100;this.#a.info(`Adaptive concurrency: ${i} \u2192 ${r} (${o}), speed=${a}MB/s, latency=${l}ms/MB`),this.#A?.({previousConcurrency:i,newConcurrency:r,reason:o,speedMbps:a,latencyMsPerMB:l})},now:s?.now}),this.#g=this.#B.concurrency}else this.#g=t;this.#i&&(this.#b=this.#i.load()),this.#o&&(this.#I=this.#o.getBandwidthLimitBps(),this.#p=this.#o.getConflictResolution()),(this.#l||this.#u)&&(this.#h=setInterval(()=>{this.#le()},this.#k)),this.#n&&(this.#O=setInterval(()=>{this.#ce()},6e4))}startUpload(e){let t=e.assetId||crypto.randomUUID(),s=!!e.assetId,r;if(s){let o=this.#e.getUploadAsset(t);if(!o)throw new Error(`Cannot retry: asset ${t} not found`);r=o.chunkSize}else{if(e.chunkSize===void 0||e.chunkSize===null)throw new Error("chunkSize is required for new uploads");r=e.chunkSize}let i=new AbortController;if(s){if(this.#e.getUploadAsset(t).status==="cancelled")return t;e.resetRetryCount&&this.#e.resetAssetForRetrying(t);let a=this.#e.getUploadAsset(t);a.abortController=i,a.fileReader=e.fileReader,e.shareContext&&(a.shareContext=e.shareContext)}else this.#e.addUploadAsset({assetId:t,fileReader:e.fileReader,abortController:i,parentId:e.directoryId,projectId:e.projectId,groupId:e.groupId,chunkSize:r,shareContext:e.shareContext});return this.#c.push(t),this.#G(),this.#R(),t}startGroupUpload(e){this.#e.clearTerminalState();let t=this.#e.addUploadGroup({type:e.type,name:e.name,assetIds:[],fileCount:e.fileCount,folderCount:e.folderCount,topLevelFileCount:e.topLevelFileCount,topLevelFolderCount:e.topLevelFolderCount,isCreatingFolders:!1,isPaused:!1,createdAt:new Date().toISOString(),rootDirectoryId:e.rootDirectoryId,projectId:e.projectId,retryCount:0,conflictResolution:e.conflictResolutionOverride??this.#p});return this.#T.set(t,Date.now()),this.#n?.("upload:started",{file_count:e.fileCount,total_bytes:e.totalBytes??0,has_folders:e.folderCount>0,project_id:e.projectId}),this.#e.dirtyHistoryGroupIds.add(t),this.#z(),this.#R(),t}pauseUpload(e){let t=this.#e.getUploadAsset(e);this.#e.pauseUpload(e),this.#c=this.#c.filter(s=>s!==e),this.#d.pauseAsset(e),!this.#C&&t&&this.#n&&this.#n("upload:file_paused",{file_name:t.fileName,file_size:t.totalBytesToUpload,bytes_uploaded:t.bytesUploaded,project_id:t.projectId??""}),this.#R()}unpauseUpload(e){this.#e.unpauseUpload(e),this.#R()}cancelUpload(e){let t=this.#e.getUploadAsset(e);if(!t||t.status==="success"||t.status==="failed"||t.status==="cancelled")return;let s=t.fileName,r=t.totalBytesToUpload,i=t.bytesUploaded,o=t.projectId,a=t.chunkedState?.assetId;(t.status==="queued"||t.status==="in-progress")&&t.abortController.abort(),this.#c=this.#c.filter(l=>l!==e),this.#d.removeAsset(e),this.#S.delete(e),this.#y.delete(e),this.#e.markUploadCancelled(e),this.#e.clearChunkedState(e),t.fileReader.close?.(),!this.#C&&this.#n&&this.#n("upload:file_cancelled",{file_name:s,file_size:r,bytes_uploaded:i,project_id:o??""}),this.#R(),this.#L(),this.#G(),this.#q(),a&&(this.#F.push(a),this.#K())}cancelAllUploads(){let e=this.#W();this.#C=!0;try{let s=Object.values(this.#e.uploadAssets).filter(r=>r.status==="queued"||r.status==="in-progress"||r.status==="paused");for(let r of s)this.cancelUpload(r.assetId)}finally{this.#C=!1}this.#n?.("upload:all_cancelled",e)}retryUpload(e){let t=this.#e.getUploadAsset(e);t&&t.status==="failed"&&this.startUpload({fileReader:t.fileReader,directoryId:t.parentId??"",projectId:t.projectId,groupId:t.groupId,assetId:e,resumeChunked:t.chunkedState,resetRetryCount:!0,shareContext:t.shareContext})}resumeUpload(e){let t=this.#e.getUploadAsset(e);if(!t||t.status!=="paused")return;!this.#C&&this.#n&&this.#n("upload:file_resumed",{file_name:t.fileName,file_size:t.totalBytesToUpload,bytes_uploaded:t.bytesUploaded,project_id:t.projectId??""});let s=new AbortController;t.abortController=s,this.#e.unpauseUpload(e),this.#d.hasAsset(e)?(this.#d.unpauseAsset(e),this.#R(),this.#L()):this.startUpload({fileReader:t.fileReader,directoryId:t.parentId??"",projectId:t.projectId,groupId:t.groupId,assetId:e,resumeChunked:t.chunkedState,shareContext:t.shareContext})}pauseUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;let s=this.#C;this.#C=!0,this.#e.pauseUploadGroup(e);for(let r of t.assetIds)this.#c=this.#c.filter(i=>i!==r),this.#d.pauseAsset(r);this.#C=s,this.#C||this.#X(e,t,"upload:group_paused"),this.#R()}unpauseUploadGroup(e){this.#e.unpauseUploadGroup(e),this.#R()}cancelUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;let{totalBytes:s,bytesUploaded:r,filesRemaining:i}=this.#Q(t),o=this.#C;this.#C=!0;for(let a of t.assetIds)this.cancelUpload(a);this.#C=o,this.#C||this.#n?.("upload:group_cancelled",{file_count:t.assetIds.length,files_remaining:i,total_bytes:s,bytes_uploaded:r,project_id:t.projectId}),this.#T.delete(e)}resumeUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;this.#C||this.#X(e,t,"upload:group_resumed");let s=this.#C;this.#C=!0,this.#e.unpauseUploadGroup(e);for(let r of t.assetIds){let i=this.#e.getUploadAsset(r);i&&i.status==="paused"&&this.resumeUpload(r)}this.#C=s}retryUploadGroup(e){let t=this.#e.uploadGroups[e];if(t)for(let s of t.assetIds){let r=this.#e.getUploadAsset(s);r&&r.status==="failed"&&this.retryUpload(s)}}setGroupCreatingFolders(e,t){this.#e.updateUploadGroup(e,{isCreatingFolders:t}),this.#R()}addAssetToGroup(e,t){this.#e.addAssetToGroup(e,t)}pauseAllUploads(){let e=this.#W();this.#C=!0;try{for(let t of Object.values(this.#e.uploadAssets))t.groupId||this.pauseUpload(t.assetId);for(let t of Object.values(this.#e.uploadGroups))t.isCreatingFolders||this.pauseUploadGroup(t.id)}finally{this.#C=!1}this.#n?.("upload:all_paused",e),this.#R()}resumeAllUploads(){let e=this.#W();this.#C=!0;try{for(let t of Object.values(this.#e.uploadAssets))!t.groupId&&t.status==="paused"&&this.resumeUpload(t.assetId);for(let t of Object.values(this.#e.uploadGroups))t.isPaused&&this.resumeUploadGroup(t.id)}finally{this.#C=!1}this.#n?.("upload:all_resumed",e),this.#R()}clearAllUploads(){this.#c=[],this.#d.clear(),this.#S.clear(),this.#y.clear(),this.#e.clearAllUploads(),this.#e.uploadGroups={},this.#B&&(this.#N=!0,this.#B.reset(),this.#N=!1),this.#r?.({all:!0}),this.#u?.(this.#H())}clearHistory(){this.#b=[],this.#i?.clear(),this.#f=!0,this.#P.clear(),this.#E=!0,this.#R()}removeHistoryItem(e){this.#b=this.#b.filter(t=>t.groupId!==e),this.#i?.remove(e),this.#P.add(e),this.#E=!0,this.#R()}removeGroup(e){this.#e.removeUploadGroup(e),this.#b=this.#b.filter(t=>t.groupId!==e),this.#i?.remove(e),this.#P.add(e),this.#E=!0,this.#r?.({groupId:e}),this.#u?.(this.#H()),this.#R()}getHttpClient(){return this.#t}setBandwidthLimit(e){this.#I=e,this.#o?.setBandwidthLimitBps(e),this.#E=!0,this.#R()}getBandwidthLimit(){return this.#I}setConflictResolution(e){this.#p=e,this.#o?.setConflictResolution(e),this.#E=!0,this.#R()}getConflictResolution(){return this.#p}getGroupConflictResolution(e){return this.#e.getUploadGroup(e)?.conflictResolution??this.#p}setMaxConcurrency(e){this.#g=e,this.#L()}#J(){return this.#I===null?null:Math.floor(this.#I/Math.max(1,this.#g))}getSnapshot(){return this.#e.updateUploadStats(),{...this.#e.getSerializableSnapshot(),uploadHistory:[...this.#b??[]],uploadSummary:this.#H(),bandwidthLimitBps:this.#I,conflictResolution:this.#p}}getUploadAsset(e){return this.#e.getSerializableAsset(e)}getUploadSummary(){return this.#H()}getGroupAssets(e){return this.#e.getGroupAssets(e)}getUploadGroupStatus(e){return this.#e.getUploadGroupStatus(e)}getUploadGroupProgress(e){return this.#e.getUploadGroupProgress(e)}hasGroupsCreatingFolders(){return this.#e.hasGroupsCreatingFolders()}areAllUploadsPaused(){return this.#e.areAllUploadsPaused()}hasPausedUploads(){return this.#e.hasPausedUploads()}hasActiveUploads(){return le(this.#e.getSerializableSnapshot().uploadAssets)}getServerAssetIdsToCancel(){return ae(this.#e.getSerializableSnapshot().uploadAssets)}async cancelActiveServerUploads(){let e=this.getServerAssetIdsToCancel();if(e.length!==0)try{await this.#t.post("/assets/cancel-uploads",{asset_ids:e})}catch{await this.#t.post("/assets/cancel-uploads",{asset_ids:e})}}destroy(){this.#m=!0,this.#h&&(clearInterval(this.#h),this.#h=null),this.#O&&(clearInterval(this.#O),this.#O=null),this.#c=[],this.#d.clear();for(let e of Object.values(this.#e.uploadAssets))e.abortController.abort(),e.fileReader.close?.()}#G(){this.#w||(this.#w=!0,queueMicrotask(()=>{this.#w=!1,this.#Z()}))}async#Z(){if(!this.#v){for(this.#v=!0;this.#c.length>0&&!(this.#S.size>5);){let e=Math.min(this.#c.length,20-this.#S.size);if(e<=0)break;let t=[],s=[];for(let r=0;r<e&&this.#c.length>0;r++){let i=this.#c[0],o=this.#e.getUploadAsset(i);if(!o||o.status==="cancelled"){this.#c.shift(),r--;continue}if(this.#c.shift(),s.push(i),o.chunkedState)try{this.#ee(i,o),this.#L()}catch(a){O(a)||this.#M(i,a)}else t.push(i)}if(t.length>0){let r=new Map;for(let i of t){let a=this.#e.getUploadAsset(i)?.shareContext?.shareId??"",l=r.get(a);l||(l=[],r.set(a,l)),l.push(i)}for(let i of r.values())try{await this.#te(i)}catch(o){for(let a of i)this.#M(a,o instanceof Error?o:new Error(String(o)))}this.#L()}}this.#v=!1}}#ee(e,t){let s=t.chunkedState,r={serverAssetId:s.assetId,chunkIds:s.chunkIds,chunkSize:s.chunkSize,totalChunks:s.totalChunks,sizeBytes:s.sizeBytes},i=s.completedChunkIndices;this.#S.set(e,r);let o=new Array(r.totalChunks).fill(0);if(i.length>0){for(let l of i){let u=l*r.chunkSize,c=Math.min(u+r.chunkSize,t.totalBytesToUpload);o[l]=c-u}let a=o.reduce((l,u)=>l+u,0);this.#e.updateUploadProgress(e,a)}if(this.#y.set(e,o),r.totalChunks===0||i.length>=r.totalChunks){this.#j(e).catch(a=>{this.#M(e,a)});return}this.#d.registerAsset({assetId:e,totalChunks:r.totalChunks,completedChunkIndices:i})}async#te(e){let t=[],s=[];for(let a of e){let l=this.#e.getUploadAsset(a);if(!l||l.status==="cancelled")continue;let u=B(l.fileName),c=l.groupId?this.#e.getUploadGroup(l.groupId)?.conflictResolution??this.#p:this.#p,d=(()=>{switch(c){case"keep_both":return{auto_rename:"parenthesized"};case"replace":return{conflict_resolution:"replace"};case"skip":return{conflict_resolution:"skip"}}})();t.push({directory_id:l.parentId,id:a,name:u,size_bytes:l.totalBytesToUpload,...d}),s.push(a)}if(t.length===0)return;let r=this.#e.getUploadAsset(s[0]),i=r?.shareContext?P(r.shareContext):void 0,o=await this.#t.post("/assets/chunked/initiate",t,i);for(let a=0;a<s.length;a++){let l=s[a],u=o[a];if(!u||u.error){this.#M(l,new Error(u?.error??"Unknown batch initiation error"));continue}if(u.skipped){let y=this.#e.getUploadAsset(l);y&&(this.#e.adjustSpeedBaselineForSkippedBytes(y.totalBytesToUpload),this.#e.markUploadSuccess(l),this.#e.dirtyHistoryGroupIds.add(y.groupId??""),this.#z(),y.fileReader.close?.());continue}let c=u.result,d=this.#e.getUploadAsset(l);if(!d||d.status==="cancelled"||d.status==="paused"){(!d||d.status==="cancelled")&&(this.#F.push(c.asset_id),this.#K());continue}let h=Math.ceil(d.totalBytesToUpload/c.chunk_size),p=Array.from({length:h},()=>crypto.randomUUID());this.#s.seedToken(c.asset_id,c.token,c.token_expires_at);let g={serverAssetId:c.asset_id,chunkIds:p,chunkSize:c.chunk_size,totalChunks:h,sizeBytes:d.totalBytesToUpload};this.#e.setChunkedState(l,{assetId:g.serverAssetId,chunkIds:g.chunkIds,completedChunkIndices:[],chunkSize:g.chunkSize,totalChunks:g.totalChunks,sizeBytes:g.sizeBytes}),this.#S.set(l,g);let C=new Array(g.totalChunks).fill(0);if(this.#y.set(l,C),g.totalChunks===0){this.#j(l).catch(y=>{this.#M(l,y)});continue}this.#d.registerAsset({assetId:l,totalChunks:g.totalChunks,completedChunkIndices:[]})}}#L(){if(!this.#m)for(;this.#_<this.#g;){let e=this.#d.claimNextChunk();if(!e)break;this.#_++;let{assetId:t,chunkIndex:s}=e;this.#se(t,s).then(r=>{this.#_--,this.#ne(t,s,r),this.#L()}).catch(r=>{if(this.#_--,O(r)){this.#L();return}this.#ie(t,s,r),this.#L()})}}async#se(e,t){let s;for(let r=0;r<3;r++)try{let i=this.#y.get(e);return i&&(i[t]=0,this.#$(e)),await this.#re(e,t)}catch(i){if(O(i))throw i;if(s=i instanceof Error?i:new Error(String(i)),this.#B?.recordError(),this.#oe(e,t,s,r),r===2)throw s;let o=this.#y.get(e);o&&(o[t]=0,this.#$(e));let a=1e3*Math.pow(2,r);await ct(a)}throw s||new Error("Unknown error during chunk upload")}async#re(e,t){let s=this.#e.getUploadAsset(e);if(!s)throw new T;if(s.abortController.signal.aborted)throw new T;let r=this.#S.get(e);if(!r)throw new Error(`No chunk metadata for asset ${e}`);let i=t*r.chunkSize,o=Math.min(i+r.chunkSize,s.totalBytesToUpload),a=await s.fileReader.readChunk(i,o),l=dt(a);if(s.abortController.signal.aborted)throw new T;let u=r.chunkIds[t],c=await this.#s.getToken(r.serverAssetId,s.shareContext),d=`/uploads/chunks/${u}`,h=Date.now(),p=await this.#t.putWithToken(d,a,c,{signal:s.abortController.signal,onProgress:y=>{let U=this.#y.get(e);U&&(U[t]=y,this.#$(e))},contentType:"application/octet-stream",getMaxUploadRate:()=>this.#J()}),g=Date.now()-h;if(!p.status||p.status<200||p.status>=300)throw this.#a.error("Chunk upload returned unexpected status",{chunkIndex:t,chunkId:u,assetId:e,serverAssetId:r.serverAssetId,chunkSizeBytes:l,durationMs:g,httpStatus:p.status,statusText:p.statusText,responseBody:p.data,responseHeaders:p.headers}),new Error(`Chunk ${t} upload failed: unexpected status ${p.status}`);let C=this.#y.get(e);return C&&(C[t]=l,this.#$(e)),g}#$(e){let t=this.#y.get(e);if(!t)return;let s=t.reduce((r,i)=>r+i,0);this.#e.updateUploadProgress(e,s)}#ne(e,t,s){if(this.#B){let i=this.#S.get(e);if(i){let o=t*i.chunkSize,l=Math.min(o+i.chunkSize,i.sizeBytes)-o;this.#B.recordSuccess(l,s)}}this.#e.addCompletedChunkIndex(e,t),this.#d.markChunkCompleted(e,t)&&this.#j(e).catch(i=>{this.#M(e,i)})}#ie(e,t,s){this.#M(e,s)}#oe(e,t,s,r){if(!this.#n)return;let i=this.#e.getUploadAsset(e);if(!i)return;let o=this.#S.get(e);if(!o)return;let a=t*o.chunkSize,u=Math.min(a+o.chunkSize,o.sizeBytes)-a,c=s,d=typeof c.code=="string"?c.code:null,h=c.response?.status,p=typeof h=="number"?h:null,g=s.cause?s.cause instanceof Error?s.cause.message:String(s.cause):null;this.#n("upload:chunk_error",{file_name:i.fileName,file_size:i.totalBytesToUpload,chunk_index:t,chunk_size:u,chunks_total:o.totalChunks,attempt:r+1,max_attempts:3,is_final_attempt:r===2,error_type:s.name,error_message:s.message,error_code:d,http_status:p,error_stack:s.stack??null,error_cause:g,project_id:i.projectId??""})}#ae(e,t,s,r){if(!this.#n||O(t))return;let i=t instanceof Error?t.message:"Unknown error",o=t,a=t instanceof Error&&t.cause?t.cause instanceof Error?t.cause.message:String(t.cause):null,l=typeof o.code=="string"?o.code:null,u=o.response?.status,c=typeof u=="number"?u:null,d=this.#S.get(e.assetId);this.#n("upload:file_error",{file_name:e.fileName,file_size:e.totalBytesToUpload,bytes_uploaded:e.bytesUploaded,chunks_completed:e.chunkedState?.completedChunkIndices.length??0,chunks_total:d?.totalChunks??0,attempt:s+1,max_attempts:4,is_final_attempt:r,error_type:t instanceof Error?t.name:"Unknown",error_message:i,error_code:l,http_status:c,error_stack:t instanceof Error?t.stack??null:null,error_cause:a,project_id:e.projectId??""})}async#j(e){let t=this.#e.getUploadAsset(e);if(!t)return;let s=this.#S.get(e);if(!s)return;if(t.abortController.signal.aborted)throw new T;let r=crypto.randomUUID(),i=JSON.stringify(s.chunkIds),o=new TextEncoder().encode(i),a=await this.#s.getToken(s.serverAssetId,t.shareContext),l=`/uploads/manifests/${r}`;try{await this.#t.putWithToken(l,o,a,{signal:t.abortController.signal,contentType:"application/json"})}catch(u){throw this.#a.error("Manifest upload failed",{assetId:e,serverAssetId:s.serverAssetId,manifestId:r},u),u}if(t.abortController.signal.aborted)throw new T;try{let u=t.shareContext?P(t.shareContext):void 0;await this.#t.post(`/assets/${s.serverAssetId}/revisions/commit`,{manifest_id:r,size_bytes:s.sizeBytes,is_initial_upload:!0,client_performed_at:new Date().toISOString()},u)}catch(u){throw this.#a.error("Commit revision failed",{assetId:e,serverAssetId:s.serverAssetId,manifestId:r,sizeBytes:s.sizeBytes},u),u}this.#e.markUploadSuccess(e),this.#e.clearChunkedState(e),this.#z(),this.#R(),this.#S.delete(e),this.#y.delete(e),this.#d.removeAsset(e),await t.fileReader.close?.(),this.#V(e),this.#G(),this.#q()}#M(e,t){let s=this.#e.getUploadAsset(e);if(!s||s.status==="paused"||s.status==="cancelled")return;let r=s.retryCount,i=r>=3||ut(t);if(this.#ae(s,t,r,i),i){let o=t instanceof Error?t.message:"Unknown error";this.#a.error("Asset upload permanently failed",{assetId:e,fileName:s.fileName,totalRetries:r,bytesUploaded:s.bytesUploaded,totalBytes:s.totalBytesToUpload,chunksCompleted:s.chunkedState?.completedChunkIndices.length??0},t),s.abortController.abort(),this.#e.markUploadFailed(e,o),this.#d.removeAsset(e),this.#S.delete(e),this.#y.delete(e),this.#z(),this.#R(),this.#V(e),this.#G(),this.#q()}else{this.#a.warn("Asset upload failed, scheduling retry",{assetId:e,fileName:s.fileName,retryAttempt:r+1,maxRetries:3},t);let o=s.chunkedState;s.abortController.abort(),this.#d.removeAsset(e),this.#S.delete(e),this.#y.delete(e),this.#e.resetAssetForRetryQueue(e),this.#R(),this.#G();let a=2e3*Math.pow(2,r);setTimeout(()=>{if(this.#m)return;let l=this.#e.getUploadAsset(e);!l||l.status!=="queued"||this.startUpload({fileReader:l.fileReader,directoryId:l.parentId??"",projectId:l.projectId,groupId:l.groupId,assetId:e,resumeChunked:o,shareContext:l.shareContext})},a)}}#q(){this.#B&&(this.hasActiveUploads()||(this.#N=!0,this.#B.reset(),this.#N=!1))}#K(){this.#x||(this.#x=!0,queueMicrotask(()=>{this.#x=!1;let e=this.#F.splice(0);e.length!==0&&this.#t.post("/assets/cancel-uploads",{asset_ids:e}).catch(t=>{this.#a.error("Failed to batch abort uploads",{assetIds:e},t)})}))}#H(){return w(this.#e.getSerializableSnapshot().uploadAssets)}#R(){this.#U||(this.#U=!0,queueMicrotask(()=>{this.#U=!1,this.#ue()}))}#le(){this.#Y(!0)}#ue(){this.#Y(!1)}#Y(e){if(this.#m||!this.#l&&!this.#u)return;e?this.#e.updateUploadStats():(this.#D++,this.#D%3===0&&this.#e.updateUploadStats());let t=this.#e.getDirtyDelta();if(!this.#E&&Object.keys(t.assets).length===0&&Object.keys(t.groups).length===0&&this.#e.dirtyHistoryGroupIds.size===0)return;this.#E=!1,this.#e.dirtyHistoryGroupIds.size>0&&this.#z();let r=this.#e.dirtyHistoryGroupIds.size>0?this.#de():void 0,i=this.#f?!0:void 0,o=this.#P.size>0?[...this.#P]:void 0;this.#f=!1,this.#P.clear();let a=this.#H(),l={assets:t.assets,groups:t.groups,uploadStats:{...this.#e.uploadStats},uploadSpeedState:this.#e.uploadSpeedState,historyItems:r,removedHistoryGroupIds:o,historyCleared:i,uploadSummary:a,bandwidthLimitBps:this.#I,conflictResolution:this.#p};this.#e.clearDirtyFlags(),this.#l?.(l),this.#u?.(a)}#Q(e){let t=0,s=0,r=0;for(let i of e.assetIds){let o=this.#e.getUploadAsset(i);o&&(t+=o.totalBytesToUpload,s+=o.bytesUploaded,o.status!=="success"&&o.status!=="failed"&&o.status!=="cancelled"&&r++)}return{totalBytes:t,bytesUploaded:s,filesRemaining:r}}#W(){let e=0,t=0,s=0,r=0;for(let i of Object.values(this.#e.uploadGroups)){e++;for(let o of i.assetIds){let a=this.#e.getUploadAsset(o);a&&(a.status==="success"||a.status==="failed"||a.status==="cancelled"||(t++,s+=a.totalBytesToUpload,r+=a.bytesUploaded))}}return{group_count:e,file_count:t,total_bytes:s,bytes_uploaded:r}}#ce(){if(!(!this.#n||this.#m))for(let e of Object.values(this.#e.uploadGroups)){let t=!1,s=0,r=0,i=0,o=0,a=0,l=0,u=0,c=0,d=0,h=0;for(let C of e.assetIds){let y=this.#e.getUploadAsset(C);if(!y)continue;let U=y.totalBytesToUpload;switch(s+=U,r+=y.bytesUploaded,y.status){case"success":i++,o+=U;break;case"failed":a++,l+=U;break;case"cancelled":u++,c+=U;break;case"in-progress":d++,t=!0;break;case"queued":h++,t=!0;break;case"paused":t=!0;break}}if(!t)continue;let p=this.#T.get(e.id),g=p?Date.now()-p:0;this.#n("upload:group_progress",{group_id:e.id,file_count:e.assetIds.length,total_bytes:s,bytes_uploaded:r,duration_ms:g,project_id:e.projectId,succeeded_count:i,succeeded_bytes:o,failed_count:a,failed_bytes:l,cancelled_count:u,cancelled_bytes:c,in_progress_count:d,queued_count:h,progress:s>0?r/s:0,concurrency:this.#g,upload_speed_mbps:this.#e.uploadStats.uploadSpeedMbps})}}#X(e,t,s){if(!this.#n)return;let{totalBytes:r,bytesUploaded:i}=this.#Q(t);this.#n(s,{file_count:t.fileCount,total_bytes:r,bytes_uploaded:i,project_id:t.projectId})}#V(e){if(!this.#n)return;let t=this.#e.getUploadAsset(e);if(!t?.groupId)return;let s=this.#e.uploadGroups[t.groupId];if(!s)return;let r=!0,i=0,o=0,a=0,l=0,u=0,c=0,d=0;for(let g of s.assetIds){let C=this.#e.getUploadAsset(g);if(!C)continue;let y=C.totalBytesToUpload;if(d+=y,C.status==="success")i++,o+=y;else if(C.status==="failed")a++,l+=y;else if(C.status==="cancelled")u++,c+=y;else{r=!1;break}}if(!r)return;let h=this.#T.get(s.id),p=h?Date.now()-h:0;this.#n("upload:group_completed",{file_count:s.assetIds.length,total_bytes:d,duration_ms:p,project_id:s.projectId,succeeded_count:i,succeeded_bytes:o,failed_count:a,failed_bytes:l,cancelled_count:u,cancelled_bytes:c}),this.#T.delete(s.id)}#de(){let e={};for(let t of this.#e.dirtyHistoryGroupIds){let s=this.#e.buildHistoryItem(t);s&&(e[t]=s)}return e}#z(){if(!this.#i)return;let e={};for(let t of this.#e.dirtyHistoryGroupIds){let s=this.#e.buildHistoryItem(t);if(s){e[t]=s;let r=this.#b.findIndex(i=>i.groupId===t);r>=0?this.#b[r]=s:this.#b.unshift(s)}}Object.keys(e).length>0&&this.#i.merge(e)}};var M=class{#t=65536;#s=0;async*createIterator(e,t,s){let r=0,i=Math.max(65536,Math.min(e.byteLength,this.#t)),o=this.#s;for(;r<e.byteLength;){if(s?.aborted)return;let a=Math.min(r+i,e.byteLength),l=e.subarray(r,a),u=l.byteLength,c=performance.now();yield l;let d=performance.now()-c;r=a;let h=t();if(h!==null&&h>0){let p=Math.round(h*50/1e3);if(i=Math.max(65536,Math.min(e.byteLength,p)),r<e.byteLength){let C=u/h*1e3-d;C>1&&await new Promise(y=>setTimeout(y,C))}}else{if(d>=.5){let p=u/d*1e3;o=o===0?p:o*(1-.3)+p*.3}else o===0&&(i=Math.min(e.byteLength,i*2));if(o>0){let p=Math.round(o*50/1e3);i=Math.max(65536,Math.min(e.byteLength,p))}}this.#t=i,this.#s=o}}};function b(n){let e=n.replace(/\\/g,"/");if(e.split("/").some(i=>i===".."))throw new Error(`Remote path cannot contain parent directory segments: ${n}`);let r=R.posix.normalize(e).replace(/^\/+/,"");if(r===""||r===".")throw new Error(`Remote path must resolve to a file path: ${n}`);return r}function Ue(n){let e=new Map;for(let i of n){let o=b(i.targetPath??i.path);e.set(o,(e.get(o)??0)+1)}let t=new Set,s=[],r=[];for(let i of n){let o=b(i.path),a=b(i.targetPath??i.path),l=N(a),u=me(l,t),c=(e.get(a)??0)>1,d=u!==o;t.add(u),s.push({...i,targetPath:u,requiresIdentityDownload:i.requiresIdentityDownload===!0||c}),(d||c)&&r.push({sourcePath:i.path,targetPath:u,reason:c||u!==l?"duplicate":"sanitized"})}return{files:s,changes:r}}function F(n){return b(n.targetPath??n.path)}function Pe(n,e){let t=F(n);return{relativePath:t,absolutePath:R.join(e,t),fileName:R.posix.basename(t),size:n.size}}function N(n){return n.split("/").map(t=>B(t)).join("/")}function me(n,e){if(!e.has(n))return n;let t=R.posix.dirname(n),s=R.posix.basename(n),r=R.posix.extname(s),i=r.length>0?s.slice(0,-r.length):s,o=2;for(;;){let a=`${i} (${o})${r}`,l=t==="."?a:`${t}/${a}`;if(!e.has(l))return l;o+=1}}function ge(n,e){if(!e.has(n))return n;let t=R.posix.dirname(n),s=R.posix.basename(n),r=2;for(;;){let i=`${s} ${r}`,o=t==="."?i:`${t}/${i}`;if(!e.has(o))return o;r+=1}}var A=class extends Error{constructor(t,s){super(t);this.stderr=s;this.name="RcloneError"}stderr};function ht(n){let e=["sync",n.remoteSource,n.localPath];return n.batchFilePath&&e.push("--files-from",n.batchFilePath),e.push("--progress","--stats","1s","--stats-one-line","-v","--transfers",String(n.rcloneOptions.transfers),"--checkers",String(n.rcloneOptions.checkers),"--multi-thread-streams",String(n.rcloneOptions.multiThreadStreams),"--multi-thread-chunk-size",n.rcloneOptions.multiThreadChunkSize,"--multi-thread-cutoff",n.rcloneOptions.multiThreadCutoff,"--fast-list","--buffer-size",n.rcloneOptions.bufferSize),n.rcloneOptions.useMmap&&e.push("--use-mmap"),n.rcloneOptions.extraRcloneArgs?.length&&e.push(...n.rcloneOptions.extraRcloneArgs),e}function pt(n){let e=["lsjson",n.remoteSource,"--recursive","--fast-list"];return n.extraArgs?.length&&e.push(...n.extraArgs),e}function mt(n){let e=["backend","query",`${n.remote}:`,n.query];return n.extraArgs?.length&&e.push(...n.extraArgs),e}function gt(n){let e=["copyto",n.remoteFileSource,n.localTargetPath,"--progress","--stats","1s","--stats-one-line","-v","--multi-thread-streams",String(n.rcloneOptions.multiThreadStreams),"--multi-thread-chunk-size",n.rcloneOptions.multiThreadChunkSize,"--multi-thread-cutoff",n.rcloneOptions.multiThreadCutoff,"--buffer-size",n.rcloneOptions.bufferSize];return n.rcloneOptions.useMmap&&e.push("--use-mmap"),n.rcloneOptions.extraRcloneArgs?.length&&e.push(...n.rcloneOptions.extraRcloneArgs),e}function ft(n){let e=["backend","copyid",`${n.remote}:`,n.fileId,n.localTargetPath];return n.rcloneOptions.extraRcloneArgs?.length&&e.push(...n.rcloneOptions.extraRcloneArgs),e}function k(n,e){let t=e.trim(),s={B:1,k:1024,Ki:1024,KiB:1024,kB:1e3,M:1024*1024,Mi:1024*1024,MiB:1024*1024,MB:1e3*1e3,G:1024*1024*1024,Gi:1024*1024*1024,GiB:1024*1024*1024,GB:1e3*1e3*1e3,T:1024*1024*1024*1024,Ti:1024*1024*1024*1024,TiB:1024*1024*1024*1024,TB:1e3*1e3*1e3*1e3};return n*(s[t]||1)}function Ie(n){let e=0,t=n.match(/(\d+)h/),s=n.match(/(\d+)m/),r=n.match(/(\d+)s/);return t&&(e+=parseInt(t[1],10)*3600),s&&(e+=parseInt(s[1],10)*60),r&&(e+=parseInt(r[1],10)),e}function yt(n){let e=n.trim(),t=/^([\d.]+)\s*([A-Za-z]+)\s*\/\s*([\d.]+)\s*([A-Za-z]+),\s*([\d.]+)%?,\s*([\d.]+)\s*([A-Za-z]+)\/s,\s*ETA\s+(.+)$/,s=e.match(t);if(s){let a=s[8].trim();return{bytesTransferred:k(parseFloat(s[1]),s[2]),totalBytes:k(parseFloat(s[3]),s[4]),percentComplete:parseFloat(s[5]),speed:k(parseFloat(s[6]),s[7]),eta:a==="-"?0:Ie(a)}}let r=e.match(/Transferred:\s+([\d.]+)\s*([A-Za-z]+)\s*\/\s*([\d.]+)\s*([A-Za-z]+),\s*([\d.]+)%/);if(!r)return null;let i=e.match(/([\d.]+)\s*([A-Za-z]+)\/s/),o=e.match(/ETA\s+([^\s]+)$/);return{bytesTransferred:k(parseFloat(r[1]),r[2]),totalBytes:k(parseFloat(r[3]),r[4]),percentComplete:parseFloat(r[5]),speed:i?k(parseFloat(i[1]),i[2]):0,eta:o&&o[1]!=="-"?Ie(o[1]):0}}function fe(n){return new Promise((e,t)=>{let s=X("rclone",n.args,{stdio:["ignore","pipe","pipe"]}),r="",i=0,o=a=>{for(let l of a.split(`
3
+ `)){if(l.trim().length===0)continue;let u=yt(l);if(!u)continue;let c=Date.now();!(u.percentComplete>=100)&&c-i<500||(i=c,n.onProgress?.(u))}};s.stdout.on("data",a=>{o(a.toString())}),s.stderr.on("data",a=>{let l=a.toString();r+=l,o(l)}),s.on("close",async a=>{a===0?e():t(new A(`rclone exited with code ${a}`,r))}),s.on("error",a=>{t(new A(`Failed to start rclone: ${a.message}`,""))})})}async function ye(){return new Promise((n,e)=>{let t=X("rclone",["version"]);t.on("error",()=>{e(new Error("rclone is not installed or not in PATH. Please install rclone first: https://rclone.org/install/"))}),t.on("close",s=>{s===0?n():e(new Error("rclone is not installed or not in PATH. Please install rclone first: https://rclone.org/install/"))})})}async function St(n,e,t,s,r,i){let o=`${n}:${e}`;return fe({args:ht({remoteSource:o,localPath:t,rcloneOptions:r,batchFilePath:s}),remoteSource:o,onProgress:i})}async function V(n,e,t=[]){let s=`${n}:${e}`;return new Promise((r,i)=>{let o=X("rclone",pt({remoteSource:s,extraArgs:t})),a="",l="";o.stdout.on("data",u=>{a+=u.toString()}),o.stderr.on("data",u=>{l+=u.toString()}),o.on("close",async u=>{if(u===0)try{let c=JSON.parse(a||"[]");if(!Array.isArray(c))throw new Error("rclone lsjson did not return an array");let d=Ct(c),h=await bt({remote:n,files:d.files,directories:d.directories,extraArgs:t});r(h)}catch(c){i(new A(`Failed to parse file listing from ${s}: ${c instanceof Error?c.message:String(c)}`,l))}else i(new A(`Failed to list files from ${s}`,l))}),o.on("error",u=>{i(new A(`Failed to start rclone: ${u.message}`,""))})})}async function Fe(n){let e=[],t=[];for(let s of n.files)Pt(s)?t.push(s):e.push(s);e.length>0&&(await G.promises.writeFile(n.batchFilePath,`${e.map(s=>s.path).join(`
4
4
  `)}
5
- `,"utf-8"),await at(n.remote,n.remotePath,n.localPath,n.batchFilePath,n.rcloneOptions,n.onProgress));for(let s of t)await ft({remote:n.remote,remotePath:n.remotePath,localPath:n.localPath,file:s,rcloneOptions:n.rcloneOptions,onProgress:n.onProgress})}function lt(n){let e=[],t=[];for(let s of n){let r=s;if(typeof r.Path!="string")continue;let i=typeof r.ID=="string"&&r.ID.length>0?r.ID:void 0;if(r.IsDir===!0){t.push({path:C(r.Path),id:i});continue}let o=typeof r.Size=="number"&&Number.isFinite(r.Size)?r.Size:0;e.push({path:C(r.Path),size:o,id:i})}return{files:e,directories:t}}async function ut(n){let e=ct(n.directories);if(e.length===0)return n.files;let t=e.map(o=>o[0].path),s=n.files.filter(o=>!t.some(a=>ke(o.path,a))),r=dt(n.directories),i=[];for(let o of e)for(let a of o){if(!a.id)throw new Error(`Cannot preserve duplicate remote folder without a stable rclone folder ID: ${a.path}`);let l=M(a.path),u=me(l,r);r.add(u),i.push(...await Fe({remote:n.remote,parentId:a.id,sourcePrefix:a.path,targetPrefix:u,extraArgs:n.extraArgs}))}return[...s,...i]}function ct(n){let e=new Map;for(let i of n){let o=e.get(i.path)??[];o.push(i),e.set(i.path,o)}let t=Array.from(e.values()).filter(i=>i.length>1).sort((i,o)=>i[0].path.split("/").length-o[0].path.split("/").length),s=[],r=[];for(let i of t){let o=i[0].path;r.some(a=>ke(o,a))||(r.push(o),s.push(i))}return s}function dt(n){let e=new Map;for(let s of n)e.set(s.path,(e.get(s.path)??0)+1);let t=new Set;for(let s of n)(e.get(s.path)??0)>1||t.add(M(s.path));return t}async function Fe(n){let e=await ht({remote:n.remote,parentId:n.parentId,extraArgs:n.extraArgs}),t=new Set,s=[];for(let r of e){if(typeof r.name!="string"||typeof r.id!="string")continue;let i=`${n.sourcePrefix}/${r.name}`,o=`${n.targetPrefix}/${M(r.name)}`,a=r.mimeType==="application/vnd.google-apps.folder"?me(o,t):pe(o,t);if(t.add(a),r.mimeType==="application/vnd.google-apps.folder"){s.push(...await Fe({remote:n.remote,parentId:r.id,sourcePrefix:i,targetPrefix:a,extraArgs:n.extraArgs}));continue}s.push({path:i,targetPath:a,size:pt(r.size),id:r.id,requiresIdentityDownload:!0})}return s}function ht(n){let e=`'${mt(n.parentId)}' in parents and trashed = false`;return new Promise((t,s)=>{let r=Y("rclone",rt({remote:n.remote,query:e,extraArgs:n.extraArgs}),{stdio:["ignore","pipe","pipe"]}),i="",o="";r.stdout.on("data",a=>{i+=a.toString()}),r.stderr.on("data",a=>{o+=a.toString()}),r.on("close",a=>{if(a!==0){s(new A(`Failed to query children for Google Drive folder ${n.parentId}`,o));return}try{let l=JSON.parse(i||"[]");if(!Array.isArray(l))throw new Error("rclone backend query did not return an array");t(l)}catch(l){s(new A(`Failed to parse children for Google Drive folder ${n.parentId}: ${l instanceof Error?l.message:String(l)}`,o))}}),r.on("error",a=>{s(new A(`Failed to start rclone: ${a.message}`,""))})})}function pt(n){if(typeof n=="number"&&Number.isFinite(n))return n;if(typeof n=="string"){let e=Number(n);return Number.isFinite(e)?e:0}return 0}function ke(n,e){return n===e||n.startsWith(`${e}/`)}function mt(n){return n.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function gt(n){let e=F(n),t=C(n.path);return n.requiresIdentityDownload===!0||e!==t}async function ft(n){let e=R.join(n.localPath,F(n.file));if(await N.promises.mkdir(R.dirname(e),{recursive:!0}),n.file.id){await ge({args:it({remote:n.remote,fileId:n.file.id,localTargetPath:e,rcloneOptions:n.rcloneOptions}),remoteSource:`${n.remote}:${n.file.path}`,onProgress:n.onProgress});return}if(n.file.requiresIdentityDownload===!0)throw new Error(`Cannot preserve duplicate remote file without a stable rclone file ID: ${n.file.path}`);await ge({args:nt({remoteFileSource:`${n.remote}:${yt(n.remotePath,n.file.path)}`,localTargetPath:e,rcloneOptions:n.rcloneOptions}),remoteSource:`${n.remote}:${n.file.path}`,onProgress:n.onProgress})}function yt(n,e){let t=n.replace(/\/+$/,""),s=e.replace(/^\/+/,"");return t.length===0?s:`${t}/${s}`}async function Ie(n){let e=[],t=new Set;async function s(r,i=""){let o=await N.promises.readdir(r,{withFileTypes:!0});for(let a of o){let l=R.join(r,a.name),u=i?R.join(i,a.name):a.name;if(a.isDirectory())await s(l,u);else if(a.isFile()){let c=await N.promises.stat(l);e.push({relativePath:u,absolutePath:l,fileName:a.name,size:c.size});let d=R.dirname(u);if(d!=="."){let h=d.split(R.sep);for(let p=0;p<h.length;p++){let g=h.slice(0,p+1).join(R.sep);t.add(g)}}}}}return await s(n),{files:e,directoryCount:t.size}}import St from"fs/promises";import bt from"path";function ve(n,e){let t=new Map;for(let u of n){let c=bt.dirname(u.targetPath??u.path);t.has(c)||t.set(c,[]),t.get(c).push(u)}let s=new Map;for(let[u,c]of t.entries()){let d=c.reduce((h,p)=>h+p.size,0);s.set(u,d)}let r=Array.from(t.keys()).sort(),i=[],o=[],a=0,l=1;for(let u of r){let c=t.get(u),d=s.get(u);if(d>e){if(o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),c.length===1)i.push({batchNumber:l++,files:c,totalSize:d});else for(let h of c)a+h.size>e&&o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),o.push(h),a+=h.size;continue}a+d>e&&o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),o.push(...c),a+=d}return o.length>0&&i.push({batchNumber:l++,files:o,totalSize:a}),i}async function we(n){try{await St.unlink(n)}catch(e){if(e.code!=="ENOENT")throw e}}import m from"chalk";import _e from"log-update";var S=(n,e=2)=>{if(n===0)return"0 B";let t=1024,s=e<0?0:e,r=["B","KB","MB","GB","TB","PB","EB"],i=Math.floor(Math.log(n)/Math.log(t));return`${(n/Math.pow(t,i)).toFixed(s)} ${r[i]}`},xe=n=>{if(n===null)return null;let t=n*8/(1024*1024);return t<1?`${(t*1024).toFixed(0)} Kbps`:`${t.toFixed(1)} Mbps`},G=n=>{if(n===null)return null;let e=Math.floor(n/3600),t=Math.floor(n%3600/60),s=Math.floor(n%60);return e>0?`${e}h ${t}m`:t>0?`${t}m ${s}s`:`${s}s`};var At=1e3,ye=class{#t=null;#s=!1;#e=null;#i=null;#o=null;#n=new Map;#a=null;#l=null;#r=null;#u=null;start(){this.#s||(this.#s=!0,this.#n.clear(),this.#a=null,this.#l=null,this.#r=null,this.#u=null,this.#t=setInterval(()=>this.render(),At))}stop(){this.#s&&(this.#s=!1,this.#t&&(clearInterval(this.#t),this.#t=null),this.render(),_e.done())}updateSnapshot(e){this.#e=e}updateBatchState(e){this.#i=e}updateDownloadProgress(e){if(!e){this.#o=null;return}let t=e.percentComplete>=100||e.bytesTransferred>=e.totalBytes;!t&&e.speed>0&&(this.#r=e),this.#o=t&&this.#r?{...e,speed:this.#r.speed,eta:this.#r.eta}:e}persistCurrentBatchLine(){!this.#i||this.#i.currentPhase!=="complete"||this.#n.set(this.#i.currentBatch,this.#h(this.#i))}resetUploadSnapshot(){this.#e=null,this.#o=null,this.#r=null,this.#u=null}render(){if(!this.#s)return;let e=this.#i?this.#I(this.#i):this.#g();_e(e.join(`
6
- `))}#A(e,t){let s=[`${m.green(S(t.bytesTransferred))} / ${m.gray(S(t.totalBytes))}`,m.cyan(`${t.percentComplete.toFixed(1)}%`),m.magenta(xe(t.speed)??"..."),`${m.yellow("ETA")}: ${m.yellow(G(t.eta)??"...")}`];return`${m.blue(e)}: ${s.join(" | ")}`}#g(){let e=this.#c();return[this.#m(e),this.#R(e)]}#I(e){let t=[];for(let s=1;s<e.currentBatch;s++){let r=this.#n.get(s);r&&t.push(r)}return t.push(this.#h(e)),t.push(this.#U(e)),t}#h(e){let t=`Batch ${e.currentBatch}/${e.totalBatches}`;switch(e.currentPhase){case"downloading":return this.#o?`${t}: ${this.#A("Downloading",this.#o)}`:`${t}: ${m.blue("Downloading...")}`;case"scanning":return`${t}: ${m.yellow(e.extraDetails??"Scanning...")}`;case"syncing_folders":return`${t}: ${m.yellow(e.extraDetails??"Syncing folders...")}`;case"uploading":return this.#B(t,e);case"cleaning":return`${t}: ${m.yellow("Cleaning...")}`;case"complete":return`${t}: ${m.green("Complete")} (${e.batchFilesTotal} files, ${S(e.batchBytesTotal)}${e.extraDetails?`, ${e.extraDetails}`:""})`}}#B(e,t){let s=this.#c(),r=s.successFileCount+s.failedFileCount+s.cancelledFileCount,i=Math.max(t.batchFilesTotal-t.batchFilesSkipped,0),o=Math.max(t.batchBytesTotal-t.batchBytesSkipped,0),a=o>0?(s.uploadedBytes/o*100).toFixed(1):"0.0",l=this.#f(t,s,o),u=l?.formattedSpeed??null,c=l?.formattedTime??null,d=u&&c?`, ${u}, ETA: ${c}`:"",h=t.batchFilesSkipped>0?`, ${m.yellow(`Skipped: ${t.batchFilesSkipped} files / ${S(t.batchBytesSkipped)}`)}`:"";return`${e}: ${m.blue("Uploading")} (${r}/${i} files, ${S(s.uploadedBytes)} / ${S(o)}, ${a}%${d}${h})`}#U(e){let t=this.#c(),s=e.batchFilesSkipped+t.successFileCount+t.failedFileCount+t.cancelledFileCount,r=e.batchBytesSkipped+t.uploadedBytes,i=e.overallFilesCompleted+s,o=e.overallBytesCompleted+r,a=Math.max(e.overallBytesTotal-o,0),l=this.#C(e),u=this.#P(e,t),c=l!==null&&u!==null?l+u:null;return[`Total: ${i}/${e.overallFilesTotal} files`,`${S(o)} / ${S(e.overallBytesTotal)}`,m.yellow(`${S(a)} remaining`),`Download ETA: ${G(l)??"..."}`,`Upload ETA: ${G(u)??"..."}`,`Total ETA: ${G(c)??"..."}`].join(", ")}#C(e){let t=e.overallBytesCompleted+e.batchBytesSkipped+(this.#o?.bytesTransferred??0),s=Math.max(e.overallBytesTotal-t,0);if(s===0)return e.currentPhase==="downloading"&&this.#o?(this.#a=this.#o.eta,this.#o.eta):(this.#a=0,0);if(this.#o&&this.#o.speed>0){let r=Math.ceil(s/this.#o.speed);return this.#a=r,r}return this.#a}#P(e,t){let s=e.overallBytesCompleted+e.batchBytesSkipped+t.uploadedBytes,r=Math.max(e.overallBytesTotal-s,0),i=Math.max(e.batchBytesTotal-e.batchBytesSkipped,0),o=this.#f(e,t,i);if(r===0)return e.currentPhase==="uploading"&&o?(this.#l=o.timeRemainingSeconds,o.timeRemainingSeconds):(this.#l=0,0);if(o&&o.uploadSpeedMbps>0){let a=o.uploadSpeedMbps*1024*1024/8,l=Math.ceil(r/a);return this.#l=l,l}return this.#l}#f(e,t,s){let r=this.#e?.uploadStats,i=s>0&&t.uploadedBytes>=s;return r&&r.uploadSpeedMbps>0&&r.formattedSpeed!=="Calculating..."&&!i?(this.#u={uploadSpeedMbps:r.uploadSpeedMbps,formattedSpeed:r.formattedSpeed,formattedTime:r.formattedTime,timeRemainingSeconds:r.timeRemainingSeconds},this.#u):e.currentPhase==="uploading"&&i&&this.#u?this.#u:r?{uploadSpeedMbps:r.uploadSpeedMbps,formattedSpeed:r.formattedSpeed,formattedTime:r.formattedTime,timeRemainingSeconds:r.timeRemainingSeconds}:null}#m(e){return[`Total: ${e.totalFileCount}`,m.green(`Success: ${e.successFileCount}`),m.red(`Failed: ${e.failedFileCount}`),m.red(`Cancelled: ${e.cancelledFileCount}`),m.blue(`Active: ${e.activeFileCount}`),m.gray(`Queued: ${e.queuedFileCount}`)].join(" | ")}#R(e){let t=Math.max(e.totalBytes-e.uploadedBytes,0),s=this.#e?` | ${m.cyan(`Speed: ${this.#e.uploadStats.formattedSpeed}`)} | ${m.magenta(`Time remaining: ${this.#e.uploadStats.formattedTime}`)}`:"";return[`Total: ${S(e.totalBytes)}`,m.green(`Uploaded: ${S(e.uploadedBytes)}`),m.yellow(`Remaining: ${S(t)}`)].join(" | ")+s}#c(){return this.#e?Object.values(this.#e.uploadAssets).reduce((t,s)=>{switch(t.totalFileCount+=1,t.totalBytes+=s.totalBytesToUpload,t.uploadedBytes+=s.bytesUploaded,s.status){case"success":t.successFileCount+=1;break;case"failed":t.failedFileCount+=1;break;case"cancelled":t.cancelledFileCount+=1;break;case"in-progress":t.activeFileCount+=1;break;default:t.queuedFileCount+=1;break}return t},{totalFileCount:0,successFileCount:0,failedFileCount:0,cancelledFileCount:0,activeFileCount:0,queuedFileCount:0,uploadedBytes:0,totalBytes:0}):{totalFileCount:0,successFileCount:0,failedFileCount:0,cancelledFileCount:0,activeFileCount:0,queuedFileCount:0,uploadedBytes:0,totalBytes:0}}},f=new ye;import{Readable as Rt}from"node:stream";import Be from"axios";var I=class{#t;#s;#e;#i;#o=new O;#n=new Set;constructor(e){this.#t=Be.create({baseURL:e.apiUrl}),this.#s=Be.create({baseURL:e.edgeWorkerUrl}),this.#e=e.apiKey,this.#i=e.sessionId}get skippedAssetIds(){return this.#n}async post(e,t,s){let r=await this.#t.post(e,t,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#i,"Content-Type":"application/json",...s}});return this.#l(e,t,r.data),r.data}async get(e,t){return(await this.#t.get(e,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#i,...t}})).data}async delete(e,t){await this.#t.delete(e,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#i,...t}})}async putWithToken(e,t,s,r){let i=await this.#a(t),o=this.#o.createIterator(i,r.getMaxUploadRate??(()=>null),r.signal),a=Rt.from(o,{highWaterMark:1}),l=await this.#s.put(e,a,{timeout:0,signal:r.signal,headers:{"Content-Type":r.contentType??"","Content-Length":i.byteLength.toString(),Authorization:`Bearer ${s}`},transformRequest:[u=>u],maxRedirects:0,onUploadProgress:u=>r.onProgress?.(u.loaded)});return{status:l.status,statusText:l.statusText,headers:Object.fromEntries(Object.entries(l.headers)),data:l.data,raw:l}}async#a(e){if(e instanceof Uint8Array)return e;let t=await e.arrayBuffer();return new Uint8Array(t)}#l(e,t,s){if(e!=="/assets/chunked/initiate"||!Array.isArray(t)||!Array.isArray(s))return;let r=t;s.forEach((o,a)=>{let l=r[a];o.skipped===!0&&typeof l?.id=="string"&&this.#n.add(l.id)})}};import z from"node:path";var V=class{#t;#s;#e=new Map;constructor(e){this.#t=e.rootDirectoryId,this.#s=e.httpClient}async ensureDirectories(e){await this.loadExistingDirectories();let t=this.#i(e);for(let s of t){if(this.#e.has(s))continue;let r=z.posix.dirname(s),i=z.posix.basename(s),o=r==="."?this.#t:this.#e.get(r);if(!o)throw new Error(`Parent directory ID not found for path: ${s}`);let a=await this.#a(o,i);if(a.name!==i)throw new Error(`Server created renamed directory "${a.name}" for planned path "${s}". Refusing to map uploads to an unexpected target path.`);this.#e.set(s,a.id)}return e.map(s=>({file:s,directoryId:this.getDirectoryIdForFile(s.relativePath)}))}async loadExistingDirectories(){let e=await this.#o(this.#t);this.#e.clear(),this.#n(e,"")}getDirectoryIdForFile(e){let t=C(e),s=z.posix.dirname(t);if(s===".")return this.#t;let r=this.#e.get(s);if(!r)throw new Error(`Directory ID not found for path: ${s}`);return r}getExistingDirectoryIdForFile(e){let t=C(e),s=z.posix.dirname(t);return s==="."?this.#t:this.#e.get(s)??null}async checkAssetsExistence(e,t=!0){return e.length===0?[]:(await this.#s.post("/assets/check-exists-and-uploaded",{items:e,delete_if_not_exist:t})).items}#i(e){let t=new Set;for(let s of e){let r=C(s.relativePath),i=z.posix.dirname(r);if(i===".")continue;let o=i.split("/");for(let a=0;a<o.length;a++)t.add(o.slice(0,a+1).join("/"))}return Array.from(t).sort((s,r)=>s.split("/").length-r.split("/").length)}async#o(e){return this.#s.get(`/directories/${e}/tree`)}#n(e,t){let s=t===""?"":t==="."?e.name:`${t}/${e.name}`;s!==""&&this.#e.set(s,e.id);for(let r of e.children){let i=t===""?".":s;this.#n(r,i)}}async#a(e,t){return this.#s.post(`/directories/${e}/directories`,{name:t,auto_rename:"numeric"})}};import*as Z from"fs/promises";import*as ee from"path";var Et={".mp4":"video/mp4",".mov":"video/quicktime",".avi":"video/x-msvideo",".mkv":"video/x-matroska",".webm":"video/webm",".wmv":"video/x-ms-wmv",".flv":"video/x-flv",".m4v":"video/x-m4v",".mpg":"video/mpeg",".mpeg":"video/mpeg",".3gp":"video/3gpp",".ts":"video/mp2t",".mts":"video/mp2t",".mxf":"application/mxf",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".bmp":"image/bmp",".tiff":"image/tiff",".tif":"image/tiff",".svg":"image/svg+xml",".heic":"image/heic",".heif":"image/heif",".avif":"image/avif",".mp3":"audio/mpeg",".wav":"audio/wav",".aac":"audio/aac",".ogg":"audio/ogg",".flac":"audio/flac",".m4a":"audio/mp4",".wma":"audio/x-ms-wma",".pdf":"application/pdf",".doc":"application/msword",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".ppt":"application/vnd.ms-powerpoint",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",".xls":"application/vnd.ms-excel",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".rtf":"application/rtf",".json":"application/json",".xml":"application/xml"};function Tt(n){let e=ee.extname(n).toLowerCase();return Et[e]??""}var J=class n{#t;#s=null;#e=null;#i=!1;#o;#n;#a;constructor(e,t,s,r){this.#t=e,this.#o=t,this.#n=s,this.#a=r}static async create(e){let t=await Z.stat(e),s=ee.basename(e),r=Tt(s);return new n(e,t.size,s,r)}get name(){return this.#n}get size(){return this.#o}get type(){return this.#a}async readChunk(e,t){if(!this.#s){this.#e||(this.#e=Z.open(this.#t,"r"));let i=await this.#e;if(this.#e=null,this.#i)return Buffer.alloc(0);this.#s=i}let s=t-e,r=Buffer.alloc(s);return await this.#s.read(r,0,s,e),r}async close(){this.#i=!0;let e=this.#e;await this.#s?.close(),this.#s=null,e&&await(await e.catch(()=>null))?.close(),this.#e=null}};var Ut=new Set(["success","failed","cancelled"]),De=1e3,te=class{#t;#s;#e;#i;constructor(e){this.#t=e.config,this.#s=e.httpClient??new I({apiUrl:e.config.apiUrl,apiKey:e.config.apiKey,edgeWorkerUrl:e.config.edgeWorkerUrl,sessionId:e.config.sessionName}),this.#e=e.createFileReader??(t=>J.create(t)),this.#i=e.onSnapshot}async uploadFiles(e){let t=e.filter(o=>o.preSkipped===!0),s=e.filter(o=>o.preSkipped!==!0);if(s.length===0)return{totalFileCount:e.length,successFileCount:0,skippedFileCount:t.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};let r=new L({httpClient:this.#s,maxConcurrency:this.#t.maxConcurrent,deltaIntervalMs:De,adaptiveConcurrency:!1}),i=[];try{let o=r.startGroupUpload({name:`${s.length} files`,type:"files",fileCount:s.length,folderCount:0,topLevelFileCount:s.length,topLevelFolderCount:0,rootDirectoryId:this.#t.directoryId,projectId:this.#t.projectId,totalBytes:s.reduce((l,u)=>l+u.file.size,0),conflictResolutionOverride:"skip"});for(let l of s){let u=await this.#e(l.file.absolutePath),c=r.startUpload({fileReader:u,directoryId:l.directoryId,projectId:this.#t.projectId,groupId:o,chunkSize:this.#t.chunkSizeBytes});i.push({assetId:c,file:l.file,fileReader:u})}await this.#o(r);let a=r.getSnapshot();return this.#i?.(a),this.#n({snapshot:a,startedUploads:i,preSkippedCount:t.length})}finally{r.destroy()}}async#o(e){let s=Date.now();for(;Date.now()-s<864e5;){let r=e.getSnapshot();this.#i?.(r);let i=Object.values(r.uploadAssets);if(i.length>0&&i.every(o=>Ut.has(o.status)))return;await new Promise(o=>setTimeout(o,De))}throw new Error("Timed out waiting for upload session to finish")}#n(e){let t=[],s=0,r=0,i=0,o=0;for(let a of e.startedUploads){let l=e.snapshot.uploadAssets[a.assetId];if(!l){i+=1,t.push({fileName:a.file.fileName,relativePath:a.file.relativePath,errorMessage:"Upload state missing from upload engine"});continue}if(l.status==="success"){this.#s.skippedAssetIds.has(a.assetId)?r+=1:s+=1;continue}l.status==="cancelled"?o+=1:i+=1,t.push({fileName:a.file.fileName,relativePath:a.file.relativePath,errorMessage:l.errorMessage})}return{totalFileCount:e.startedUploads.length+e.preSkippedCount,successFileCount:s,skippedFileCount:e.preSkippedCount+r,failedFileCount:i,cancelledFileCount:o,failedFiles:t}}};var re=class{#t;#s;#e;#i;constructor(e){this.#t=e,this.#s=new I({apiUrl:e.apiUrl,apiKey:e.apiKey,edgeWorkerUrl:e.edgeWorkerUrl,sessionId:e.sessionName}),this.#e=new V({rootDirectoryId:e.directoryId,httpClient:this.#s}),this.#i=new te({config:e,httpClient:this.#s,onSnapshot:t=>f.updateSnapshot(t)})}async run(){this.#I("Starting data sync..."),await this.#a(),console.log("Listing all remote files...");let e=await X(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[]);console.log(`Found ${e.length} files`),console.log(`Total size: ${S(this.#f(e))}`),console.log("");let t=this.#o(e);if(t.length===0){console.log("No files to sync. Exiting."),await this.#l();return}let s={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},r=[],i={batchNumber:1,files:t,totalSize:this.#f(t)};f.start();try{let a=await this.#n({batch:i,totalBatches:1,overallFilesTotal:t.length,overallBytesTotal:i.totalSize,completedTotals:s,batchDir:this.#t.localTempDir});this.#U(s,r,a,i.totalSize)}finally{f.stop()}let o={...s,failedFiles:r};this.#h({summary:o}),await this.#r(o),this.#C(o)}async runBatched(){if(!this.#t.batchSizeBytes)throw new Error("Batch size not configured. Use batchSizeBytes in config.");this.#I("Starting batched data sync...",[`Batch size: ${S(this.#t.batchSizeBytes)}`,`Upload chunk size: ${S(this.#t.chunkSizeBytes)}`,`Max concurrent chunks: ${this.#t.maxConcurrent}`]),await this.#a(),console.log("Listing all remote files...");let e=await X(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[]);console.log(`Found ${e.length} files`),console.log(`Total size: ${S(this.#f(e))}`),console.log("");let t=this.#o(e);if(t.length===0){console.log("No files to sync. Exiting."),await this.#l();return}let s=ve(t,this.#t.batchSizeBytes);await this.#g(s);let r={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},i=[];f.start();try{for(let a of s){let l=await this.#n({batch:a,totalBatches:s.length,overallFilesTotal:t.length,overallBytesTotal:this.#f(t),completedTotals:r});this.#U(r,i,l,a.totalSize)}}finally{f.stop()}this.#h({summary:{...r,failedFiles:i},extraLines:[`Batches: ${s.length}`]});let o={...r,failedFiles:i};await this.#r(o),this.#C(o)}async runCheckOnly(){console.log("Running in check-only mode (no downloads/uploads)..."),await fe(),console.log(`Listing remote files from ${this.#t.remote}:${this.#t.remotePath}...`);let e=await X(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[]);console.log(`Found ${e.length} remote files to check`);let t=this.#o(e);if(t.length===0){console.log("No remote files to check. Exiting.");return}console.log("Fetching existing directory structure..."),await this.#e.loadExistingDirectories();let s=[],r=[];for(let a of t){let l=F(a),u=C(l),c=this.#e.getExistingDirectoryIdForFile(u);if(!c){r.push(l);continue}s.push({displayPath:l,request:{directory_id:c,name:se.posix.basename(u),size_bytes:a.size}})}let i=await this.#e.checkAssetsExistence(s.map(a=>a.request),!1),o=0;for(let a=0;a<s.length;a++)i[a]?.exists?o+=1:r.push(s[a].displayPath);this.#B({totalRemoteCount:e.length,existingCount:o,missingFiles:r})}#o(e){let t=Ee(e);if(t.changes.length===0)return t.files;let s=t.changes.slice(0,10).map(o=>`${o.sourcePath} -> ${o.targetPath}`).join(`
5
+ `,"utf-8"),await St(n.remote,n.remotePath,n.localPath,n.batchFilePath,n.rcloneOptions,n.onProgress));for(let s of t)await It({remote:n.remote,remotePath:n.remotePath,localPath:n.localPath,file:s,rcloneOptions:n.rcloneOptions,onProgress:n.onProgress})}function Ct(n){let e=[],t=[];for(let s of n){let r=s;if(typeof r.Path!="string")continue;let i=typeof r.ID=="string"&&r.ID.length>0?r.ID:void 0;if(r.IsDir===!0){t.push({path:b(r.Path),id:i});continue}let o=typeof r.Size=="number"&&Number.isFinite(r.Size)?r.Size:0;e.push({path:b(r.Path),size:o,id:i})}return{files:e,directories:t}}async function bt(n){let e=At(n.directories);if(e.length===0)return n.files;let t=e.map(o=>o[0].path),s=n.files.filter(o=>!t.some(a=>ve(o.path,a))),r=Et(n.directories),i=[];for(let o of e)for(let a of o){if(!a.id)throw new Error(`Cannot preserve duplicate remote folder without a stable rclone folder ID: ${a.path}`);let l=N(a.path),u=ge(l,r);r.add(u),i.push(...await ke({remote:n.remote,parentId:a.id,sourcePrefix:a.path,targetPrefix:u,extraArgs:n.extraArgs}))}return[...s,...i]}function At(n){let e=new Map;for(let i of n){let o=e.get(i.path)??[];o.push(i),e.set(i.path,o)}let t=Array.from(e.values()).filter(i=>i.length>1).sort((i,o)=>i[0].path.split("/").length-o[0].path.split("/").length),s=[],r=[];for(let i of t){let o=i[0].path;r.some(a=>ve(o,a))||(r.push(o),s.push(i))}return s}function Et(n){let e=new Map;for(let s of n)e.set(s.path,(e.get(s.path)??0)+1);let t=new Set;for(let s of n)(e.get(s.path)??0)>1||t.add(N(s.path));return t}async function ke(n){let e=await Tt({remote:n.remote,parentId:n.parentId,extraArgs:n.extraArgs}),t=new Set,s=[];for(let r of e){if(typeof r.name!="string"||typeof r.id!="string")continue;let i=`${n.sourcePrefix}/${r.name}`,o=`${n.targetPrefix}/${N(r.name)}`,a=r.mimeType==="application/vnd.google-apps.folder"?ge(o,t):me(o,t);if(t.add(a),r.mimeType==="application/vnd.google-apps.folder"){s.push(...await ke({remote:n.remote,parentId:r.id,sourcePrefix:i,targetPrefix:a,extraArgs:n.extraArgs}));continue}s.push({path:i,targetPath:a,size:Rt(r.size),id:r.id,requiresIdentityDownload:!0})}return s}function Tt(n){let e=`'${Ut(n.parentId)}' in parents and trashed = false`;return new Promise((t,s)=>{let r=X("rclone",mt({remote:n.remote,query:e,extraArgs:n.extraArgs}),{stdio:["ignore","pipe","pipe"]}),i="",o="";r.stdout.on("data",a=>{i+=a.toString()}),r.stderr.on("data",a=>{o+=a.toString()}),r.on("close",a=>{if(a!==0){s(new A(`Failed to query children for Google Drive folder ${n.parentId}`,o));return}try{let l=JSON.parse(i||"[]");if(!Array.isArray(l))throw new Error("rclone backend query did not return an array");t(l)}catch(l){s(new A(`Failed to parse children for Google Drive folder ${n.parentId}: ${l instanceof Error?l.message:String(l)}`,o))}}),r.on("error",a=>{s(new A(`Failed to start rclone: ${a.message}`,""))})})}function Rt(n){if(typeof n=="number"&&Number.isFinite(n))return n;if(typeof n=="string"){let e=Number(n);return Number.isFinite(e)?e:0}return 0}function ve(n,e){return n===e||n.startsWith(`${e}/`)}function Ut(n){return n.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function Pt(n){let e=F(n),t=b(n.path);return n.requiresIdentityDownload===!0||e!==t}async function It(n){let e=E.join(n.localPath,F(n.file));if(await G.promises.mkdir(E.dirname(e),{recursive:!0}),n.file.id){await fe({args:ft({remote:n.remote,fileId:n.file.id,localTargetPath:e,rcloneOptions:n.rcloneOptions}),remoteSource:`${n.remote}:${n.file.path}`,onProgress:n.onProgress});return}if(n.file.requiresIdentityDownload===!0)throw new Error(`Cannot preserve duplicate remote file without a stable rclone file ID: ${n.file.path}`);await fe({args:gt({remoteFileSource:`${n.remote}:${Ft(n.remotePath,n.file.path)}`,localTargetPath:e,rcloneOptions:n.rcloneOptions}),remoteSource:`${n.remote}:${n.file.path}`,onProgress:n.onProgress})}function Ft(n,e){let t=n.replace(/\/+$/,""),s=e.replace(/^\/+/,"");return t.length===0?s:`${t}/${s}`}async function _e(n){let e=[],t=new Set;async function s(r,i=""){let o=await G.promises.readdir(r,{withFileTypes:!0});for(let a of o){let l=E.join(r,a.name),u=i?E.join(i,a.name):a.name;if(a.isDirectory())await s(l,u);else if(a.isFile()){let c=await G.promises.stat(l);e.push({relativePath:u,absolutePath:l,fileName:a.name,size:c.size});let d=E.dirname(u);if(d!=="."){let h=d.split(E.sep);for(let p=0;p<h.length;p++){let g=h.slice(0,p+1).join(E.sep);t.add(g)}}}}}return await s(n),{files:e,directoryCount:t.size}}import kt from"fs/promises";import vt from"path";function we(n,e){let t=new Map;for(let u of n){let c=vt.dirname(u.targetPath??u.path);t.has(c)||t.set(c,[]),t.get(c).push(u)}let s=new Map;for(let[u,c]of t.entries()){let d=c.reduce((h,p)=>h+p.size,0);s.set(u,d)}let r=Array.from(t.keys()).sort(),i=[],o=[],a=0,l=1;for(let u of r){let c=t.get(u),d=s.get(u);if(d>e){if(o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),c.length===1)i.push({batchNumber:l++,files:c,totalSize:d});else for(let h of c)a+h.size>e&&o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),o.push(h),a+=h.size;continue}a+d>e&&o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),o.push(...c),a+=d}return o.length>0&&i.push({batchNumber:l++,files:o,totalSize:a}),i}async function xe(n){try{await kt.unlink(n)}catch(e){if(e.code!=="ENOENT")throw e}}import m from"chalk";import Be from"log-update";var S=(n,e=2)=>{if(n===0)return"0 B";let t=1024,s=e<0?0:e,r=["B","KB","MB","GB","TB","PB","EB"],i=Math.floor(Math.log(n)/Math.log(t));return`${(n/Math.pow(t,i)).toFixed(s)} ${r[i]}`},De=n=>{if(n===null)return null;let t=n*8/(1024*1024);return t<1?`${(t*1024).toFixed(0)} Kbps`:`${t.toFixed(1)} Mbps`},H=n=>{if(n===null)return null;let e=Math.floor(n/3600),t=Math.floor(n%3600/60),s=Math.floor(n%60);return e>0?`${e}h ${t}m`:t>0?`${t}m ${s}s`:`${s}s`};var wt=1e3,Se=class{#t=null;#s=!1;#e=null;#i=null;#o=null;#n=new Map;#a=null;#l=null;#r=null;#u=null;start(){this.#s||(this.#s=!0,this.#n.clear(),this.#a=null,this.#l=null,this.#r=null,this.#u=null,this.#t=setInterval(()=>this.render(),wt))}stop(){this.#s&&(this.#s=!1,this.#t&&(clearInterval(this.#t),this.#t=null),this.render(),Be.done())}updateSnapshot(e){this.#e=e}updateBatchState(e){this.#i=e}updateDownloadProgress(e){if(!e){this.#o=null;return}let t=e.percentComplete>=100||e.bytesTransferred>=e.totalBytes;!t&&e.speed>0&&(this.#r=e),this.#o=t&&this.#r?{...e,speed:this.#r.speed,eta:this.#r.eta}:e}persistCurrentBatchLine(){!this.#i||this.#i.currentPhase!=="complete"||this.#n.set(this.#i.currentBatch,this.#h(this.#i))}resetUploadSnapshot(){this.#e=null,this.#o=null,this.#r=null,this.#u=null}render(){if(!this.#s)return;let e=this.#i?this.#k(this.#i):this.#g();Be(e.join(`
6
+ `))}#A(e,t){let s=[`${m.green(S(t.bytesTransferred))} / ${m.gray(S(t.totalBytes))}`,m.cyan(`${t.percentComplete.toFixed(1)}%`),m.magenta(De(t.speed)??"..."),`${m.yellow("ETA")}: ${m.yellow(H(t.eta)??"...")}`];return`${m.blue(e)}: ${s.join(" | ")}`}#g(){let e=this.#c();return[this.#m(e),this.#E(e)]}#k(e){let t=[];for(let s=1;s<e.currentBatch;s++){let r=this.#n.get(s);r&&t.push(r)}return t.push(this.#h(e)),t.push(this.#U(e)),t}#h(e){let t=`Batch ${e.currentBatch}/${e.totalBatches}`;switch(e.currentPhase){case"downloading":return this.#o?`${t}: ${this.#A("Downloading",this.#o)}`:`${t}: ${m.blue("Downloading...")}`;case"scanning":return`${t}: ${m.yellow(e.extraDetails??"Scanning...")}`;case"syncing_folders":return`${t}: ${m.yellow(e.extraDetails??"Syncing folders...")}`;case"uploading":return this.#D(t,e);case"cleaning":return`${t}: ${m.yellow("Cleaning...")}`;case"complete":return`${t}: ${m.green("Complete")} (${e.batchFilesTotal} files, ${S(e.batchBytesTotal)}${e.extraDetails?`, ${e.extraDetails}`:""})`}}#D(e,t){let s=this.#c(),r=s.successFileCount+s.failedFileCount+s.cancelledFileCount,i=Math.max(t.batchFilesTotal-t.batchFilesSkipped,0),o=Math.max(t.batchBytesTotal-t.batchBytesSkipped,0),a=o>0?(s.uploadedBytes/o*100).toFixed(1):"0.0",l=this.#f(t,s,o),u=l?.formattedSpeed??null,c=l?.formattedTime??null,d=u&&c?`, ${u}, ETA: ${c}`:"",h=t.batchFilesSkipped>0?`, ${m.yellow(`Skipped: ${t.batchFilesSkipped} files / ${S(t.batchBytesSkipped)}`)}`:"";return`${e}: ${m.blue("Uploading")} (${r}/${i} files, ${S(s.uploadedBytes)} / ${S(o)}, ${a}%${d}${h})`}#U(e){let t=this.#c(),s=e.batchFilesSkipped+t.successFileCount+t.failedFileCount+t.cancelledFileCount,r=e.batchBytesSkipped+t.uploadedBytes,i=e.overallFilesCompleted+s,o=e.overallBytesCompleted+r,a=Math.max(e.overallBytesTotal-o,0),l=this.#b(e),u=this.#P(e,t),c=l!==null&&u!==null?l+u:null;return[`Total: ${i}/${e.overallFilesTotal} files`,`${S(o)} / ${S(e.overallBytesTotal)}`,m.yellow(`${S(a)} remaining`),`Download ETA: ${H(l)??"..."}`,`Upload ETA: ${H(u)??"..."}`,`Total ETA: ${H(c)??"..."}`].join(", ")}#b(e){let t=e.overallBytesCompleted+e.batchBytesSkipped+(this.#o?.bytesTransferred??0),s=Math.max(e.overallBytesTotal-t,0);if(s===0)return e.currentPhase==="downloading"&&this.#o?(this.#a=this.#o.eta,this.#o.eta):(this.#a=0,0);if(this.#o&&this.#o.speed>0){let r=Math.ceil(s/this.#o.speed);return this.#a=r,r}return this.#a}#P(e,t){let s=e.overallBytesCompleted+e.batchBytesSkipped+t.uploadedBytes,r=Math.max(e.overallBytesTotal-s,0),i=Math.max(e.batchBytesTotal-e.batchBytesSkipped,0),o=this.#f(e,t,i);if(r===0)return e.currentPhase==="uploading"&&o?(this.#l=o.timeRemainingSeconds,o.timeRemainingSeconds):(this.#l=0,0);if(o&&o.uploadSpeedMbps>0){let a=o.uploadSpeedMbps*1024*1024/8,l=Math.ceil(r/a);return this.#l=l,l}return this.#l}#f(e,t,s){let r=this.#e?.uploadStats,i=s>0&&t.uploadedBytes>=s;return r&&r.uploadSpeedMbps>0&&r.formattedSpeed!=="Calculating..."&&!i?(this.#u={uploadSpeedMbps:r.uploadSpeedMbps,formattedSpeed:r.formattedSpeed,formattedTime:r.formattedTime,timeRemainingSeconds:r.timeRemainingSeconds},this.#u):e.currentPhase==="uploading"&&i&&this.#u?this.#u:r?{uploadSpeedMbps:r.uploadSpeedMbps,formattedSpeed:r.formattedSpeed,formattedTime:r.formattedTime,timeRemainingSeconds:r.timeRemainingSeconds}:null}#m(e){return[`Total: ${e.totalFileCount}`,m.green(`Success: ${e.successFileCount}`),m.red(`Failed: ${e.failedFileCount}`),m.red(`Cancelled: ${e.cancelledFileCount}`),m.blue(`Active: ${e.activeFileCount}`),m.gray(`Queued: ${e.queuedFileCount}`)].join(" | ")}#E(e){let t=Math.max(e.totalBytes-e.uploadedBytes,0),s=this.#e?` | ${m.cyan(`Speed: ${this.#e.uploadStats.formattedSpeed}`)} | ${m.magenta(`Time remaining: ${this.#e.uploadStats.formattedTime}`)}`:"";return[`Total: ${S(e.totalBytes)}`,m.green(`Uploaded: ${S(e.uploadedBytes)}`),m.yellow(`Remaining: ${S(t)}`)].join(" | ")+s}#c(){return this.#e?Object.values(this.#e.uploadAssets).reduce((t,s)=>{switch(t.totalFileCount+=1,t.totalBytes+=s.totalBytesToUpload,t.uploadedBytes+=s.bytesUploaded,s.status){case"success":t.successFileCount+=1;break;case"failed":t.failedFileCount+=1;break;case"cancelled":t.cancelledFileCount+=1;break;case"in-progress":t.activeFileCount+=1;break;default:t.queuedFileCount+=1;break}return t},{totalFileCount:0,successFileCount:0,failedFileCount:0,cancelledFileCount:0,activeFileCount:0,queuedFileCount:0,uploadedBytes:0,totalBytes:0}):{totalFileCount:0,successFileCount:0,failedFileCount:0,cancelledFileCount:0,activeFileCount:0,queuedFileCount:0,uploadedBytes:0,totalBytes:0}}},f=new Se;import{Readable as xt}from"node:stream";import Oe from"axios";var v=class{#t;#s;#e;#i;#o=new M;#n=new Set;constructor(e){this.#t=Oe.create({baseURL:e.apiUrl}),this.#s=Oe.create({baseURL:e.edgeWorkerUrl}),this.#e=e.apiKey,this.#i=e.sessionId}get skippedAssetIds(){return this.#n}async post(e,t,s){let r=await this.#t.post(e,t,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#i,"Content-Type":"application/json",...s}});return this.#l(e,t,r.data),r.data}async get(e,t){return(await this.#t.get(e,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#i,...t}})).data}async delete(e,t){await this.#t.delete(e,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#i,...t}})}async putWithToken(e,t,s,r){let i=await this.#a(t),o=this.#o.createIterator(i,r.getMaxUploadRate??(()=>null),r.signal),a=xt.from(o,{highWaterMark:1}),l=await this.#s.put(e,a,{timeout:0,signal:r.signal,headers:{"Content-Type":r.contentType??"","Content-Length":i.byteLength.toString(),Authorization:`Bearer ${s}`},transformRequest:[u=>u],maxRedirects:0,onUploadProgress:u=>r.onProgress?.(u.loaded)});return{status:l.status,statusText:l.statusText,headers:Object.fromEntries(Object.entries(l.headers)),data:l.data,raw:l}}async#a(e){if(e instanceof Uint8Array)return e;let t=await e.arrayBuffer();return new Uint8Array(t)}#l(e,t,s){if(e!=="/assets/chunked/initiate"||!Array.isArray(t)||!Array.isArray(s))return;let r=t;s.forEach((o,a)=>{let l=r[a];o.skipped===!0&&typeof l?.id=="string"&&this.#n.add(l.id)})}};import z from"node:path";var J=class{#t;#s;#e=new Map;constructor(e){this.#t=e.rootDirectoryId,this.#s=e.httpClient}async ensureDirectories(e){await this.loadExistingDirectories();let t=this.#i(e);for(let s of t){if(this.#e.has(s))continue;let r=z.posix.dirname(s),i=z.posix.basename(s),o=r==="."?this.#t:this.#e.get(r);if(!o)throw new Error(`Parent directory ID not found for path: ${s}`);let a=await this.#a(o,i);if(a.name!==i)throw new Error(`Server created renamed directory "${a.name}" for planned path "${s}". Refusing to map uploads to an unexpected target path.`);this.#e.set(s,a.id)}return e.map(s=>({file:s,directoryId:this.getDirectoryIdForFile(s.relativePath)}))}async loadExistingDirectories(){let e=await this.#o(this.#t);this.#e.clear(),this.#n(e,"")}getDirectoryIdForFile(e){let t=b(e),s=z.posix.dirname(t);if(s===".")return this.#t;let r=this.#e.get(s);if(!r)throw new Error(`Directory ID not found for path: ${s}`);return r}getExistingDirectoryIdForFile(e){let t=b(e),s=z.posix.dirname(t);return s==="."?this.#t:this.#e.get(s)??null}async checkAssetsExistence(e,t=!0){return e.length===0?[]:(await this.#s.post("/assets/check-exists-and-uploaded",{items:e,delete_if_not_exist:t})).items}#i(e){let t=new Set;for(let s of e){let r=b(s.relativePath),i=z.posix.dirname(r);if(i===".")continue;let o=i.split("/");for(let a=0;a<o.length;a++)t.add(o.slice(0,a+1).join("/"))}return Array.from(t).sort((s,r)=>s.split("/").length-r.split("/").length)}async#o(e){return this.#s.get(`/directories/${e}/tree`)}#n(e,t){let s=t===""?"":t==="."?e.name:`${t}/${e.name}`;s!==""&&this.#e.set(s,e.id);for(let r of e.children){let i=t===""?".":s;this.#n(r,i)}}async#a(e,t){return this.#s.post(`/directories/${e}/directories`,{name:t,auto_rename:"numeric"})}};import{createHash as Dt}from"node:crypto";import{PostHog as Bt}from"posthog-node";var I=null,Le="",Me={};function Ne(n){I||n.config.analytics.disabled||!n.config.analytics.posthogKey||(Le=Ot(n.config.apiKey),Me={service:"data-sync",package_version:n.packageVersion,platform:process.platform,arch:process.arch,node_version:process.version,max_concurrent:n.config.maxConcurrent,batch_mode:n.config.batchSizeBytes!==void 0,batch_size_bytes:n.config.batchSizeBytes??null,rclone_transfers:n.config.rcloneOptions.transfers,rclone_multi_thread_streams:n.config.rcloneOptions.multiThreadStreams},I=new Bt(n.config.analytics.posthogKey,{host:n.config.analytics.posthogHost,flushAt:20,flushInterval:1e4}))}function Ge(n,e){I&&I.capture({distinctId:Le,event:n,properties:{...Me,...e}})}async function He(){if(!I)return;let n=I;I=null;try{await n.flush()}catch{}}function Ot(n){return`api_key_sha256:${Dt("sha256").update(n).digest("hex")}`}import*as ee from"fs/promises";import*as te from"path";var Lt={".mp4":"video/mp4",".mov":"video/quicktime",".avi":"video/x-msvideo",".mkv":"video/x-matroska",".webm":"video/webm",".wmv":"video/x-ms-wmv",".flv":"video/x-flv",".m4v":"video/x-m4v",".mpg":"video/mpeg",".mpeg":"video/mpeg",".3gp":"video/3gpp",".ts":"video/mp2t",".mts":"video/mp2t",".mxf":"application/mxf",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".bmp":"image/bmp",".tiff":"image/tiff",".tif":"image/tiff",".svg":"image/svg+xml",".heic":"image/heic",".heif":"image/heif",".avif":"image/avif",".mp3":"audio/mpeg",".wav":"audio/wav",".aac":"audio/aac",".ogg":"audio/ogg",".flac":"audio/flac",".m4a":"audio/mp4",".wma":"audio/x-ms-wma",".pdf":"application/pdf",".doc":"application/msword",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".ppt":"application/vnd.ms-powerpoint",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",".xls":"application/vnd.ms-excel",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".rtf":"application/rtf",".json":"application/json",".xml":"application/xml"};function Mt(n){let e=te.extname(n).toLowerCase();return Lt[e]??""}var Z=class n{#t;#s=null;#e=null;#i=!1;#o;#n;#a;constructor(e,t,s,r){this.#t=e,this.#o=t,this.#n=s,this.#a=r}static async create(e){let t=await ee.stat(e),s=te.basename(e),r=Mt(s);return new n(e,t.size,s,r)}get name(){return this.#n}get size(){return this.#o}get type(){return this.#a}async readChunk(e,t){if(!this.#s){this.#e||(this.#e=ee.open(this.#t,"r"));let i=await this.#e;if(this.#e=null,this.#i)return Buffer.alloc(0);this.#s=i}let s=t-e,r=Buffer.alloc(s);return await this.#s.read(r,0,s,e),r}async close(){this.#i=!0;let e=this.#e;await this.#s?.close(),this.#s=null,e&&await(await e.catch(()=>null))?.close(),this.#e=null}};var Nt=new Set(["success","failed","cancelled"]),ze=1e3,Gt=4*1024*1024,se=class{#t;#s;#e;#i;#o;constructor(e){this.#t=e.config,this.#s=e.httpClient??new v({apiUrl:e.config.apiUrl,apiKey:e.config.apiKey,edgeWorkerUrl:e.config.edgeWorkerUrl,sessionId:e.config.sessionName}),this.#e=e.createFileReader??(t=>Z.create(t)),this.#i=e.onSnapshot,this.#o=e.analytics}async uploadFiles(e){let t=e.filter(o=>o.preSkipped===!0),s=e.filter(o=>o.preSkipped!==!0);if(s.length===0)return{totalFileCount:e.length,successFileCount:0,skippedFileCount:t.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};let r=new L({httpClient:this.#s,maxConcurrency:this.#t.maxConcurrent,deltaIntervalMs:ze,adaptiveConcurrency:!1,analytics:this.#o}),i=[];try{let o=r.startGroupUpload({name:`${s.length} files`,type:"files",fileCount:s.length,folderCount:0,topLevelFileCount:s.length,topLevelFolderCount:0,rootDirectoryId:this.#t.directoryId,projectId:this.#t.projectId,totalBytes:s.reduce((l,u)=>l+u.file.size,0),conflictResolutionOverride:"skip"});for(let l of s){let u=await this.#e(l.file.absolutePath),c=r.startUpload({fileReader:u,directoryId:l.directoryId,projectId:this.#t.projectId,groupId:o,chunkSize:Gt});r.addAssetToGroup(o,c),i.push({assetId:c,file:l.file,fileReader:u})}await this.#n(r);let a=r.getSnapshot();return this.#i?.(a),this.#a({snapshot:a,startedUploads:i,preSkippedCount:t.length})}finally{r.destroy()}}async#n(e){let s=Date.now();for(;Date.now()-s<864e5;){let r=e.getSnapshot();this.#i?.(r);let i=Object.values(r.uploadAssets);if(i.length>0&&i.every(o=>Nt.has(o.status)))return;await new Promise(o=>setTimeout(o,ze))}throw new Error("Timed out waiting for upload session to finish")}#a(e){let t=[],s=0,r=0,i=0,o=0;for(let a of e.startedUploads){let l=e.snapshot.uploadAssets[a.assetId];if(!l){i+=1,t.push({fileName:a.file.fileName,relativePath:a.file.relativePath,errorMessage:"Upload state missing from upload engine"});continue}if(l.status==="success"){this.#s.skippedAssetIds.has(a.assetId)?r+=1:s+=1;continue}l.status==="cancelled"?o+=1:i+=1,t.push({fileName:a.file.fileName,relativePath:a.file.relativePath,errorMessage:l.errorMessage})}return{totalFileCount:e.startedUploads.length+e.preSkippedCount,successFileCount:s,skippedFileCount:e.preSkippedCount+r,failedFileCount:i,cancelledFileCount:o,failedFiles:t}}};var ne=class{#t;#s;#e;#i;constructor(e){this.#t=e,this.#s=new v({apiUrl:e.apiUrl,apiKey:e.apiKey,edgeWorkerUrl:e.edgeWorkerUrl,sessionId:e.sessionName}),this.#e=new J({rootDirectoryId:e.directoryId,httpClient:this.#s}),this.#i=new se({config:e,httpClient:this.#s,onSnapshot:t=>f.updateSnapshot(t),analytics:Ge})}async run(){this.#k("Starting data sync..."),await this.#a(),console.log("Listing all remote files...");let e=await V(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[]);console.log(`Found ${e.length} files`),console.log(`Total size: ${S(this.#f(e))}`),console.log("");let t=this.#o(e);if(t.length===0){console.log("No files to sync. Exiting."),await this.#l();return}let s={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},r=[],i={batchNumber:1,files:t,totalSize:this.#f(t)};f.start();try{let a=await this.#n({batch:i,totalBatches:1,overallFilesTotal:t.length,overallBytesTotal:i.totalSize,completedTotals:s,batchDir:this.#t.localTempDir});this.#U(s,r,a,i.totalSize)}finally{f.stop()}let o={...s,failedFiles:r};this.#h({summary:o}),await this.#r(o),this.#b(o)}async runBatched(){if(!this.#t.batchSizeBytes)throw new Error("Batch size not configured. Use batchSizeBytes in config.");this.#k("Starting batched data sync...",[`Batch size: ${S(this.#t.batchSizeBytes)}`,`Max concurrent chunks: ${this.#t.maxConcurrent}`]),await this.#a(),console.log("Listing all remote files...");let e=await V(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[]);console.log(`Found ${e.length} files`),console.log(`Total size: ${S(this.#f(e))}`),console.log("");let t=this.#o(e);if(t.length===0){console.log("No files to sync. Exiting."),await this.#l();return}let s=we(t,this.#t.batchSizeBytes);await this.#g(s);let r={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},i=[];f.start();try{for(let a of s){let l=await this.#n({batch:a,totalBatches:s.length,overallFilesTotal:t.length,overallBytesTotal:this.#f(t),completedTotals:r});this.#U(r,i,l,a.totalSize)}}finally{f.stop()}this.#h({summary:{...r,failedFiles:i},extraLines:[`Batches: ${s.length}`]});let o={...r,failedFiles:i};await this.#r(o),this.#b(o)}async runCheckOnly(){console.log("Running in check-only mode (no downloads/uploads)..."),await ye(),console.log(`Listing remote files from ${this.#t.remote}:${this.#t.remotePath}...`);let e=await V(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[]);console.log(`Found ${e.length} remote files to check`);let t=this.#o(e);if(t.length===0){console.log("No remote files to check. Exiting.");return}console.log("Fetching existing directory structure..."),await this.#e.loadExistingDirectories();let s=[],r=[];for(let a of t){let l=F(a),u=b(l),c=this.#e.getExistingDirectoryIdForFile(u);if(!c){r.push(l);continue}s.push({displayPath:l,request:{directory_id:c,name:re.posix.basename(u),size_bytes:a.size}})}let i=await this.#e.checkAssetsExistence(s.map(a=>a.request),!1),o=0;for(let a=0;a<s.length;a++)i[a]?.exists?o+=1:r.push(s[a].displayPath);this.#D({totalRemoteCount:e.length,existingCount:o,missingFiles:r})}#o(e){let t=Ue(e);if(t.changes.length===0)return t.files;let s=t.changes.slice(0,10).map(o=>`${o.sourcePath} -> ${o.targetPath}`).join(`
7
7
  `),r=t.changes.length-10,i=r>0?`
8
8
  ...and ${r} more renamed target path(s)`:"";return console.warn(`Warning: ${t.changes.length} remote file path(s) were renamed for Aspect compatibility.
9
9
  ${s}${i}
10
- `),console.log(""),t.files}async#n(e){let t=e.batchDir??se.join(this.#t.localTempDir,`batch${e.batch.batchNumber}`);await $.mkdir(t,{recursive:!0});let s=e.batch.files.map(d=>Te(d,t));f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:`Preparing ${s.length} files...`}),f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"syncing_folders",extraDetails:"Ensuring target directories exist..."});let r=await this.#e.ensureDirectories(s);f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:"Checking existing assets..."});let i=await this.#u(r),o=this.#A(i),a=e.batch.files.filter((d,h)=>i[h]?.preSkipped!==!0),l=se.join(this.#t.localTempDir,`batch${e.batch.batchNumber}.txt`),u=async()=>{await we(l),this.#t.keepLocal||await $.rm(t,{recursive:!0,force:!0}),f.resetUploadSnapshot(),f.updateDownloadProgress(null)};if(a.length===0){let d={totalFileCount:i.length,successFileCount:0,skippedFileCount:i.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};return f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+d.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"everything already synced"}),f.persistCurrentBatchLine(),await u(),d}f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"downloading"}),await Pe({remote:this.#t.remote,remotePath:this.#t.remotePath,localPath:t,batchFilePath:l,files:a,rcloneOptions:this.#t.rcloneOptions,onProgress:d=>f.updateDownloadProgress(d)}),await Ie(t),f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"uploading"});let c=await this.#i.uploadFiles(i);return this.#P(c)?(f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+c.successFileCount+c.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"failed; local files preserved"}),f.persistCurrentBatchLine(),c):(f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+c.successFileCount+c.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"cleaning"}),await u(),f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+c.successFileCount+c.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete"}),f.persistCurrentBatchLine(),c)}async#a(){console.log("Checking rclone installation..."),await fe(),console.log("rclone is installed"),console.log(""),console.log("Creating session directory..."),await $.mkdir(this.#t.localTempDir,{recursive:!0}),console.log(`Session directory: ${this.#t.localTempDir}`),console.log("")}async#l(){this.#t.keepLocal||(console.log(""),console.log("Cleaning up session directory..."),await $.rm(this.#t.localTempDir,{recursive:!0,force:!0}),console.log(`Deleted session directory: ${this.#t.localTempDir}`))}async#r(e){if(this.#P(e)){console.log(""),console.log(`Preserving session directory for retry/debugging: ${this.#t.localTempDir}`);return}await this.#l()}async#u(e){let t=await this.#e.checkAssetsExistence(e.map(s=>({directory_id:s.directoryId,name:s.file.fileName,size_bytes:s.file.size})));return e.map((s,r)=>({file:s.file,directoryId:s.directoryId,preSkipped:t[r]?.exists===!0}))}#A(e){return e.reduce((t,s)=>(s.preSkipped===!0&&(t.skippedFileCount+=1,t.skippedByteCount+=s.file.size),t),{skippedFileCount:0,skippedByteCount:0})}async#g(e){console.log("Creating batches..."),console.log(`Created ${e.length} batches`);let t=[];for(let s of e){let r=`Batch ${s.batchNumber}: ${s.files.length} files, ${S(s.totalSize)}`;t.push(r),console.log(r)}await $.writeFile(se.join(this.#t.localTempDir,"batches.txt"),`${t.join(`
10
+ `),console.log(""),t.files}async#n(e){let t=e.batchDir??re.join(this.#t.localTempDir,`batch${e.batch.batchNumber}`);await $.mkdir(t,{recursive:!0});let s=e.batch.files.map(d=>Pe(d,t));f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:`Preparing ${s.length} files...`}),f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"syncing_folders",extraDetails:"Ensuring target directories exist..."});let r=await this.#e.ensureDirectories(s);f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:"Checking existing assets..."});let i=await this.#u(r),o=this.#A(i),a=e.batch.files.filter((d,h)=>i[h]?.preSkipped!==!0),l=re.join(this.#t.localTempDir,`batch${e.batch.batchNumber}.txt`),u=async()=>{await xe(l),this.#t.keepLocal||await $.rm(t,{recursive:!0,force:!0}),f.resetUploadSnapshot(),f.updateDownloadProgress(null)};if(a.length===0){let d={totalFileCount:i.length,successFileCount:0,skippedFileCount:i.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};return f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+d.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"everything already synced"}),f.persistCurrentBatchLine(),await u(),d}f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"downloading"}),await Fe({remote:this.#t.remote,remotePath:this.#t.remotePath,localPath:t,batchFilePath:l,files:a,rcloneOptions:this.#t.rcloneOptions,onProgress:d=>f.updateDownloadProgress(d)}),await _e(t),f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"uploading"});let c=await this.#i.uploadFiles(i);return this.#P(c)?(f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+c.successFileCount+c.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"failed; local files preserved"}),f.persistCurrentBatchLine(),c):(f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+c.successFileCount+c.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"cleaning"}),await u(),f.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:s.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+c.successFileCount+c.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#m(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete"}),f.persistCurrentBatchLine(),c)}async#a(){console.log("Checking rclone installation..."),await ye(),console.log("rclone is installed"),console.log(""),console.log("Creating session directory..."),await $.mkdir(this.#t.localTempDir,{recursive:!0}),console.log(`Session directory: ${this.#t.localTempDir}`),console.log("")}async#l(){this.#t.keepLocal||(console.log(""),console.log("Cleaning up session directory..."),await $.rm(this.#t.localTempDir,{recursive:!0,force:!0}),console.log(`Deleted session directory: ${this.#t.localTempDir}`))}async#r(e){if(this.#P(e)){console.log(""),console.log(`Preserving session directory for retry/debugging: ${this.#t.localTempDir}`);return}await this.#l()}async#u(e){let t=await this.#e.checkAssetsExistence(e.map(s=>({directory_id:s.directoryId,name:s.file.fileName,size_bytes:s.file.size})));return e.map((s,r)=>({file:s.file,directoryId:s.directoryId,preSkipped:t[r]?.exists===!0}))}#A(e){return e.reduce((t,s)=>(s.preSkipped===!0&&(t.skippedFileCount+=1,t.skippedByteCount+=s.file.size),t),{skippedFileCount:0,skippedByteCount:0})}async#g(e){console.log("Creating batches..."),console.log(`Created ${e.length} batches`);let t=[];for(let s of e){let r=`Batch ${s.batchNumber}: ${s.files.length} files, ${S(s.totalSize)}`;t.push(r),console.log(r)}await $.writeFile(re.join(this.#t.localTempDir,"batches.txt"),`${t.join(`
11
11
  `)}
12
- `,"utf-8"),console.log("")}#I(e,t=[]){console.log(e),console.log(`Session: ${this.#t.sessionName}`),console.log(`Remote: ${this.#t.remote}:${this.#t.remotePath}`),console.log(`Root directory ID: ${this.#t.directoryId}`),console.log(`Project ID: ${this.#t.projectId}`),console.log(`Temp directory: ${this.#t.localTempDir}`),console.log(`Edge worker URL: ${this.#t.edgeWorkerUrl}`);for(let s of t)console.log(s);console.log("")}#h(e){console.log(""),console.log("=".repeat(60)),console.log("Sync Summary"),console.log("=".repeat(60)),console.log(`Total files: ${e.summary.totalFileCount}`),console.log(`Successful: ${e.summary.successFileCount}`),console.log(`Skipped: ${e.summary.skippedFileCount}`),console.log(`Failed: ${e.summary.failedFileCount}`),console.log(`Cancelled: ${e.summary.cancelledFileCount}`);for(let t of e.extraLines??[])console.log(t);if(console.log("=".repeat(60)),e.summary.failedFiles.length>0){console.log(""),console.log("Failed files:");for(let t of e.summary.failedFiles)console.log(` - ${t.relativePath}: ${t.errorMessage??"Unknown error"}`)}}#B(e){if(console.log(""),console.log("=".repeat(60)),console.log("Check Summary"),console.log("=".repeat(60)),console.log(`Total (remote): ${e.totalRemoteCount}`),console.log(`Already exist: ${e.existingCount}`),console.log(`Missing: ${e.missingFiles.length}`),console.log("=".repeat(60)),e.missingFiles.length>0){console.log(""),console.log("Files missing on server:");for(let t of e.missingFiles)console.log(` - ${t}`)}}#U(e,t,s,r){e.totalFileCount+=s.totalFileCount,e.successFileCount+=s.successFileCount,e.skippedFileCount+=s.skippedFileCount,e.failedFileCount+=s.failedFileCount,e.cancelledFileCount+=s.cancelledFileCount,e.completedByteCount+=r,t.push(...s.failedFiles)}#C(e){let t=e.failedFileCount+e.cancelledFileCount;if(t>0)throw new Error(`Sync completed with ${t} unsuccessful upload(s)`)}#P(e){return e.failedFileCount+e.cancelledFileCount>0}#f(e){return e.reduce((t,s)=>t+s.size,0)}#m(e,t){return Math.min(e.completedByteCount,t)}};var It=kt(import.meta.url),vt=Le.dirname(It),wt=JSON.parse(Ft(Le.join(vt,"..","package.json"),"utf-8")),Se=new Pt;Se.name("aspect-sync").description("Sync files from external services to Aspect via rclone").version(wt.version);Se.requiredOption("--remote <remote>","rclone remote name (e.g., dropbox)").requiredOption("--path <path>","remote path to sync from").requiredOption("--directory-id <id>","Aspect directory ID to upload to").requiredOption("--project-id <id>","Aspect project ID").option("--api-url <url>","Aspect API URL").option("--edge-worker-url <url>","Aspect edge worker URL").option("--api-key <key>","Aspect API key").option("--upload-concurrent <number>","Maximum concurrent chunk uploads to Aspect (default: 16)","16").option("--keep-local","Keep local files after upload (for debugging)",!1).option("--temp-dir <path>","Local temporary directory for synced files").option("--session <name>","Session name for isolation (default: auto-generated timestamp)").option("--check","Check remote files against Aspect without downloading/uploading",!1).option("--batch-size <size>","Enable batched mode with max batch size (e.g., 500GB, 1TB). Helps with large migrations.","").option("--rclone-transfers <number>","Number of parallel file transfers (default: 4)","4").option("--rclone-multi-thread-streams <number>","Streams per large file (default: 4, higher = faster large files)","4").option("--rclone-multi-thread-chunk-size <size>","Chunk size for multi-threading (default: 64MiB)","64MiB").option("--rclone-multi-thread-cutoff <size>","Minimum file size for multi-threading (default: 64MiB)","64MiB").option("--rclone-buffer-size <size>","Buffer size per transfer (default: 64M, memory = transfers \xD7 buffer-size)","64M").option("--rclone-no-mmap","Disable memory-mapped I/O (reduces memory efficiency)",!1).option("--upload-chunk-size <size>","Multipart upload chunk size in MB (default: 64)","64").option("--rclone-extra <arg>","Additional rclone argument to append (repeatable)",(n,e)=>(e??[]).concat(n),[]).action(async n=>{try{let e={ASPECT_API_URL:process.env.ASPECT_API_URL,ASPECT_EDGE_WORKER_URL:process.env.ASPECT_EDGE_WORKER_URL,ASPECT_API_KEY:process.env.ASPECT_API_KEY},t=Ce({options:n,environment:e}),s=new re(t);n.check?await s.runCheckOnly():t.batchSizeBytes!==void 0?await s.runBatched():await s.run(),process.exit(0)}catch(e){console.error("Fatal error:",e),process.exit(1)}});Se.parse();
12
+ `,"utf-8"),console.log("")}#k(e,t=[]){console.log(e),console.log(`Session: ${this.#t.sessionName}`),console.log(`Remote: ${this.#t.remote}:${this.#t.remotePath}`),console.log(`Root directory ID: ${this.#t.directoryId}`),console.log(`Project ID: ${this.#t.projectId}`),console.log(`Temp directory: ${this.#t.localTempDir}`),console.log(`Edge worker URL: ${this.#t.edgeWorkerUrl}`);for(let s of t)console.log(s);console.log("")}#h(e){console.log(""),console.log("=".repeat(60)),console.log("Sync Summary"),console.log("=".repeat(60)),console.log(`Total files: ${e.summary.totalFileCount}`),console.log(`Successful: ${e.summary.successFileCount}`),console.log(`Skipped: ${e.summary.skippedFileCount}`),console.log(`Failed: ${e.summary.failedFileCount}`),console.log(`Cancelled: ${e.summary.cancelledFileCount}`);for(let t of e.extraLines??[])console.log(t);if(console.log("=".repeat(60)),e.summary.failedFiles.length>0){console.log(""),console.log("Failed files:");for(let t of e.summary.failedFiles)console.log(` - ${t.relativePath}: ${t.errorMessage??"Unknown error"}`)}}#D(e){if(console.log(""),console.log("=".repeat(60)),console.log("Check Summary"),console.log("=".repeat(60)),console.log(`Total (remote): ${e.totalRemoteCount}`),console.log(`Already exist: ${e.existingCount}`),console.log(`Missing: ${e.missingFiles.length}`),console.log("=".repeat(60)),e.missingFiles.length>0){console.log(""),console.log("Files missing on server:");for(let t of e.missingFiles)console.log(` - ${t}`)}}#U(e,t,s,r){e.totalFileCount+=s.totalFileCount,e.successFileCount+=s.successFileCount,e.skippedFileCount+=s.skippedFileCount,e.failedFileCount+=s.failedFileCount,e.cancelledFileCount+=s.cancelledFileCount,e.completedByteCount+=r,t.push(...s.failedFiles)}#b(e){let t=e.failedFileCount+e.cancelledFileCount;if(t>0)throw new Error(`Sync completed with ${t} unsuccessful upload(s)`)}#P(e){return e.failedFileCount+e.cancelledFileCount>0}#f(e){return e.reduce((t,s)=>t+s.size,0)}#m(e,t){return Math.min(e.completedByteCount,t)}};var jt=$t(import.meta.url),qt=$e.dirname(jt),je=JSON.parse(zt($e.join(qt,"..","package.json"),"utf-8")),Ce=new Ht;Ce.name("aspect-sync").description("Sync files from external services to Aspect via rclone").version(je.version);Ce.requiredOption("--remote <remote>","rclone remote name (e.g., dropbox)").requiredOption("--path <path>","remote path to sync from").requiredOption("--directory-id <id>","Aspect directory ID to upload to").requiredOption("--project-id <id>","Aspect project ID").option("--api-url <url>","Aspect API URL").option("--edge-worker-url <url>","Aspect edge worker URL").option("--api-key <key>","Aspect API key").option("--upload-concurrent <number>","Maximum concurrent chunk uploads to Aspect (default: 16)","16").option("--keep-local","Keep local files after upload (for debugging)",!1).option("--temp-dir <path>","Local temporary directory for synced files").option("--session <name>","Session name for isolation (default: auto-generated timestamp)").option("--check","Check remote files against Aspect without downloading/uploading",!1).option("--batch-size <size>","Enable batched mode with max batch size (e.g., 500GB, 1TB). Helps with large migrations.","").option("--rclone-transfers <number>","Number of parallel file transfers (default: 4)","4").option("--rclone-multi-thread-streams <number>","Streams per large file (default: 4, higher = faster large files)","4").option("--rclone-multi-thread-chunk-size <size>","Chunk size for multi-threading (default: 64MiB)","64MiB").option("--rclone-multi-thread-cutoff <size>","Minimum file size for multi-threading (default: 64MiB)","64MiB").option("--rclone-buffer-size <size>","Buffer size per transfer (default: 64M, memory = transfers \xD7 buffer-size)","64M").option("--rclone-no-mmap","Disable memory-mapped I/O (reduces memory efficiency)",!1).option("--rclone-extra <arg>","Additional rclone argument to append (repeatable)",(n,e)=>(e??[]).concat(n),[]).action(async n=>{let e=0;try{let t={ASPECT_API_URL:process.env.ASPECT_API_URL,ASPECT_EDGE_WORKER_URL:process.env.ASPECT_EDGE_WORKER_URL,ASPECT_API_KEY:process.env.ASPECT_API_KEY,ASPECT_POSTHOG_KEY:process.env.ASPECT_POSTHOG_KEY,ASPECT_POSTHOG_HOST:process.env.ASPECT_POSTHOG_HOST,ASPECT_DISABLE_POSTHOG:process.env.ASPECT_DISABLE_POSTHOG,POSTHOG_KEY:process.env.POSTHOG_KEY,POSTHOG_API_KEY:process.env.POSTHOG_API_KEY,POSTHOG_HOST:process.env.POSTHOG_HOST,POSTHOG_DISABLED:process.env.POSTHOG_DISABLED},s=Ee({options:n,environment:t});Ne({config:s,packageVersion:je.version});let r=new ne(s);n.check?await r.runCheckOnly():s.batchSizeBytes!==void 0?await r.runBatched():await r.run()}catch(t){console.error("Fatal error:",t),e=1}finally{await He()}process.exit(e)});Ce.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aspect-sync",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "CLI tool to sync files from external services to Aspect via rclone",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "type": "module",
16
16
  "scripts": {
17
- "build": "tsc && esbuild src/index.ts --bundle --platform=node --format=esm --minify --outfile=dist/index.js --external:axios --external:chalk --external:commander --external:log-update",
17
+ "build": "tsc && node scripts/build.mjs",
18
18
  "build:watch": "tsc --watch",
19
19
  "dev": "tsx src/index.ts",
20
20
  "test": "vitest run",
@@ -35,7 +35,8 @@
35
35
  "axios": "^1.11.0",
36
36
  "chalk": "^5.3.0",
37
37
  "commander": "^12.0.0",
38
- "log-update": "^6.0.0"
38
+ "log-update": "^6.0.0",
39
+ "posthog-node": "^5.34.1"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@aspect/transfer-utils": "file:../packages/transfer-utils",