aspect-sync 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,116 +2,7 @@
2
2
 
3
3
  A CLI tool to sync files from external services to the Aspect platform.
4
4
 
5
- ## Sources
6
-
7
- The `--source` flag selects where files come from:
8
-
9
- | Source | Description | Data path |
10
- |--------|-------------|-----------|
11
- | `rclone` (default) | Any rclone-supported remote (Dropbox, Google Drive, S3, ...) | Downloaded to local staging, then uploaded |
12
- | `local` | A local directory (including externally mounted filesystems) | Uploaded in place, no staging copy |
13
- | `lucidlink` | A LucidLink filespace, mounted headlessly for the duration of the sync | Mounted via `lucid daemon`, uploaded in place |
14
-
15
- ```bash
16
- # rclone remote (default; --source rclone is implied)
17
- aspect-sync --remote dropbox --path /videos ...
18
- aspect-sync --source rclone --remote gdrive ...
19
-
20
- # local directory
21
- aspect-sync --source local --path /data/staged-customer-files ...
22
-
23
- # LucidLink filespace (requires the LucidLink client installed and a password
24
- # via --lucid-password-file or the LUCID_PASSWORD env variable)
25
- aspect-sync --source lucidlink \
26
- --lucid-fs filespace.domain \
27
- --lucid-user user@example.com \
28
- --lucid-password-file ~/.lucid_pwd \
29
- --lucid-cache-size 100GB \
30
- --path /Projects/Customer ...
31
- ```
32
-
33
- For `lucidlink`, the filespace is mounted at a session-scoped mount point with its cache on the sync temp volume, linked before listing starts, and unmounted (and its cache deleted) when the sync finishes or fails. `--path` is the folder within the filespace ("/" syncs the whole filespace).
34
-
35
- ## Features
36
-
37
- - **Rclone integration**: Lists and downloads from any rclone-supported remote.
38
- - **In-place local sources**: Local directories and mounted filespaces upload directly with no staging copy.
39
- - **LucidLink lifecycle management**: Mounts and unmounts filespaces headlessly around the sync.
40
- - **Aspect-compatible path planning**: Preserves source hierarchy while sanitizing names that Aspect rejects.
41
- - **Duplicate preservation when supported**: Preserves duplicate file and folder names when the rclone provider exposes stable IDs.
42
- - **Idempotent reruns**: Reuses existing directories and skips assets that are already uploaded.
43
- - **Batched migrations**: Downloads and uploads large remotes in size-limited batches.
44
- - **Progress display**: Shows download, upload, skip, and failure progress in the terminal.
45
- - **Session isolation**: Uses unique session directories so concurrent syncs do not collide.
46
- - **Automatic cleanup**: Removes local staged files after successful upload unless `--keep-local` is set.
47
-
48
- ## Prerequisites
49
-
50
- 1. **Node.js 22+** installed
51
- 2. **rclone** installed and configured
52
- - Install: https://rclone.org/install/
53
- - Configure your remote: `rclone config`
54
- 3. **Aspect API Key** for authentication
55
-
56
- ## Configuring Rclone
57
-
58
- Before using this tool, you must configure rclone with your cloud storage provider.
59
-
60
- ### Initial Setup
61
-
62
- 1. Run the rclone configuration wizard:
63
- ```bash
64
- rclone config
65
- ```
66
-
67
- 2. Choose `n` for "New remote"
68
-
69
- 3. Give it a name (e.g., `dropbox`, `gdrive`, `my-s3`)
70
- - **This name is what you'll use for the `--remote` parameter**
71
- - Use only letters, numbers, hyphens, and underscores
72
- - Don't include special characters or colons
73
-
74
- 4. Select your storage provider from the list (Dropbox, Google Drive, S3, etc.)
75
-
76
- 5. Follow the prompts to authenticate with your cloud provider
77
-
78
- ### Verify Configuration
79
-
80
- Check your configured remotes:
81
- ```bash
82
- rclone listremotes
83
- ```
84
-
85
- Output example:
86
- ```
87
- dropbox:
88
- gdrive:
89
- my-s3:
90
- ```
91
-
92
- **Important:** The remote names are shown **with a colon** (`:`) but you use them **without the colon** in the `--remote` parameter.
93
-
94
- Examples:
95
- - If you see `dropbox:`, use `--remote dropbox`
96
- - If you see `my-dropbox:`, use `--remote my-dropbox`
97
- - If you see `gdrive:`, use `--remote gdrive`
98
-
99
- ### Test Your Remote
100
-
101
- Before syncing, test that your remote works:
102
- ```bash
103
- # List files in the root of your remote
104
- rclone lsjson dropbox: --recursive
105
-
106
- # List files in a specific folder
107
- rclone lsjson dropbox:my-folder --recursive
108
- ```
109
-
110
- This should list files in your cloud storage. If you see files listed, your remote is configured correctly!
111
-
112
- ## Installation
113
-
114
- Install globally via npm:
5
+ ## Install
115
6
 
116
7
  ```bash
117
8
  npm install -g aspect-sync
@@ -119,353 +10,91 @@ npm install -g aspect-sync
119
10
 
120
11
  ## Usage
121
12
 
122
- ### Basic Command
123
-
124
- If installed globally:
125
- ```bash
126
- aspect-sync \
127
- --remote dropbox \
128
- --path /my-videos \
129
- --directory-id <aspect-directory-id> \
130
- --project-id <aspect-project-id> \
131
- --api-key <your-api-key>
132
- ```
133
-
134
- Or with npx (no installation):
135
13
  ```bash
136
- npx aspect-sync \
137
- --remote dropbox \
138
- --path /my-videos \
139
- --directory-id <aspect-directory-id> \
140
- --project-id <aspect-project-id> \
141
- --api-key <your-api-key>
14
+ aspect-sync --help
142
15
  ```
143
16
 
144
- ### Command Options
145
-
146
- Required:
147
-
148
- | Option | Description |
149
- |--------|-------------|
150
- | `--path <path>` | Path to sync from: remote path (`rclone`), local directory (`local`), or path within the filespace (`lucidlink`). |
151
- | `--directory-id <id>` | Aspect directory ID to upload into. |
152
- | `--project-id <id>` | Aspect project ID. |
153
- | `--api-key <key>` | Aspect API key. Can also be set with `ASPECT_API_KEY`. |
154
-
155
- Source selection:
156
-
157
- | Option | Description | Default |
158
- |--------|-------------|---------|
159
- | `--source <kind>` | Source kind: `rclone`, `local`, or `lucidlink`. | `rclone` |
160
- | `--remote <name>` | rclone remote name from your rclone config, without the trailing colon. Required for `--source rclone`. | Not set |
161
-
162
- LucidLink options:
163
- | Option | Description | Default |
164
- | ------ | ----------- | ------- |
165
- | `--lucid-fs <filespace>` | LucidLink filespace (e.g. `myspace.mydomain`). Required for `--source lucidlink`. | Not set |
166
- | `--lucid-user <user>` | LucidLink filespace user. Required for `--source lucidlink`. | Not set |
167
- | `--lucid-password-file <path>` | File containing the LucidLink password. Alternatively set `LUCID_PASSWORD`. | Not set |
168
- | `--lucid-instance <number>` | LucidLink daemon instance ID. | `9001` |
169
- | `--lucid-cache-size <size>` | LucidLink `DataCache.Size` applied after mount (e.g. `100GB`). | Client default |
170
-
171
- Aspect API options:
172
-
173
- | Option | Description | Default |
174
- |--------|-------------|---------|
175
- | `--api-url <url>` | Aspect API URL. Can also be set with `ASPECT_API_URL`. | `https://api.aspect.inc` |
176
- | `--edge-worker-url <url>` | Aspect edge worker URL. Can also be set with `ASPECT_EDGE_WORKER_URL`. | `https://mackinac.aspect.inc` |
177
-
178
- Sync behavior:
179
-
180
- | Option | Description | Default |
181
- |--------|-------------|---------|
182
- | `--upload-concurrent <number>` | Maximum concurrent chunk uploads to Aspect. | `16` |
183
- | `--batch-size <size>` | Enables batched mode with a maximum batch size, for example `500GB` or `1TB`. | Disabled |
184
- | `--keep-local` | Keep local staged files after upload for debugging. | `false` |
185
- | `--check` | Compare remote files against Aspect without downloading or uploading, including missing, extra, incomplete, and size-mismatched files. | `false` |
186
- | `--temp-dir <path>` | Base temporary directory for sync sessions. | `~/.aspect/sync` |
187
- | `--session <name>` | Session name. If omitted, a nanosecond-precision timestamp is generated. | Auto-generated |
188
-
189
- rclone tuning:
190
-
191
- | Option | Description | Default |
192
- |--------|-------------|---------|
193
- | `--rclone-transfers <number>` | Parallel file transfers for bulk rclone sync. Also controls rclone checkers. | `4` |
194
- | `--rclone-multi-thread-streams <number>` | Streams per large file for rclone transfers. | `4` |
195
- | `--rclone-multi-thread-chunk-size <size>` | rclone multi-thread chunk size. | `64MiB` |
196
- | `--rclone-multi-thread-cutoff <size>` | Minimum file size for rclone multi-threading. | `64MiB` |
197
- | `--rclone-buffer-size <size>` | rclone buffer size per transfer. | `64M` |
198
- | `--rclone-no-mmap` | Disable rclone memory-mapped I/O. | `false` |
199
- | `--rclone-extra <arg>` | Extra rclone argument. Repeat for multiple args. | Not set |
200
-
201
- Repeat `--rclone-extra` for each passthrough value. Example:
17
+ Sync commands:
202
18
 
203
19
  ```bash
204
- aspect-sync \
205
- --remote gdrive \
206
- --path /Videos \
207
- --directory-id <directory-id> \
208
- --project-id <project-id> \
209
- --api-key <api-key> \
210
- --rclone-extra --drive-root-folder-id \
211
- --rclone-extra <folder-id>
20
+ aspect-sync sync rclone
21
+ aspect-sync sync local
22
+ aspect-sync sync lucidlink
23
+ aspect-sync sync frameio
212
24
  ```
213
25
 
214
- ### Environment Variables
215
-
216
- You can set API credentials via environment variables:
26
+ Shared Aspect destination options:
217
27
 
218
28
  ```bash
219
- export ASPECT_API_KEY=your-api-key
220
- export ASPECT_API_URL=https://api.aspect.inc
221
- export ASPECT_EDGE_WORKER_URL=https://mackinac.aspect.inc
222
-
223
- aspect-sync \
224
- --remote dropbox \
225
- --path /my-videos \
226
- --directory-id <directory-id> \
227
- --project-id <project-id>
29
+ --asp-directory-id <aspect-directory-id>
30
+ --asp-project-id <aspect-project-id>
31
+ --asp-api-key <aspect-api-key>
32
+ --asp-api-url <url>
33
+ --asp-edge-worker-url <url>
34
+ --temp-dir <path>
35
+ --batch-size <size>
36
+ --upload-concurrent <number>
228
37
  ```
229
38
 
230
- 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.
231
-
232
- ## Examples
233
-
234
- ### Sync from Dropbox
39
+ Rclone example:
235
40
 
236
41
  ```bash
237
- aspect-sync \
42
+ aspect-sync sync rclone \
238
43
  --remote dropbox \
239
- --path /Camera Uploads \
240
- --directory-id abc-123-def \
241
- --project-id xyz-789-uvw \
242
- --api-key your-api-key
243
- ```
244
-
245
- ### Sync from Google Drive with Custom Concurrency
246
-
247
- ```bash
248
- aspect-sync \
249
- --remote gdrive \
250
- --path /Videos/2024 \
251
- --directory-id abc-123-def \
252
- --project-id xyz-789-uvw \
253
- --api-key your-api-key \
254
- --upload-concurrent 8 \
255
- --rclone-extra --drive-shared-with-me
256
- ```
257
-
258
- ### Sync a Specific Google Drive Folder by ID
259
-
260
- ```bash
261
- aspect-sync \
262
- --remote gdrive \
263
- --path / \
264
- --directory-id abc-123-def \
265
- --project-id xyz-789-uvw \
266
- --api-key your-api-key \
267
- --rclone-extra --drive-root-folder-id \
268
- --rclone-extra 1truv6wvzgXM3CkGMzuC8c-hrpMk5RAAs
44
+ --source-path /Customer/Folder \
45
+ --asp-directory-id <aspect-directory-id> \
46
+ --asp-project-id <aspect-project-id> \
47
+ --asp-api-key <aspect-api-key>
269
48
  ```
270
49
 
271
- ### Sync from S3 Bucket
50
+ Local example:
272
51
 
273
52
  ```bash
274
- aspect-sync \
275
- --remote s3 \
276
- --path mybucket/videos \
277
- --directory-id abc-123-def \
278
- --project-id xyz-789-uvw \
279
- --api-key your-api-key
53
+ aspect-sync sync local \
54
+ --source-path /data/customer-files \
55
+ --asp-directory-id <aspect-directory-id> \
56
+ --asp-project-id <aspect-project-id> \
57
+ --asp-api-key <aspect-api-key>
280
58
  ```
281
59
 
282
- ### Concurrent Syncs
283
-
284
- Multiple syncs can run simultaneously using sessions for isolation. Each session gets its own subdirectory.
285
-
286
- **Auto-generated sessions (default):**
287
-
288
- Each sync automatically gets a unique nanosecond-precision timestamp, allowing unlimited concurrent syncs without conflicts.
60
+ LucidLink example:
289
61
 
290
62
  ```bash
291
- # Terminal 1
292
- aspect-sync --remote dropbox --path /project-a --directory-id abc-123 --project-id p1 --api-key key
293
- # Session: 2025-10-21_20h-15m-30s-487123456ns
294
-
295
- # Terminal 2
296
- aspect-sync --remote dropbox --path /project-b --directory-id def-456 --project-id p2 --api-key key
297
- # Session: 2025-10-21_20h-15m-30s-487945821ns
63
+ aspect-sync lucidlink login
298
64
 
299
- # Terminal 3
300
- aspect-sync --remote gdrive --path /project-c --directory-id ghi-789 --project-id p3 --api-key key
301
- # Session: 2025-10-21_20h-15m-30s-488201937ns
65
+ aspect-sync sync lucidlink \
66
+ --source-path /Projects \
67
+ --lucid-instance 9001 \
68
+ --lucid-cache-size 500GB \
69
+ --asp-directory-id <aspect-directory-id> \
70
+ --asp-project-id <aspect-project-id> \
71
+ --asp-api-key <aspect-api-key>
302
72
  ```
303
73
 
304
- **Custom sessions:**
305
- ```bash
306
- # Terminal 1
307
- aspect-sync --remote dropbox --path /videos --directory-id abc-123 --project-id p1 --session prod-sync --api-key key
308
- # Session: prod-sync
309
-
310
- # Terminal 2
311
- aspect-sync --remote gdrive --path /images --directory-id def-456 --project-id p2 --session dev-sync --api-key key
312
- # Session: dev-sync
313
- ```
314
-
315
- **Finding your temp files:**
316
-
317
- Sessions are stored in `~/.aspect/sync/{session-name}` by default. The full path is shown in the logs at startup.
318
-
319
- ## How It Works
320
-
321
- 1. **Session creation**: Creates an isolated local session directory.
322
- 2. **Remote listing**: Uses `rclone lsjson` to list files and directories with IDs when the remote exposes them.
323
- 3. **Path planning**: Sanitizes names for Aspect and assigns unique targets for duplicate files and folders.
324
- 4. **Directory planning**: Fetches the existing Aspect directory tree and creates only missing directories.
325
- 5. **Asset existence check**: Skips assets that already exist and are fully uploaded.
326
- 6. **Download**: Downloads unchanged files with bulk `rclone sync --files-from`; downloads renamed or duplicate files by ID when needed.
327
- 7. **Upload**: Uploads staged files through `@aspect/upload-core` and the Aspect edge worker.
328
- 8. **Cleanup**: Deletes local staged files after successful upload unless `--keep-local` is set.
329
-
330
- Aspect upload chunk size is controlled by the server. There is no CLI flag for upload chunk size.
331
-
332
- ## Name Sanitization And Duplicates
333
-
334
- 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:
335
-
336
- - forbidden characters such as `:`, `*`, `?`, `"`, `<`, `>`, and `|` are replaced with `_`
337
- - trailing dots/spaces are trimmed
338
- - reserved Windows names such as `CON`, `AUX`, and `COM1` are prefixed with `_`
339
- - names are truncated to the backend byte limit
340
-
341
- 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:
342
-
343
- - duplicate files use parenthesized suffixes, for example `IMG_1891.MOV`, `IMG_1891 (2).MOV`
344
- - duplicate folders use numeric suffixes, for example `Shoot`, `Shoot 2`
345
-
346
- Provider behavior:
347
-
348
- - Providers without duplicate folder ambiguity work normally.
349
- - 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.
350
- - 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.
351
- - Duplicate folders without stable folder IDs fail with a clear error instead of silently merging folders.
352
-
353
- 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.
354
-
355
- ## Idempotent Behavior
356
-
357
- The syncer is **fully idempotent** - you can safely re-run the same sync multiple times:
358
-
359
- **Existing directories are reused** - The tool fetches the directory tree first and only creates missing directories.
360
-
361
- **Existing assets are skipped** - Before uploading, checks if an asset with the same name, size, and location already exists.
362
- - If found and fully uploaded: Skips upload
363
- - If found but incomplete: Deletes incomplete asset and re-uploads
364
- - If not found: Proceeds with upload
365
-
366
- **Clean re-runs** - If a sync fails halfway:
74
+ Frame.io example:
367
75
 
368
76
  ```bash
369
- # First run - uploads 50 of 100 files then crashes
370
- aspect-sync --remote dropbox --path /videos --directory-id abc --project-id xyz --api-key key
371
-
372
- # Re-run - skips the 50 uploaded files, uploads remaining 50
373
- aspect-sync --remote dropbox --path /videos --directory-id abc --project-id xyz --api-key key
374
- ```
375
-
376
- **Output on re-run:**
377
- ```
378
- video1.mp4 (100%)
379
- video2.mp4 (Skipped - already uploaded)
380
- video3.mp4 (Skipped - already uploaded)
381
- video4.mp4 (45%)
77
+ aspect-sync frameio login
382
78
 
383
- Total: 100 | Success: 1 | Failed: 0 | Skipped: 98 | In Progress: 1 | Queued: 0
79
+ aspect-sync sync frameio \
80
+ --source-folder-id <frameio-folder-id> \
81
+ --frameio-download-concurrent 8 \
82
+ --asp-directory-id <aspect-directory-id> \
83
+ --asp-project-id <aspect-project-id> \
84
+ --asp-api-key <aspect-api-key>
384
85
  ```
385
86
 
386
- ## CLI Progress Display
387
-
388
- The tool shows dynamic, in-place progress updates:
389
-
390
- ```
391
- video1.mp4 (100%)
392
- video2.mp4 (100%)
393
- video3.mp4 (Skipped - already uploaded)
394
- video4.mp4 (47%)
395
- video5.mp4 (23%)
396
-
397
- Total: 10 | Success: 2 | Failed: 0 | Skipped: 1 | In Progress: 2 | Queued: 5 | Speed: 45.3 Mbps | Time remaining: 2m 15s
398
- ```
399
-
400
- Only files that are actively uploading are shown (not the entire queue).
401
-
402
- ## Error Handling
403
-
404
- ### Retry Logic
405
-
406
- - **Chunk retries**: Upload chunks are retried on transient failures.
407
- - **File retries**: Failed files can be retried by rerunning the sync.
408
- - **Exponential backoff**: Delays increase exponentially between retries
409
-
410
- ### Common Errors
411
-
412
- **rclone not found:**
413
- ```
414
- Error: rclone is not installed or not in PATH
415
- ```
416
- Solution: Install rclone from https://rclone.org/install/
417
-
418
- **Authentication failed:**
419
- ```
420
- Error: 401 Unauthorized
421
- ```
422
- Solution: Check your `--api-key` is correct
423
-
424
- **Directory not found:**
425
- ```
426
- Error: 404 Not Found - Directory not found
427
- ```
428
- Solution: Verify `--directory-id` exists and you have access
429
-
430
- ## Troubleshooting
431
-
432
- ### Keep local files for debugging
433
-
434
- Use `--keep-local` to prevent deletion of synced files:
435
-
436
- ```bash
437
- aspect-sync \
438
- --remote dropbox \
439
- --path /test \
440
- --directory-id abc-123 \
441
- --project-id xyz-789 \
442
- --api-key your-key \
443
- --keep-local
444
- ```
445
-
446
- ### Increase concurrency
447
-
448
- If you have high bandwidth, increase `--upload-concurrent`:
87
+ Source helpers:
449
88
 
450
89
  ```bash
451
- aspect-sync \
452
- --remote dropbox \
453
- --path /test \
454
- --directory-id abc-123 \
455
- --project-id xyz-789 \
456
- --api-key your-key \
457
- --upload-concurrent 16
90
+ aspect-sync rclone login|doctor|list|probe
91
+ aspect-sync lucidlink login|doctor|list|probe
92
+ aspect-sync frameio login|doctor|list|probe
458
93
  ```
459
94
 
460
- ### Check rclone configuration
461
-
462
- Verify your rclone remote is configured:
463
-
464
- ```bash
465
- rclone listremotes
466
- rclone lsjson dropbox: --recursive
467
- ```
95
+ ## Notes
468
96
 
469
- ## License
97
+ - Use only with accounts and data you are authorized to access.
98
+ - The CLI preserves source hierarchy, skips assets that are already uploaded, and can be rerun safely.
99
+ - Large migrations should use `--batch-size`, `--temp-dir`, and tuned concurrency appropriate for the runner.
470
100
 
471
- MIT
package/dist/index.d.ts CHANGED
@@ -1,3 +1,11 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ import { Command } from "commander";
3
+ import type { DataSyncEnvironment } from "./config.js";
4
+ import { type ExecuteSyncCommand } from "./sync/commands.js";
5
+ export interface CreateProgramOptions {
6
+ packageVersion?: string;
7
+ executeSyncCommand?: ExecuteSyncCommand;
8
+ getEnvironment?: () => DataSyncEnvironment;
9
+ }
10
+ export declare function createProgram(options?: CreateProgramOptions): Command;
3
11
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,18 +1,28 @@
1
1
  #!/usr/bin/env node
2
- import{Command as Rs}from"commander";import ut from"node:path";import{readFileSync as Ts}from"node:fs";import{fileURLToPath as Ps}from"node:url";import ht from"node:fs";import pt from"node:os";import N from"node:path";var mt="phc_rDzmwduU3NzHyELgLEg7nMjqpTgaSpC2a6tMKL8VyjN",gt="https://t.aspect.inc",ft="https://t.aspect.inc";function yt(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 $e(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=Z({value:n.options.uploadConcurrent,optionName:"--upload-concurrent"}),s=Tt(n.options.batchSize),r=n.options.session??Pt({now:n.now??new Date,highResolutionTime:n.highResolutionTime??process.hrtime.bigint()}),i=n.options.tempDir||N.join(pt.homedir(),".aspect","sync"),o=N.join(i,r);return{source:St({options:n.options,environment:n.environment,localTempDir:o}),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:t,keepLocal:n.options.keepLocal,localTempDir:o,sessionName:r,batchSizeBytes:s,analytics:{posthogKey:n.environment.ASPECT_POSTHOG_KEY||n.environment.POSTHOG_KEY||n.environment.POSTHOG_API_KEY||mt,posthogHost:n.environment.ASPECT_POSTHOG_HOST||n.environment.POSTHOG_HOST||gt||ft,disabled:Ge(n.environment.ASPECT_DISABLE_POSTHOG)||Ge(n.environment.POSTHOG_DISABLED)}}}function St(n){let e=n.options.source;switch(e){case"rclone":return Ct(n.options);case"local":return bt(n.options);case"lucidlink":return At({options:n.options,environment:n.environment,localTempDir:n.localTempDir});default:throw new Error(`Error: unknown --source "${e}". Supported sources: rclone, local, lucidlink`)}}function Ct(n){if(!n.remote)throw new Error("Error: --remote is required when using --source rclone");let e=Z({value:n.rcloneTransfers,optionName:"--rclone-transfers"}),t=Z({value:n.rcloneMultiThreadStreams,optionName:"--rclone-multi-thread-streams"});return{kind:"rclone",remote:n.remote,remotePath:n.path,rcloneOptions:{transfers:e,checkers:e>=16?Math.floor(e/4):e,multiThreadStreams:t,multiThreadChunkSize:n.rcloneMultiThreadChunkSize,multiThreadCutoff:n.rcloneMultiThreadCutoff,bufferSize:n.rcloneBufferSize,useMmap:!n.rcloneNoMmap,extraRcloneArgs:n.rcloneExtra}}}function bt(n){return{kind:"local",rootPath:N.resolve(n.path)}}function At(n){let e=n.options.lucidFs;if(!e)throw new Error("Error: --lucid-fs is required when using --source lucidlink");let t=n.options.lucidUser;if(!t)throw new Error("Error: --lucid-user is required when using --source lucidlink");let s=Et({passwordFile:n.options.lucidPasswordFile,environment:n.environment}),r=Z({value:n.options.lucidInstance,optionName:"--lucid-instance"}),i=`${n.localTempDir}-lucid`;return{kind:"lucidlink",filespace:e,user:t,password:s,filespacePath:Rt(n.options.path),instanceId:r,workDir:i,mountPoint:N.join(i,"mnt"),cacheRootPath:N.join(i,"cache"),cacheSize:n.options.lucidCacheSize}}function Et(n){if(n.passwordFile){let t=ht.readFileSync(n.passwordFile,"utf-8").replace(/\r?\n$/,"");if(t.length===0)throw new Error(`Error: LucidLink password file is empty: ${n.passwordFile}`);return t}let e=n.environment.LUCID_PASSWORD;if(e)return e;throw new Error("Error: LucidLink password is required. Provide --lucid-password-file or set LUCID_PASSWORD.")}function Rt(n){let e=n.replace(/^\/+/,"").replace(/\/+$/,"");if(e.split("/").some(t=>t===".."))throw new Error(`Error: --path cannot contain parent directory segments: ${n}`);return e}function Z(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 Tt(n){if(!n)return;let e=yt(n);if(e===null)throw new Error(`Error: Invalid batch size format: ${n}`);return e}function Ge(n){return n?["1","true","yes"].includes(n.toLowerCase()):!1}function Pt(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 X from"node:fs/promises";import Ne from"node:path";import Ut from"fs/promises";import Ft from"path";function He(n,e){let t=new Map;for(let u of n){let c=Ft.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((p,g)=>p+g.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 p of c)a+p.size>e&&o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),o.push(p),a+=p.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 je(n){try{await Ut.unlink(n)}catch(e){if(e.code!=="ENOENT")throw e}}import m from"chalk";import Ke from"log-update";function ee(n,e){if(e.length===0)return n.finalizedStatus?n.finalizedStatus:n.isCreatingFolders?"creating-folders":"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 Ee(n,e){let t=ee(n,e);return t==="creating-folders"||t==="in-progress"||t==="queued"||t==="paused"?"cancelled":t}function Re(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 Te(n){for(let e of Object.values(n))if(e.status==="queued"||e.status==="in-progress"||e.status==="paused")return!0;return!1}function G(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 Pe(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 Fe(n){return Object.values(n).some(e=>e.status==="paused")}import js from"axios";var $=class{#t;#s;#e;#r;#n;#i=0;#a=0;#u=0;#o=0;#c=0;#m=0;constructor(e){this.#t=e?.alphaFast??.1,this.#s=e?.alphaMax??.5,this.#e=e?.consecutiveForBoost??3,this.#r=e?.minSamples??3,this.#n=e?.maxGapSeconds??2}sample(e){let t=Date.now();if(this.#o===0){this.#o=t,this.#c=e;return}let r=(t-this.#o)/1e3,i=e-this.#c;if(r<=0||i<0)return;if(r>this.#n){this.#o=t,this.#c=e;return}let o=i/r;if(this.#m===0)this.#i=o;else{let l=o-this.#i>=0?1:-1;this.#u!==0&&l===this.#u?this.#a++:this.#a=0,this.#u=l;let u=Math.min(1,this.#a/this.#e),c=this.#t+(this.#s-this.#t)*u;this.#i=c*o+(1-c)*this.#i}this.#o=t,this.#c=e,this.#m++}etaSeconds(e){return!this.isWarmedUp||this.#i<=0?0:e/this.#i}adjustTotalBytes(e){this.#c+=e}reset(){this.#i=0,this.#a=0,this.#u=0,this.#o=0,this.#c=0,this.#m=0}serialize(){return{displaySpeedBps:this.#i,lastSampleTimestamp:this.#o,lastSampleTotalBytes:this.#c,sampleCount:this.#m}}get speedBps(){return this.#i}get speedMbps(){return this.#i*8/1e6}get isWarmedUp(){return this.#m>=this.#r}};function I(n){let e={"X-Aspect-Share-Id":n.shareId};return n.shareAuthentication&&(e["X-Aspect-Share-Authentication"]=n.shareAuthentication),e}var H=class{#t;#s;#e;#r;#n;#i;#a;#u;#o;#c;#m;#l;#D;#f;#A;#v;#b;#S;#P;#U;#F;#p;#C;#T;#d;#k;#g;#E;#I;#L;#x;#B;constructor(e){this.#s=e?.minConcurrency??1,this.#e=e?.maxConcurrency??8,this.#t=this.#H(e?.initialConcurrency??this.#s),this.#r=e?.errorThreshold??1,this.#n=(e?.cooldownSeconds??10)*1e3,this.#i=e?.plateauThreshold??.05,this.#a=Math.max(this.#e,Math.floor(e?.sampleWindowSize??64)),this.#u=Math.max(2,Math.floor(e?.minSamples??4)),this.#o=Math.max(1.1,e?.increaseFactor??1.5),this.#c=e?.onChange,this.#m=e?.now??Date.now,this.#l=this.#t,this.#D=0,this.#f=[],this.#A=0,this.#v=0,this.#b=-1,this.#S=0,this.#P=void 0,this.#U=0,this.#F=0,this.#p=0,this.#C=this.#l,this.#T=0,this.#d=1/0,this.#k=0,this.#g=6e4,this.#E=0,this.#I=1/0,this.#L=0,this.#x=0,this.#B=0}recordSuccess(e,t,s){if(e<=0)return;if(s?.generation!==void 0){if(s.generation!==this.#D){s.generation===this.#b&&this.#S>0&&(this.#S--,this.#S===0&&(this.#P=s.completedAtMs??this.#m()));return}if(this.#S>0||this.#P!==void 0&&s.startedAtMs!==void 0&&s.startedAtMs<this.#P)return}else if(this.#v>0){this.#v--;return}let r=s?.completedAtMs??this.#m();for(this.#f.push({bytes:e,completedAtMs:r,startedAtMs:s?.startedAtMs,durationMs:t!==void 0&&t>0?t:void 0});this.#f.length>this.#a;)this.#f.shift();this.#A++,this.#U=0;let i=this.#M();this.#x=i.throughputBps,this.#B=i.latencyMsPerMB,this.#_(i)}recordError(){if(this.#U++,this.#U<this.#r)return;let e=this.#l;e===this.#E&&(this.#I=Math.min(this.#I,e),this.#L=this.#m()+3e4),this.#E=e;let t=this.#H(Math.floor(e/2));this.#F=this.#m()+this.#n,this.#U=0,e<=this.#C&&(this.#C=t,this.#T=0),e>t&&(this.#d=Math.min(this.#d,e),this.#q()),this.#R(t)}get concurrency(){return this.#l}get generation(){return this.#D}get speedBps(){return this.#x}get latencyMsPerMB(){return this.#B}reset(){this.#l=this.#t,this.#D++,this.#f=[],this.#A=0,this.#v=0,this.#b=-1,this.#S=0,this.#P=void 0,this.#U=0,this.#F=0,this.#p=0,this.#C=this.#l,this.#T=0,this.#d=1/0,this.#k=0,this.#g=6e4,this.#E=0,this.#I=1/0,this.#L=0,this.#x=0,this.#B=0,this.#c?.(this.#l)}#_(e){if(this.#f.length<this.#W()||this.#A<this.#W()||e.throughputBps<=0)return;let t=this.#m();if(t<this.#F)return;if(e.averageDurationMs>=2e4&&this.#l>=4){this.#C=Math.max(this.#s,Math.floor(this.#l/2)),this.#T=0,this.#R(this.#C);return}if(this.#T===0){this.#O(e.throughputBps),this.#w(e);return}let s=(e.throughputBps-this.#T)/this.#T;if(s>=this.#i){this.#O(e.throughputBps),this.#w(e);return}if(this.#l>this.#C){let r=s<=-.08,i=s<this.#i;(r||i)&&(this.#d=Math.min(this.#d,this.#l),this.#q(),this.#R(this.#C));return}if(this.#l<this.#C){this.#w(e);return}this.#l===this.#C&&(this.#T=Math.max(this.#T,e.throughputBps),t>=this.#p&&this.#w(e))}#w(e){let t=this.#Q();if(this.#l>=t){this.#A=0;return}if(e.averageDurationMs>=5e3&&this.#l>=4&&this.#T>0){this.#A=0;return}if(this.#$()){let r=this.#m();if(this.#k===0){this.#k=r+this.#g,this.#p=this.#k,this.#A=0;return}if(r<this.#k){this.#A=0;return}}let s=this.#h(t);if(s===this.#l){this.#A=0;return}this.#R(s)}#O(e){this.#C=this.#l,this.#T=e,this.#d<=this.#l&&(this.#d=1/0),this.#k=0,this.#g=6e4,this.#p=0}#h(e){if(this.#d<1/0){let r=Math.floor((this.#l+this.#d)/2);return r>this.#l&&r<this.#d?Math.min(e,r):Math.min(e,this.#l+1)}if(this.#l<4)return Math.min(e,this.#l+1);let t=Math.ceil(this.#l*this.#o),s=this.#l+2;return Math.min(e,Math.max(s,t))}#R(e){let t=this.#l,s=this.#D,r=this.#H(e);r!==t&&(this.#N(),this.#l=r,this.#D++,this.#b=s,this.#S=Math.max(0,t-1),this.#P=this.#S===0?this.#m():void 0,this.#v=Math.max(0,t-1),this.#c?.(this.#l))}#N(){this.#f=[],this.#A=0,this.#v=0}#$(){return this.#d<1/0&&this.#l===this.#C&&this.#d<=this.#C+1}#q(){let e=this.#d<1/0&&this.#d<=this.#C+1,t=e?this.#g:1e4;this.#p=this.#m()+t,e&&(this.#k=this.#p,this.#g=Math.min(this.#g*2,3e5))}#W(){return Math.max(this.#u,this.#l)}#Q(){return this.#I<1/0&&this.#m()>=this.#L&&(this.#I=1/0,this.#L=0),Math.max(this.#s,Math.min(this.#e,this.#I-1))}#H(e){return Math.max(this.#s,Math.min(this.#e,e))}#M(){let e=0,t=0,s=0,r=0;for(let l of this.#f)e+=l.bytes,l.durationMs!==void 0&&(t+=l.durationMs,s++,r+=l.durationMs/(l.bytes/(1024*1024)));if(s>0&&t>0)return{throughputBps:e/(t/1e3)*this.#l,latencyMsPerMB:r/s,averageDurationMs:t/s,durationSampleCount:s};if(this.#f.length<2)return{throughputBps:0,latencyMsPerMB:0,averageDurationMs:0,durationSampleCount:0};let i=this.#f[0],a=this.#f[this.#f.length-1].completedAtMs-i.completedAtMs;return{throughputBps:a>0?e/a*1e3:0,latencyMsPerMB:0,averageDurationMs:a>0?a/Math.max(1,this.#f.length-1):0,durationSampleCount:0}}};var L=class{#t;#s;#e;#r;#n;constructor(e){let t=e===0?null:e;this.#t=t,this.#s=t??0,this.#e=Date.now(),this.#r=[],this.#n=null}setLimit(e){let t=e===0?null:e;if(t===null){this.#t=null,this.#s=0,this.#c();let r=this.#r.splice(0);for(let i of r)i.resolve();return}let s=this.#t;this.#t=t,s===null?(this.#s=t,this.#e=Date.now()):(this.#i(),this.#s=Math.min(this.#s,t)),this.#o()}getLimit(){return this.#t}acquire(e){if(this.#t!==null){if(this.#i(),this.#r.length===0&&this.#s>=e){this.#s-=e;return}return this.#a(e)}}#i(){let e=Date.now(),t=(e-this.#e)/1e3;if(t<=0)return;let s=this.#t,r=t*s,i=this.#r.length>0?Math.max(s,this.#r[0].bytes):s;this.#s=Math.min(this.#s+r,i),this.#e=e}#a(e){return new Promise(t=>{this.#r.push({bytes:e,resolve:t}),this.#n===null&&this.#u()})}#u(){if(this.#r.length===0||this.#t===null){this.#n=null;return}let t=this.#r[0].bytes-this.#s,s=t>0?Math.ceil(t/this.#t*1e3):0;if(s<=0){this.#n=null,this.#o();return}this.#n=setTimeout(()=>{this.#n=null,this.#i(),this.#o()},s)}#o(){for(;this.#r.length>0;){if(this.#t===null){let t=this.#r.splice(0);for(let s of t)s.resolve();return}this.#i();let e=this.#r[0];if(this.#s>=e.bytes)this.#s-=e.bytes,this.#r.shift(),e.resolve();else{this.#u();return}}}#c(){this.#n!==null&&(clearTimeout(this.#n),this.#n=null)}};function qe(n){let e=`[${n}]`;return{info:(...t)=>console.info(e,...t),warn:(...t)=>console.warn(e,...t),error:(...t)=>console.error(e,...t)}}var ve=qe("transfer");var te=class{uploadAssets={};uploadGroups={};#t=new $;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()}#r(e){this.dirtyAssetIds.add(e)}#n(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.#r(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.#r(e)}markUploadInProgress(e){let t=this.uploadAssets[e];t&&(t.status="in-progress",this.#r(e))}markUploadSuccess(e){let t=this.uploadAssets[e];t&&(t.status="success",t.bytesUploaded=t.totalBytesToUpload,this.#r(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.#r(e),this.#s(r),this.#e(),this.cleanupOnCompletion(e)}removeUploadAsset(e){let s=this.uploadAssets[e]?.bytesUploaded??0;delete this.uploadAssets[e],this.#r(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.#r(e))}resetAssetForRetrying(e){let t=this.uploadAssets[e];t&&(t.status="queued",t.bytesUploaded=0,t.retryCount=0,this.#r(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.#r(e),this.#s(r),this.#e(),t.abortController.abort()}unpauseUpload(e){let t=this.uploadAssets[e];t&&t.status==="paused"&&(t.status="queued",this.#r(e))}pauseUploadGroup(e){let t=this.uploadGroups[e];if(t&&!t.isCreatingFolders){t.isPaused=!0,this.#n(e);for(let s of t.assetIds)this.pauseUpload(s)}}unpauseUploadGroup(e){let t=this.uploadGroups[e];t&&(t.isPaused=!1,this.#n(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.#r(e),this.#s(s),this.#e(),this.cleanupOnCompletion(e)}setChunkedState(e,t){let s=this.uploadAssets[e];s&&(s.chunkedState=t,this.#r(e))}addCompletedChunkIndex(e,t){let s=this.uploadAssets[e];!s||!s.chunkedState||(s.chunkedState={...s.chunkedState,completedChunkIndices:[...s.chunkedState.completedChunkIndices,t]},this.#r(e))}clearChunkedState(e){let t=this.uploadAssets[e];t&&(t.chunkedState=void 0,this.#r(e))}hasGroupsCreatingFolders(){return Object.values(this.uploadGroups).some(e=>e.isCreatingFolders===!0)}areAllUploadsPaused(){return Ue(this.uploadAssets)}hasPausedUploads(){return Fe(this.uploadAssets)}getUploadAsset(e){return this.uploadAssets[e]}getSerializableAsset(e){let t=this.uploadAssets[e];if(t)return this.#u(t)}getUploadSummary(){return G(this.#c())}getAllUploadAssetsSortedByRecent(){return Object.values(this.uploadAssets).map(e=>this.#u(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.#u(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.#n(t),t}updateUploadGroup(e,t){let s=this.uploadGroups[e];s&&(Object.assign(s,t),this.#n(e))}addAssetToGroup(e,t){let s=this.uploadGroups[e];s&&(s.assetIds.push(t),this.#n(e))}finalizeEmptyGroup({groupId:e,status:t,errorMessage:s}){let r=this.uploadGroups[e];r&&(r.assetIds.length>0||r.finalizedStatus||(r.finalizedStatus=t,r.errorMessage=s,r.isCreatingFolders=!1,r.completedAt=new Date().toISOString(),this.#n(e),this.dirtyHistoryGroupIds.add(e)))}removeUploadGroup(e){let t=this.uploadGroups[e];if(t)for(let s of t.assetIds)delete this.uploadAssets[s],this.#r(s);delete this.uploadGroups[e],this.#n(e)}getUploadGroup(e){let t=this.uploadGroups[e];if(t)return this.#o(t)}getAllUploadGroups(){return Object.values(this.uploadGroups).map(e=>this.#o(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 Pe(this.#o(t),s)}getUploadGroupStatus(e){let t=this.uploadGroups[e];if(!t)return null;let s=this.getGroupAssets(e);return ee(this.#o(t),s)}getAssetsByParentId(e){return Object.values(this.uploadAssets).filter(t=>t.parentId===e).map(t=>this.#u(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.#o(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.#o(i);this.dirtyHistoryGroupIds.add(s),!o.some(u=>u.status==="queued"||u.status==="in-progress")&&!i.completedAt&&(i.completedAt=new Date().toISOString(),this.#n(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.#r(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.#i(s),formattedTime:this.#a(r)}}#i(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.#o(t);return{groupId:t.id,name:t.name,type:t.type,fileCount:t.fileCount,folderCount:t.folderCount,topLevelFileCount:t.topLevelFileCount,topLevelFolderCount:t.topLevelFolderCount,status:Ee(r,s),createdAt:t.createdAt,completedAt:t.completedAt,rootDirectoryId:t.rootDirectoryId,projectId:t.projectId,errorMessage:t.errorMessage,conflictResolution:t.conflictResolution}}#u({fileReader:e,abortController:t,shareContext:s,...r}){return r}#o({fileReaders:e,...t}){return t}#c(){let e={};for(let[t,s]of Object.entries(this.uploadAssets))e[t]=this.#u(s);return e}#m(){let e={};for(let[t,s]of Object.entries(this.uploadGroups))e[t]=this.#o(s);return e}getSerializableSnapshot(){return{uploadAssets:this.#c(),uploadGroups:this.#m(),uploadStats:{...this.uploadStats},uploadSpeedState:this.uploadSpeedState}}getDirtyDelta(){let e={};for(let s of this.dirtyAssetIds){let r=this.uploadAssets[s];r&&(e[s]=this.#u(r))}let t={};for(let s of this.dirtyGroupIds){let r=this.uploadGroups[s];r&&(t[s]=this.#o(r))}return{assets:e,groups:t}}clearDirtyFlags(){this.dirtyAssetIds.clear(),this.dirtyGroupIds.clear(),this.dirtyHistoryGroupIds.clear()}};function wt(n,e){let t=new Date(n).getTime(),s=Date.now();return t-s<=e}var se=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&&!wt(s.expiresAt,3e5))return s.token;let r=this.#e.get(e);if(r)return r;let i=t?I(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 re=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)}isAssetComplete(e){let t=this.#s(e);return t?t.completedChunkIndices.size>=t.totalChunks:!1}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 It=/[/\\:*?"<>|\x00-\x1F]/g,xt=["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(It,"_");e=e.replace(/[. ]+$/,""),(!e||e==="."||e==="..")&&(e="unnamed");let t=e.includes(".")?e.substring(0,e.lastIndexOf(".")):e;xt.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 F=class extends Error{constructor(){super("Upload cancelled"),this.name="CancelledError"}};function x(n){return n instanceof F||n instanceof Error&&n.name==="CancelledError"||n instanceof Error&&n.name==="CanceledError"||n instanceof Error&&n.name==="AbortError"}function Nt(n){return x(n)||n instanceof Error&&n.name==="NoAuthError"}function zt(n){return new Promise(e=>setTimeout(e,n))}function Gt(n){return n instanceof Blob?n.size:n.byteLength}var j=class{#t;#s;#e;#r;#n;#i;#a;#u;#o;#c;#m;#l;#D;#f=null;#A=0;#v=!1;#b=[];#S=new Set;#P=!1;#U=!1;#F=!1;#p=[];#C=!1;#T=!1;#d=new re;#k=0;#g=new Map;#E=new Map;#I=[];#L=!1;#x=null;#B;#_="keep_both";#w=new Map;#O=null;#h=!1;#R=null;#N=!1;constructor(e){this.#t=e.httpClient,this.#s=new se(e.httpClient),this.#e=new te,this.#r=e.historyStore??null,this.#n=e.settingsStore??null,this.#i=e.analytics??null,this.#a=e.logger??ve,this.#u=e.onChange??null,this.#o=e.onClear??null,this.#c=e.onSummary??null,this.#m=e.onConcurrencyAdjusted??null,this.#D=e.deltaIntervalMs??333;let t=e.maxConcurrency??4;if(e.adaptiveConcurrency!==!1){let s=e.adaptiveConcurrencyConfig;this.#R=new H({initialConcurrency:s?.initialConcurrency??Math.min(4,t),minConcurrency:s?.minConcurrency??1,maxConcurrency:s?.maxConcurrency??t,errorThreshold:s?.errorThreshold,cooldownSeconds:s?.cooldownSeconds??10,plateauThreshold:s?.plateauThreshold,onChange:r=>{let i=this.#l;if(this.setMaxConcurrency(r),i===r)return;let o=this.#N?"reset":r>i?"probe_increase":"error_decrease",a=Math.round(this.#R.speedBps*8/1e6*100)/100,l=Math.round(this.#R.latencyMsPerMB*100)/100;this.#a.info(`Adaptive concurrency: ${i} \u2192 ${r} (${o}), measuredAt=${i}, speed=${a}Mbps, latency=${l}ms/MB`),this.#m?.({previousConcurrency:i,newConcurrency:r,reason:o,speedMbps:a,latencyMsPerMB:l})},now:s?.now}),this.#l=this.#R.concurrency}else this.#l=t;this.#r&&(this.#b=this.#r.load()),this.#n&&(this.#x=this.#n.getBandwidthLimitBps(),this.#_=this.#n.getConflictResolution()),this.#B=new L(this.#x),(this.#u||this.#c)&&(this.#f=setInterval(()=>{this.#ue()},this.#D)),this.#i&&(this.#O=setInterval(()=>{this.#de()},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.#p.push(t),this.#$(),this.#y(),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.#_});return this.#w.set(t,Date.now()),this.#i?.("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.#G(),this.#y(),t}pauseUpload(e){let t=this.#e.getUploadAsset(e);this.#e.pauseUpload(e),this.#p=this.#p.filter(s=>s!==e),this.#d.pauseAsset(e),!this.#h&&t&&this.#i&&this.#i("upload:file_paused",{file_name:t.fileName,file_size:t.totalBytesToUpload,bytes_uploaded:t.bytesUploaded,project_id:t.projectId??""}),this.#y()}unpauseUpload(e){this.#e.unpauseUpload(e),this.#y()}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.#p=this.#p.filter(l=>l!==e),this.#d.removeAsset(e),this.#g.delete(e),this.#E.delete(e),this.#e.markUploadCancelled(e),this.#e.clearChunkedState(e),t.fileReader.close?.(),!this.#h&&this.#i&&this.#i("upload:file_cancelled",{file_name:s,file_size:r,bytes_uploaded:i,project_id:o??""}),this.#y(),this.#M(),this.#$(),this.#X(),a&&(this.#I.push(a),this.#J())}cancelAllUploads(){let e=this.#V();this.#h=!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.#h=!1}this.#i?.("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.#h&&this.#i&&this.#i("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.#y(),this.#d.isAssetComplete(e)?this.#Y(e).catch(r=>{this.#z(e,r)}):this.#M()):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.#h;this.#h=!0,this.#e.pauseUploadGroup(e);for(let r of t.assetIds)this.#p=this.#p.filter(i=>i!==r),this.#d.pauseAsset(r);this.#h=s,this.#h||this.#te(e,t,"upload:group_paused"),this.#y()}unpauseUploadGroup(e){this.#e.unpauseUploadGroup(e),this.#y()}cancelUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;let{totalBytes:s,bytesUploaded:r,filesRemaining:i}=this.#ee(t),o=this.#h;this.#h=!0;for(let a of t.assetIds)this.cancelUpload(a);t.assetIds.length===0&&(this.#e.finalizeEmptyGroup({groupId:e,status:"cancelled"}),this.#G(),this.#y()),this.#h=o,this.#h||this.#i?.("upload:group_cancelled",{file_count:t.assetIds.length,files_remaining:i,total_bytes:s,bytes_uploaded:r,project_id:t.projectId}),this.#w.delete(e)}resumeUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;this.#h||this.#te(e,t,"upload:group_resumed");let s=this.#h;this.#h=!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.#h=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.#y()}markEmptyGroupFailed(e,t){let s=this.#e.uploadGroups[e];s&&(s.assetIds.length>0||s.finalizedStatus||(this.#a.error("Empty group upload failed",{groupId:e,groupName:s.name,errorMessage:t}),this.#e.finalizeEmptyGroup({groupId:e,status:"all-failed",errorMessage:t}),this.#G(),this.#w.delete(e),this.#y()))}markEmptyGroupCompleted(e){this.#e.finalizeEmptyGroup({groupId:e,status:"success"}),this.#G(),this.#w.delete(e),this.#y()}addAssetToGroup(e,t){this.#e.addAssetToGroup(e,t)}pauseAllUploads(){let e=this.#V();this.#h=!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.#h=!1}this.#i?.("upload:all_paused",e),this.#y()}resumeAllUploads(){let e=this.#V();this.#h=!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.#h=!1}this.#i?.("upload:all_resumed",e),this.#y()}clearAllUploads(){this.#p=[],this.#d.clear(),this.#g.clear(),this.#E.clear(),this.#e.clearAllUploads(),this.#e.uploadGroups={},this.#R&&(this.#N=!0,this.#R.reset(),this.#N=!1),this.#o?.({all:!0}),this.#c?.(this.#j())}clearHistory(){this.#b=[],this.#r?.clear(),this.#P=!0,this.#S.clear(),this.#F=!0,this.#y()}removeHistoryItem(e){this.#b=this.#b.filter(t=>t.groupId!==e),this.#r?.remove(e),this.#S.add(e),this.#F=!0,this.#y()}removeGroup(e){this.#e.removeUploadGroup(e),this.#b=this.#b.filter(t=>t.groupId!==e),this.#r?.remove(e),this.#S.add(e),this.#F=!0,this.#o?.({groupId:e}),this.#c?.(this.#j()),this.#y()}getHttpClient(){return this.#t}setBandwidthLimit(e){let t=e!==this.#x;this.#x=e,this.#B.setLimit(e),this.#n?.setBandwidthLimitBps(e),t&&this.#R&&(this.#N=!0,this.#R.reset(),this.#N=!1),this.#F=!0,this.#y()}getBandwidthLimit(){return this.#x}setConflictResolution(e){this.#_=e,this.#n?.setConflictResolution(e),this.#F=!0,this.#y()}getConflictResolution(){return this.#_}getGroupConflictResolution(e){return this.#e.getUploadGroup(e)?.conflictResolution??this.#_}setMaxConcurrency(e){this.#l=e,this.#M()}getSnapshot(){return this.#e.updateUploadStats(),{...this.#e.getSerializableSnapshot(),uploadHistory:[...this.#b??[]],uploadSummary:this.#j(),bandwidthLimitBps:this.#x,conflictResolution:this.#_}}getUploadAsset(e){return this.#e.getSerializableAsset(e)}getUploadSummary(){return this.#j()}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 Te(this.#e.getSerializableSnapshot().uploadAssets)}getServerAssetIdsToCancel(){return Re(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.#U=!0,this.#f&&(clearInterval(this.#f),this.#f=null),this.#O&&(clearInterval(this.#O),this.#O=null),this.#p=[],this.#d.clear();for(let e of Object.values(this.#e.uploadAssets))e.abortController.abort(),e.fileReader.close?.()}#$(){this.#T||(this.#T=!0,queueMicrotask(()=>{this.#T=!1,this.#q().catch(e=>{this.#a.error("Initiation pipeline error",{queueLength:this.#p.length},e)})}))}async#q(){if(!this.#C){this.#C=!0;try{await this.#W()}finally{this.#C=!1}}}async#W(){for(;this.#p.length>0&&!(this.#g.size>5);){let e=Math.min(this.#p.length,20-this.#g.size);if(e<=0)break;let t=[],s=[];for(let r=0;r<e&&this.#p.length>0;r++){let i=this.#p[0],o=this.#e.getUploadAsset(i);if(!o||o.status==="cancelled"){this.#p.shift(),r--;continue}if(this.#p.shift(),s.push(i),o.chunkedState)try{this.#Q(i,o),this.#M()}catch(a){x(a)||this.#z(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.#H(i)}catch(o){for(let a of i)this.#z(a,o instanceof Error?o:new Error(String(o)))}this.#M()}}}#Q(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.#g.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.#E.set(e,o),r.totalChunks===0||i.length>=r.totalChunks){this.#Y(e).catch(a=>{this.#z(e,a)});return}this.#d.registerAsset({assetId:e,totalChunks:r.totalChunks,completedChunkIndices:i})}async#H(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.#_:this.#_,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?I(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.#z(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.#G(),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.#I.push(c.asset_id),this.#J());continue}let p=Math.ceil(d.totalBytesToUpload/c.chunk_size),g=Array.from({length:p},()=>crypto.randomUUID());this.#s.seedToken(c.asset_id,c.token,c.token_expires_at);let h={serverAssetId:c.asset_id,chunkIds:g,chunkSize:c.chunk_size,totalChunks:p,sizeBytes:d.totalBytesToUpload};this.#e.setChunkedState(l,{assetId:h.serverAssetId,chunkIds:h.chunkIds,completedChunkIndices:[],chunkSize:h.chunkSize,totalChunks:h.totalChunks,sizeBytes:h.sizeBytes}),this.#g.set(l,h);let A=new Array(h.totalChunks).fill(0);if(this.#E.set(l,A),h.totalChunks===0){this.#Y(l).catch(y=>{this.#z(l,y)});continue}this.#d.registerAsset({assetId:l,totalChunks:h.totalChunks,completedChunkIndices:[]})}}#M(){if(!this.#U)for(;this.#k<this.#l;){let e=this.#d.claimNextChunk();if(!e)break;this.#k++;let{assetId:t,chunkIndex:s}=e,r=this.#R?.generation;this.#re(t,s,r).then(i=>{this.#k--,this.#ie(t,s,i),this.#M()}).catch(i=>{if(this.#k--,x(i)){this.#M();return}this.#oe(t,s,i),this.#M()})}}async#re(e,t,s){let r;for(let i=0;i<3;i++)try{let o=this.#E.get(e);return o&&(o[t]=0,this.#K(e)),await this.#ne(e,t,s)}catch(o){if(x(o))throw o;if(r=o instanceof Error?o:new Error(String(o)),this.#R?.recordError(),this.#ae(e,t,r,i),i===2)throw r;let a=this.#E.get(e);a&&(a[t]=0,this.#K(e));let l=1e3*Math.pow(2,i);await zt(l)}throw r||new Error("Unknown error during chunk upload")}async#ne(e,t,s){let r=this.#e.getUploadAsset(e);if(!r)throw new F;if(r.abortController.signal.aborted)throw new F;let i=this.#g.get(e);if(!i)throw new Error(`No chunk metadata for asset ${e}`);let o=t*i.chunkSize,a=Math.min(o+i.chunkSize,r.totalBytesToUpload),l=await r.fileReader.readChunk(o,a),u=Gt(l);if(r.abortController.signal.aborted)throw new F;let c=i.chunkIds[t],d=await this.#s.getToken(i.serverAssetId,r.shareContext),p=`/uploads/chunks/${c}`,g=Date.now(),h=await this.#t.putWithToken(p,l,d,{signal:r.abortController.signal,onProgress:P=>{let R=this.#E.get(e);R&&(R[t]=P,this.#K(e))},contentType:"application/octet-stream",limiter:this.#B}),A=Date.now(),y=h.uploadCompletedAtMs??A,f=y-g;if(!h.status||h.status<200||h.status>=300)throw this.#a.error("Chunk upload returned unexpected status",{chunkIndex:t,chunkId:c,assetId:e,serverAssetId:i.serverAssetId,chunkSizeBytes:u,durationMs:f,httpStatus:h.status,statusText:h.statusText,responseBody:h.data,responseHeaders:h.headers}),new Error(`Chunk ${t} upload failed: unexpected status ${h.status}`);let V=this.#E.get(e);return V&&(V[t]=u,this.#K(e)),{durationMs:f,startedAtMs:g,completedAtMs:y,adaptiveGeneration:s}}#K(e){let t=this.#E.get(e);if(!t)return;let s=t.reduce((r,i)=>r+i,0);this.#e.updateUploadProgress(e,s)}#ie(e,t,s){if(this.#R){let i=this.#g.get(e);if(i){let o=t*i.chunkSize,l=Math.min(o+i.chunkSize,i.sizeBytes)-o;this.#R.recordSuccess(l,s.durationMs,{generation:s.adaptiveGeneration,startedAtMs:s.startedAtMs,completedAtMs:s.completedAtMs})}}this.#e.addCompletedChunkIndex(e,t),this.#d.markChunkCompleted(e,t)&&this.#Y(e).catch(i=>{this.#z(e,i)})}#oe(e,t,s){this.#z(e,s)}#ae(e,t,s,r){if(!this.#i)return;let i=this.#e.getUploadAsset(e);if(!i)return;let o=this.#g.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,p=c.response?.status,g=typeof p=="number"?p:null,h=s.cause?s.cause instanceof Error?s.cause.message:String(s.cause):null;this.#i("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:g,error_stack:s.stack??null,error_cause:h,project_id:i.projectId??""})}#le(e,t,s,r){if(!this.#i||x(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.#g.get(e.assetId);this.#i("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#Y(e){let t=this.#e.getUploadAsset(e);if(!t)return;let s=this.#g.get(e);if(!s)return;if(t.abortController.signal.aborted)throw new F;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 x(u)||this.#a.error("Manifest upload failed",{assetId:e,serverAssetId:s.serverAssetId,manifestId:r},u),u}if(t.abortController.signal.aborted)throw new F;try{let u=t.shareContext?I(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.#G(),this.#y(),this.#g.delete(e),this.#E.delete(e),this.#d.removeAsset(e),await t.fileReader.close?.(),this.#se(e),this.#$(),this.#X()}#z(e,t){let s=this.#e.getUploadAsset(e);if(!s||x(t)||s.status==="paused"||s.status==="cancelled")return;let r=s.retryCount,i=r>=3||Nt(t);if(this.#le(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.#g.delete(e),this.#E.delete(e),this.#G(),this.#y(),this.#se(e),this.#$(),this.#X()}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.#g.delete(e),this.#E.delete(e),this.#e.resetAssetForRetryQueue(e),this.#y(),this.#$();let a=2e3*Math.pow(2,r);setTimeout(()=>{if(this.#U)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)}}#X(){this.#R&&(this.hasActiveUploads()||(this.#N=!0,this.#R.reset(),this.#N=!1))}#J(){this.#L||(this.#L=!0,queueMicrotask(()=>{this.#L=!1;let e=this.#I.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)})}))}#j(){return G(this.#e.getSerializableSnapshot().uploadAssets)}#y(){this.#v||(this.#v=!0,queueMicrotask(()=>{this.#v=!1,this.#ce()}))}#ue(){this.#Z(!0)}#ce(){this.#Z(!1)}#Z(e){if(this.#U||!this.#u&&!this.#c)return;e?this.#e.updateUploadStats():(this.#A++,this.#A%3===0&&this.#e.updateUploadStats());let t=this.#e.getDirtyDelta();if(!this.#F&&Object.keys(t.assets).length===0&&Object.keys(t.groups).length===0&&this.#e.dirtyHistoryGroupIds.size===0)return;this.#F=!1,this.#e.dirtyHistoryGroupIds.size>0&&this.#G();let r=this.#e.dirtyHistoryGroupIds.size>0?this.#he():void 0,i=this.#P?!0:void 0,o=this.#S.size>0?[...this.#S]:void 0;this.#P=!1,this.#S.clear();let a=this.#j(),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.#x,conflictResolution:this.#_};this.#e.clearDirtyFlags(),this.#u?.(l),this.#c?.(a)}#ee(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}}#V(){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}}#de(){if(!(!this.#i||this.#U))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,p=0;for(let A of e.assetIds){let y=this.#e.getUploadAsset(A);if(!y)continue;let f=y.totalBytesToUpload;switch(s+=f,r+=y.bytesUploaded,y.status){case"success":i++,o+=f;break;case"failed":a++,l+=f;break;case"cancelled":u++,c+=f;break;case"in-progress":d++,t=!0;break;case"queued":p++,t=!0;break;case"paused":t=!0;break}}if(!t)continue;let g=this.#w.get(e.id),h=g?Date.now()-g:0;this.#i("upload:group_progress",{group_id:e.id,file_count:e.assetIds.length,total_bytes:s,bytes_uploaded:r,duration_ms:h,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:p,progress:s>0?r/s:0,concurrency:this.#l,upload_speed_mbps:this.#e.uploadStats.uploadSpeedMbps})}}#te(e,t,s){if(!this.#i)return;let{totalBytes:r,bytesUploaded:i}=this.#ee(t);this.#i(s,{file_count:t.fileCount,total_bytes:r,bytes_uploaded:i,project_id:t.projectId})}#se(e){if(!this.#i)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 h of s.assetIds){let A=this.#e.getUploadAsset(h);if(!A)continue;let y=A.totalBytesToUpload;if(d+=y,A.status==="success")i++,o+=y;else if(A.status==="failed")a++,l+=y;else if(A.status==="cancelled")u++,c+=y;else{r=!1;break}}if(!r)return;let p=this.#w.get(s.id),g=p?Date.now()-p:0;this.#i("upload:group_completed",{file_count:s.assetIds.length,total_bytes:d,duration_ms:g,project_id:s.projectId,succeeded_count:i,succeeded_bytes:o,failed_count:a,failed_bytes:l,cancelled_count:u,cancelled_bytes:c}),this.#w.delete(s.id)}#he(){let e={};for(let t of this.#e.dirtyHistoryGroupIds){let s=this.#e.buildHistoryItem(t);s&&(e[t]=s)}return e}#G(){if(!this.#r)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.#r.merge(e)}};var q=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=t?t.getLimit():null,l=a!==null&&a>0;if(l){let h=Math.round(a*50/1e3);i=Math.max(65536,Math.min(e.byteLength,h))}let u=Math.min(r+i,e.byteLength),c=e.subarray(r,u),d=c.byteLength;if(l&&(await t.acquire(d),s?.aborted))return;let p=performance.now();yield c;let g=performance.now()-p;if(r=u,!l){if(g>=.5){let h=d/g*1e3;o=o===0?h:o*(1-.3)+h*.3}else o===0&&(i=Math.min(e.byteLength,i*2));if(o>0){let h=Math.round(o*50/1e3);i=Math.max(65536,Math.min(e.byteLength,h))}}this.#t=i,this.#s=o}}};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]}`},We=n=>{if(n===null)return null;let t=n*8/(1024*1024);return t<1?`${(t*1024).toFixed(0)} Kbps`:`${t.toFixed(1)} Mbps`},W=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 Ht=1e3,we=class{#t=null;#s=!1;#e=null;#r=null;#n=null;#i=new Map;#a=null;#u=null;#o=null;#c=null;start(){this.#s||(this.#s=!0,this.#i.clear(),this.#a=null,this.#u=null,this.#o=null,this.#c=null,this.#t=setInterval(()=>this.render(),Ht))}stop(){this.#s&&(this.#s=!1,this.#t&&(clearInterval(this.#t),this.#t=null),this.render(),Ke.done())}updateSnapshot(e){this.#e=e}updateBatchState(e){this.#r=e}updateDownloadProgress(e){if(!e){this.#n=null;return}let t=e.percentComplete>=100||e.bytesTransferred>=e.totalBytes;!t&&e.speed>0&&(this.#o=e),this.#n=t&&this.#o?{...e,speed:this.#o.speed,eta:this.#o.eta}:e}persistCurrentBatchLine(){!this.#r||this.#r.currentPhase!=="complete"||this.#i.set(this.#r.currentBatch,this.#f(this.#r))}resetUploadSnapshot(){this.#e=null,this.#n=null,this.#o=null,this.#c=null}render(){if(!this.#s)return;let e=this.#r?this.#D(this.#r):this.#l();Ke(e.join(`
3
- `))}#m(e,t){let s=[`${m.green(S(t.bytesTransferred))} / ${m.gray(S(t.totalBytes))}`,m.cyan(`${t.percentComplete.toFixed(1)}%`),m.magenta(We(t.speed)??"..."),`${m.yellow("ETA")}: ${m.yellow(W(t.eta)??"...")}`];return`${m.blue(e)}: ${s.join(" | ")}`}#l(){let e=this.#p();return[this.#U(e),this.#F(e)]}#D(e){let t=[];for(let s=1;s<e.currentBatch;s++){let r=this.#i.get(s);r&&t.push(r)}return t.push(this.#f(e)),t.push(this.#v(e)),t}#f(e){let t=`Batch ${e.currentBatch}/${e.totalBatches}`;switch(e.currentPhase){case"downloading":return this.#n?`${t}: ${this.#m("Downloading",this.#n)}`:`${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.#A(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}`:""})`}}#A(e,t){let s=this.#p(),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.#P(t,s,o),u=l?.formattedSpeed??null,c=l?.formattedTime??null,d=s.totalFileCount>0&&s.totalFileCount<i?`, ${m.gray(`Enqueued: ${s.totalFileCount}/${i}`)}`:"",p=u&&c?`, ${u}, ETA: ${c}`:"",g=t.batchFilesSkipped>0?`, ${m.yellow(`Skipped: ${t.batchFilesSkipped} files / ${S(t.batchBytesSkipped)}`)}`:"",h=o>0&&s.uploadedBytes>=o&&r<i?"Finalizing":"Uploading";return`${e}: ${m.blue(h)} (${r}/${i} files, ${S(s.uploadedBytes)} / ${S(o)}, ${a}%${d}${p}${g})`}#v(e){let t=this.#p(),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.#S(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: ${W(l)??"..."}`,`Upload ETA: ${W(u)??"..."}`,`Total ETA: ${W(c)??"..."}`].join(", ")}#b(e){let t=e.overallBytesCompleted+e.batchBytesSkipped+(this.#n?.bytesTransferred??0),s=Math.max(e.overallBytesTotal-t,0);if(s===0)return e.currentPhase==="downloading"&&this.#n?(this.#a=this.#n.eta,this.#n.eta):(this.#a=0,0);if(this.#n&&this.#n.speed>0){let r=Math.ceil(s/this.#n.speed);return this.#a=r,r}return e.currentPhase==="uploading"||e.currentPhase==="cleaning"||e.currentPhase==="complete"?(this.#a=0,0):this.#a}#S(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.#P(e,t,i);if(r===0)return e.currentPhase==="uploading"&&o?(this.#u=o.timeRemainingSeconds,o.timeRemainingSeconds):(this.#u=0,0);if(o&&o.uploadSpeedMbps>0){let a=o.uploadSpeedMbps*1024*1024/8,l=Math.ceil(r/a);return this.#u=l,l}return this.#u}#P(e,t,s){let r=this.#e?.uploadStats,i=s>0&&t.uploadedBytes>=s;return r&&r.uploadSpeedMbps>0&&r.formattedSpeed!=="Calculating..."&&!i?(this.#c={uploadSpeedMbps:r.uploadSpeedMbps,formattedSpeed:r.formattedSpeed,formattedTime:r.formattedTime,timeRemainingSeconds:r.timeRemainingSeconds},this.#c):e.currentPhase==="uploading"&&i&&this.#c?this.#c:r?{uploadSpeedMbps:r.uploadSpeedMbps,formattedSpeed:r.formattedSpeed,formattedTime:r.formattedTime,timeRemainingSeconds:r.timeRemainingSeconds}:null}#U(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(" | ")}#F(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}#p(){return this.#e?Object.values(this.#e.uploadAssets).reduce((t,s)=>{switch(t.totalFileCount+=1,t.totalBytes+=s.totalBytesToUpload,t.uploadedBytes+=s.status==="success"?s.totalBytesToUpload: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}}},C=new we;import{Readable as jt}from"node:stream";import Ye from"axios";var v=class{#t;#s;#e;#r;#n=new q;#i=new Set;constructor(e){this.#t=Ye.create({baseURL:e.apiUrl}),this.#s=Ye.create({baseURL:e.edgeWorkerUrl}),this.#e=e.apiKey,this.#r=e.sessionId}get skippedAssetIds(){return this.#i}async post(e,t,s){let r=await this.#t.post(e,t,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#r,"Content-Type":"application/json",...s}});return this.#u(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.#r,...t}})).data}async delete(e,t){await this.#t.delete(e,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#r,...t}})}async putWithToken(e,t,s,r){let i=await this.#a(t),o=this.#n.createIterator(i,r.limiter??null,r.signal),a=jt.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)}#u(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.#i.add(l.id)})}};import Y from"node:path";import k from"node:path";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=k.posix.normalize(e).replace(/^\/+/,"");if(r===""||r===".")throw new Error(`Remote path must resolve to a file path: ${n}`);return r}function Qe(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=K(a),u=Ie(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 w(n){return b(n.targetPath??n.path)}function Xe(n,e){let t=w(n);return{relativePath:t,absolutePath:k.join(e,t),fileName:k.posix.basename(t),size:n.size}}function K(n){return n.split("/").map(t=>B(t)).join("/")}function Ie(n,e){if(!e.has(n))return n;let t=k.posix.dirname(n),s=k.posix.basename(n),r=k.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 xe(n,e){if(!e.has(n))return n;let t=k.posix.dirname(n),s=k.posix.basename(n),r=2;for(;;){let i=`${s} ${r}`,o=t==="."?i:`${t}/${i}`;if(!e.has(o))return o;r+=1}}var Ve=500,qt=8,oe=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.#r(e);for(let s of t){if(this.#e.has(s))continue;let r=Y.posix.dirname(s),i=Y.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.#o(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.#n(this.#t);this.#e.clear(),this.#u(e,"")}getDirectoryIdForFile(e){let t=b(e),s=Y.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=Y.posix.dirname(t);return s==="."?this.#t:this.#e.get(s)??null}async checkAssetsExistence(e,t=!0){if(e.length===0)return[];let s=[];for(let r=0;r<e.length;r+=Ve){let i=e.slice(r,r+Ve),o=await this.#s.post("/assets/check-exists-and-uploaded",{items:i,delete_if_not_exist:t});s.push(...o.items)}return s}async listFilesInSubtree(e={}){let t=[{id:this.#t,relativePath:""}],s=[],r=0;for(;r<t.length;){let i=t.slice(r,r+qt),o=await Promise.all(i.map(a=>this.#i(a)));r+=i.length;for(let a of o)t.push(...a.directories),s.push(...a.files);e.onProgress?.({scannedDirectoryCount:r,queuedDirectoryCount:t.length,fileCount:s.length})}return s}#r(e){let t=new Set;for(let s of e){let r=b(s.relativePath),i=Y.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#n(e){return this.#s.get(`/directories/${e}/tree`)}async#i(e){let[t,s]=await Promise.all([this.#s.post("/fs/list/directories",{parent_id:e.id}),this.#s.post("/fs/list/assets",{parent_id:e.id})]);return{directories:t.map(r=>({id:r.id,relativePath:this.#a(e.relativePath,r.name)})),files:s.map(r=>({assetId:r.id,relativePath:this.#a(e.relativePath,r.name),sizeBytes:r.size_bytes,isUploaded:r.is_uploaded??!0,uploadStateKnown:typeof r.is_uploaded=="boolean"}))}}#a(e,t){let s=e===""?t:`${e}/${t}`;return b(s)}#u(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.#u(r,i)}}async#o(e,t){return this.#s.post(`/directories/${e}/directories`,{name:t,auto_rename:"numeric"})}};import{PostHog as Wt}from"posthog-node";var _=null,ae="",_e={};function Je(n){_||n.config.analytics.disabled||!n.config.analytics.posthogKey||(ae=n.user.id,_e={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,source_kind:n.config.source.kind,...n.config.source.kind==="rclone"?{rclone_transfers:n.config.source.rcloneOptions.transfers,rclone_multi_thread_streams:n.config.source.rcloneOptions.multiThreadStreams}:{}},_=new Wt(n.config.analytics.posthogKey,{host:n.config.analytics.posthogHost}),_.identify({distinctId:ae,properties:{user_id:n.user.id,email:n.user.email,first_name:n.user.first_name,last_name:n.user.last_name,utm_source_latest:null,utm_medium_latest:null,utm_campaign_latest:null,utm_content_latest:null}}))}function Ze(n,e){_&&_.capture({distinctId:ae,event:n,properties:{..._e,...e}})}async function et(){let n=_;if(Kt(),!!n)try{await n.flush()}catch{}}function Kt(){_=null,ae="",_e={}}import{spawn as le}from"child_process";import*as Le from"fs";import*as Q from"path";var T=class extends Error{constructor(t,s){super(t);this.stderr=s;this.name="RcloneError"}stderr};function Yt(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 Qt(n){let e=["lsjson",n.remoteSource,"--recursive","--fast-list"];return n.extraArgs?.length&&e.push(...n.extraArgs),e}function Xt(n){let e=["backend","query",`${n.remote}:`,n.query];return n.extraArgs?.length&&e.push(...n.extraArgs),e}function Vt(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 Jt(n){let e=["backend","copyid",`${n.remote}:`,n.fileId,n.localTargetPath];return n.rcloneOptions.extraRcloneArgs?.length&&e.push(...n.rcloneOptions.extraRcloneArgs),e}function O(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 tt(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 Zt(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:O(parseFloat(s[1]),s[2]),totalBytes:O(parseFloat(s[3]),s[4]),percentComplete:parseFloat(s[5]),speed:O(parseFloat(s[6]),s[7]),eta:a==="-"?0:tt(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:O(parseFloat(r[1]),r[2]),totalBytes:O(parseFloat(r[3]),r[4]),percentComplete:parseFloat(r[5]),speed:i?O(parseFloat(i[1]),i[2]):0,eta:o&&o[1]!=="-"?tt(o[1]):0}}function De(n){return new Promise((e,t)=>{let s=le("rclone",n.args,{stdio:["ignore","pipe","pipe"]}),r="",i=0,o=a=>{for(let l of a.split(`
4
- `)){if(l.trim().length===0)continue;let u=Zt(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 T(`rclone exited with code ${a}`,r))}),s.on("error",a=>{t(new T(`Failed to start rclone: ${a.message}`,""))})})}async function st(){return new Promise((n,e)=>{let t=le("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 es(n,e,t,s,r,i){let o=`${n}:${e}`;return De({args:Yt({remoteSource:o,localPath:t,rcloneOptions:r,batchFilePath:s}),remoteSource:o,onProgress:i})}async function rt(n,e,t=[]){let s=`${n}:${e}`;return new Promise((r,i)=>{let o=le("rclone",Qt({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=ts(c),p=await ss({remote:n,files:d.files,directories:d.directories,extraArgs:t});r(p)}catch(c){i(new T(`Failed to parse file listing from ${s}: ${c instanceof Error?c.message:String(c)}`,l))}else i(new T(`Failed to list files from ${s}`,l))}),o.on("error",u=>{i(new T(`Failed to start rclone: ${u.message}`,""))})})}async function nt(n){let e=[],t=[];for(let s of n.files)ls(s)?t.push(s):e.push(s);e.length>0&&(await Le.promises.writeFile(n.batchFilePath,`${e.map(s=>s.path).join(`
2
+ import{Command as ni}from"commander";import Ot from"node:path";import{readFileSync as ri}from"node:fs";import{fileURLToPath as si}from"node:url";import ue from"node:fs/promises";import wt from"node:path";import Nn from"fs/promises";import zn from"path";function Bt(r,e){let t=new Map;for(let c of r){let u=zn.dirname(c.targetPath??c.path);t.has(u)||t.set(u,[]),t.get(u).push(c)}let n=new Map;for(let[c,u]of t.entries()){let d=u.reduce((m,g)=>m+g.size,0);n.set(c,d)}let s=Array.from(t.keys()).sort(),i=[],o=[],a=0,l=1;for(let c of s){let u=t.get(c),d=n.get(c);if(d>e){if(o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),u.length===1)i.push({batchNumber:l++,files:u,totalSize:d});else for(let m of u)a+m.size>e&&o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),o.push(m),a+=m.size;continue}a+d>e&&o.length>0&&(i.push({batchNumber:l++,files:o,totalSize:a}),o=[],a=0),o.push(...u),a+=d}return o.length>0&&i.push({batchNumber:l++,files:o,totalSize:a}),i}async function Mt(r){try{await Nn.unlink(r)}catch(e){if(e.code!=="ENOENT")throw e}}import f from"chalk";import zt from"log-update";function be(r,e){if(e.length===0)return r.finalizedStatus?r.finalizedStatus:r.isCreatingFolders?"creating-folders":"queued";if(r.isCreatingFolders)return"creating-folders";let t={queued:0,paused:0,inProgress:0,success:0,failed:0,cancelled:0};for(let s of e)switch(s.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 n=e.length;return t.failed===n?"all-failed":t.failed>0?"some-failed":t.success===n?"success":t.paused>0&&t.queued===0&&t.inProgress===0?"paused":t.queued>0||t.inProgress>0?t.queued+t.paused===n?"queued":"in-progress":"cancelled"}function et(r,e){let t=be(r,e);return t==="creating-folders"||t==="in-progress"||t==="queued"||t==="paused"?"cancelled":t}function tt(r){let e=[];for(let t of Object.values(r))t.chunkedState&&(t.status==="queued"||t.status==="in-progress"||t.status==="paused")&&e.push(t.chunkedState.assetId);return e}function nt(r){for(let e of Object.values(r))if(e.status==="queued"||e.status==="in-progress"||e.status==="paused")return!0;return!1}function Z(r){let t=Object.values(r).reduce((n,s)=>{switch(s.status!=="failed"&&s.status!=="cancelled"&&(n.totalBytesToUpload+=s.totalBytesToUpload,n.totalBytesUploaded+=s.bytesUploaded),n.totalAssetCount+=1,s.status){case"queued":n.queuedAssetCount+=1;break;case"paused":n.pausedAssetCount+=1;break;case"in-progress":n.inProgressAssetCount+=1;break;case"success":n.successAssetCount+=1;break;case"failed":n.failedAssetCount+=1;break;case"cancelled":n.cancelledAssetCount+=1;break}return n},{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 rt(r,e){if(e.length===0)return null;let t=e.reduce((n,s)=>(s.status!=="failed"&&s.status!=="cancelled"&&(n.totalBytes+=s.totalBytesToUpload,n.uploadedBytes+=s.bytesUploaded),s.status==="success"?n.filesSucceeded++:s.status==="failed"&&n.filesFailed++,(s.status==="success"||s.status==="failed"||s.status==="cancelled")&&n.filesCompleted++,n),{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 st(r){let e=Object.values(r).filter(t=>t.status==="queued"||t.status==="in-progress"||t.status==="paused");return e.length===0?!1:e.every(t=>t.status==="paused")}function it(r){return Object.values(r).some(e=>e.status==="paused")}import Ai from"axios";var ee=class{#t;#n;#e;#r;#s;#i=0;#a=0;#c=0;#o=0;#u=0;#m=0;constructor(e){this.#t=e?.alphaFast??.1,this.#n=e?.alphaMax??.5,this.#e=e?.consecutiveForBoost??3,this.#r=e?.minSamples??3,this.#s=e?.maxGapSeconds??2}sample(e){let t=Date.now();if(this.#o===0){this.#o=t,this.#u=e;return}let s=(t-this.#o)/1e3,i=e-this.#u;if(s<=0||i<0)return;if(s>this.#s){this.#o=t,this.#u=e;return}let o=i/s;if(this.#m===0)this.#i=o;else{let l=o-this.#i>=0?1:-1;this.#c!==0&&l===this.#c?this.#a++:this.#a=0,this.#c=l;let c=Math.min(1,this.#a/this.#e),u=this.#t+(this.#n-this.#t)*c;this.#i=u*o+(1-u)*this.#i}this.#o=t,this.#u=e,this.#m++}etaSeconds(e){return!this.isWarmedUp||this.#i<=0?0:e/this.#i}adjustTotalBytes(e){this.#u+=e}reset(){this.#i=0,this.#a=0,this.#c=0,this.#o=0,this.#u=0,this.#m=0}serialize(){return{displaySpeedBps:this.#i,lastSampleTimestamp:this.#o,lastSampleTotalBytes:this.#u,sampleCount:this.#m}}get speedBps(){return this.#i}get speedMbps(){return this.#i*8/1e6}get isWarmedUp(){return this.#m>=this.#r}};function D(r){let e={"X-Aspect-Share-Id":r.shareId};return r.shareAuthentication&&(e["X-Aspect-Share-Authentication"]=r.shareAuthentication),e}var te=class{#t;#n;#e;#r;#s;#i;#a;#c;#o;#u;#m;#l;#D;#g;#A;#k;#b;#S;#P;#R;#I;#h;#C;#E;#d;#T;#f;#F;#L;#_;#x;#O;constructor(e){this.#n=e?.minConcurrency??1,this.#e=e?.maxConcurrency??8,this.#t=this.#H(e?.initialConcurrency??this.#n),this.#r=e?.errorThreshold??1,this.#s=(e?.cooldownSeconds??10)*1e3,this.#i=e?.plateauThreshold??.05,this.#a=Math.max(this.#e,Math.floor(e?.sampleWindowSize??64)),this.#c=Math.max(2,Math.floor(e?.minSamples??4)),this.#o=Math.max(1.1,e?.increaseFactor??1.5),this.#u=e?.onChange,this.#m=e?.now??Date.now,this.#l=this.#t,this.#D=0,this.#g=[],this.#A=0,this.#k=0,this.#b=-1,this.#S=0,this.#P=void 0,this.#R=0,this.#I=0,this.#h=0,this.#C=this.#l,this.#E=0,this.#d=1/0,this.#T=0,this.#f=6e4,this.#F=0,this.#L=1/0,this.#_=0,this.#x=0,this.#O=0}recordSuccess(e,t,n){if(e<=0)return;if(n?.generation!==void 0){if(n.generation!==this.#D){n.generation===this.#b&&this.#S>0&&(this.#S--,this.#S===0&&(this.#P=n.completedAtMs??this.#m()));return}if(this.#S>0||this.#P!==void 0&&n.startedAtMs!==void 0&&n.startedAtMs<this.#P)return}else if(this.#k>0){this.#k--;return}let s=n?.completedAtMs??this.#m();for(this.#g.push({bytes:e,completedAtMs:s,startedAtMs:n?.startedAtMs,durationMs:t!==void 0&&t>0?t:void 0});this.#g.length>this.#a;)this.#g.shift();this.#A++,this.#R=0;let i=this.#M();this.#x=i.throughputBps,this.#O=i.latencyMsPerMB,this.#U(i)}recordError(){if(this.#R++,this.#R<this.#r)return;let e=this.#l;e===this.#F&&(this.#L=Math.min(this.#L,e),this.#_=this.#m()+3e4),this.#F=e;let t=this.#H(Math.floor(e/2));this.#I=this.#m()+this.#s,this.#R=0,e<=this.#C&&(this.#C=t,this.#E=0),e>t&&(this.#d=Math.min(this.#d,e),this.#W()),this.#w(t)}get concurrency(){return this.#l}get generation(){return this.#D}get speedBps(){return this.#x}get latencyMsPerMB(){return this.#O}reset(){this.#l=this.#t,this.#D++,this.#g=[],this.#A=0,this.#k=0,this.#b=-1,this.#S=0,this.#P=void 0,this.#R=0,this.#I=0,this.#h=0,this.#C=this.#l,this.#E=0,this.#d=1/0,this.#T=0,this.#f=6e4,this.#F=0,this.#L=1/0,this.#_=0,this.#x=0,this.#O=0,this.#u?.(this.#l)}#U(e){if(this.#g.length<this.#q()||this.#A<this.#q()||e.throughputBps<=0)return;let t=this.#m();if(t<this.#I)return;if(e.averageDurationMs>=2e4&&this.#l>=4){this.#C=Math.max(this.#n,Math.floor(this.#l/2)),this.#E=0,this.#w(this.#C);return}if(this.#E===0){this.#B(e.throughputBps),this.#v(e);return}let n=(e.throughputBps-this.#E)/this.#E;if(n>=this.#i){this.#B(e.throughputBps),this.#v(e);return}if(this.#l>this.#C){let s=n<=-.08,i=n<this.#i;(s||i)&&(this.#d=Math.min(this.#d,this.#l),this.#W(),this.#w(this.#C));return}if(this.#l<this.#C){this.#v(e);return}this.#l===this.#C&&(this.#E=Math.max(this.#E,e.throughputBps),t>=this.#h&&this.#v(e))}#v(e){let t=this.#V();if(this.#l>=t){this.#A=0;return}if(e.averageDurationMs>=5e3&&this.#l>=4&&this.#E>0){this.#A=0;return}if(this.#G()){let s=this.#m();if(this.#T===0){this.#T=s+this.#f,this.#h=this.#T,this.#A=0;return}if(s<this.#T){this.#A=0;return}}let n=this.#p(t);if(n===this.#l){this.#A=0;return}this.#w(n)}#B(e){this.#C=this.#l,this.#E=e,this.#d<=this.#l&&(this.#d=1/0),this.#T=0,this.#f=6e4,this.#h=0}#p(e){if(this.#d<1/0){let s=Math.floor((this.#l+this.#d)/2);return s>this.#l&&s<this.#d?Math.min(e,s):Math.min(e,this.#l+1)}if(this.#l<4)return Math.min(e,this.#l+1);let t=Math.ceil(this.#l*this.#o),n=this.#l+2;return Math.min(e,Math.max(n,t))}#w(e){let t=this.#l,n=this.#D,s=this.#H(e);s!==t&&(this.#N(),this.#l=s,this.#D++,this.#b=n,this.#S=Math.max(0,t-1),this.#P=this.#S===0?this.#m():void 0,this.#k=Math.max(0,t-1),this.#u?.(this.#l))}#N(){this.#g=[],this.#A=0,this.#k=0}#G(){return this.#d<1/0&&this.#l===this.#C&&this.#d<=this.#C+1}#W(){let e=this.#d<1/0&&this.#d<=this.#C+1,t=e?this.#f:1e4;this.#h=this.#m()+t,e&&(this.#T=this.#h,this.#f=Math.min(this.#f*2,3e5))}#q(){return Math.max(this.#c,this.#l)}#V(){return this.#L<1/0&&this.#m()>=this.#_&&(this.#L=1/0,this.#_=0),Math.max(this.#n,Math.min(this.#e,this.#L-1))}#H(e){return Math.max(this.#n,Math.min(this.#e,e))}#M(){let e=0,t=0,n=0,s=0;for(let l of this.#g)e+=l.bytes,l.durationMs!==void 0&&(t+=l.durationMs,n++,s+=l.durationMs/(l.bytes/(1024*1024)));if(n>0&&t>0)return{throughputBps:e/(t/1e3)*this.#l,latencyMsPerMB:s/n,averageDurationMs:t/n,durationSampleCount:n};if(this.#g.length<2)return{throughputBps:0,latencyMsPerMB:0,averageDurationMs:0,durationSampleCount:0};let i=this.#g[0],a=this.#g[this.#g.length-1].completedAtMs-i.completedAtMs;return{throughputBps:a>0?e/a*1e3:0,latencyMsPerMB:0,averageDurationMs:a>0?a/Math.max(1,this.#g.length-1):0,durationSampleCount:0}}};var N=class{#t;#n;#e;#r;#s;constructor(e){let t=e===0?null:e;this.#t=t,this.#n=t??0,this.#e=Date.now(),this.#r=[],this.#s=null}setLimit(e){let t=e===0?null:e;if(t===null){this.#t=null,this.#n=0,this.#u();let s=this.#r.splice(0);for(let i of s)i.resolve();return}let n=this.#t;this.#t=t,n===null?(this.#n=t,this.#e=Date.now()):(this.#i(),this.#n=Math.min(this.#n,t)),this.#o()}getLimit(){return this.#t}acquire(e){if(this.#t!==null){if(this.#i(),this.#r.length===0&&this.#n>=e){this.#n-=e;return}return this.#a(e)}}#i(){let e=Date.now(),t=(e-this.#e)/1e3;if(t<=0)return;let n=this.#t,s=t*n,i=this.#r.length>0?Math.max(n,this.#r[0].bytes):n;this.#n=Math.min(this.#n+s,i),this.#e=e}#a(e){return new Promise(t=>{this.#r.push({bytes:e,resolve:t}),this.#s===null&&this.#c()})}#c(){if(this.#r.length===0||this.#t===null){this.#s=null;return}let t=this.#r[0].bytes-this.#n,n=t>0?Math.ceil(t/this.#t*1e3):0;if(n<=0){this.#s=null,this.#o();return}this.#s=setTimeout(()=>{this.#s=null,this.#i(),this.#o()},n)}#o(){for(;this.#r.length>0;){if(this.#t===null){let t=this.#r.splice(0);for(let n of t)n.resolve();return}this.#i();let e=this.#r[0];if(this.#n>=e.bytes)this.#n-=e.bytes,this.#r.shift(),e.resolve();else{this.#c();return}}}#u(){this.#s!==null&&(clearTimeout(this.#s),this.#s=null)}};function Nt(r){let e=`[${r}]`;return{info:(...t)=>console.info(e,...t),warn:(...t)=>console.warn(e,...t),error:(...t)=>console.error(e,...t)}}var ot=Nt("transfer");var Ae=class{uploadAssets={};uploadGroups={};#t=new ee;get uploadSpeedState(){return this.#t.serialize()}uploadStats={uploadSpeedMbps:0,timeRemainingSeconds:0,formattedSpeed:"Calculating...",formattedTime:"Calculating..."};dirtyAssetIds=new Set;dirtyGroupIds=new Set;dirtyHistoryGroupIds=new Set;#n(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()}#r(e){this.dirtyAssetIds.add(e)}#s(e){this.dirtyGroupIds.add(e)}addUploadAsset({assetId:e,fileReader:t,abortController:n,parentId:s,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:s,projectId:i,groupId:o,retryCount:0,chunkSize:a??0,fileReader:t,abortController:n,shareContext:l},this.#r(e)}updateUploadProgress(e,t){let n=this.uploadAssets[e];if(!n||n.status==="paused"||n.status==="cancelled"||n.status==="success"||n.status==="failed")return;let s=t>0&&n.status==="queued"?"in-progress":n.status,i=Math.min(t,n.totalBytesToUpload);n.bytesUploaded=i,n.status=s,this.#r(e)}markUploadInProgress(e){let t=this.uploadAssets[e];t&&(t.status="in-progress",this.#r(e))}markUploadSuccess(e){let t=this.uploadAssets[e];t&&(t.status="success",t.bytesUploaded=t.totalBytesToUpload,this.#r(e),this.#e(),this.cleanupOnCompletion(e))}markUploadFailed(e,t){let n=this.uploadAssets[e];if(!n)return;let s=n.bytesUploaded;n.status="failed",n.errorMessage=t,n.bytesUploaded=0,this.#r(e),this.#n(s),this.#e(),this.cleanupOnCompletion(e)}removeUploadAsset(e){let n=this.uploadAssets[e]?.bytesUploaded??0;delete this.uploadAssets[e],this.#r(e),this.#n(n),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.#r(e))}resetAssetForRetrying(e){let t=this.uploadAssets[e];t&&(t.status="queued",t.bytesUploaded=0,t.retryCount=0,this.#r(e))}pauseUpload(e){let t=this.uploadAssets[e];if(!t||t.status!=="queued"&&t.status!=="in-progress")return;let n=0;if(t.chunkedState){let{completedChunkIndices:i,chunkSize:o}=t.chunkedState;for(let a of i){let l=a*o,c=Math.min(l+o,t.totalBytesToUpload);n+=c-l}}let s=t.bytesUploaded-n;t.status="paused",t.bytesUploaded=n,this.#r(e),this.#n(s),this.#e(),t.abortController.abort()}unpauseUpload(e){let t=this.uploadAssets[e];t&&t.status==="paused"&&(t.status="queued",this.#r(e))}pauseUploadGroup(e){let t=this.uploadGroups[e];if(t&&!t.isCreatingFolders){t.isPaused=!0,this.#s(e);for(let n of t.assetIds)this.pauseUpload(n)}}unpauseUploadGroup(e){let t=this.uploadGroups[e];t&&(t.isPaused=!1,this.#s(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 n=t.bytesUploaded;t.status="cancelled",this.#r(e),this.#n(n),this.#e(),this.cleanupOnCompletion(e)}setChunkedState(e,t){let n=this.uploadAssets[e];n&&(n.chunkedState=t,this.#r(e))}addCompletedChunkIndex(e,t){let n=this.uploadAssets[e];!n||!n.chunkedState||(n.chunkedState={...n.chunkedState,completedChunkIndices:[...n.chunkedState.completedChunkIndices,t]},this.#r(e))}clearChunkedState(e){let t=this.uploadAssets[e];t&&(t.chunkedState=void 0,this.#r(e))}hasGroupsCreatingFolders(){return Object.values(this.uploadGroups).some(e=>e.isCreatingFolders===!0)}areAllUploadsPaused(){return st(this.uploadAssets)}hasPausedUploads(){return it(this.uploadAssets)}getUploadAsset(e){return this.uploadAssets[e]}getSerializableAsset(e){let t=this.uploadAssets[e];if(t)return this.#c(t)}getUploadSummary(){return Z(this.#u())}getAllUploadAssetsSortedByRecent(){return Object.values(this.uploadAssets).map(e=>this.#c(e)).sort((e,t)=>t.i-e.i)}getGroupAssets(e){let t=this.uploadGroups[e];return!t||!t.assetIds?[]:t.assetIds.map(n=>this.uploadAssets[n]).filter(Boolean).map(n=>this.#c(n))}getGroupAssetsInternal(e){let t=this.uploadGroups[e];return!t||!t.assetIds?[]:t.assetIds.map(n=>this.uploadAssets[n]).filter(Boolean)}addUploadGroup(e){let t=crypto.randomUUID();return this.uploadGroups[t]={...e,id:t,fileReaders:new Map},this.#s(t),t}updateUploadGroup(e,t){let n=this.uploadGroups[e];n&&(Object.assign(n,t),this.#s(e))}addAssetToGroup(e,t){let n=this.uploadGroups[e];n&&(n.assetIds.push(t),this.#s(e))}finalizeEmptyGroup({groupId:e,status:t,errorMessage:n}){let s=this.uploadGroups[e];s&&(s.assetIds.length>0||s.finalizedStatus||(s.finalizedStatus=t,s.errorMessage=n,s.isCreatingFolders=!1,s.completedAt=new Date().toISOString(),this.#s(e),this.dirtyHistoryGroupIds.add(e)))}removeUploadGroup(e){let t=this.uploadGroups[e];if(t)for(let n of t.assetIds)delete this.uploadAssets[n],this.#r(n);delete this.uploadGroups[e],this.#s(e)}getUploadGroup(e){let t=this.uploadGroups[e];if(t)return this.#o(t)}getAllUploadGroups(){return Object.values(this.uploadGroups).map(e=>this.#o(e)).sort((e,t)=>t.createdAt.localeCompare(e.createdAt))}getUploadGroupProgress(e){let t=this.uploadGroups[e];if(!t)return null;let n=this.getGroupAssets(e);return rt(this.#o(t),n)}getUploadGroupStatus(e){let t=this.uploadGroups[e];if(!t)return null;let n=this.getGroupAssets(e);return be(this.#o(t),n)}getAssetsByParentId(e){return Object.values(this.uploadAssets).filter(t=>t.parentId===e).map(t=>this.#c(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.#o(e))}cleanupOnCompletion(e){let t=this.uploadAssets[e];if(!t)return;let n=t.groupId;if(n){let i=this.uploadGroups[n];if(i){let o=this.getGroupAssets(n),a=this.#o(i);this.dirtyHistoryGroupIds.add(n),!o.some(c=>c.status==="queued"||c.status==="in-progress")&&!i.completedAt&&(i.completedAt=new Date().toISOString(),this.#s(n))}}let s=this.getUploadSummary();if(s.cancelledAssetCount+s.failedAssetCount+s.successAssetCount===s.totalAssetCount)for(let i of Object.keys(this.uploadAssets)){let o=this.uploadAssets[i];o&&(o.bytesUploaded=0,this.#r(i))}}updateUploadStats(){let e=this.getUploadSummary(),t=e.queuedAssetCount>0||e.inProgressAssetCount>0;t&&this.#t.sample(e.totalBytesUploaded);let n=this.#t.isWarmedUp?this.#t.speedMbps:0,s=t&&this.#t.isWarmedUp?this.#t.etaSeconds(e.totalBytesToUpload-e.totalBytesUploaded):0;this.uploadStats={uploadSpeedMbps:n,timeRemainingSeconds:s,formattedSpeed:this.#i(n),formattedTime:this.#a(s)}}#i(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),n=Math.floor(e%3600/60),s=Math.floor(e%60);return t>0?`${t}h ${n}m left`:n>0?`${n}m ${s}s left`:`${s}s left`}buildHistoryItem(e){let t=this.uploadGroups[e];if(!t)return null;let n=this.getGroupAssets(e),s=this.#o(t);return{groupId:t.id,name:t.name,type:t.type,fileCount:t.fileCount,folderCount:t.folderCount,topLevelFileCount:t.topLevelFileCount,topLevelFolderCount:t.topLevelFolderCount,status:et(s,n),createdAt:t.createdAt,completedAt:t.completedAt,rootDirectoryId:t.rootDirectoryId,projectId:t.projectId,errorMessage:t.errorMessage,conflictResolution:t.conflictResolution}}#c({fileReader:e,abortController:t,shareContext:n,...s}){return s}#o({fileReaders:e,...t}){return t}#u(){let e={};for(let[t,n]of Object.entries(this.uploadAssets))e[t]=this.#c(n);return e}#m(){let e={};for(let[t,n]of Object.entries(this.uploadGroups))e[t]=this.#o(n);return e}getSerializableSnapshot(){return{uploadAssets:this.#u(),uploadGroups:this.#m(),uploadStats:{...this.uploadStats},uploadSpeedState:this.uploadSpeedState}}getDirtyDelta(){let e={};for(let n of this.dirtyAssetIds){let s=this.uploadAssets[n];s&&(e[n]=this.#c(s))}let t={};for(let n of this.dirtyGroupIds){let s=this.uploadGroups[n];s&&(t[n]=this.#o(s))}return{assets:e,groups:t}}clearDirtyFlags(){this.dirtyAssetIds.clear(),this.dirtyGroupIds.clear(),this.dirtyHistoryGroupIds.clear()}};function Hn(r,e){let t=new Date(r).getTime(),n=Date.now();return t-n<=e}var Fe=class{#t;#n=new Map;#e=new Map;constructor(e){this.#t=e}seedToken(e,t,n){this.#n.set(e,{token:t,expiresAt:n})}async getToken(e,t){let n=this.#n.get(e);if(n&&!Hn(n.expiresAt,3e5))return n.token;let s=this.#e.get(e);if(s)return s;let i=t?D(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.#n.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.#n.delete(e):this.#n.clear()}};var we=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 n=this.#n(e);return n?(n.completedChunkIndices.add(t),n.completedChunkIndices.size>=n.totalChunks):!1}pauseAsset(e){let t=this.#n(e);t&&(t.isPaused=!0)}unpauseAsset(e){let t=this.#n(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)}isAssetComplete(e){let t=this.#n(e);return t?t.completedChunkIndices.size>=t.totalChunks:!1}clear(){this.#t=[]}#n(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 jn=/[/\\:*?"<>|\x00-\x1F]/g,Wn=["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"];function z(r){let e=r.replace(jn,"_");e=e.replace(/[. ]+$/,""),(!e||e==="."||e==="..")&&(e="unnamed");let t=e.includes(".")?e.substring(0,e.lastIndexOf(".")):e;Wn.includes(t.toUpperCase())&&(e=`_${e}`);let n=new TextEncoder;if(n.encode(e).length>255){let s=e.lastIndexOf("."),i=s>0?e.substring(s):"",o=s>0?e.substring(0,s):e,l=255-n.encode(i).length;for(;n.encode(o).length>l&&o.length>0;)o=o.slice(0,-1);e=o+i}return e}var L=class extends Error{constructor(){super("Upload cancelled"),this.name="CancelledError"}};function _(r){return r instanceof L||r instanceof Error&&r.name==="CancelledError"||r instanceof Error&&r.name==="CanceledError"||r instanceof Error&&r.name==="AbortError"}function Xn(r){return _(r)||r instanceof Error&&r.name==="NoAuthError"}function Zn(r){return new Promise(e=>setTimeout(e,r))}function er(r){return r instanceof Blob?r.size:r.byteLength}var ne=class{#t;#n;#e;#r;#s;#i;#a;#c;#o;#u;#m;#l;#D;#g=null;#A=0;#k=!1;#b=[];#S=new Set;#P=!1;#R=!1;#I=!1;#h=[];#C=!1;#E=!1;#d=new we;#T=0;#f=new Map;#F=new Map;#L=[];#_=!1;#x=null;#O;#U="keep_both";#v=new Map;#B=null;#p=!1;#w=null;#N=!1;constructor(e){this.#t=e.httpClient,this.#n=new Fe(e.httpClient),this.#e=new Ae,this.#r=e.historyStore??null,this.#s=e.settingsStore??null,this.#i=e.analytics??null,this.#a=e.logger??ot,this.#c=e.onChange??null,this.#o=e.onClear??null,this.#u=e.onSummary??null,this.#m=e.onConcurrencyAdjusted??null,this.#D=e.deltaIntervalMs??333;let t=e.maxConcurrency??4;if(e.adaptiveConcurrency!==!1){let n=e.adaptiveConcurrencyConfig;this.#w=new te({initialConcurrency:n?.initialConcurrency??Math.min(4,t),minConcurrency:n?.minConcurrency??1,maxConcurrency:n?.maxConcurrency??t,errorThreshold:n?.errorThreshold,cooldownSeconds:n?.cooldownSeconds??10,plateauThreshold:n?.plateauThreshold,onChange:s=>{let i=this.#l;if(this.setMaxConcurrency(s),i===s)return;let o=this.#N?"reset":s>i?"probe_increase":"error_decrease",a=Math.round(this.#w.speedBps*8/1e6*100)/100,l=Math.round(this.#w.latencyMsPerMB*100)/100;this.#a.info(`Adaptive concurrency: ${i} \u2192 ${s} (${o}), measuredAt=${i}, speed=${a}Mbps, latency=${l}ms/MB`),this.#m?.({previousConcurrency:i,newConcurrency:s,reason:o,speedMbps:a,latencyMsPerMB:l})},now:n?.now}),this.#l=this.#w.concurrency}else this.#l=t;this.#r&&(this.#b=this.#r.load()),this.#s&&(this.#x=this.#s.getBandwidthLimitBps(),this.#U=this.#s.getConflictResolution()),this.#O=new N(this.#x),(this.#c||this.#u)&&(this.#g=setInterval(()=>{this.#ce()},this.#D)),this.#i&&(this.#B=setInterval(()=>{this.#de()},6e4))}startUpload(e){let t=e.assetId||crypto.randomUUID(),n=!!e.assetId,s;if(n){let o=this.#e.getUploadAsset(t);if(!o)throw new Error(`Cannot retry: asset ${t} not found`);s=o.chunkSize}else{if(e.chunkSize===void 0||e.chunkSize===null)throw new Error("chunkSize is required for new uploads");s=e.chunkSize}let i=new AbortController;if(n){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:s,shareContext:e.shareContext});return this.#h.push(t),this.#G(),this.#y(),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.#U});return this.#v.set(t,Date.now()),this.#i?.("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.#y(),t}pauseUpload(e){let t=this.#e.getUploadAsset(e);this.#e.pauseUpload(e),this.#h=this.#h.filter(n=>n!==e),this.#d.pauseAsset(e),!this.#p&&t&&this.#i&&this.#i("upload:file_paused",{file_name:t.fileName,file_size:t.totalBytesToUpload,bytes_uploaded:t.bytesUploaded,project_id:t.projectId??""}),this.#y()}unpauseUpload(e){this.#e.unpauseUpload(e),this.#y()}cancelUpload(e){let t=this.#e.getUploadAsset(e);if(!t||t.status==="success"||t.status==="failed"||t.status==="cancelled")return;let n=t.fileName,s=t.totalBytesToUpload,i=t.bytesUploaded,o=t.projectId,a=t.chunkedState?.assetId;(t.status==="queued"||t.status==="in-progress")&&t.abortController.abort(),this.#h=this.#h.filter(l=>l!==e),this.#d.removeAsset(e),this.#f.delete(e),this.#F.delete(e),this.#e.markUploadCancelled(e),this.#e.clearChunkedState(e),t.fileReader.close?.(),!this.#p&&this.#i&&this.#i("upload:file_cancelled",{file_name:n,file_size:s,bytes_uploaded:i,project_id:o??""}),this.#y(),this.#M(),this.#G(),this.#Q(),a&&(this.#L.push(a),this.#X())}cancelAllUploads(){let e=this.#J();this.#p=!0;try{let n=Object.values(this.#e.uploadAssets).filter(s=>s.status==="queued"||s.status==="in-progress"||s.status==="paused");for(let s of n)this.cancelUpload(s.assetId)}finally{this.#p=!1}this.#i?.("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.#p&&this.#i&&this.#i("upload:file_resumed",{file_name:t.fileName,file_size:t.totalBytesToUpload,bytes_uploaded:t.bytesUploaded,project_id:t.projectId??""});let n=new AbortController;t.abortController=n,this.#e.unpauseUpload(e),this.#d.hasAsset(e)?(this.#d.unpauseAsset(e),this.#y(),this.#d.isAssetComplete(e)?this.#Y(e).catch(s=>{this.#z(e,s)}):this.#M()):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 n=this.#p;this.#p=!0,this.#e.pauseUploadGroup(e);for(let s of t.assetIds)this.#h=this.#h.filter(i=>i!==s),this.#d.pauseAsset(s);this.#p=n,this.#p||this.#te(e,t,"upload:group_paused"),this.#y()}unpauseUploadGroup(e){this.#e.unpauseUploadGroup(e),this.#y()}cancelUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;let{totalBytes:n,bytesUploaded:s,filesRemaining:i}=this.#ee(t),o=this.#p;this.#p=!0;for(let a of t.assetIds)this.cancelUpload(a);t.assetIds.length===0&&(this.#e.finalizeEmptyGroup({groupId:e,status:"cancelled"}),this.#$(),this.#y()),this.#p=o,this.#p||this.#i?.("upload:group_cancelled",{file_count:t.assetIds.length,files_remaining:i,total_bytes:n,bytes_uploaded:s,project_id:t.projectId}),this.#v.delete(e)}resumeUploadGroup(e){let t=this.#e.uploadGroups[e];if(!t)return;this.#p||this.#te(e,t,"upload:group_resumed");let n=this.#p;this.#p=!0,this.#e.unpauseUploadGroup(e);for(let s of t.assetIds){let i=this.#e.getUploadAsset(s);i&&i.status==="paused"&&this.resumeUpload(s)}this.#p=n}retryUploadGroup(e){let t=this.#e.uploadGroups[e];if(t)for(let n of t.assetIds){let s=this.#e.getUploadAsset(n);s&&s.status==="failed"&&this.retryUpload(n)}}setGroupCreatingFolders(e,t){this.#e.updateUploadGroup(e,{isCreatingFolders:t}),this.#y()}markEmptyGroupFailed(e,t){let n=this.#e.uploadGroups[e];n&&(n.assetIds.length>0||n.finalizedStatus||(this.#a.error("Empty group upload failed",{groupId:e,groupName:n.name,errorMessage:t}),this.#e.finalizeEmptyGroup({groupId:e,status:"all-failed",errorMessage:t}),this.#$(),this.#v.delete(e),this.#y()))}markEmptyGroupCompleted(e){this.#e.finalizeEmptyGroup({groupId:e,status:"success"}),this.#$(),this.#v.delete(e),this.#y()}addAssetToGroup(e,t){this.#e.addAssetToGroup(e,t)}pauseAllUploads(){let e=this.#J();this.#p=!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.#p=!1}this.#i?.("upload:all_paused",e),this.#y()}resumeAllUploads(){let e=this.#J();this.#p=!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.#p=!1}this.#i?.("upload:all_resumed",e),this.#y()}clearAllUploads(){this.#h=[],this.#d.clear(),this.#f.clear(),this.#F.clear(),this.#e.clearAllUploads(),this.#e.uploadGroups={},this.#w&&(this.#N=!0,this.#w.reset(),this.#N=!1),this.#o?.({all:!0}),this.#u?.(this.#j())}clearHistory(){this.#b=[],this.#r?.clear(),this.#P=!0,this.#S.clear(),this.#I=!0,this.#y()}removeHistoryItem(e){this.#b=this.#b.filter(t=>t.groupId!==e),this.#r?.remove(e),this.#S.add(e),this.#I=!0,this.#y()}removeGroup(e){this.#e.removeUploadGroup(e),this.#b=this.#b.filter(t=>t.groupId!==e),this.#r?.remove(e),this.#S.add(e),this.#I=!0,this.#o?.({groupId:e}),this.#u?.(this.#j()),this.#y()}getHttpClient(){return this.#t}setBandwidthLimit(e){let t=e!==this.#x;this.#x=e,this.#O.setLimit(e),this.#s?.setBandwidthLimitBps(e),t&&this.#w&&(this.#N=!0,this.#w.reset(),this.#N=!1),this.#I=!0,this.#y()}getBandwidthLimit(){return this.#x}setConflictResolution(e){this.#U=e,this.#s?.setConflictResolution(e),this.#I=!0,this.#y()}getConflictResolution(){return this.#U}getGroupConflictResolution(e){return this.#e.getUploadGroup(e)?.conflictResolution??this.#U}setMaxConcurrency(e){this.#l=e,this.#M()}getSnapshot(){return this.#e.updateUploadStats(),{...this.#e.getSerializableSnapshot(),uploadHistory:[...this.#b??[]],uploadSummary:this.#j(),bandwidthLimitBps:this.#x,conflictResolution:this.#U}}getUploadAsset(e){return this.#e.getSerializableAsset(e)}getUploadSummary(){return this.#j()}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 nt(this.#e.getSerializableSnapshot().uploadAssets)}getServerAssetIdsToCancel(){return tt(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.#R=!0,this.#g&&(clearInterval(this.#g),this.#g=null),this.#B&&(clearInterval(this.#B),this.#B=null),this.#h=[],this.#d.clear();for(let e of Object.values(this.#e.uploadAssets))e.abortController.abort(),e.fileReader.close?.()}#G(){this.#E||(this.#E=!0,queueMicrotask(()=>{this.#E=!1,this.#W().catch(e=>{this.#a.error("Initiation pipeline error",{queueLength:this.#h.length},e)})}))}async#W(){if(!this.#C){this.#C=!0;try{await this.#q()}finally{this.#C=!1}}}async#q(){for(;this.#h.length>0&&!(this.#f.size>5);){let e=Math.min(this.#h.length,20-this.#f.size);if(e<=0)break;let t=[],n=[];for(let s=0;s<e&&this.#h.length>0;s++){let i=this.#h[0],o=this.#e.getUploadAsset(i);if(!o||o.status==="cancelled"){this.#h.shift(),s--;continue}if(this.#h.shift(),n.push(i),o.chunkedState)try{this.#V(i,o),this.#M()}catch(a){_(a)||this.#z(i,a)}else t.push(i)}if(t.length>0){let s=new Map;for(let i of t){let a=this.#e.getUploadAsset(i)?.shareContext?.shareId??"",l=s.get(a);l||(l=[],s.set(a,l)),l.push(i)}for(let i of s.values())try{await this.#H(i)}catch(o){for(let a of i)this.#z(a,o instanceof Error?o:new Error(String(o)))}this.#M()}}}#V(e,t){let n=t.chunkedState,s={serverAssetId:n.assetId,chunkIds:n.chunkIds,chunkSize:n.chunkSize,totalChunks:n.totalChunks,sizeBytes:n.sizeBytes},i=n.completedChunkIndices;this.#f.set(e,s);let o=new Array(s.totalChunks).fill(0);if(i.length>0){for(let l of i){let c=l*s.chunkSize,u=Math.min(c+s.chunkSize,t.totalBytesToUpload);o[l]=u-c}let a=o.reduce((l,c)=>l+c,0);this.#e.updateUploadProgress(e,a)}if(this.#F.set(e,o),s.totalChunks===0||i.length>=s.totalChunks){this.#Y(e).catch(a=>{this.#z(e,a)});return}this.#d.registerAsset({assetId:e,totalChunks:s.totalChunks,completedChunkIndices:i})}async#H(e){let t=[],n=[];for(let a of e){let l=this.#e.getUploadAsset(a);if(!l||l.status==="cancelled")continue;let c=z(l.fileName),u=l.groupId?this.#e.getUploadGroup(l.groupId)?.conflictResolution??this.#U:this.#U,d=(()=>{switch(u){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:c,size_bytes:l.totalBytesToUpload,...d}),n.push(a)}if(t.length===0)return;let s=this.#e.getUploadAsset(n[0]),i=s?.shareContext?D(s.shareContext):void 0,o=await this.#t.post("/assets/chunked/initiate",t,i);for(let a=0;a<n.length;a++){let l=n[a],c=o[a];if(!c||c.error){this.#z(l,new Error(c?.error??"Unknown batch initiation error"));continue}if(c.skipped){let S=this.#e.getUploadAsset(l);S&&(this.#e.adjustSpeedBaselineForSkippedBytes(S.totalBytesToUpload),this.#e.markUploadSuccess(l),this.#e.dirtyHistoryGroupIds.add(S.groupId??""),this.#$(),S.fileReader.close?.());continue}let u=c.result,d=this.#e.getUploadAsset(l);if(!d||d.status==="cancelled"||d.status==="paused"){(!d||d.status==="cancelled")&&(this.#L.push(u.asset_id),this.#X());continue}let m=Math.ceil(d.totalBytesToUpload/u.chunk_size),g=Array.from({length:m},()=>crypto.randomUUID());this.#n.seedToken(u.asset_id,u.token,u.token_expires_at);let p={serverAssetId:u.asset_id,chunkIds:g,chunkSize:u.chunk_size,totalChunks:m,sizeBytes:d.totalBytesToUpload};this.#e.setChunkedState(l,{assetId:p.serverAssetId,chunkIds:p.chunkIds,completedChunkIndices:[],chunkSize:p.chunkSize,totalChunks:p.totalChunks,sizeBytes:p.sizeBytes}),this.#f.set(l,p);let A=new Array(p.totalChunks).fill(0);if(this.#F.set(l,A),p.totalChunks===0){this.#Y(l).catch(S=>{this.#z(l,S)});continue}this.#d.registerAsset({assetId:l,totalChunks:p.totalChunks,completedChunkIndices:[]})}}#M(){if(!this.#R)for(;this.#T<this.#l;){let e=this.#d.claimNextChunk();if(!e)break;this.#T++;let{assetId:t,chunkIndex:n}=e,s=this.#w?.generation;this.#re(t,n,s).then(i=>{this.#T--,this.#ie(t,n,i),this.#M()}).catch(i=>{if(this.#T--,_(i)){this.#M();return}this.#oe(t,n,i),this.#M()})}}async#re(e,t,n){let s;for(let i=0;i<3;i++)try{let o=this.#F.get(e);return o&&(o[t]=0,this.#K(e)),await this.#se(e,t,n)}catch(o){if(_(o))throw o;if(s=o instanceof Error?o:new Error(String(o)),this.#w?.recordError(),this.#ae(e,t,s,i),i===2)throw s;let a=this.#F.get(e);a&&(a[t]=0,this.#K(e));let l=1e3*Math.pow(2,i);await Zn(l)}throw s||new Error("Unknown error during chunk upload")}async#se(e,t,n){let s=this.#e.getUploadAsset(e);if(!s)throw new L;if(s.abortController.signal.aborted)throw new L;let i=this.#f.get(e);if(!i)throw new Error(`No chunk metadata for asset ${e}`);let o=t*i.chunkSize,a=Math.min(o+i.chunkSize,s.totalBytesToUpload),l=await s.fileReader.readChunk(o,a),c=er(l);if(s.abortController.signal.aborted)throw new L;let u=i.chunkIds[t],d=await this.#n.getToken(i.serverAssetId,s.shareContext),m=`/uploads/chunks/${u}`,g=Date.now(),p=await this.#t.putWithToken(m,l,d,{signal:s.abortController.signal,onProgress:T=>{let E=this.#F.get(e);E&&(E[t]=T,this.#K(e))},contentType:"application/octet-stream",limiter:this.#O}),A=Date.now(),S=p.uploadCompletedAtMs??A,y=S-g;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:i.serverAssetId,chunkSizeBytes:c,durationMs:y,httpStatus:p.status,statusText:p.statusText,responseBody:p.data,responseHeaders:p.headers}),new Error(`Chunk ${t} upload failed: unexpected status ${p.status}`);let Se=this.#F.get(e);return Se&&(Se[t]=c,this.#K(e)),{durationMs:y,startedAtMs:g,completedAtMs:S,adaptiveGeneration:n}}#K(e){let t=this.#F.get(e);if(!t)return;let n=t.reduce((s,i)=>s+i,0);this.#e.updateUploadProgress(e,n)}#ie(e,t,n){if(this.#w){let i=this.#f.get(e);if(i){let o=t*i.chunkSize,l=Math.min(o+i.chunkSize,i.sizeBytes)-o;this.#w.recordSuccess(l,n.durationMs,{generation:n.adaptiveGeneration,startedAtMs:n.startedAtMs,completedAtMs:n.completedAtMs})}}this.#e.addCompletedChunkIndex(e,t),this.#d.markChunkCompleted(e,t)&&this.#Y(e).catch(i=>{this.#z(e,i)})}#oe(e,t,n){this.#z(e,n)}#ae(e,t,n,s){if(!this.#i)return;let i=this.#e.getUploadAsset(e);if(!i)return;let o=this.#f.get(e);if(!o)return;let a=t*o.chunkSize,c=Math.min(a+o.chunkSize,o.sizeBytes)-a,u=n,d=typeof u.code=="string"?u.code:null,m=u.response?.status,g=typeof m=="number"?m:null,p=n.cause?n.cause instanceof Error?n.cause.message:String(n.cause):null;this.#i("upload:chunk_error",{file_name:i.fileName,file_size:i.totalBytesToUpload,chunk_index:t,chunk_size:c,chunks_total:o.totalChunks,attempt:s+1,max_attempts:3,is_final_attempt:s===2,error_type:n.name,error_message:n.message,error_code:d,http_status:g,error_stack:n.stack??null,error_cause:p,project_id:i.projectId??""})}#le(e,t,n,s){if(!this.#i||_(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,c=o.response?.status,u=typeof c=="number"?c:null,d=this.#f.get(e.assetId);this.#i("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:n+1,max_attempts:4,is_final_attempt:s,error_type:t instanceof Error?t.name:"Unknown",error_message:i,error_code:l,http_status:u,error_stack:t instanceof Error?t.stack??null:null,error_cause:a,project_id:e.projectId??""})}async#Y(e){let t=this.#e.getUploadAsset(e);if(!t)return;let n=this.#f.get(e);if(!n)return;if(t.abortController.signal.aborted)throw new L;let s=crypto.randomUUID(),i=JSON.stringify(n.chunkIds),o=new TextEncoder().encode(i),a=await this.#n.getToken(n.serverAssetId,t.shareContext),l=`/uploads/manifests/${s}`;try{await this.#t.putWithToken(l,o,a,{signal:t.abortController.signal,contentType:"application/json"})}catch(c){throw _(c)||this.#a.error("Manifest upload failed",{assetId:e,serverAssetId:n.serverAssetId,manifestId:s},c),c}if(t.abortController.signal.aborted)throw new L;try{let c=t.shareContext?D(t.shareContext):void 0;await this.#t.post(`/assets/${n.serverAssetId}/revisions/commit`,{manifest_id:s,size_bytes:n.sizeBytes,is_initial_upload:!0,client_performed_at:new Date().toISOString()},c)}catch(c){throw this.#a.error("Commit revision failed",{assetId:e,serverAssetId:n.serverAssetId,manifestId:s,sizeBytes:n.sizeBytes},c),c}this.#e.markUploadSuccess(e),this.#e.clearChunkedState(e),this.#$(),this.#y(),this.#f.delete(e),this.#F.delete(e),this.#d.removeAsset(e),await t.fileReader.close?.(),this.#ne(e),this.#G(),this.#Q()}#z(e,t){let n=this.#e.getUploadAsset(e);if(!n||_(t)||n.status==="paused"||n.status==="cancelled")return;let s=n.retryCount,i=s>=3||Xn(t);if(this.#le(n,t,s,i),i){let o=t instanceof Error?t.message:"Unknown error";this.#a.error("Asset upload permanently failed",{assetId:e,fileName:n.fileName,totalRetries:s,bytesUploaded:n.bytesUploaded,totalBytes:n.totalBytesToUpload,chunksCompleted:n.chunkedState?.completedChunkIndices.length??0},t),n.abortController.abort(),this.#e.markUploadFailed(e,o),this.#d.removeAsset(e),this.#f.delete(e),this.#F.delete(e),this.#$(),this.#y(),this.#ne(e),this.#G(),this.#Q()}else{this.#a.warn("Asset upload failed, scheduling retry",{assetId:e,fileName:n.fileName,retryAttempt:s+1,maxRetries:3},t);let o=n.chunkedState;n.abortController.abort(),this.#d.removeAsset(e),this.#f.delete(e),this.#F.delete(e),this.#e.resetAssetForRetryQueue(e),this.#y(),this.#G();let a=2e3*Math.pow(2,s);setTimeout(()=>{if(this.#R)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.#w&&(this.hasActiveUploads()||(this.#N=!0,this.#w.reset(),this.#N=!1))}#X(){this.#_||(this.#_=!0,queueMicrotask(()=>{this.#_=!1;let e=this.#L.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)})}))}#j(){return Z(this.#e.getSerializableSnapshot().uploadAssets)}#y(){this.#k||(this.#k=!0,queueMicrotask(()=>{this.#k=!1,this.#ue()}))}#ce(){this.#Z(!0)}#ue(){this.#Z(!1)}#Z(e){if(this.#R||!this.#c&&!this.#u)return;e?this.#e.updateUploadStats():(this.#A++,this.#A%3===0&&this.#e.updateUploadStats());let t=this.#e.getDirtyDelta();if(!this.#I&&Object.keys(t.assets).length===0&&Object.keys(t.groups).length===0&&this.#e.dirtyHistoryGroupIds.size===0)return;this.#I=!1,this.#e.dirtyHistoryGroupIds.size>0&&this.#$();let s=this.#e.dirtyHistoryGroupIds.size>0?this.#pe():void 0,i=this.#P?!0:void 0,o=this.#S.size>0?[...this.#S]:void 0;this.#P=!1,this.#S.clear();let a=this.#j(),l={assets:t.assets,groups:t.groups,uploadStats:{...this.#e.uploadStats},uploadSpeedState:this.#e.uploadSpeedState,historyItems:s,removedHistoryGroupIds:o,historyCleared:i,uploadSummary:a,bandwidthLimitBps:this.#x,conflictResolution:this.#U};this.#e.clearDirtyFlags(),this.#c?.(l),this.#u?.(a)}#ee(e){let t=0,n=0,s=0;for(let i of e.assetIds){let o=this.#e.getUploadAsset(i);o&&(t+=o.totalBytesToUpload,n+=o.bytesUploaded,o.status!=="success"&&o.status!=="failed"&&o.status!=="cancelled"&&s++)}return{totalBytes:t,bytesUploaded:n,filesRemaining:s}}#J(){let e=0,t=0,n=0,s=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++,n+=a.totalBytesToUpload,s+=a.bytesUploaded))}}return{group_count:e,file_count:t,total_bytes:n,bytes_uploaded:s}}#de(){if(!(!this.#i||this.#R))for(let e of Object.values(this.#e.uploadGroups)){let t=!1,n=0,s=0,i=0,o=0,a=0,l=0,c=0,u=0,d=0,m=0;for(let A of e.assetIds){let S=this.#e.getUploadAsset(A);if(!S)continue;let y=S.totalBytesToUpload;switch(n+=y,s+=S.bytesUploaded,S.status){case"success":i++,o+=y;break;case"failed":a++,l+=y;break;case"cancelled":c++,u+=y;break;case"in-progress":d++,t=!0;break;case"queued":m++,t=!0;break;case"paused":t=!0;break}}if(!t)continue;let g=this.#v.get(e.id),p=g?Date.now()-g:0;this.#i("upload:group_progress",{group_id:e.id,file_count:e.assetIds.length,total_bytes:n,bytes_uploaded:s,duration_ms:p,project_id:e.projectId,succeeded_count:i,succeeded_bytes:o,failed_count:a,failed_bytes:l,cancelled_count:c,cancelled_bytes:u,in_progress_count:d,queued_count:m,progress:n>0?s/n:0,concurrency:this.#l,upload_speed_mbps:this.#e.uploadStats.uploadSpeedMbps})}}#te(e,t,n){if(!this.#i)return;let{totalBytes:s,bytesUploaded:i}=this.#ee(t);this.#i(n,{file_count:t.fileCount,total_bytes:s,bytes_uploaded:i,project_id:t.projectId})}#ne(e){if(!this.#i)return;let t=this.#e.getUploadAsset(e);if(!t?.groupId)return;let n=this.#e.uploadGroups[t.groupId];if(!n)return;let s=!0,i=0,o=0,a=0,l=0,c=0,u=0,d=0;for(let p of n.assetIds){let A=this.#e.getUploadAsset(p);if(!A)continue;let S=A.totalBytesToUpload;if(d+=S,A.status==="success")i++,o+=S;else if(A.status==="failed")a++,l+=S;else if(A.status==="cancelled")c++,u+=S;else{s=!1;break}}if(!s)return;let m=this.#v.get(n.id),g=m?Date.now()-m:0;this.#i("upload:group_completed",{file_count:n.assetIds.length,total_bytes:d,duration_ms:g,project_id:n.projectId,succeeded_count:i,succeeded_bytes:o,failed_count:a,failed_bytes:l,cancelled_count:c,cancelled_bytes:u}),this.#v.delete(n.id)}#pe(){let e={};for(let t of this.#e.dirtyHistoryGroupIds){let n=this.#e.buildHistoryItem(t);n&&(e[t]=n)}return e}#$(){if(!this.#r)return;let e={};for(let t of this.#e.dirtyHistoryGroupIds){let n=this.#e.buildHistoryItem(t);if(n){e[t]=n;let s=this.#b.findIndex(i=>i.groupId===t);s>=0?this.#b[s]=n:this.#b.unshift(n)}}Object.keys(e).length>0&&this.#r.merge(e)}};var re=class{#t=65536;#n=0;async*createIterator(e,t,n){let s=0,i=Math.max(65536,Math.min(e.byteLength,this.#t)),o=this.#n;for(;s<e.byteLength;){if(n?.aborted)return;let a=t?t.getLimit():null,l=a!==null&&a>0;if(l){let p=Math.round(a*50/1e3);i=Math.max(65536,Math.min(e.byteLength,p))}let c=Math.min(s+i,e.byteLength),u=e.subarray(s,c),d=u.byteLength;if(l&&(await t.acquire(d),n?.aborted))return;let m=performance.now();yield u;let g=performance.now()-m;if(s=c,!l){if(g>=.5){let p=d/g*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.#n=o}}};var h=(r,e=2)=>{if(r===0)return"0 B";let t=1024,n=e<0?0:e,s=["B","KB","MB","GB","TB","PB","EB"],i=Math.floor(Math.log(r)/Math.log(t));return`${(r/Math.pow(t,i)).toFixed(n)} ${s[i]}`},Re=r=>{if(r===null)return null;let t=r*8/(1024*1024);return t<1?`${(t*1024).toFixed(0)} Kbps`:`${t.toFixed(1)} Mbps`},se=r=>{if(r===null)return null;let e=Math.floor(r/3600),t=Math.floor(r%3600/60),n=Math.floor(r%60);return e>0?`${e}h ${t}m`:t>0?`${t}m ${n}s`:`${n}s`};var nr=1e3,lt=class{#t=null;#n=!1;#e=null;#r=null;#s=null;#i=new Map;#a=null;#c=null;#o=null;#u=null;start(){this.#n||(this.#n=!0,this.#i.clear(),this.#a=null,this.#c=null,this.#o=null,this.#u=null,this.#t=setInterval(()=>this.render(),nr))}stop(){this.#n&&(this.#n=!1,this.#t&&(clearInterval(this.#t),this.#t=null),this.render(),zt.done())}updateSnapshot(e){this.#e=e}updateBatchState(e){this.#r=e}updateDownloadProgress(e){if(!e){this.#s=null;return}let t=e.percentComplete>=100||e.bytesTransferred>=e.totalBytes;!t&&e.speed>0&&(this.#o=e),this.#s=t&&this.#o?{...e,speed:this.#o.speed,eta:this.#o.eta}:e}persistCurrentBatchLine(){!this.#r||this.#r.currentPhase!=="complete"||this.#i.set(this.#r.currentBatch,this.#g(this.#r))}resetUploadSnapshot(){this.#e=null,this.#s=null,this.#o=null,this.#u=null}render(){if(!this.#n)return;let e=this.#r?this.#D(this.#r):this.#l();zt(e.join(`
3
+ `))}#m(e,t){let n=[`${f.green(h(t.bytesTransferred))} / ${f.gray(h(t.totalBytes))}`,f.cyan(`${t.percentComplete.toFixed(1)}%`),f.magenta(Re(t.speed)??"..."),`${f.yellow("ETA")}: ${f.yellow(se(t.eta)??"...")}`];return`${f.blue(e)}: ${n.join(" | ")}`}#l(){let e=this.#h();return[this.#R(e),this.#I(e)]}#D(e){let t=[];for(let n=1;n<e.currentBatch;n++){let s=this.#i.get(n);s&&t.push(s)}return t.push(this.#g(e)),t.push(this.#k(e)),t}#g(e){let t=`Batch ${e.currentBatch}/${e.totalBatches}`;switch(e.currentPhase){case"downloading":return this.#s?`${t}: ${this.#m("Downloading",this.#s)}`:`${t}: ${f.blue("Downloading...")}`;case"scanning":return`${t}: ${f.yellow(e.extraDetails??"Scanning...")}`;case"syncing_folders":return`${t}: ${f.yellow(e.extraDetails??"Syncing folders...")}`;case"uploading":return this.#A(t,e);case"cleaning":return`${t}: ${f.yellow("Cleaning...")}`;case"complete":return`${t}: ${f.green("Complete")} (${e.batchFilesTotal} files, ${h(e.batchBytesTotal)}${e.extraDetails?`, ${e.extraDetails}`:""})`}}#A(e,t){let n=this.#h(),s=n.successFileCount+n.failedFileCount+n.cancelledFileCount,i=Math.max(t.batchFilesTotal-t.batchFilesSkipped,0),o=Math.max(t.batchBytesTotal-t.batchBytesSkipped,0),a=o>0?(n.uploadedBytes/o*100).toFixed(1):"0.0",l=this.#P(t,n,o),c=l?.formattedSpeed??null,u=l?.formattedTime??null,d=n.totalFileCount>0&&n.totalFileCount<i?`, ${f.gray(`Enqueued: ${n.totalFileCount}/${i}`)}`:"",m=c&&u?`, ${c}, ETA: ${u}`:"",g=t.batchFilesSkipped>0?`, ${f.yellow(`Skipped: ${t.batchFilesSkipped} files / ${h(t.batchBytesSkipped)}`)}`:"",p=o>0&&n.uploadedBytes>=o&&s<i?"Finalizing":"Uploading";return`${e}: ${f.blue(p)} (${s}/${i} files, ${h(n.uploadedBytes)} / ${h(o)}, ${a}%${d}${m}${g})`}#k(e){let t=this.#h(),n=e.batchFilesSkipped+t.successFileCount+t.failedFileCount+t.cancelledFileCount,s=e.batchBytesSkipped+t.uploadedBytes,i=e.overallFilesCompleted+n,o=e.overallBytesCompleted+s,a=Math.max(e.overallBytesTotal-o,0),l=this.#b(e),c=this.#S(e,t),u=l!==null&&c!==null?l+c:null;return[`Total: ${i}/${e.overallFilesTotal} files`,`${h(o)} / ${h(e.overallBytesTotal)}`,f.yellow(`${h(a)} remaining`),`Download ETA: ${se(l)??"..."}`,`Upload ETA: ${se(c)??"..."}`,`Total ETA: ${se(u)??"..."}`].join(", ")}#b(e){let t=e.overallBytesCompleted+e.batchBytesSkipped+(this.#s?.bytesTransferred??0),n=Math.max(e.overallBytesTotal-t,0);if(n===0)return e.currentPhase==="downloading"&&this.#s?(this.#a=this.#s.eta,this.#s.eta):(this.#a=0,0);if(this.#s&&this.#s.speed>0){let s=Math.ceil(n/this.#s.speed);return this.#a=s,s}return e.currentPhase==="uploading"||e.currentPhase==="cleaning"||e.currentPhase==="complete"?(this.#a=0,0):this.#a}#S(e,t){let n=e.overallBytesCompleted+e.batchBytesSkipped+t.uploadedBytes,s=Math.max(e.overallBytesTotal-n,0),i=Math.max(e.batchBytesTotal-e.batchBytesSkipped,0),o=this.#P(e,t,i);if(s===0)return e.currentPhase==="uploading"&&o?(this.#c=o.timeRemainingSeconds,o.timeRemainingSeconds):(this.#c=0,0);if(o&&o.uploadSpeedMbps>0){let a=o.uploadSpeedMbps*1024*1024/8,l=Math.ceil(s/a);return this.#c=l,l}return this.#c}#P(e,t,n){let s=this.#e?.uploadStats,i=n>0&&t.uploadedBytes>=n;return s&&s.uploadSpeedMbps>0&&s.formattedSpeed!=="Calculating..."&&!i?(this.#u={uploadSpeedMbps:s.uploadSpeedMbps,formattedSpeed:s.formattedSpeed,formattedTime:s.formattedTime,timeRemainingSeconds:s.timeRemainingSeconds},this.#u):e.currentPhase==="uploading"&&i&&this.#u?this.#u:s?{uploadSpeedMbps:s.uploadSpeedMbps,formattedSpeed:s.formattedSpeed,formattedTime:s.formattedTime,timeRemainingSeconds:s.timeRemainingSeconds}:null}#R(e){return[`Total: ${e.totalFileCount}`,f.green(`Success: ${e.successFileCount}`),f.red(`Failed: ${e.failedFileCount}`),f.red(`Cancelled: ${e.cancelledFileCount}`),f.blue(`Active: ${e.activeFileCount}`),f.gray(`Queued: ${e.queuedFileCount}`)].join(" | ")}#I(e){let t=Math.max(e.totalBytes-e.uploadedBytes,0),n=this.#e?` | ${f.cyan(`Speed: ${this.#e.uploadStats.formattedSpeed}`)} | ${f.magenta(`Time remaining: ${this.#e.uploadStats.formattedTime}`)}`:"";return[`Total: ${h(e.totalBytes)}`,f.green(`Uploaded: ${h(e.uploadedBytes)}`),f.yellow(`Remaining: ${h(t)}`)].join(" | ")+n}#h(){return this.#e?Object.values(this.#e.uploadAssets).reduce((t,n)=>{switch(t.totalFileCount+=1,t.totalBytes+=n.totalBytesToUpload,t.uploadedBytes+=n.status==="success"?n.totalBytesToUpload:n.bytesUploaded,n.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}}},C=new lt;import{Readable as rr}from"node:stream";import $t from"axios";var x=class{#t;#n;#e;#r;#s=new re;#i=new Set;constructor(e){this.#t=$t.create({baseURL:e.apiUrl}),this.#n=$t.create({baseURL:e.edgeWorkerUrl}),this.#e=e.apiKey,this.#r=e.sessionId}get skippedAssetIds(){return this.#i}async post(e,t,n){let s=await this.#t.post(e,t,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#r,"Content-Type":"application/json",...n}});return this.#c(e,t,s.data),s.data}async get(e,t){return(await this.#t.get(e,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#r,...t}})).data}async delete(e,t){await this.#t.delete(e,{headers:{Authorization:`Bearer ${this.#e}`,"X-Aspect-Session-Id":this.#r,...t}})}async putWithToken(e,t,n,s){let i=await this.#a(t),o=this.#s.createIterator(i,s.limiter??null,s.signal),a=rr.from(o,{highWaterMark:1}),l=await this.#n.put(e,a,{timeout:0,signal:s.signal,headers:{"Content-Type":s.contentType??"","Content-Length":i.byteLength.toString(),Authorization:`Bearer ${n}`},transformRequest:[c=>c],maxRedirects:0,onUploadProgress:c=>s.onProgress?.(c.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)}#c(e,t,n){if(e!=="/assets/chunked/initiate"||!Array.isArray(t)||!Array.isArray(n))return;let s=t;n.forEach((o,a)=>{let l=s[a];o.skipped===!0&&typeof l?.id=="string"&&this.#i.add(l.id)})}};import oe from"node:path";import U from"node:path";function b(r){let e=r.replace(/\\/g,"/");if(e.split("/").some(i=>i===".."))throw new Error(`Remote path cannot contain parent directory segments: ${r}`);let s=U.posix.normalize(e).replace(/^\/+/,"");if(s===""||s===".")throw new Error(`Remote path must resolve to a file path: ${r}`);return s}function Ie(r){let e=new Map;for(let i of r){let o=b(i.targetPath??i.path);e.set(o,(e.get(o)??0)+1)}let t=new Set,n=[],s=[];for(let i of r){let o=b(i.path),a=b(i.targetPath??i.path),l=ie(a),c=ct(l,t),u=(e.get(a)??0)>1,d=c!==o;t.add(c),n.push({...i,targetPath:c,requiresIdentityDownload:i.requiresIdentityDownload===!0||u}),(d||u)&&s.push({sourcePath:i.path,targetPath:c,reason:u||c!==l?"duplicate":"sanitized"})}return{files:n,changes:s}}function w(r){return b(r.targetPath??r.path)}function ke(r,e){let t=w(r);return{relativePath:t,absolutePath:U.join(e,t),fileName:U.posix.basename(t),size:r.size}}function ie(r){return r.split("/").map(t=>z(t)).join("/")}function ct(r,e){if(!e.has(r))return r;let t=U.posix.dirname(r),n=U.posix.basename(r),s=U.posix.extname(n),i=s.length>0?n.slice(0,-s.length):n,o=2;for(;;){let a=`${i} (${o})${s}`,l=t==="."?a:`${t}/${a}`;if(!e.has(l))return l;o+=1}}function ut(r,e){if(!e.has(r))return r;let t=U.posix.dirname(r),n=U.posix.basename(r),s=2;for(;;){let i=`${n} ${s}`,o=t==="."?i:`${t}/${i}`;if(!e.has(o))return o;s+=1}}var Gt=500,sr=8,Te=class{#t;#n;#e=new Map;constructor(e){this.#t=e.rootDirectoryId,this.#n=e.httpClient}async ensureDirectories(e){await this.loadExistingDirectories();let t=this.#r(e);for(let n of t){if(this.#e.has(n))continue;let s=oe.posix.dirname(n),i=oe.posix.basename(n),o=s==="."?this.#t:this.#e.get(s);if(!o)throw new Error(`Parent directory ID not found for path: ${n}`);let a=await this.#o(o,i);if(a.name!==i)throw new Error(`Server created renamed directory "${a.name}" for planned path "${n}". Refusing to map uploads to an unexpected target path.`);this.#e.set(n,a.id)}return e.map(n=>({file:n,directoryId:this.getDirectoryIdForFile(n.relativePath)}))}async loadExistingDirectories(){let e=await this.#s(this.#t);this.#e.clear(),this.#c(e,"")}getDirectoryIdForFile(e){let t=b(e),n=oe.posix.dirname(t);if(n===".")return this.#t;let s=this.#e.get(n);if(!s)throw new Error(`Directory ID not found for path: ${n}`);return s}getExistingDirectoryIdForFile(e){let t=b(e),n=oe.posix.dirname(t);return n==="."?this.#t:this.#e.get(n)??null}async checkAssetsExistence(e,t=!0){if(e.length===0)return[];let n=[];for(let s=0;s<e.length;s+=Gt){let i=e.slice(s,s+Gt),o=await this.#n.post("/assets/check-exists-and-uploaded",{items:i,delete_if_not_exist:t});n.push(...o.items)}return n}async listFilesInSubtree(e={}){let t=[{id:this.#t,relativePath:""}],n=[],s=0;for(;s<t.length;){let i=t.slice(s,s+sr),o=await Promise.all(i.map(a=>this.#i(a)));s+=i.length;for(let a of o)t.push(...a.directories),n.push(...a.files);e.onProgress?.({scannedDirectoryCount:s,queuedDirectoryCount:t.length,fileCount:n.length})}return n}#r(e){let t=new Set;for(let n of e){let s=b(n.relativePath),i=oe.posix.dirname(s);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((n,s)=>n.split("/").length-s.split("/").length)}async#s(e){return this.#n.get(`/directories/${e}/tree`)}async#i(e){let[t,n]=await Promise.all([this.#n.post("/fs/list/directories",{parent_id:e.id}),this.#n.post("/fs/list/assets",{parent_id:e.id})]);return{directories:t.map(s=>({id:s.id,relativePath:this.#a(e.relativePath,s.name)})),files:n.map(s=>({assetId:s.id,relativePath:this.#a(e.relativePath,s.name),sizeBytes:s.size_bytes,isUploaded:s.is_uploaded??!0,uploadStateKnown:typeof s.is_uploaded=="boolean"}))}}#a(e,t){let n=e===""?t:`${e}/${t}`;return b(n)}#c(e,t){let n=t===""?"":t==="."?e.name:`${t}/${e.name}`;n!==""&&this.#e.set(n,e.id);for(let s of e.children){let i=t===""?".":n;this.#c(s,i)}}async#o(e,t){return this.#n.post(`/directories/${e}/directories`,{name:t,auto_rename:"numeric"})}};import{PostHog as ir}from"posthog-node";var O=null,ve="",dt={};function Ht(r){O||r.config.analytics.disabled||!r.config.analytics.posthogKey||(ve=r.user.id,dt={service:"data-sync",package_version:r.packageVersion,platform:process.platform,arch:process.arch,node_version:process.version,max_concurrent:r.config.maxConcurrent,batch_mode:r.config.batchSizeBytes!==void 0,batch_size_bytes:r.config.batchSizeBytes??null,source_kind:r.config.source.kind,...r.config.source.kind==="rclone"?{rclone_transfers:r.config.source.rcloneOptions.transfers,rclone_multi_thread_streams:r.config.source.rcloneOptions.multiThreadStreams}:{}},O=new ir(r.config.analytics.posthogKey,{host:r.config.analytics.posthogHost}),O.identify({distinctId:ve,properties:{user_id:r.user.id,email:r.user.email,first_name:r.user.first_name,last_name:r.user.last_name,utm_source_latest:null,utm_medium_latest:null,utm_campaign_latest:null,utm_content_latest:null}}))}function jt(r,e){O&&O.capture({distinctId:ve,event:r,properties:{...dt,...e}})}async function Wt(){let r=O;if(or(),!!r)try{await r.flush()}catch{}}function or(){O=null,ve="",dt={}}import{spawn as xe}from"child_process";import*as mt from"fs";import*as ae from"path";var P=class extends Error{constructor(t,n){super(t);this.stderr=n;this.name="RcloneError"}stderr};function ar(r){let e=["sync",r.remoteSource,r.localPath];return r.batchFilePath&&e.push("--files-from",r.batchFilePath),e.push("--progress","--stats","1s","--stats-one-line","-v","--transfers",String(r.rcloneOptions.transfers),"--checkers",String(r.rcloneOptions.checkers),"--multi-thread-streams",String(r.rcloneOptions.multiThreadStreams),"--multi-thread-chunk-size",r.rcloneOptions.multiThreadChunkSize,"--multi-thread-cutoff",r.rcloneOptions.multiThreadCutoff,"--fast-list","--buffer-size",r.rcloneOptions.bufferSize),r.rcloneOptions.useMmap&&e.push("--use-mmap"),r.rcloneOptions.extraRcloneArgs?.length&&e.push(...r.rcloneOptions.extraRcloneArgs),e}function lr(r){let e=["lsjson",r.remoteSource,"--recursive","--fast-list"];return r.extraArgs?.length&&e.push(...r.extraArgs),e}function cr(r){let e=["backend","query",`${r.remote}:`,r.query];return r.extraArgs?.length&&e.push(...r.extraArgs),e}function ur(r){let e=["copyto",r.remoteFileSource,r.localTargetPath,"--progress","--stats","1s","--stats-one-line","-v","--multi-thread-streams",String(r.rcloneOptions.multiThreadStreams),"--multi-thread-chunk-size",r.rcloneOptions.multiThreadChunkSize,"--multi-thread-cutoff",r.rcloneOptions.multiThreadCutoff,"--buffer-size",r.rcloneOptions.bufferSize];return r.rcloneOptions.useMmap&&e.push("--use-mmap"),r.rcloneOptions.extraRcloneArgs?.length&&e.push(...r.rcloneOptions.extraRcloneArgs),e}function dr(r){let e=["backend","copyid",`${r.remote}:`,r.fileId,r.localTargetPath];return r.rcloneOptions.extraRcloneArgs?.length&&e.push(...r.rcloneOptions.extraRcloneArgs),e}function $(r,e){let t=e.trim(),n={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 r*(n[t]||1)}function qt(r){let e=0,t=r.match(/(\d+)h/),n=r.match(/(\d+)m/),s=r.match(/(\d+)s/);return t&&(e+=parseInt(t[1],10)*3600),n&&(e+=parseInt(n[1],10)*60),s&&(e+=parseInt(s[1],10)),e}function pr(r){let e=r.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+(.+)$/,n=e.match(t);if(n){let a=n[8].trim();return{bytesTransferred:$(parseFloat(n[1]),n[2]),totalBytes:$(parseFloat(n[3]),n[4]),percentComplete:parseFloat(n[5]),speed:$(parseFloat(n[6]),n[7]),eta:a==="-"?0:qt(a)}}let s=e.match(/Transferred:\s+([\d.]+)\s*([A-Za-z]+)\s*\/\s*([\d.]+)\s*([A-Za-z]+),\s*([\d.]+)%/);if(!s)return null;let i=e.match(/([\d.]+)\s*([A-Za-z]+)\/s/),o=e.match(/ETA\s+([^\s]+)$/);return{bytesTransferred:$(parseFloat(s[1]),s[2]),totalBytes:$(parseFloat(s[3]),s[4]),percentComplete:parseFloat(s[5]),speed:i?$(parseFloat(i[1]),i[2]):0,eta:o&&o[1]!=="-"?qt(o[1]):0}}function pt(r){return new Promise((e,t)=>{let n=xe("rclone",r.args,{stdio:["ignore","pipe","pipe"]}),s="",i=0,o=a=>{for(let l of a.split(`
4
+ `)){if(l.trim().length===0)continue;let c=pr(l);if(!c)continue;let u=Date.now();!(c.percentComplete>=100)&&u-i<500||(i=u,r.onProgress?.(c))}};n.stdout.on("data",a=>{o(a.toString())}),n.stderr.on("data",a=>{let l=a.toString();s+=l,o(l)}),n.on("close",async a=>{a===0?e():t(new P(`rclone exited with code ${a}`,s))}),n.on("error",a=>{t(new P(`Failed to start rclone: ${a.message}`,""))})})}async function Ue(){return new Promise((r,e)=>{let t=xe("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",n=>{n===0?r():e(new Error("rclone is not installed or not in PATH. Please install rclone first: https://rclone.org/install/"))})})}async function mr(r,e,t,n,s,i){let o=`${r}:${e}`;return pt({args:ar({remoteSource:o,localPath:t,rcloneOptions:s,batchFilePath:n}),remoteSource:o,onProgress:i})}async function Kt(r,e,t=[]){let n=`${r}:${e}`;return new Promise((s,i)=>{let o=xe("rclone",lr({remoteSource:n,extraArgs:t})),a="",l="";o.stdout.on("data",c=>{a+=c.toString()}),o.stderr.on("data",c=>{l+=c.toString()}),o.on("close",async c=>{if(c===0)try{let u=JSON.parse(a||"[]");if(!Array.isArray(u))throw new Error("rclone lsjson did not return an array");let d=hr(u),m=await fr({remote:r,files:d.files,directories:d.directories,extraArgs:t});s(m)}catch(u){i(new P(`Failed to parse file listing from ${n}: ${u instanceof Error?u.message:String(u)}`,l))}else i(new P(`Failed to list files from ${n}`,l))}),o.on("error",c=>{i(new P(`Failed to start rclone: ${c.message}`,""))})})}async function Yt(r){let e=[],t=[];for(let n of r.files)Ar(n)?t.push(n):e.push(n);e.length>0&&(await mt.promises.writeFile(r.batchFilePath,`${e.map(n=>n.path).join(`
5
5
  `)}
6
- `,"utf-8"),await es(n.remote,n.remotePath,n.localPath,n.batchFilePath,n.rcloneOptions,n.onProgress));for(let s of t)await us({remote:n.remote,remotePath:n.remotePath,localPath:n.localPath,file:s,rcloneOptions:n.rcloneOptions,onProgress:n.onProgress})}function ts(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 ss(n){let e=rs(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=>ot(o.path,a))),r=ns(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=K(a.path),u=xe(l,r);r.add(u),i.push(...await it({remote:n.remote,parentId:a.id,sourcePrefix:a.path,targetPrefix:u,extraArgs:n.extraArgs}))}return[...s,...i]}function rs(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=>ot(o,a))||(r.push(o),s.push(i))}return s}function ns(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(K(s.path));return t}async function it(n){let e=await is({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}/${K(r.name)}`,a=r.mimeType==="application/vnd.google-apps.folder"?xe(o,t):Ie(o,t);if(t.add(a),r.mimeType==="application/vnd.google-apps.folder"){s.push(...await it({remote:n.remote,parentId:r.id,sourcePrefix:i,targetPrefix:a,extraArgs:n.extraArgs}));continue}s.push({path:i,targetPath:a,size:os(r.size),id:r.id,requiresIdentityDownload:!0})}return s}function is(n){let e=`'${as(n.parentId)}' in parents and trashed = false`;return new Promise((t,s)=>{let r=le("rclone",Xt({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 T(`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 T(`Failed to parse children for Google Drive folder ${n.parentId}: ${l instanceof Error?l.message:String(l)}`,o))}}),r.on("error",a=>{s(new T(`Failed to start rclone: ${a.message}`,""))})})}function os(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 ot(n,e){return n===e||n.startsWith(`${e}/`)}function as(n){return n.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function ls(n){let e=w(n),t=b(n.path);return n.requiresIdentityDownload===!0||e!==t}async function us(n){let e=Q.join(n.localPath,w(n.file));if(await Le.promises.mkdir(Q.dirname(e),{recursive:!0}),n.file.requiresIdentityDownload===!0){if(!n.file.id)throw new Error(`Cannot preserve duplicate remote file without a stable rclone file ID: ${n.file.path}`);await De({args:Jt({remote:n.remote,fileId:n.file.id,localTargetPath:e,rcloneOptions:n.rcloneOptions}),remoteSource:`${n.remote}:${n.file.path}`,onProgress:n.onProgress});return}await De({args:Vt({remoteFileSource:`${n.remote}:${cs(n.remotePath,n.file.path)}`,localTargetPath:e,rcloneOptions:n.rcloneOptions}),remoteSource:`${n.remote}:${n.file.path}`,onProgress:n.onProgress})}function cs(n,e){let t=n.replace(/\/+$/,""),s=e.replace(/^\/+/,"");return t.length===0?s:`${t}/${s}`}var ue=class{#t;constructor(e){this.#t=e}get displayName(){return`${this.#t.remote}:${this.#t.remotePath}`}async prepare(){await st()}async listFiles(){return rt(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[])}resolveLocalFile(e,t){return Xe(e,t)}async materializeBatch(e){await nt({remote:this.#t.remote,remotePath:this.#t.remotePath,localPath:e.batchDir,batchFilePath:e.batchFilePath,files:e.files,rcloneOptions:this.#t.rcloneOptions,onProgress:e.onProgress})}async shutdown(){}};import Be from"node:fs/promises";import Oe from"node:path";var M=class{#t;constructor(e){this.#t=e}get displayName(){return this.#t.rootPath}async prepare(){let e=await Be.stat(this.#t.rootPath).catch(()=>null);if(!e||!e.isDirectory())throw new Error(`Local source path is not a readable directory: ${this.#t.rootPath}`)}async listFiles(){let e=[];return await this.#s(this.#t.rootPath,"",e),e.sort((t,s)=>t.path.localeCompare(s.path)),e}resolveLocalFile(e,t){let s=w(e);return{relativePath:s,absolutePath:Oe.join(this.#t.rootPath,...e.path.split("/")),fileName:Oe.posix.basename(s),size:e.size}}async materializeBatch(e){}async shutdown(){}async#s(e,t,s){let r=await Be.readdir(e,{withFileTypes:!0});for(let i of r){let o=Oe.join(e,i.name),a=t===""?i.name:`${t}/${i.name}`;if(i.isDirectory()){await this.#s(o,a,s);continue}if(!i.isFile())continue;let l=await Be.stat(o);s.push({path:a,size:l.size})}}};import de from"node:fs/promises";import ys from"node:path";import{spawn as ds}from"node:child_process";var hs=18e4,ps=2e3,ms=3e4,gs=4e3,ce=class{#t;#s;#e=null;#r="";#n=null;#i=!1;constructor(e){this.#t=e,this.#s=e.spawnFn??ds}get isRunning(){return this.#e!==null&&this.#n===null}get daemonOutputTail(){return this.#r}async checkClientInstalled(){await this.#o({args:["list"],failureMessage:"LucidLink client is not installed or not in PATH. Install it from https://www.lucidlink.com/download before using --source lucidlink."})}async start(){if(this.#e)throw new Error("LucidLink daemon already started");let e=["--instance",String(this.#t.instanceId),"daemon","--fs",this.#t.filespace,"--user",this.#t.user,"--mount-point",this.#t.mountPoint,"--root-path",this.#t.cacheRootPath],t=this.#s("lucid",e,{stdio:["pipe","pipe","pipe"]});this.#e=t,t.stdout?.on("data",s=>this.#m(s)),t.stderr?.on("data",s=>this.#m(s)),t.on("exit",s=>{this.#n=s??-1,this.#i||console.error(`LucidLink daemon exited unexpectedly (code ${this.#n}). Recent output:
7
- ${this.#r}`)}),t.on("error",s=>{this.#n=-1,this.#m(Buffer.from(`spawn error: ${s.message}
6
+ `,"utf-8"),await mr(r.remote,r.remotePath,r.localPath,r.batchFilePath,r.rcloneOptions,r.onProgress));for(let n of t)await Fr({remote:r.remote,remotePath:r.remotePath,localPath:r.localPath,file:n,rcloneOptions:r.rcloneOptions,onProgress:r.onProgress})}function hr(r){let e=[],t=[];for(let n of r){let s=n;if(typeof s.Path!="string")continue;let i=typeof s.ID=="string"&&s.ID.length>0?s.ID:void 0;if(s.IsDir===!0){t.push({path:b(s.Path),id:i});continue}let o=typeof s.Size=="number"&&Number.isFinite(s.Size)?s.Size:0;e.push({path:b(s.Path),size:o,id:i})}return{files:e,directories:t}}async function fr(r){let e=gr(r.directories);if(e.length===0)return r.files;let t=e.map(o=>o[0].path),n=r.files.filter(o=>!t.some(a=>Qt(o.path,a))),s=yr(r.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=ie(a.path),c=ut(l,s);s.add(c),i.push(...await Vt({remote:r.remote,parentId:a.id,sourcePrefix:a.path,targetPrefix:c,extraArgs:r.extraArgs}))}return[...n,...i]}function gr(r){let e=new Map;for(let i of r){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),n=[],s=[];for(let i of t){let o=i[0].path;s.some(a=>Qt(o,a))||(s.push(o),n.push(i))}return n}function yr(r){let e=new Map;for(let n of r)e.set(n.path,(e.get(n.path)??0)+1);let t=new Set;for(let n of r)(e.get(n.path)??0)>1||t.add(ie(n.path));return t}async function Vt(r){let e=await Sr({remote:r.remote,parentId:r.parentId,extraArgs:r.extraArgs}),t=new Set,n=[];for(let s of e){if(typeof s.name!="string"||typeof s.id!="string")continue;let i=`${r.sourcePrefix}/${s.name}`,o=`${r.targetPrefix}/${ie(s.name)}`,a=s.mimeType==="application/vnd.google-apps.folder"?ut(o,t):ct(o,t);if(t.add(a),s.mimeType==="application/vnd.google-apps.folder"){n.push(...await Vt({remote:r.remote,parentId:s.id,sourcePrefix:i,targetPrefix:a,extraArgs:r.extraArgs}));continue}n.push({path:i,targetPath:a,size:Cr(s.size),id:s.id,requiresIdentityDownload:!0})}return n}function Sr(r){let e=`'${br(r.parentId)}' in parents and trashed = false`;return new Promise((t,n)=>{let s=xe("rclone",cr({remote:r.remote,query:e,extraArgs:r.extraArgs}),{stdio:["ignore","pipe","pipe"]}),i="",o="";s.stdout.on("data",a=>{i+=a.toString()}),s.stderr.on("data",a=>{o+=a.toString()}),s.on("close",a=>{if(a!==0){n(new P(`Failed to query children for Google Drive folder ${r.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){n(new P(`Failed to parse children for Google Drive folder ${r.parentId}: ${l instanceof Error?l.message:String(l)}`,o))}}),s.on("error",a=>{n(new P(`Failed to start rclone: ${a.message}`,""))})})}function Cr(r){if(typeof r=="number"&&Number.isFinite(r))return r;if(typeof r=="string"){let e=Number(r);return Number.isFinite(e)?e:0}return 0}function Qt(r,e){return r===e||r.startsWith(`${e}/`)}function br(r){return r.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}function Ar(r){let e=w(r),t=b(r.path);return r.requiresIdentityDownload===!0||e!==t}async function Fr(r){let e=ae.join(r.localPath,w(r.file));if(await mt.promises.mkdir(ae.dirname(e),{recursive:!0}),r.file.requiresIdentityDownload===!0){if(!r.file.id)throw new Error(`Cannot preserve duplicate remote file without a stable rclone file ID: ${r.file.path}`);await pt({args:dr({remote:r.remote,fileId:r.file.id,localTargetPath:e,rcloneOptions:r.rcloneOptions}),remoteSource:`${r.remote}:${r.file.path}`,onProgress:r.onProgress});return}await pt({args:ur({remoteFileSource:`${r.remote}:${wr(r.remotePath,r.file.path)}`,localTargetPath:e,rcloneOptions:r.rcloneOptions}),remoteSource:`${r.remote}:${r.file.path}`,onProgress:r.onProgress})}function wr(r,e){let t=r.replace(/\/+$/,""),n=e.replace(/^\/+/,"");return t.length===0?n:`${t}/${n}`}var De=class{#t;constructor(e){this.#t=e}get displayName(){return`${this.#t.remote}:${this.#t.remotePath}`}async prepare(){await Ue()}async listFiles(){return Kt(this.#t.remote,this.#t.remotePath,this.#t.rcloneOptions.extraRcloneArgs??[])}resolveLocalFile(e,t){return ke(e,t)}async materializeBatch(e){await Yt({remote:this.#t.remote,remotePath:this.#t.remotePath,localPath:e.batchDir,batchFilePath:e.batchFilePath,files:e.files,rcloneOptions:this.#t.rcloneOptions,onProgress:e.onProgress})}async shutdown(){}};import ht from"node:fs/promises";import ft from"node:path";var G=class{#t;constructor(e){this.#t=e}get displayName(){return this.#t.rootPath}async prepare(){let e=await ht.stat(this.#t.rootPath).catch(()=>null);if(!e||!e.isDirectory())throw new Error(`Local source path is not a readable directory: ${this.#t.rootPath}`)}async listFiles(){let e=[];return await this.#n(this.#t.rootPath,"",e),e.sort((t,n)=>t.path.localeCompare(n.path)),e}resolveLocalFile(e,t){let n=w(e);return{relativePath:n,absolutePath:ft.join(this.#t.rootPath,...e.path.split("/")),fileName:ft.posix.basename(n),size:e.size}}async materializeBatch(e){}async shutdown(){}async#n(e,t,n){let s=await ht.readdir(e,{withFileTypes:!0});for(let i of s){let o=ft.join(e,i.name),a=t===""?i.name:`${t}/${i.name}`;if(i.isDirectory()){await this.#n(o,a,n);continue}if(!i.isFile())continue;let l=await ht.stat(o);n.push({path:a,size:l.size})}}};import _e from"node:fs/promises";import vr from"node:path";import{spawn as Er}from"node:child_process";var Pr=18e4,Rr=2e3,Ir=3e4,kr=4e3,H=class{#t;#n;#e=null;#r="";#s=null;#i=!1;constructor(e){this.#t=e,this.#n=e.spawnFn??Er}get isRunning(){return this.#e!==null&&this.#s===null}get daemonOutputTail(){return this.#r}async checkClientInstalled(){await this.#o({args:["list"],failureMessage:"LucidLink client is not installed or not in PATH. Install it from https://www.lucidlink.com/download before running aspect-sync sync lucidlink."})}async start(){if(this.#e)throw new Error("LucidLink daemon already started");let e=["--instance",String(this.#t.instanceId),"daemon","--fs",this.#t.filespace,"--user",this.#t.user,"--mount-point",this.#t.mountPoint,"--root-path",this.#t.cacheRootPath],t=this.#n("lucid",e,{stdio:["pipe","pipe","pipe"]});this.#e=t,t.stdout?.on("data",n=>this.#m(n)),t.stderr?.on("data",n=>this.#m(n)),t.on("exit",n=>{this.#s=n??-1,this.#i||console.error(`LucidLink daemon exited unexpectedly (code ${this.#s}). Recent output:
7
+ ${this.#r}`)}),t.on("error",n=>{this.#s=-1,this.#m(Buffer.from(`spawn error: ${n.message}
8
8
  `))}),t.stdin?.write(`${this.#t.password}
9
- `),t.stdin?.end(),await this.#a(),this.#t.cacheSize&&await this.#o({args:["--instance",String(this.#t.instanceId),"config","--set","--local","--DataCache.Size",this.#t.cacheSize],failureMessage:`Failed to set LucidLink DataCache.Size to ${this.#t.cacheSize}`})}async stop(){let e=this.#e;if(!e||this.#n!==null){this.#e=null;return}this.#i=!0,await this.#o({args:["--instance",String(this.#t.instanceId),"exit"],failureMessage:"Failed to request LucidLink daemon exit"}).catch(t=>{console.error(t.message)}),await this.#c(e),this.#e=null}assertHealthy(){if(this.#e&&this.#n!==null&&!this.#i)throw new Error(`LucidLink daemon exited unexpectedly (code ${this.#n}). Recent output:
10
- ${this.#r}`)}async#a(){let e=this.#t.linkTimeoutMs??hs,t=this.#t.linkPollIntervalMs??ps,s=Date.now();for(;Date.now()-s<e;){if(this.#n!==null)throw new Error(`LucidLink daemon exited before linking (code ${this.#n}). Check the filespace name and credentials. Recent output:
11
- `+this.#r);let r=await this.#u();if(r!==null&&/\bLinked\b/i.test(r))return;await fs(t)}throw new Error(`Timed out after ${Math.round(e/1e3)}s waiting for LucidLink filespace "${this.#t.filespace}" to link. Recent daemon output:
12
- ${this.#r}`)}async#u(){return new Promise(e=>{let t=this.#s("lucid",["--instance",String(this.#t.instanceId),"status"],{stdio:["ignore","pipe","pipe"]}),s="";t.stdout?.on("data",r=>{s+=r.toString()}),t.on("exit",r=>{e(r===0?s:null)}),t.on("error",()=>{e(null)})})}#o(e){return new Promise((t,s)=>{let r=this.#s("lucid",e.args,{stdio:["ignore","pipe","pipe"]}),i="";r.stderr?.on("data",o=>{i+=o.toString()}),r.on("exit",o=>{o===0?t():s(new Error(`${e.failureMessage} (exit code ${o}): ${i.trim()}`))}),r.on("error",o=>{s(new Error(`${e.failureMessage}: ${o.message}`))})})}async#c(e){this.#n===null&&await new Promise(t=>{let s=setTimeout(()=>{e.kill("SIGKILL")},ms);e.on("exit",()=>{clearTimeout(s),t()}),this.#n!==null&&(clearTimeout(s),t())})}#m(e){this.#r=(this.#r+e.toString()).slice(-gs)}};function fs(n){return new Promise(e=>setTimeout(e,n))}var he=class{#t;#s;#e;constructor(e,t){this.#t=e,this.#s=t??new ce({filespace:e.filespace,user:e.user,password:e.password,instanceId:e.instanceId,mountPoint:e.mountPoint,cacheRootPath:e.cacheRootPath,cacheSize:e.cacheSize}),this.#e=new M({kind:"local",rootPath:this.#r()})}get displayName(){let e=this.#t.filespacePath===""?"":`/${this.#t.filespacePath}`;return`lucidlink:${this.#t.filespace}${e}`}async prepare(){await this.#s.checkClientInstalled(),await de.mkdir(this.#t.mountPoint,{recursive:!0}),await de.mkdir(this.#t.cacheRootPath,{recursive:!0}),console.log(`Mounting LucidLink filespace ${this.#t.filespace} at ${this.#t.mountPoint}...`),await this.#s.start(),console.log("Filespace linked and mounted");let e=await de.stat(this.#r()).catch(()=>null);if(!e||!e.isDirectory())throw new Error(`Path "${this.#t.filespacePath}" does not exist in filespace ${this.#t.filespace}`)}async listFiles(){return this.#s.assertHealthy(),this.#e.listFiles()}resolveLocalFile(e,t){return this.#e.resolveLocalFile(e,t)}async materializeBatch(e){this.#s.assertHealthy(),await this.#e.materializeBatch(e)}async shutdown(){await this.#s.stop(),await de.rm(this.#t.workDir,{recursive:!0,force:!0})}#r(){return this.#t.filespacePath===""?this.#t.mountPoint:ys.join(this.#t.mountPoint,...this.#t.filespacePath.split("/"))}};function at(n){switch(n.kind){case"rclone":return new ue(n);case"local":return new M(n);case"lucidlink":return new he(n);default:{let e=n;throw new Error(`Unsupported sync source: ${JSON.stringify(e)}`)}}}import*as me from"fs/promises";import*as ge from"path";var Ss={".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 Cs(n){let e=ge.extname(n).toLowerCase();return Ss[e]??""}var pe=class n{#t;#s=null;#e=null;#r=!1;#n;#i;#a;constructor(e,t,s,r){this.#t=e,this.#n=t,this.#i=s,this.#a=r}static async create(e){let t=await me.stat(e),s=ge.basename(e),r=Cs(s);return new n(e,t.size,s,r)}get name(){return this.#i}get size(){return this.#n}get type(){return this.#a}async readChunk(e,t){if(!this.#s){this.#e||(this.#e=me.open(this.#t,"r"));let i=await this.#e;if(this.#e=null,this.#r)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.#r=!0;let e=this.#e;await this.#s?.close(),this.#s=null,e&&await(await e.catch(()=>null))?.close(),this.#e=null}};var bs=new Set(["success","failed","cancelled"]),lt=1e3,As=250,Es=4*1024*1024,Me=class{#t;name;constructor(e,t){this.#t=e,this.name=t}get size(){return this.#t.size}get type(){return this.#t.type}readChunk(e,t){return this.#t.readChunk(e,t)}async close(){await this.#t.close?.()}},fe=class{#t;#s;#e;#r;#n;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=>pe.create(t)),this.#r=e.onSnapshot,this.#n=e.analytics}async uploadFiles(e){let t=e.filter(a=>a.preSkipped===!0),s=e.filter(a=>a.preSkipped!==!0);if(s.length===0)return{totalFileCount:e.length,successFileCount:0,skippedFileCount:t.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};let r=new j({httpClient:this.#s,maxConcurrency:this.#t.maxConcurrent,deltaIntervalMs:lt,adaptiveConcurrency:!1,analytics:this.#n}),i=[],o=0;try{let a=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((u,c)=>u+c.file.size,0),conflictResolutionOverride:"skip"});for(let u of s){let c=await this.#e(u.file.absolutePath),d=c.name===u.file.fileName?c:new Me(c,u.file.fileName),p=r.startUpload({fileReader:d,directoryId:u.directoryId,projectId:this.#t.projectId,groupId:a,chunkSize:Es});r.addAssetToGroup(a,p),i.push({assetId:p,file:u.file,fileReader:d});let g=Date.now();(i.length===1||i.length===s.length||g-o>=As)&&(o=g,this.#r?.(r.getSnapshot()))}await this.#i(r);let l=r.getSnapshot();return this.#r?.(l),this.#a({snapshot:l,startedUploads:i,preSkippedCount:t.length})}finally{r.destroy()}}async#i(e){let s=Date.now();for(;Date.now()-s<864e5;){let r=e.getSnapshot();this.#r?.(r);let i=Object.values(r.uploadAssets);if(i.length>0&&i.every(o=>bs.has(o.status)))return;await new Promise(o=>setTimeout(o,lt))}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 ye=200,Se=class{#t;#s;#e;#r;#n;constructor(e,t,s){this.#t=e,this.#s=t??new v({apiUrl:e.apiUrl,apiKey:e.apiKey,edgeWorkerUrl:e.edgeWorkerUrl,sessionId:e.sessionName}),this.#e=new oe({rootDirectoryId:e.directoryId,httpClient:this.#s}),this.#r=new fe({config:e,httpClient:this.#s,onSnapshot:r=>C.updateSnapshot(r),analytics:Ze}),this.#n=s??at(e.source)}async run(){try{await this.#i()}finally{await this.#n.shutdown()}}async runBatched(){try{await this.#a()}finally{await this.#n.shutdown()}}async runCheckOnly(){try{await this.#u()}finally{await this.#n.shutdown()}}async#i(){this.#C("Starting data sync..."),await this.#b();let e=this.#A(await this.#o());if(e.length===0){console.log("No files to sync. Exiting."),await this.#S();return}let t={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},s=[],r={batchNumber:1,files:e,totalSize:this.#O(e)};C.start();try{let o=await this.#v({batch:r,totalBatches:1,overallFilesTotal:e.length,overallBytesTotal:r.totalSize,completedTotals:t,batchDir:this.#t.localTempDir});this.#B(t,s,o,r.totalSize)}finally{C.stop()}let i={...t,failedFiles:s};this.#T({summary:i}),await this.#P(i),this.#_(i)}async#a(){if(!this.#t.batchSizeBytes)throw new Error("Batch size not configured. Use batchSizeBytes in config.");this.#C("Starting batched data sync...",[`Batch size: ${S(this.#t.batchSizeBytes)}`,`Max concurrent chunks: ${this.#t.maxConcurrent}`]),await this.#b();let e=this.#A(await this.#o());if(e.length===0){console.log("No files to sync. Exiting."),await this.#S();return}let t=He(e,this.#t.batchSizeBytes);await this.#p(t);let s={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},r=[],i=this.#O(e);C.start();try{for(let a of t){let l=await this.#v({batch:a,totalBatches:t.length,overallFilesTotal:e.length,overallBytesTotal:i,completedTotals:s});this.#B(s,r,l,a.totalSize)}}finally{C.stop()}this.#T({summary:{...s,failedFiles:r},extraLines:[`Batches: ${t.length}`]});let o={...s,failedFiles:r};await this.#P(o),this.#_(o)}async#u(){console.log("Running in check-only mode (no downloads/uploads)..."),await this.#n.prepare(),console.log(`Listing source files from ${this.#n.displayName}...`);let e=await this.#n.listFiles();console.log(`Found ${e.length} source files to check`);let t=this.#A(e);if(t.length===0){console.log("No source files to check. Exiting.");return}console.log("Fetching Aspect project summary...");let s=await this.#c();console.log("Fetching existing Aspect files...");let r=await this.#e.listFilesInSubtree({onProgress:o=>this.#d(o)}),i=this.#m(t,r,s);this.#k(i)}async#o(){console.log("Listing all source files...");let e=await this.#n.listFiles();return console.log(`Found ${e.length} files`),console.log(`Total size: ${S(this.#O(e))}`),console.log(""),e}async#c(){return await this.#s.get(`/projects/${this.#t.projectId}`)}#m(e,t,s){let r=e.map(f=>({relativePath:w(f),sizeBytes:this.#f(f.size)})),i=r.filter(f=>f.sizeBytes===null).length,o=t.filter(f=>f.isUploaded),a=t.filter(f=>f.uploadStateKnown&&!f.isUploaded),l=t.filter(f=>!f.uploadStateKnown).length;l>0&&(console.warn(`Warning: ${l} server asset(s) did not include upload status; treating them as uploaded for check comparison.`),console.log(""));let u=this.#l(r),c=this.#D(o),d=new Set([...u.keys(),...c.keys()]),p=0,g=0,h=[],A=[],y=[];for(let f of d){let V=u.get(f)??[],P=c.get(f)??[],R=new Set,Ce=[];for(let E of V){if(E.sizeBytes===null){Ce.push(E);continue}let D=P.findIndex((U,J)=>!R.has(J)&&U.sizeBytes===E.sizeBytes);D>=0?(p+=1,R.add(D)):Ce.push(E)}for(let E of Ce){if(E.sizeBytes===null){let U=P.findIndex((J,dt)=>!R.has(dt));U>=0?(R.add(U),g+=1):h.push(E);continue}let D=P.findIndex((U,J)=>!R.has(J));if(D>=0){let U=P[D];R.add(D),A.push({relativePath:f,remoteSizeBytes:E.sizeBytes,serverSizeBytes:U.sizeBytes,assetId:U.assetId})}else h.push(E)}for(let E=0;E<P.length;E++)R.has(E)||y.push(P[E])}return{totalRemoteCount:e.length,totalServerCount:t.length,projectAssetCount:s.num_assets,projectRootDirectoryId:s.root_directory_id,uploadedServerCount:o.length,unknownUploadStateCount:l,unknownRemoteSizeCount:i,pathOnlyMatchCount:g,existingCount:p,missingFiles:h,sizeMismatches:A,extraUploadedFiles:y,incompleteServerFiles:a}}#l(e){let t=new Map;for(let s of e){let r=b(s.relativePath),i=t.get(r)??[];i.push({...s,relativePath:r}),t.set(r,i)}return t}#D(e){let t=new Map;for(let s of e){let r=b(s.relativePath),i=t.get(r)??[];i.push({...s,relativePath:r}),t.set(r,i)}return t}#f(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:null}#A(e){let t=Qe(e);if(t.changes.length===0)return t.files;let s=t.changes.slice(0,10).map(o=>`${o.sourcePath} -> ${o.targetPath}`).join(`
13
- `),r=t.changes.length-10,i=r>0?`
14
- ...and ${r} more renamed target path(s)`:"";return console.warn(`Warning: ${t.changes.length} remote file path(s) were renamed for Aspect compatibility.
15
- ${s}${i}
16
- `),console.log(""),t.files}async#v(e){let t=e.batchDir??Ne.join(this.#t.localTempDir,`batch${e.batch.batchNumber}`);await X.mkdir(t,{recursive:!0});let s=e.batch.files.map(d=>this.#n.resolveLocalFile(d,t));C.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.#h(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:`Preparing ${s.length} files...`}),C.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.#h(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"syncing_folders",extraDetails:"Ensuring target directories exist..."});let r=await this.#e.ensureDirectories(s);C.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.#h(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:"Checking existing assets..."});let i=await this.#U(r),o=this.#F(i),a=e.batch.files.filter((d,p)=>i[p]?.preSkipped!==!0),l=Ne.join(this.#t.localTempDir,`batch${e.batch.batchNumber}.txt`),u=async()=>{await je(l),this.#t.keepLocal||await X.rm(t,{recursive:!0,force:!0}),C.resetUploadSnapshot(),C.updateDownloadProgress(null)};if(a.length===0){let d={totalFileCount:i.length,successFileCount:0,skippedFileCount:i.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};return C.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.#h(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"everything already synced"}),C.persistCurrentBatchLine(),await u(),d}C.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.#h(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"downloading"}),await this.#n.materializeBatch({files:a,batchDir:t,batchFilePath:l,onProgress:d=>C.updateDownloadProgress(d)}),C.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.#h(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"uploading"});let c=await this.#r.uploadFiles(i);return this.#w(c)?(C.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.#h(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"failed; local files preserved"}),C.persistCurrentBatchLine(),c):(C.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.#h(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"cleaning"}),await u(),C.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.#h(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete"}),C.persistCurrentBatchLine(),c)}async#b(){console.log("Preparing source..."),await this.#n.prepare(),console.log("Source ready"),console.log(""),console.log("Creating session directory..."),await X.mkdir(this.#t.localTempDir,{recursive:!0}),console.log(`Session directory: ${this.#t.localTempDir}`),console.log("")}async#S(){this.#t.keepLocal||(console.log(""),console.log("Cleaning up session directory..."),await X.rm(this.#t.localTempDir,{recursive:!0,force:!0}),console.log(`Deleted session directory: ${this.#t.localTempDir}`))}async#P(e){if(this.#w(e)){console.log(""),console.log(`Preserving session directory for retry/debugging: ${this.#t.localTempDir}`);return}await this.#S()}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}))}#F(e){return e.reduce((t,s)=>(s.preSkipped===!0&&(t.skippedFileCount+=1,t.skippedByteCount+=s.file.size),t),{skippedFileCount:0,skippedByteCount:0})}async#p(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 X.writeFile(Ne.join(this.#t.localTempDir,"batches.txt"),`${t.join(`
9
+ `),t.stdin?.end(),await this.#a(),this.#t.cacheSize&&await this.#o({args:["--instance",String(this.#t.instanceId),"config","--set","--local","--DataCache.Size",this.#t.cacheSize],failureMessage:`Failed to set LucidLink DataCache.Size to ${this.#t.cacheSize}`})}async stop(){let e=this.#e;if(!e||this.#s!==null){this.#e=null;return}this.#i=!0,await this.#o({args:["--instance",String(this.#t.instanceId),"exit"],failureMessage:"Failed to request LucidLink daemon exit"}).catch(t=>{console.error(t.message)}),await this.#u(e),this.#e=null}assertHealthy(){if(this.#e&&this.#s!==null&&!this.#i)throw new Error(`LucidLink daemon exited unexpectedly (code ${this.#s}). Recent output:
10
+ ${this.#r}`)}async#a(){let e=this.#t.linkTimeoutMs??Pr,t=this.#t.linkPollIntervalMs??Rr,n=Date.now();for(;Date.now()-n<e;){if(this.#s!==null)throw new Error(`LucidLink daemon exited before linking (code ${this.#s}). Check the filespace name and credentials. Recent output:
11
+ `+this.#r);let s=await this.#c();if(s!==null&&/\bLinked\b/i.test(s))return;await Tr(t)}throw new Error(`Timed out after ${Math.round(e/1e3)}s waiting for LucidLink filespace "${this.#t.filespace}" to link. Recent daemon output:
12
+ ${this.#r}`)}async#c(){return new Promise(e=>{let t=this.#n("lucid",["--instance",String(this.#t.instanceId),"status"],{stdio:["ignore","pipe","pipe"]}),n="";t.stdout?.on("data",s=>{n+=s.toString()}),t.on("exit",s=>{e(s===0?n:null)}),t.on("error",()=>{e(null)})})}#o(e){return new Promise((t,n)=>{let s=this.#n("lucid",e.args,{stdio:["ignore","pipe","pipe"]}),i="";s.stderr?.on("data",o=>{i+=o.toString()}),s.on("exit",o=>{o===0?t():n(new Error(`${e.failureMessage} (exit code ${o}): ${i.trim()}`))}),s.on("error",o=>{n(new Error(`${e.failureMessage}: ${o.message}`))})})}async#u(e){this.#s===null&&await new Promise(t=>{let n=setTimeout(()=>{e.kill("SIGKILL")},Ir);e.on("exit",()=>{clearTimeout(n),t()}),this.#s!==null&&(clearTimeout(n),t())})}#m(e){this.#r=(this.#r+e.toString()).slice(-kr)}};function Tr(r){return new Promise(e=>setTimeout(e,r))}var Oe=class{#t;#n;#e;constructor(e,t){this.#t=e,this.#n=t??new H({filespace:e.filespace,user:e.user,password:e.password,instanceId:e.instanceId,mountPoint:e.mountPoint,cacheRootPath:e.cacheRootPath,cacheSize:e.cacheSize}),this.#e=new G({kind:"local",rootPath:this.#r()})}get displayName(){let e=this.#t.filespacePath===""?"":`/${this.#t.filespacePath}`;return`lucidlink:${this.#t.filespace}${e}`}async prepare(){await this.#n.checkClientInstalled(),await _e.mkdir(this.#t.mountPoint,{recursive:!0}),await _e.mkdir(this.#t.cacheRootPath,{recursive:!0}),console.log(`Mounting LucidLink filespace ${this.#t.filespace} at ${this.#t.mountPoint}...`),await this.#n.start(),console.log("Filespace linked and mounted");let e=await _e.stat(this.#r()).catch(()=>null);if(!e||!e.isDirectory())throw new Error(`Path "${this.#t.filespacePath}" does not exist in filespace ${this.#t.filespace}`)}async listFiles(){return this.#n.assertHealthy(),this.#e.listFiles()}resolveLocalFile(e,t){return this.#e.resolveLocalFile(e,t)}async materializeBatch(e){this.#n.assertHealthy(),await this.#e.materializeBatch(e)}async shutdown(){await this.#n.stop(),await _e.rm(this.#t.workDir,{recursive:!0,force:!0})}#r(){return this.#t.filespacePath===""?this.#t.mountPoint:vr.join(this.#t.mountPoint,...this.#t.filespacePath.split("/"))}};import Vr from"node:path";import Jt from"node:fs";import Lr from"node:path";var xr="https://api.frame.io/v4",le=4,Ur=1e3,Dr=15e3,B=class{#t;constructor(e){this.#t=e.token}async listAccounts(){return(await this.#n("/accounts")).data}async listWorkspaces(e){return(await this.#n(`/accounts/${e}/workspaces`)).data}async listProjects(e){let t=[],n=`/accounts/${e.accountId}/workspaces/${e.workspaceId}/projects`,s={page_size:String(e.pageSize??100)};for(;n;){let i=await this.#n(n,s);t.push(...i.data),n=i.links?.next??null,s=void 0}return t}async listAccountProjects(e){let t=[],n=`/accounts/${e.accountId}/projects`,s={page_size:String(e.pageSize??100)};for(;n;){let i=await this.#n(n,s,{"api-version":"experimental"});t.push(...i.data),n=i.links?.next??null,s=void 0}return t}async getProject(e){let t=await this.#n(`/accounts/${e.accountId}/projects/${e.projectId}`);return"data"in t&&t.data?t.data:t}async listFolderChildren(e){let t=[],n=`/accounts/${e.accountId}/folders/${e.folderId}/children`,s={page_size:String(e.pageSize),type:"file,folder,version_stack",...e.includeOriginalMediaLinks?{include:"media_links.original"}:{}};for(;n;){let i=await this.#n(n,s);t.push(...i.data),n=i.links?.next??null,s=void 0}return t}async validateFolderAccess(e){await this.#n(`/accounts/${e.accountId}/folders/${e.folderId}/children`,{page_size:"1"})}async getFileWithOriginalMediaLink(e){let t=await this.#n(`/accounts/${e.accountId}/files/${e.fileId}`,{include:"media_links.original"}),n="data"in t&&t.data?t.data:t;return yt(n)}async#n(e,t,n={}){let s=new URL(e.startsWith("http")?e:`${xr}${e}`);for(let[i,o]of Object.entries(t??{}))s.searchParams.set(i,o);for(let i=0;i<le;i+=1)try{let o=await fetch(s,{headers:{Authorization:`Bearer ${this.#t}`,Accept:"application/json",...n}});if(!o.ok){let a=await o.text().catch(()=>"");if(Br(o)&&i<le-1){await gt(Be(o.headers.get("retry-after"),i));continue}throw new Error(`Frame.io API ${o.status} ${o.statusText} for ${s.pathname}: ${a}`)}return await o.json()}catch(o){if(Zt(o)&&i<le-1){await gt(Be(null,i));continue}throw o}throw new Error(`Frame.io API request failed for ${s.pathname}`)}};function yt(r){return{id:r.id,name:r.name??r.id,sizeBytes:_r(r),downloadUrl:r.media_links?.original?.download_url??void 0}}function _r(r){let e=[r.file_size,r.filesize,r.size,r.size_bytes,r.bytes];for(let t of e){if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t=="string"){let n=Number(t);if(Number.isFinite(n))return n}}return 0}async function Xt(r){if(!r.file.downloadUrl)throw new Error(`Frame.io file ${r.file.id} has no original download URL`);for(let e=0;e<le;e+=1)try{return await Or(r)}catch(t){if(Mr(t)&&e<le-1){await gt(zr(t,e));continue}throw t}throw new Error(`Download failed for ${r.file.name}`)}async function Or(r){if(!r.file.downloadUrl)throw new Error(`Frame.io file ${r.file.id} has no original download URL`);let e=new AbortController,t=r.maxSeconds===void 0?null:setTimeout(()=>e.abort(),r.maxSeconds*1e3),n=null,s=Date.now(),i=0;try{r.outputPath&&(await Jt.promises.mkdir(Lr.dirname(r.outputPath),{recursive:!0}),n=Jt.createWriteStream(r.outputPath));let a=await fetch(r.file.downloadUrl,{signal:e.signal,headers:{Accept:"application/octet-stream"}});if(!a.ok||!a.body){let c=await a.text().catch(()=>"");throw new ce(`Download failed for ${r.file.name}: ${a.status} ${a.statusText} ${c}`,a.status,a.headers.get("retry-after"))}let l=a.body.getReader();for(;;){let{done:c,value:u}=await l.read();if(c)break;i+=u.byteLength,r.onProgress?.(i),n&&await Gr(n,u)}}catch(a){if(a.name!=="AbortError")throw a}finally{t&&clearTimeout(t),n&&await Hr(n)}let o=Math.max((Date.now()-s)/1e3,.001);return{id:r.file.id,name:r.file.name,bytesRead:i,seconds:o,outputPath:r.outputPath}}var ce=class extends Error{status;retryAfter;constructor(e,t,n){super(e),this.status=t,this.retryAfter=n}};function Br(r){return r.status===408||r.status===425||r.status===429||r.status>=500}function Mr(r){return r instanceof ce?Nr(r.status):Zt(r)}function Nr(r){return r===408||r===425||r===429||r>=500}function Zt(r){if(!(r instanceof Error)||r.name==="AbortError")return!1;if(r instanceof TypeError)return!0;let e=r.code;return e==="ECONNRESET"||e==="ETIMEDOUT"||e==="UND_ERR_SOCKET"}function zr(r,e){return r instanceof ce?Be(r.retryAfter,e):Be(null,e)}function Be(r,e){let t=$r(r);return t!==null?t:Math.min(Ur*2**e,Dr)}function $r(r){if(!r)return null;let e=Number(r);if(Number.isFinite(e))return Math.max(e*1e3,0);let t=Date.parse(r);return Number.isFinite(t)?Math.max(t-Date.now(),0):null}function gt(r){return new Promise(e=>setTimeout(e,r))}function Gr(r,e){return new Promise((t,n)=>{if(r.write(e)){t();return}r.once("drain",t),r.once("error",n)})}function Hr(r){return new Promise((e,t)=>{r.end(e),r.once("error",t)})}import St from"node:crypto";import Me from"node:fs/promises";import jr from"node:os";import en from"node:path";var Wr="https://ims-na1.adobelogin.com/ims/authorize/v2",tn="https://ims-na1.adobelogin.com/ims/token/v3",qr="eac24c58b3bb4e8ab26105ad17adf779",Kr=300*1e3;function nn(){return process.env.FRAMEIO_CLIENT_ID||qr}function j(){return en.join(jr.homedir(),".config","aspect-sync","frameio-auth.json")}function rn(){let r=St.randomBytes(32).toString("base64url"),e=St.createHash("sha256").update(r).digest("base64url");return{verifier:r,challenge:e}}function sn(r){let e=new URL(Wr);return e.searchParams.set("client_id",r.clientId),e.searchParams.set("scope","openid email profile offline_access additional_info.roles"),e.searchParams.set("response_type","code"),e.searchParams.set("code_challenge",r.codeChallenge),e.searchParams.set("code_challenge_method","S256"),e.searchParams.set("state",r.state??St.randomBytes(16).toString("hex")),e.toString()}function on(r){let e=r.trim();if(!e)throw new Error("Authorization code cannot be empty");if(!e.includes("code="))return e;let n=new URL(e).searchParams.get("code");if(!n)throw new Error("Redirect URL did not include a code parameter");return n}async function an(r){let e=await fetch(`${tn}?client_id=${encodeURIComponent(r.clientId)}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({code:r.code,grant_type:"authorization_code",code_verifier:r.codeVerifier})});return ln(e,"authorization code exchange")}async function Yr(r){let e=await fetch(`${tn}?client_id=${encodeURIComponent(r.clientId)}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:r.refreshToken})});return ln(e,"refresh token exchange")}async function Ne(){let r=j(),e=await Ct(r),t=Date.parse(e.expiresAt);if(Number.isFinite(t)&&t-Date.now()>Kr)return e.accessToken;if(!e.refreshToken)throw new Error(`Frame.io auth file ${r} has no refresh token; run aspect-sync frameio login`);let n=await Yr({clientId:e.clientId,refreshToken:e.refreshToken}),s=At({clientId:e.clientId,token:n,previousRefreshToken:e.refreshToken,defaultAccountId:e.defaultAccountId});return await bt(r,s),s.accessToken}async function Ct(r){let e=await Me.readFile(r,"utf-8").catch(t=>{throw t.code==="ENOENT"?new Error(`Frame.io auth file not found at ${r}; run aspect-sync frameio login`):t});return JSON.parse(e)}async function bt(r,e){await Me.mkdir(en.dirname(r),{recursive:!0}),await Me.writeFile(r,`${JSON.stringify(e,null,2)}
13
+ `,{encoding:"utf-8",mode:384}),await Me.chmod(r,384)}function At(r){let e={clientId:r.clientId,accessToken:r.token.access_token,refreshToken:r.token.refresh_token??r.previousRefreshToken,expiresAt:new Date(Date.now()+r.token.expires_in*1e3).toISOString(),tokenType:r.token.token_type};return r.defaultAccountId&&(e.defaultAccountId=r.defaultAccountId),e}async function ln(r,e){let t=await r.text();if(!r.ok)throw new Error(`Adobe IMS ${e} failed: ${r.status} ${r.statusText} ${t}`);let s=JSON.parse(t);if(!s.access_token||typeof s.expires_in!="number")throw new Error(`Adobe IMS ${e} returned an invalid token response: ${t}`);return s}var ze=class{#t;#n=null;#e=null;#r=null;#s=new Map;constructor(e){this.#t=e}get displayName(){return`frameio:${this.#t.accountId}/${this.#t.folderId}`}async prepare(){await(await this.#u()).validateFolderAccess({accountId:this.#t.accountId,folderId:this.#t.folderId})}async listFiles(){let e=await this.#u(),t=[];await this.#i({client:e,folderId:this.#t.folderId,relativePrefix:"",files:t}),t.sort((n,s)=>n.path.localeCompare(s.path)),this.#s.clear();for(let n of t)this.#s.set(n.id,n);return t}resolveLocalFile(e,t){return ke(e,t)}async materializeBatch(e){let t={bytesTransferred:0,totalBytes:e.files.reduce((i,o)=>i+o.size,0),startedAt:Date.now()},n=0,s=async()=>{for(;n<e.files.length;){let i=n;n+=1,await this.#a({file:e.files[i],batchDir:e.batchDir,totals:t,onProgress:e.onProgress})}};await Promise.all(Array.from({length:Math.min(this.#t.downloadConcurrency,e.files.length)},()=>s()))}async shutdown(){}async#i(e){let t=await e.client.listFolderChildren({accountId:this.#t.accountId,folderId:e.folderId,pageSize:this.#t.pageSize});for(let n of t){if(n.type==="folder"){let i=n;await this.#i({client:e.client,folderId:i.id,relativePrefix:this.#o(e.relativePrefix,i.name),files:e.files});continue}if(n.type!=="file")continue;let s=yt(n);e.files.push({id:s.id,path:this.#o(e.relativePrefix,s.name),size:s.sizeBytes})}}async#a(e){if(!e.file.id)throw new Error(`Frame.io listing missing file ID for ${e.file.path}`);let t=Vr.join(e.batchDir,w(e.file)),n=this.#s.get(e.file.id),i=await(await this.#u()).getFileWithOriginalMediaLink({accountId:this.#t.accountId,fileId:e.file.id}),o={...i,name:n?.path??i.name,sizeBytes:e.file.size},a=0;await Xt({file:o,outputPath:t,onProgress:l=>{e.totals.bytesTransferred+=Math.max(l-a,0),a=l,e.onProgress?.(this.#c(e.totals))}})}#c(e){let t=Math.max((Date.now()-e.startedAt)/1e3,.001),n=e.bytesTransferred/t,s=Math.max(e.totalBytes-e.bytesTransferred,0);return{bytesTransferred:e.bytesTransferred,totalBytes:e.totalBytes,speed:n,eta:n>0?Math.ceil(s/n):0,percentComplete:e.totalBytes>0?e.bytesTransferred/e.totalBytes*100:100}}#o(e,t){let n=e===""?t:`${e}/${t}`;return b(n)}async#u(){if(this.#r)return await this.#r;this.#r=this.#m();try{return await this.#r}finally{this.#r=null}}async#m(){let e=await Ne();return(!this.#n||this.#e!==e)&&(this.#n=new B({token:e}),this.#e=e),this.#n}};function W(r){switch(r.kind){case"rclone":return new De(r);case"local":return new G(r);case"lucidlink":return new Oe(r);case"frameio":return new ze(r);default:{let e=r;throw new Error(`Unsupported sync source: ${JSON.stringify(e)}`)}}}import*as Ge from"fs/promises";import*as He from"path";var Qr={".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 Jr(r){let e=He.extname(r).toLowerCase();return Qr[e]??""}var $e=class r{#t;#n=null;#e=null;#r=!1;#s;#i;#a;constructor(e,t,n,s){this.#t=e,this.#s=t,this.#i=n,this.#a=s}static async create(e){let t=await Ge.stat(e),n=He.basename(e),s=Jr(n);return new r(e,t.size,n,s)}get name(){return this.#i}get size(){return this.#s}get type(){return this.#a}async readChunk(e,t){if(!this.#n){this.#e||(this.#e=Ge.open(this.#t,"r"));let i=await this.#e;if(this.#e=null,this.#r)return Buffer.alloc(0);this.#n=i}let n=t-e,s=Buffer.alloc(n);return await this.#n.read(s,0,n,e),s}async close(){this.#r=!0;let e=this.#e;await this.#n?.close(),this.#n=null,e&&await(await e.catch(()=>null))?.close(),this.#e=null}};var Xr=new Set(["success","failed","cancelled"]),cn=1e3,Zr=250,es=4*1024*1024,Ft=class{#t;name;constructor(e,t){this.#t=e,this.name=t}get size(){return this.#t.size}get type(){return this.#t.type}readChunk(e,t){return this.#t.readChunk(e,t)}async close(){await this.#t.close?.()}},je=class{#t;#n;#e;#r;#s;constructor(e){this.#t=e.config,this.#n=e.httpClient??new x({apiUrl:e.config.apiUrl,apiKey:e.config.apiKey,edgeWorkerUrl:e.config.edgeWorkerUrl,sessionId:e.config.sessionName}),this.#e=e.createFileReader??(t=>$e.create(t)),this.#r=e.onSnapshot,this.#s=e.analytics}async uploadFiles(e){let t=e.filter(a=>a.preSkipped===!0),n=e.filter(a=>a.preSkipped!==!0);if(n.length===0)return{totalFileCount:e.length,successFileCount:0,skippedFileCount:t.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};let s=new ne({httpClient:this.#n,maxConcurrency:this.#t.maxConcurrent,deltaIntervalMs:cn,adaptiveConcurrency:!1,analytics:this.#s}),i=[],o=0;try{let a=s.startGroupUpload({name:`${n.length} files`,type:"files",fileCount:n.length,folderCount:0,topLevelFileCount:n.length,topLevelFolderCount:0,rootDirectoryId:this.#t.directoryId,projectId:this.#t.projectId,totalBytes:n.reduce((c,u)=>c+u.file.size,0),conflictResolutionOverride:"skip"});for(let c of n){let u=await this.#e(c.file.absolutePath),d=u.name===c.file.fileName?u:new Ft(u,c.file.fileName),m=s.startUpload({fileReader:d,directoryId:c.directoryId,projectId:this.#t.projectId,groupId:a,chunkSize:es});s.addAssetToGroup(a,m),i.push({assetId:m,file:c.file,fileReader:d});let g=Date.now();(i.length===1||i.length===n.length||g-o>=Zr)&&(o=g,this.#r?.(s.getSnapshot()))}await this.#i(s);let l=s.getSnapshot();return this.#r?.(l),this.#a({snapshot:l,startedUploads:i,preSkippedCount:t.length})}finally{s.destroy()}}async#i(e){let n=Date.now();for(;Date.now()-n<864e5;){let s=e.getSnapshot();this.#r?.(s);let i=Object.values(s.uploadAssets);if(i.length>0&&i.every(o=>Xr.has(o.status)))return;await new Promise(o=>setTimeout(o,cn))}throw new Error("Timed out waiting for upload session to finish")}#a(e){let t=[],n=0,s=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.#n.skippedAssetIds.has(a.assetId)?s+=1:n+=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:n,skippedFileCount:e.preSkippedCount+s,failedFileCount:i,cancelledFileCount:o,failedFiles:t}}};var We=200,qe=class{#t;#n;#e;#r;#s;constructor(e,t,n){this.#t=e,this.#n=t??new x({apiUrl:e.apiUrl,apiKey:e.apiKey,edgeWorkerUrl:e.edgeWorkerUrl,sessionId:e.sessionName}),this.#e=new Te({rootDirectoryId:e.directoryId,httpClient:this.#n}),this.#r=new je({config:e,httpClient:this.#n,onSnapshot:s=>C.updateSnapshot(s),analytics:jt}),this.#s=n??W(e.source)}async run(){try{await this.#i()}finally{await this.#s.shutdown()}}async runBatched(){try{await this.#a()}finally{await this.#s.shutdown()}}async runCheckOnly(){try{await this.#c()}finally{await this.#s.shutdown()}}async#i(){this.#C("Starting data sync..."),await this.#b();let e=this.#A(await this.#o());if(e.length===0){console.log("No files to sync. Exiting."),await this.#S();return}let t={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},n=[],s={batchNumber:1,files:e,totalSize:this.#B(e)};C.start();try{let o=await this.#k({batch:s,totalBatches:1,overallFilesTotal:e.length,overallBytesTotal:s.totalSize,completedTotals:t,batchDir:this.#t.localTempDir});this.#O(t,n,o,s.totalSize)}finally{C.stop()}let i={...t,failedFiles:n};this.#E({summary:i}),await this.#P(i),this.#U(i)}async#a(){if(!this.#t.batchSizeBytes)throw new Error("Batch size not configured. Use batchSizeBytes in config.");this.#C("Starting batched data sync...",[`Batch size: ${h(this.#t.batchSizeBytes)}`,`Max concurrent chunks: ${this.#t.maxConcurrent}`]),await this.#b();let e=this.#A(await this.#o());if(e.length===0){console.log("No files to sync. Exiting."),await this.#S();return}let t=Bt(e,this.#t.batchSizeBytes);await this.#h(t);let n={totalFileCount:0,successFileCount:0,skippedFileCount:0,failedFileCount:0,cancelledFileCount:0,completedByteCount:0},s=[],i=this.#B(e);C.start();try{for(let a of t){let l=await this.#k({batch:a,totalBatches:t.length,overallFilesTotal:e.length,overallBytesTotal:i,completedTotals:n});this.#O(n,s,l,a.totalSize)}}finally{C.stop()}this.#E({summary:{...n,failedFiles:s},extraLines:[`Batches: ${t.length}`]});let o={...n,failedFiles:s};await this.#P(o),this.#U(o)}async#c(){console.log("Running in check-only mode (no downloads/uploads)..."),await this.#s.prepare(),console.log(`Listing source files from ${this.#s.displayName}...`);let e=await this.#s.listFiles();console.log(`Found ${e.length} source files to check`);let t=this.#A(e);if(t.length===0){console.log("No source files to check. Exiting.");return}console.log("Fetching Aspect project summary...");let n=await this.#u();console.log("Fetching existing Aspect files...");let s=await this.#e.listFilesInSubtree({onProgress:o=>this.#d(o)}),i=this.#m(t,s,n);this.#T(i)}async#o(){console.log("Listing all source files...");let e=await this.#s.listFiles();return console.log(`Found ${e.length} files`),console.log(`Total size: ${h(this.#B(e))}`),console.log(""),e}async#u(){return await this.#n.get(`/projects/${this.#t.projectId}`)}#m(e,t,n){let s=e.map(y=>({relativePath:w(y),sizeBytes:this.#g(y.size)})),i=s.filter(y=>y.sizeBytes===null).length,o=t.filter(y=>y.isUploaded),a=t.filter(y=>y.uploadStateKnown&&!y.isUploaded),l=t.filter(y=>!y.uploadStateKnown).length;l>0&&(console.warn(`Warning: ${l} server asset(s) did not include upload status; treating them as uploaded for check comparison.`),console.log(""));let c=this.#l(s),u=this.#D(o),d=new Set([...c.keys(),...u.keys()]),m=0,g=0,p=[],A=[],S=[];for(let y of d){let Se=c.get(y)??[],T=u.get(y)??[],E=new Set,Xe=[];for(let F of Se){if(F.sizeBytes===null){Xe.push(F);continue}let M=T.findIndex((v,Ce)=>!E.has(Ce)&&v.sizeBytes===F.sizeBytes);M>=0?(m+=1,E.add(M)):Xe.push(F)}for(let F of Xe){if(F.sizeBytes===null){let v=T.findIndex((Ce,Mn)=>!E.has(Mn));v>=0?(E.add(v),g+=1):p.push(F);continue}let M=T.findIndex((v,Ce)=>!E.has(Ce));if(M>=0){let v=T[M];E.add(M),A.push({relativePath:y,remoteSizeBytes:F.sizeBytes,serverSizeBytes:v.sizeBytes,assetId:v.assetId})}else p.push(F)}for(let F=0;F<T.length;F++)E.has(F)||S.push(T[F])}return{totalRemoteCount:e.length,totalServerCount:t.length,projectAssetCount:n.num_assets,projectRootDirectoryId:n.root_directory_id,uploadedServerCount:o.length,unknownUploadStateCount:l,unknownRemoteSizeCount:i,pathOnlyMatchCount:g,existingCount:m,missingFiles:p,sizeMismatches:A,extraUploadedFiles:S,incompleteServerFiles:a}}#l(e){let t=new Map;for(let n of e){let s=b(n.relativePath),i=t.get(s)??[];i.push({...n,relativePath:s}),t.set(s,i)}return t}#D(e){let t=new Map;for(let n of e){let s=b(n.relativePath),i=t.get(s)??[];i.push({...n,relativePath:s}),t.set(s,i)}return t}#g(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:null}#A(e){let t=Ie(e);if(t.changes.length===0)return t.files;let n=t.changes.slice(0,10).map(o=>`${o.sourcePath} -> ${o.targetPath}`).join(`
14
+ `),s=t.changes.length-10,i=s>0?`
15
+ ...and ${s} more renamed target path(s)`:"";return console.warn(`Warning: ${t.changes.length} remote file path(s) were renamed for Aspect compatibility.
16
+ ${n}${i}
17
+ `),console.log(""),t.files}async#k(e){let t=e.batchDir??wt.join(this.#t.localTempDir,`batch${e.batch.batchNumber}`);await ue.mkdir(t,{recursive:!0});let n=e.batch.files.map(d=>this.#s.resolveLocalFile(d,t));C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:`Preparing ${n.length} files...`}),C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"syncing_folders",extraDetails:"Ensuring target directories exist..."});let s=await this.#e.ensureDirectories(n);C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:0,batchBytesSkipped:0,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"scanning",extraDetails:"Checking existing assets..."});let i=await this.#R(s),o=this.#I(i),a=e.batch.files.filter((d,m)=>i[m]?.preSkipped!==!0),l=wt.join(this.#t.localTempDir,`batch${e.batch.batchNumber}.txt`),c=async()=>{await Mt(l),this.#t.keepLocal||await ue.rm(t,{recursive:!0,force:!0}),C.resetUploadSnapshot(),C.updateDownloadProgress(null)};if(a.length===0){let d={totalFileCount:i.length,successFileCount:0,skippedFileCount:i.length,failedFileCount:0,cancelledFileCount:0,failedFiles:[]};return C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.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.#p(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"everything already synced"}),C.persistCurrentBatchLine(),await c(),d}C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"downloading"}),await this.#s.materializeBatch({files:a,batchDir:t,batchFilePath:l,onProgress:d=>C.updateDownloadProgress(d)}),C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal),overallBytesTotal:e.overallBytesTotal,currentPhase:"uploading"});let u=await this.#r.uploadFiles(i);return this.#v(u)?(C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+u.successFileCount+u.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete",extraDetails:"failed; local files preserved"}),C.persistCurrentBatchLine(),u):(C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+u.successFileCount+u.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"cleaning"}),await c(),C.updateBatchState({currentBatch:e.batch.batchNumber,totalBatches:e.totalBatches,batchFilesTotal:n.length,batchBytesTotal:e.batch.totalSize,batchFilesSkipped:o.skippedFileCount,batchBytesSkipped:o.skippedByteCount,overallFilesCompleted:e.completedTotals.successFileCount+e.completedTotals.skippedFileCount+u.successFileCount+u.skippedFileCount,overallFilesTotal:e.overallFilesTotal,overallBytesCompleted:this.#p(e.completedTotals,e.overallBytesTotal)+e.batch.totalSize,overallBytesTotal:e.overallBytesTotal,currentPhase:"complete"}),C.persistCurrentBatchLine(),u)}async#b(){console.log("Preparing source..."),await this.#s.prepare(),console.log("Source ready"),console.log(""),console.log("Creating session directory..."),await ue.mkdir(this.#t.localTempDir,{recursive:!0}),console.log(`Session directory: ${this.#t.localTempDir}`),console.log("")}async#S(){this.#t.keepLocal||(console.log(""),console.log("Cleaning up session directory..."),await ue.rm(this.#t.localTempDir,{recursive:!0,force:!0}),console.log(`Deleted session directory: ${this.#t.localTempDir}`))}async#P(e){if(this.#v(e)){console.log(""),console.log(`Preserving session directory for retry/debugging: ${this.#t.localTempDir}`);return}await this.#S()}async#R(e){let t=await this.#e.checkAssetsExistence(e.map(n=>({directory_id:n.directoryId,name:n.file.fileName,size_bytes:n.file.size})));return e.map((n,s)=>({file:n.file,directoryId:n.directoryId,preSkipped:t[s]?.exists===!0}))}#I(e){return e.reduce((t,n)=>(n.preSkipped===!0&&(t.skippedFileCount+=1,t.skippedByteCount+=n.file.size),t),{skippedFileCount:0,skippedByteCount:0})}async#h(e){console.log("Creating batches..."),console.log(`Created ${e.length} batches`);let t=[];for(let n of e){let s=`Batch ${n.batchNumber}: ${n.files.length} files, ${h(n.totalSize)}`;t.push(s),console.log(s)}await ue.writeFile(wt.join(this.#t.localTempDir,"batches.txt"),`${t.join(`
17
18
  `)}
18
- `,"utf-8"),console.log("")}#C(e,t=[]){console.log(e),console.log(`Session: ${this.#t.sessionName}`),console.log(`Source: ${this.#n.displayName}`),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("")}#T(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){console.log(`Aspect scan: ${e.scannedDirectoryCount}/${e.queuedDirectoryCount} directories, ${e.fileCount} files found`)}#k(e){let t=e.missingFiles.length+e.sizeMismatches.length+e.extraUploadedFiles.length+e.incompleteServerFiles.length;console.log(""),console.log("=".repeat(60)),console.log("Check Summary"),console.log("=".repeat(60)),console.log(`Total (remote): ${e.totalRemoteCount}`),console.log(`Total (server): ${e.totalServerCount}`),console.log(`Project asset count: ${e.projectAssetCount}`),console.log(`Project count vs scanned server: ${e.projectAssetCount-e.totalServerCount}`),console.log(`Uploaded (server): ${e.uploadedServerCount}`),console.log(`Upload status unknown: ${e.unknownUploadStateCount}`),console.log(`Exact matches: ${e.existingCount}`),console.log(`Path-only matches (unknown remote size): ${e.pathOnlyMatchCount}`),console.log(`Remote sizes unknown: ${e.unknownRemoteSizeCount}`),console.log(`Missing on server: ${e.missingFiles.length}`),console.log(`Size mismatches: ${e.sizeMismatches.length}`),console.log(`Extra on server: ${e.extraUploadedFiles.length}`),console.log(`Incomplete uploads on server: ${e.incompleteServerFiles.length}`),console.log(`Total mismatches: ${t}`),console.log("=".repeat(60)),e.projectRootDirectoryId!==this.#t.directoryId?(console.log(""),console.log(`Warning: --directory-id (${this.#t.directoryId}) is not the project root directory (${e.projectRootDirectoryId}), so --check is comparing only that directory subtree.`)):e.projectAssetCount!==e.totalServerCount&&(console.log(""),console.log("Warning: project asset count differs from the live filesystem subtree scan. The project card uses cached project stats; the subtree scan is what --check compared against Drive.")),this.#g("Files missing on server:",e.missingFiles),this.#E(e.sizeMismatches),this.#I("Extra files on server:",e.extraUploadedFiles),this.#I("Incomplete uploads on server:",e.incompleteServerFiles)}#g(e,t){if(t.length!==0){console.log(""),console.log(e);for(let s of t.slice(0,ye))console.log(` - ${s.relativePath} (${this.#x(s.sizeBytes)})`);this.#L(t.length)}}#E(e){if(e.length!==0){console.log(""),console.log("Files with size mismatches:");for(let t of e.slice(0,ye))console.log(` - ${t.relativePath} (remote ${S(t.remoteSizeBytes)}, server ${S(t.serverSizeBytes)}, asset ${t.assetId})`);this.#L(e.length)}}#I(e,t){if(t.length!==0){console.log(""),console.log(e);for(let s of t.slice(0,ye))console.log(` - ${s.relativePath} (${S(s.sizeBytes)}, asset ${s.assetId})`);this.#L(t.length)}}#L(e){let t=e-ye;t>0&&console.log(` ...and ${t} more`)}#x(e){return e===null?"unknown remote size":S(e)}#B(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)}#_(e){let t=e.failedFileCount+e.cancelledFileCount;if(t>0)throw new Error(`Sync completed with ${t} unsuccessful upload(s)`)}#w(e){return e.failedFileCount+e.cancelledFileCount>0}#O(e){return e.reduce((t,s)=>t+s.size,0)}#h(e,t){return Math.min(e.completedByteCount,t)}};var Us=Ps(import.meta.url),Fs=ut.dirname(Us),ct=JSON.parse(Ts(ut.join(Fs,"..","package.json"),"utf-8")),ze=new Rs;ze.name("aspect-sync").description("Sync files from external services to Aspect").version(ct.version);ze.option("--source <kind>","source kind: rclone, local, or lucidlink (default: rclone)","rclone").option("--remote <remote>","rclone remote name (e.g., dropbox); required for --source rclone").requiredOption("--path <path>","path to sync from: remote path (rclone), local directory (local), or path within the filespace (lucidlink)").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("--lucid-fs <filespace>","LucidLink filespace (e.g., myspace.mydomain); required for --source lucidlink").option("--lucid-user <user>","LucidLink filespace user; required for --source lucidlink").option("--lucid-password-file <path>","File containing the LucidLink password (or set LUCID_PASSWORD)").option("--lucid-instance <number>","LucidLink daemon instance ID (default: 9001)","9001").option("--lucid-cache-size <size>","LucidLink DataCache.Size applied after mount (e.g., 100GB)").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,LUCID_PASSWORD:process.env.LUCID_PASSWORD,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=$e({options:n,environment:t}),r=vs(s),i=await ks(s,r);i&&Je({config:s,packageVersion:ct.version,user:i});let o=new Se(s,r);n.check?await o.runCheckOnly():s.batchSizeBytes!==void 0?await o.runBatched():await o.run()}catch(t){console.error("Fatal error:",t),e=1}finally{await et()}process.exit(e)});ze.parse();function vs(n){return new v({apiUrl:n.apiUrl,apiKey:n.apiKey,edgeWorkerUrl:n.edgeWorkerUrl,sessionId:n.sessionName})}async function ks(n,e){return n.analytics.disabled||!n.analytics.posthogKey?null:await e.get("/users/me")}
19
+ `,"utf-8"),console.log("")}#C(e,t=[]){console.log(e),console.log(`Session: ${this.#t.sessionName}`),console.log(`Source: ${this.#s.displayName}`),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 n of t)console.log(n);console.log("")}#E(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){console.log(`Aspect scan: ${e.scannedDirectoryCount}/${e.queuedDirectoryCount} directories, ${e.fileCount} files found`)}#T(e){let t=e.missingFiles.length+e.sizeMismatches.length+e.extraUploadedFiles.length+e.incompleteServerFiles.length;console.log(""),console.log("=".repeat(60)),console.log("Check Summary"),console.log("=".repeat(60)),console.log(`Total (remote): ${e.totalRemoteCount}`),console.log(`Total (server): ${e.totalServerCount}`),console.log(`Project asset count: ${e.projectAssetCount}`),console.log(`Project count vs scanned server: ${e.projectAssetCount-e.totalServerCount}`),console.log(`Uploaded (server): ${e.uploadedServerCount}`),console.log(`Upload status unknown: ${e.unknownUploadStateCount}`),console.log(`Exact matches: ${e.existingCount}`),console.log(`Path-only matches (unknown remote size): ${e.pathOnlyMatchCount}`),console.log(`Remote sizes unknown: ${e.unknownRemoteSizeCount}`),console.log(`Missing on server: ${e.missingFiles.length}`),console.log(`Size mismatches: ${e.sizeMismatches.length}`),console.log(`Extra on server: ${e.extraUploadedFiles.length}`),console.log(`Incomplete uploads on server: ${e.incompleteServerFiles.length}`),console.log(`Total mismatches: ${t}`),console.log("=".repeat(60)),e.projectRootDirectoryId!==this.#t.directoryId?(console.log(""),console.log(`Warning: --asp-directory-id (${this.#t.directoryId}) is not the project root directory (${e.projectRootDirectoryId}), so --check is comparing only that directory subtree.`)):e.projectAssetCount!==e.totalServerCount&&(console.log(""),console.log("Warning: project asset count differs from the live filesystem subtree scan. The project card uses cached project stats; the subtree scan is what --check compared against Drive.")),this.#f("Files missing on server:",e.missingFiles),this.#F(e.sizeMismatches),this.#L("Extra files on server:",e.extraUploadedFiles),this.#L("Incomplete uploads on server:",e.incompleteServerFiles)}#f(e,t){if(t.length!==0){console.log(""),console.log(e);for(let n of t.slice(0,We))console.log(` - ${n.relativePath} (${this.#x(n.sizeBytes)})`);this.#_(t.length)}}#F(e){if(e.length!==0){console.log(""),console.log("Files with size mismatches:");for(let t of e.slice(0,We))console.log(` - ${t.relativePath} (remote ${h(t.remoteSizeBytes)}, server ${h(t.serverSizeBytes)}, asset ${t.assetId})`);this.#_(e.length)}}#L(e,t){if(t.length!==0){console.log(""),console.log(e);for(let n of t.slice(0,We))console.log(` - ${n.relativePath} (${h(n.sizeBytes)}, asset ${n.assetId})`);this.#_(t.length)}}#_(e){let t=e-We;t>0&&console.log(` ...and ${t} more`)}#x(e){return e===null?"unknown remote size":h(e)}#O(e,t,n,s){e.totalFileCount+=n.totalFileCount,e.successFileCount+=n.successFileCount,e.skippedFileCount+=n.skippedFileCount,e.failedFileCount+=n.failedFileCount,e.cancelledFileCount+=n.cancelledFileCount,e.completedByteCount+=s,t.push(...n.failedFiles)}#U(e){let t=e.failedFileCount+e.cancelledFileCount;if(t>0)throw new Error(`Sync completed with ${t} unsuccessful upload(s)`)}#v(e){return e.failedFileCount+e.cancelledFileCount>0}#B(e){return e.reduce((t,n)=>t+n.size,0)}#p(e,t){return Math.min(e.completedByteCount,t)}};import{createInterface as Ts}from"node:readline/promises";import{stdin as vs,stdout as Ls}from"node:process";import os from"node:fs";import as from"node:os";import pe from"node:path";import mn from"node:fs";import{chmod as un,mkdir as ts,writeFile as ns}from"node:fs/promises";import rs from"node:os";import hn from"node:path";var dn=448,pn=384;function de(){return hn.join(rs.homedir(),".config","aspect-sync","lucidlink-auth.json")}function fn(r=de()){let e;try{e=mn.readFileSync(r,"utf-8")}catch(n){throw n.code==="ENOENT"?ss(r):n}let t;try{t=JSON.parse(e)}catch(n){throw new Error(`LucidLink auth file ${r} is not valid JSON: ${n.message}`)}return Sn({authFilePath:r,value:t})}async function gn(r,e){Sn({authFilePath:r,value:e});let t=hn.dirname(r);await ts(t,{recursive:!0,mode:dn}),await un(t,dn),await ns(r,`${JSON.stringify(e,null,2)}
20
+ `,{encoding:"utf-8",mode:pn}),await un(r,pn)}function yn(r){let e=mn.readFileSync(r,"utf-8").replace(/\r?\n$/,"");if(e.length===0)throw new Error(`Error: LucidLink password file is empty: ${r}`);return e}function ss(r){let e=new Error(`Error: LucidLink auth file not found at ${r}; run aspect-sync lucidlink login before syncing`);return e.code="ENOENT",e}function Sn(r){if(!is(r.value))throw new Error(`LucidLink auth file ${r.authFilePath} must contain non-empty filespace, user, and password strings`);return r.value}function is(r){if(!r||typeof r!="object")return!1;let e=r;return Et(e.filespace)&&Et(e.user)&&Et(e.password)}function Et(r){return typeof r=="string"&&r.length>0}var ls="phc_rDzmwduU3NzHyELgLEg7nMjqpTgaSpC2a6tMKL8VyjN",cs="https://t.aspect.inc",us="https://t.aspect.inc";function Pt(r){let e=r.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)$/i);if(!e)return null;let t=parseFloat(e[1]),n=e[2].toUpperCase(),s={B:1,KB:1024,MB:1024*1024,GB:1024*1024*1024,TB:1024*1024*1024*1024};return t*(s[n]||1)}function bn(r){return Ke({options:r.options,environment:r.environment,now:r.now,highResolutionTime:r.highResolutionTime,buildSourceConfig:()=>me(r.options)})}function An(r){return Ke({options:r.options,environment:r.environment,now:r.now,highResolutionTime:r.highResolutionTime,buildSourceConfig:()=>ds(r.options)})}function Fn(r){return Ke({options:r.options,environment:r.environment,now:r.now,highResolutionTime:r.highResolutionTime,buildSourceConfig:e=>he({options:r.options,localTempDir:e.localTempDir})})}function wn(r){return Ke({options:r.options,environment:r.environment,now:r.now,highResolutionTime:r.highResolutionTime,buildSourceConfig:()=>fe({options:r.options})})}function Ke(r){let e=q({value:r.options.aspDirectoryId,optionName:"--asp-directory-id"}),t=q({value:r.options.aspProjectId,optionName:"--asp-project-id"}),n=r.options.aspApiKey||r.environment.ASPECT_API_KEY||"";if(!n)throw new Error("Error: --asp-api-key is required (or set ASPECT_API_KEY env variable)");let s=K({value:r.options.uploadConcurrent,optionName:"--upload-concurrent"}),i=fs(r.options.batchSize),o=r.options.session??gs({now:r.now??new Date,highResolutionTime:r.highResolutionTime??process.hrtime.bigint()}),a=r.options.tempDir||pe.join(as.homedir(),".aspect","sync"),l=pe.join(a,o);return{source:r.buildSourceConfig({localTempDir:l}),directoryId:e,projectId:t,apiUrl:r.options.aspApiUrl||r.environment.ASPECT_API_URL||"https://api.aspect.inc",edgeWorkerUrl:r.options.aspEdgeWorkerUrl||r.environment.ASPECT_EDGE_WORKER_URL||"https://mackinac.aspect.inc",apiKey:n,maxConcurrent:s,keepLocal:r.options.keepLocal,localTempDir:l,sessionName:o,batchSizeBytes:i,analytics:{posthogKey:r.environment.ASPECT_POSTHOG_KEY||r.environment.POSTHOG_KEY||r.environment.POSTHOG_API_KEY||ls,posthogHost:r.environment.ASPECT_POSTHOG_HOST||r.environment.POSTHOG_HOST||cs||us,disabled:Cn(r.environment.ASPECT_DISABLE_POSTHOG)||Cn(r.environment.POSTHOG_DISABLED)}}}function me(r){let e=q({value:r.sourcePath,optionName:"--source-path"});if(!r.remote)throw new Error("Error: --remote is required for rclone");let t=K({value:r.rcloneTransfers??"4",optionName:"--rclone-transfers"}),n=K({value:r.rcloneMultiThreadStreams??"4",optionName:"--rclone-multi-thread-streams"});return{kind:"rclone",remote:r.remote,remotePath:e,rcloneOptions:{transfers:t,checkers:t>=16?Math.floor(t/4):t,multiThreadStreams:n,multiThreadChunkSize:r.rcloneMultiThreadChunkSize??"64MiB",multiThreadCutoff:r.rcloneMultiThreadCutoff??"64MiB",bufferSize:r.rcloneBufferSize??"64M",useMmap:r.rcloneNoMmap!==!0,extraRcloneArgs:r.rcloneExtra??[]}}}function ds(r){let e=q({value:r.sourcePath,optionName:"--source-path"});return{kind:"local",rootPath:pe.resolve(e)}}function he(r){let e=q({value:r.options.sourcePath,optionName:"--source-path"}),t=de(),n=fn(t),s=K({value:r.options.lucidInstance??"9001",optionName:"--lucid-instance"}),i=`${r.localTempDir}-lucid`;return{kind:"lucidlink",filespace:n.filespace,user:n.user,password:n.password,filespacePath:hs(e),instanceId:s,workDir:i,mountPoint:pe.join(i,"mnt"),cacheRootPath:pe.join(i,"cache"),cacheSize:r.options.lucidCacheSize}}function fe(r){let e=q({value:r.options.sourceFolderId,optionName:"--source-folder-id"}),t=j(),n=ps(t);return{kind:"frameio",accountId:n,folderId:e,downloadConcurrency:K({value:r.options.frameioDownloadConcurrent??"4",optionName:"--frameio-download-concurrent"}),pageSize:K({value:r.options.frameioPageSize??"100",optionName:"--frameio-page-size"})}}function q(r){if(!r.value)throw new Error(`Error: ${r.optionName} is required`);return r.value}function ps(r){let e;try{e=os.readFileSync(r,"utf-8")}catch(n){throw n.code==="ENOENT"?new Error(`Error: Frame.io auth file not found at ${r}; run aspect-sync frameio login before syncing`):n}let t=JSON.parse(e);if(!ms(t))throw new Error(`Error: Frame.io sync requires a default account ID in ${r}; run aspect-sync frameio login to select a default account, or add defaultAccountId to the auth file.`);return t.defaultAccountId}function ms(r){if(!r||typeof r!="object")return!1;let e=r;return typeof e.defaultAccountId=="string"&&e.defaultAccountId.length>0}function hs(r){let e=r.replace(/^\/+/,"").replace(/\/+$/,"");if(e.split("/").some(t=>t===".."))throw new Error(`Error: --source-path cannot contain parent directory segments: ${r}`);return e}function K(r){let e=parseInt(r.value,10);if(Number.isNaN(e)||e<1)throw new Error(`Error: ${r.optionName} must be a positive integer`);return e}function fs(r){if(!r)return;let e=Pt(r);if(e===null)throw new Error(`Error: Invalid batch size format: ${r}`);return e}function Cn(r){return r?["1","true","yes"].includes(r.toLowerCase()):!1}function gs(r){let e=r.now.getFullYear(),t=String(r.now.getMonth()+1).padStart(2,"0"),n=String(r.now.getDate()).padStart(2,"0"),s=String(r.now.getHours()).padStart(2,"0"),i=String(r.now.getMinutes()).padStart(2,"0"),o=String(r.now.getSeconds()).padStart(2,"0"),a=r.highResolutionTime%1000000000n,l=String(a).padStart(9,"0");return`${e}-${t}-${n}_${s}h-${i}m-${o}s-${l}ns`}import{createReadStream as ys}from"node:fs";import{mkdir as Rt,rm as It,writeFile as Ss}from"node:fs/promises";import Cs from"node:os";import ge from"node:path";var bs=20;function R(r){let e=r.session??ks(r.commandName),t=r.tempDir??ge.join(Cs.homedir(),".aspect","sync");return{sessionName:e,localTempDir:ge.join(t,e)}}function I(r,e){let t=parseInt(r,10);if(Number.isNaN(t)||t<1)throw new Error(`${e} must be a positive integer`);return t}function Y(r,e){if(!r)return;let t=Pt(r);if(t===null)throw new Error(`${e} must be a size like 500MB, 10GB, or 1TB`);return t}async function V(r){let e=W(r.sourceConfig);try{console.log(`Doctor: ${e.displayName}`),await En(r.localTempDir),console.log(`Writable temp path: ${r.localTempDir}`);for(let n of Rs(r.sourceConfig))await En(n),console.log(`Writable cache path: ${n}`);for(let n of r.tuningWarnings??[])console.warn(`Warning: ${n}`);await e.prepare(),console.log("Source prepared");let t=await kt(e);Pn(t.changes),console.log(`Source root access: OK (${t.files.length} files, ${h(Ye(t.files))})`),console.log("Doctor checks passed")}finally{try{await It(r.localTempDir,{recursive:!0,force:!0})}finally{await e.shutdown()}}}async function Q(r){let e=W(r.sourceConfig);try{await e.prepare();let t=await kt(e);Pn(t.changes),As({source:e,files:t.files,sampleSize:r.sampleSize??bs})}finally{await e.shutdown()}}async function J(r){let e=W(r.sourceConfig);try{await e.prepare();let t=await kt(e),n=Ps({files:t.files,maxFiles:r.maxFiles,maxBytes:r.maxBytes});if(n.length===0)throw new Error("No source files available to probe");console.log(`Probe source: ${e.displayName}`),console.log(`Probe files: ${n.length}`),console.log(`Probe size: ${h(Ye(n))}`);let s=Date.now(),i=await Fs({source:e,sourceConfig:r.sourceConfig,files:n,localTempDir:r.localTempDir}),o=Math.max((Date.now()-s)/1e3,.001);console.log(`Probe complete: ${h(i)} in ${o.toFixed(2)}s (${Re(i/o)})`)}finally{try{r.keepLocal!==!0&&await It(r.localTempDir,{recursive:!0,force:!0})}finally{await e.shutdown()}}}async function kt(r){console.log(`Listing source files from ${r.displayName}...`);let e=await r.listFiles();return Ie(e)}function As(r){console.log(`Source: ${r.source.displayName}`),console.log(`Files: ${r.files.length}`),console.log(`Total size: ${h(Ye(r.files))}`);let e=r.files.slice(0,r.sampleSize);if(e.length===0)return;console.log("Sample paths:");for(let n of e)console.log(`- ${Is(n)} (${h(n.size)})`);let t=r.files.length-e.length;t>0&&console.log(`...and ${t} more`)}function Pn(r){if(r.length===0)return;let e=r.slice(0,10).map(s=>`${s.sourcePath} -> ${s.targetPath}`).join(`
21
+ `),t=r.length-10,n=t>0?`
22
+ ...and ${t} more renamed target path(s)`:"";console.warn(`Warning: ${r.length} remote file path(s) were renamed for Aspect compatibility.
23
+ ${e}${n}
24
+ `)}async function Fs(r){await Rt(r.localTempDir,{recursive:!0});let e=ge.join(r.localTempDir,"probe"),t=ge.join(r.localTempDir,"probe-files.txt");if(ws(r.sourceConfig))return await Rt(e,{recursive:!0}),await r.source.materializeBatch({files:r.files,batchDir:e,batchFilePath:t}),Ye(r.files);let n=0;for(let s of r.files){let i=r.source.resolveLocalFile(s,e);n+=await Es(i.absolutePath)}return n}function ws(r){switch(r.kind){case"rclone":case"frameio":return!0;case"local":case"lucidlink":return!1;default:{let e=r;throw new Error(`Unsupported source kind: ${JSON.stringify(e)}`)}}}async function Es(r){return await new Promise((e,t)=>{let n=ys(r),s=0;n.on("data",i=>{s+=Buffer.isBuffer(i)?i.length:Buffer.byteLength(i)}),n.on("error",t),n.on("end",()=>e(s))})}function Ps(r){let e=[],t=0;for(let n of r.files){if(e.length>=r.maxFiles||r.maxBytes!==void 0&&e.length>0&&t+n.size>r.maxBytes)break;e.push(n),t+=n.size}return e}async function En(r){await Rt(r,{recursive:!0});let e=ge.join(r,`.aspect-sync-write-test-${process.pid}-${Date.now()}`);await Ss(e,"","utf-8"),await It(e,{force:!0})}function Rs(r){return r.kind!=="lucidlink"?[]:[r.cacheRootPath]}function Is(r){let e=w(r);return e===r.path?e:`${r.path} -> ${e}`}function Ye(r){return r.reduce((e,t)=>e+t.size,0)}function ks(r){let e=new Date().toISOString().replace(/[:.]/g,"-");return`${r}-${e}`}function kn(r){let e=r.command("frameio").description("Frame.io auth, discovery, and bandwidth diagnostics");e.command("login").description("Authenticate to Frame.io V4 via Adobe OAuth PKCE and store refresh credentials").option("--client-id <id>","Adobe OAuth client ID",nn()).action(async s=>{await xs(s)}),e.command("accounts").description("List Frame.io accounts accessible to the current token").action(async s=>{let o=await(await Ve(s)).listAccounts();Qe(o)}),e.command("workspaces").description("List workspaces in the login-selected Frame.io account").action(async s=>{let i=await Ve(s),o=await vt(s),a=await i.listWorkspaces(o);Qe(a)}),e.command("projects").description("List Frame.io projects in the login-selected account").option("--workspace-id <id>","Optionally scope projects to a Frame.io workspace ID").option("--page-size <number>","Frame.io page size","100").action(async s=>{let i=await Ve(s),o=await vt(s),a=In(s.pageSize,"--page-size"),l=s.workspaceId?await i.listProjects({accountId:o,workspaceId:s.workspaceId,pageSize:a}):await i.listAccountProjects({accountId:o,pageSize:a});Qe(l)}),e.command("folders").description("List children in a Frame.io folder in the login-selected account").requiredOption("--folder-id <id>","Frame.io folder ID").option("--page-size <number>","Frame.io page size","100").action(async s=>{let i=await Ve(s),o=await vt(s),a=await i.listFolderChildren({accountId:o,folderId:s.folderId,pageSize:In(s.pageSize,"--page-size")});Qe(a)});let t=Tt(e.command("doctor").description("Check Frame.io auth, account, and source folder access"));Rn(t).action(async s=>{let i=R({tempDir:s.tempDir,session:s.session,commandName:"frameio-doctor"});await V({sourceConfig:fe({options:s}),localTempDir:i.localTempDir})}),Tt(e.command("list").description("List planned Frame.io source files before syncing")).option("--sample-size <number>","Number of planned paths to print","20").action(async s=>{await Q({sourceConfig:fe({options:s}),sampleSize:I(s.sampleSize,"--sample-size")})});let n=Tt(e.command("probe").description("Measure Frame.io original download throughput without uploading to Aspect")).option("--max-files <number>","Maximum files to download for the probe","1").option("--max-bytes <size>","Soft maximum bytes to download for the probe").option("--keep-local","Keep downloaded probe files in the temp directory",!1);Rn(n).action(async s=>{let i=R({tempDir:s.tempDir,session:s.session,commandName:"frameio-probe"});await J({sourceConfig:fe({options:s}),localTempDir:i.localTempDir,maxFiles:I(s.maxFiles,"--max-files"),maxBytes:Y(s.maxBytes,"--max-bytes"),keepLocal:s.keepLocal})})}function Tt(r){return r.requiredOption("--source-folder-id <id>","Frame.io folder ID to use as the source root").option("--frameio-download-concurrent <number>","Concurrent Frame.io original downloads","4").option("--frameio-page-size <number>","Frame.io folder listing page size","100")}function Rn(r){return r.option("--temp-dir <path>","Local temporary directory for helper downloads and checks").option("--session <name>","Session name for helper temp paths")}async function xs(r){let e=rn(),t=sn({clientId:r.clientId,codeChallenge:e.challenge});console.log("Open this URL in a browser and approve access:"),console.log(t),console.log("");let n=await Tn("Paste the full redirected URL or code: "),s=on(n),i=await an({clientId:r.clientId,code:s,codeVerifier:e.verifier}),a=await new B({token:i.access_token}).listAccounts(),l=await Us({accounts:a}),c=j();await bt(c,At({clientId:r.clientId,token:i,defaultAccountId:l})),console.log(`Saved Frame.io auth to ${c}`)}async function Ve(r){let e=await Ne();return new B({token:e})}async function vt(r){let e=j(),t=await Ct(e);if(t.defaultAccountId)return t.defaultAccountId;throw new Error("Frame.io default account ID is missing; run aspect-sync frameio login.")}async function Us(r){if(r.accounts.length===0)throw new Error("Frame.io login did not return any accessible accounts");let e=r.writeOutput??(n=>console.log(n));if(r.accounts.length===1){let n=r.accounts[0];return e(`Selected default Frame.io account: ${Lt(n)}`),n.id}let t=r.promptForInput??Tn;for(e("Select the default Frame.io account for sync:"),r.accounts.forEach((n,s)=>{e(`${s+1}. ${Lt(n)}`)});;){let n=(await t("Account number or ID: ")).trim(),s=Ds(r.accounts,n);if(s)return e(`Selected default Frame.io account: ${Lt(s)}`),s.id;e("Invalid account selection. Enter a listed number or account ID.")}}async function Tn(r){let e=Ts({input:vs,output:Ls});try{return await e.question(r)}finally{e.close()}}function Ds(r,e){let t=Number.parseInt(e,10);return String(t)===e&&t>=1&&t<=r.length?r[t-1]:r.find(n=>n.id===e)}function Lt(r){let e=r.display_name?.trim();return e?`${e} (${r.id})`:r.id}function In(r,e){let t=parseInt(r,10);if(Number.isNaN(t)||t<1)throw new Error(`${e} must be a positive integer`);return t}function Qe(r){console.log(JSON.stringify(r,null,2))}import{stdin as k,stdout as ye}from"node:process";import{createInterface as _s}from"node:readline/promises";import{mkdir as vn,mkdtemp as Os,rm as Bs}from"node:fs/promises";import Ms from"node:os";import xt from"node:path";function xn(r){let e=r.command("lucidlink").description("LucidLink auth and diagnostics");e.command("login").description("Validate LucidLink credentials and store reusable auth").option("--filespace <filespace>","LucidLink filespace identifier: <filespace>.<workspace>").option("--user <user>","LucidLink filespace user").option("--password-file <path>","File containing the LucidLink password").option("--instance <number>","LucidLink daemon instance ID for validation","9001").action(async i=>{await Ns(i)});let t=Ut(e.command("doctor").description("Check LucidLink runner readiness and source access"));Dt(t).action(async i=>{let o=R({tempDir:i.tempDir,session:i.session,commandName:"lucidlink-doctor"});await V({sourceConfig:he({options:i,localTempDir:o.localTempDir}),localTempDir:o.localTempDir,tuningWarnings:Ks(i)})});let n=Ut(e.command("list").description("List planned LucidLink source files before syncing")).option("--sample-size <number>","Number of planned paths to print","20");Dt(n).action(async i=>{let o=R({tempDir:i.tempDir,session:i.session,commandName:"lucidlink-list"});await Q({sourceConfig:he({options:i,localTempDir:o.localTempDir}),sampleSize:I(i.sampleSize,"--sample-size")})});let s=Ut(e.command("probe").description("Measure LucidLink source read throughput without uploading to Aspect")).option("--max-files <number>","Maximum files to read for the probe","1").option("--max-bytes <size>","Soft maximum bytes to read for the probe").option("--keep-local","Keep helper temp files in the temp directory",!1);Dt(s).action(async i=>{let o=R({tempDir:i.tempDir,session:i.session,commandName:"lucidlink-probe"});await J({sourceConfig:he({options:i,localTempDir:o.localTempDir}),localTempDir:o.localTempDir,maxFiles:I(i.maxFiles,"--max-files"),maxBytes:Y(i.maxBytes,"--max-bytes"),keepLocal:i.keepLocal})})}async function Ns(r,e={}){let t=e.prompts??Hs(),n=await Ln({value:r.filespace,optionName:"--filespace",promptMessage:"LucidLink filespace (<filespace>.<workspace>): ",promptText:t.promptText}),s=await Ln({value:r.user,optionName:"--user",promptMessage:"LucidLink user: ",promptText:t.promptText}),i=r.passwordFile?yn(r.passwordFile):await Gs(t.promptPassword),o={filespace:n,user:s,password:i},a=r.authFile??de(),l=qs(r.instance,"--instance");console.log(`Validating LucidLink filespace ${n}...`),await zs({authFile:o,instanceId:l,createDaemon:e.createDaemon}),await gn(a,o),console.log(`Saved LucidLink auth to ${a}`)}async function zs(r){let e=await Os(xt.join(Ms.tmpdir(),"aspect-sync-lucidlink-login-")),t=xt.join(e,"mnt"),n=xt.join(e,"cache"),i=(r.createDaemon??(a=>new H(a)))({filespace:r.authFile.filespace,user:r.authFile.user,password:r.authFile.password,instanceId:r.instanceId,mountPoint:t,cacheRootPath:n}),o;try{await i.checkClientInstalled(),await vn(t,{recursive:!0}),await vn(n,{recursive:!0}),await i.start()}catch(a){throw o=a,a}finally{try{await $s({daemon:i,validationError:o})}finally{await Bs(e,{recursive:!0,force:!0})}}}async function $s(r){try{await r.daemon.stop()}catch(e){if(!r.validationError)throw e;console.error(`Failed to stop LucidLink validation daemon: ${e.message}`)}}async function Ln(r){let t=(r.value??await r.promptText(r.promptMessage)).trim();if(!t)throw new Error(`${r.optionName} cannot be empty`);return t}async function Gs(r){let e=await r("LucidLink password: ");if(!e)throw new Error("--password-file or password prompt cannot be empty");return e}function Hs(){return{promptText:js,promptPassword:Ws}}async function js(r){let e=_s({input:k,output:ye});try{return await e.question(r)}finally{e.close()}}function Ws(r){if(!k.isTTY||!ye.isTTY)throw new Error("Interactive LucidLink password prompt requires a TTY; provide --password-file");return new Promise((e,t)=>{let n=[],s=k.isRaw,i=()=>{k.off("data",o),k.setRawMode(s),k.pause()},o=a=>{let l=a.toString("utf-8");for(let c of l){if(c===""){i(),ye.write(`
25
+ `),t(new Error("LucidLink password prompt cancelled"));return}if(c==="\r"||c===`
26
+ `){i(),ye.write(`
27
+ `),e(n.join(""));return}if(c==="\x7F"){n.pop();continue}c>=" "&&n.push(c)}};ye.write(r),k.setRawMode(!0),k.resume(),k.on("data",o)})}function qs(r,e){let t=parseInt(r,10);if(Number.isNaN(t)||t<1)throw new Error(`${e} must be a positive integer`);return t}function Ut(r){return r.requiredOption("--source-path <path>","path within the LucidLink filespace").option("--lucid-instance <number>","LucidLink daemon instance ID","9001").option("--lucid-cache-size <size>","LucidLink DataCache.Size applied after mount")}function Dt(r){return r.option("--temp-dir <path>","Local temporary directory for helper reads and checks").option("--session <name>","Session name for helper temp paths")}function Ks(r){return r.lucidCacheSize?[]:["--lucid-cache-size is not set; LucidLink will use its current local cache configuration."]}import{spawn as Ys}from"node:child_process";function Dn(r){let e=r.command("rclone").description("rclone auth validation and source diagnostics");e.command("login").description("Validate a native rclone remote for reuse by aspect-sync").requiredOption("--remote <remote>","rclone remote name (e.g., dropbox)").action(async s=>{await Vs(s)});let t=_t(e.command("doctor").description("Check rclone runner readiness and source access"));Un(t).action(async s=>{let i=R({tempDir:s.tempDir,session:s.session,commandName:"rclone-doctor"});await V({sourceConfig:me(s),localTempDir:i.localTempDir,tuningWarnings:Qs(s)})}),_t(e.command("list").description("List planned rclone source files before syncing")).option("--sample-size <number>","Number of planned paths to print","20").action(async s=>{await Q({sourceConfig:me(s),sampleSize:I(s.sampleSize,"--sample-size")})});let n=_t(e.command("probe").description("Measure rclone source download throughput without uploading to Aspect")).option("--max-files <number>","Maximum files to download for the probe","1").option("--max-bytes <size>","Soft maximum bytes to download for the probe").option("--keep-local","Keep downloaded probe files in the temp directory",!1);Un(n).action(async s=>{let i=R({tempDir:s.tempDir,session:s.session,commandName:"rclone-probe"});await J({sourceConfig:me(s),localTempDir:i.localTempDir,maxFiles:I(s.maxFiles,"--max-files"),maxBytes:Y(s.maxBytes,"--max-bytes"),keepLocal:s.keepLocal})})}async function Vs(r){await Ue(),await Js(r.remote),console.log(`rclone remote "${r.remote}" is configured and ready for aspect-sync.`)}function _t(r){return r.requiredOption("--remote <remote>","rclone remote name (e.g., dropbox)").requiredOption("--source-path <path>","path within the rclone remote").option("--rclone-transfers <number>","Number of parallel file transfers","4").option("--rclone-multi-thread-streams <number>","Streams per large file","4").option("--rclone-multi-thread-chunk-size <size>","Chunk size for multi-threading","64MiB").option("--rclone-multi-thread-cutoff <size>","Minimum file size for multi-threading","64MiB").option("--rclone-buffer-size <size>","Buffer size per transfer","64M").option("--rclone-no-mmap","Disable memory-mapped I/O",!1).option("--rclone-extra <arg>","Additional rclone argument to append (repeatable)",(e,t)=>(t??[]).concat(e),[])}function Un(r){return r.option("--temp-dir <path>","Local temporary directory for helper downloads and checks").option("--session <name>","Session name for helper temp paths")}function Qs(r){let e=[],t=Number.parseInt(r.rcloneTransfers??"4",10);return Number.isFinite(t)&&t>=32&&e.push("--rclone-transfers is high; confirm the source provider and runner network can sustain this concurrency."),r.rcloneNoMmap===!0&&e.push("--rclone-no-mmap reduces memory efficiency and should only be used for known mmap issues."),e}function Js(r){return new Promise((e,t)=>{let n=Ys("rclone",["config","show",r],{stdio:["ignore","pipe","pipe"]}),s="";n.stderr?.on("data",i=>{s+=i.toString()}),n.on("close",i=>{if(i===0){e();return}t(new Error(`rclone remote "${r}" is not configured or could not be loaded. Run "rclone config" to create or repair the remote, then rerun "aspect-sync rclone login --remote ${r}".`+(s.trim()?`
28
+ ${s.trim()}`:"")))}),n.on("error",i=>{t(new Error(`Failed to start rclone config validation: ${i.message}`))})})}function _n(r,e){let t=r.command("sync").description("Sync files from a source into Aspect");Xs(t,e),Zs(t,e),ei(t,e),ti(t,e)}function Xs(r,e){Je(r.command("rclone").description("Sync from an rclone remote")).option("--remote <remote>","rclone remote name (e.g., dropbox)").option("--source-path <path>","path within the rclone remote to sync").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 x 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,s)=>(s??[]).concat(n),[]).action(async n=>{await e({commandOptions:n,buildConfig:s=>bn({options:n,environment:s})})})}function Zs(r,e){Je(r.command("local").description("Sync from a local directory")).option("--source-path <path>","local directory to sync").action(async n=>{await e({commandOptions:n,buildConfig:s=>An({options:n,environment:s})})})}function ei(r,e){Je(r.command("lucidlink").description("Sync from a LucidLink filespace")).option("--source-path <path>","path within the LucidLink filespace to sync").option("--lucid-instance <number>","LucidLink daemon instance ID (default: 9001)","9001").option("--lucid-cache-size <size>","LucidLink DataCache.Size applied after mount (e.g., 100GB)").action(async n=>{await e({commandOptions:n,buildConfig:s=>Fn({options:n,environment:s})})})}function ti(r,e){Je(r.command("frameio").description("Sync from a Frame.io folder")).option("--source-folder-id <id>","Frame.io folder ID to use as the source root").option("--frameio-download-concurrent <number>","Concurrent Frame.io original downloads (default: 4)","4").option("--frameio-page-size <number>","Frame.io folder listing page size (default: 100)","100").action(async n=>{await e({commandOptions:n,buildConfig:s=>wn({options:n,environment:s})})})}function Je(r){return r.option("--asp-directory-id <id>","Aspect directory ID to upload to").option("--asp-project-id <id>","Aspect project ID").option("--asp-api-url <url>","Aspect API URL").option("--asp-edge-worker-url <url>","Aspect edge worker URL").option("--asp-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.","")}var On=si(import.meta.url),ii=Ot.dirname(On),Bn=JSON.parse(ri(Ot.join(ii,"..","package.json"),"utf-8"));function oi(r={}){let e=new ni;return e.name("aspect-sync").description("Sync files from external services to Aspect").version(r.packageVersion??Bn.version),kn(e),xn(e),Dn(e),_n(e,r.executeSyncCommand??ai(r)),e}function ai(r){return async e=>{await li({execution:e,environment:r.getEnvironment?.()??ci()})}}async function li(r){let e=0;try{let t=r.execution.buildConfig(r.environment),n=ui(t),s=await di(t,n);s&&Ht({config:t,packageVersion:Bn.version,user:s});let i=new qe(t,n);r.execution.commandOptions.check?await i.runCheckOnly():t.batchSizeBytes!==void 0?await i.runBatched():await i.run()}catch(t){console.error("Fatal error:",t),e=1}finally{await Wt()}process.exit(e)}function ci(){return{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}}pi()&&await oi().parseAsync();function ui(r){return new x({apiUrl:r.apiUrl,apiKey:r.apiKey,edgeWorkerUrl:r.edgeWorkerUrl,sessionId:r.sessionName})}async function di(r,e){return r.analytics.disabled||!r.analytics.posthogKey?null:await e.get("/users/me")}function pi(){let r=process.argv[1];return r!==void 0&&Ot.resolve(r)===On}export{oi as createProgram};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "aspect-sync",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "CLI tool to sync files from external services to Aspect via rclone",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
- "aspect-sync": "./dist/index.js"
7
+ "aspect-sync": "dist/index.js"
8
8
  },
9
9
  "files": [
10
10
  "dist/index.js",