diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 280d772..5463857 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -150,7 +150,7 @@ jobs: update-homebrew: needs: [release, build-binaries] - if: needs.release.outputs.new_release_published == 'true' + if: needs.release.outputs.new_release_published == 'true' && github.ref == 'refs/heads/release' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/sync-release-to-main.yaml b/.github/workflows/sync-release-to-main.yaml index a61dac8..1777a04 100644 --- a/.github/workflows/sync-release-to-main.yaml +++ b/.github/workflows/sync-release-to-main.yaml @@ -40,15 +40,5 @@ jobs: --base main \ --head release \ --title "chore: sync release to main" \ - --body "Automated sync of release tags back to main." - fi - - - name: Enable auto-merge on sync PR - if: steps.check.outputs.ahead != '0' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PR=$(gh pr list --repo ${{ github.repository }} --base main --head release --state open --json number --jq '.[0].number') - if [ -n "$PR" ]; then - gh pr merge "$PR" --repo ${{ github.repository }} --merge --auto + --body "Automated sync of release tags back to main. Merge with **merge commit**." fi diff --git a/.gitignore b/.gitignore index f4662d6..d2a7f21 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ dist/ *.log .DS_Store .env +.env.test .env.local .env.development.local .env.test.local diff --git a/README.md b/README.md index fc9c0ae..4b98b6a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,12 @@ Command line interface for Tigris object storage. npm install -g @tigrisdata/cli ``` +You can also install CLI using brew + +```sh +brew install tigrisdata/tap/tigris +``` + ## Usage ``` @@ -25,6 +31,8 @@ Run `tigris help` to see all available commands, or `tigris help` for - `tigris mv ` - Move (rename) objects within Tigris. Both source and destination must be remote t3:// paths - `tigris rm ` - Remove a bucket, folder, or object from Tigris. A bare bucket name deletes the bucket itself - `tigris stat [path]` - Show storage stats (no args), bucket info, or object metadata +- `tigris presign ` - Generate a presigned URL for temporary access to an object without credentials +- `tigris bundle ` - Download multiple objects as a streaming tar archive in a single request. Designed for batch workloads that need many objects without per-object HTTP overhead ### Authentication @@ -33,13 +41,17 @@ Run `tigris help` to see all available commands, or `tigris help` for - `tigris whoami` - Print the currently authenticated user, organization, and auth method - `tigris configure` - Save access-key credentials to ~/.tigris/config.json for persistent use across all commands +### Other + +- `tigris update` - Update the CLI to the latest version + ### Resources - `tigris organizations` - List, create, and switch between organizations. An organization is a workspace that contains your resources like buckets and access keys - `tigris access-keys` - Create, list, inspect, delete, and assign roles to access keys. Access keys are credentials used for programmatic API access - `tigris credentials` - Test whether your current credentials can reach Tigris and optionally verify access to a specific bucket - `tigris buckets` - Create, inspect, update, and delete buckets. Buckets are top-level containers that hold objects -- `tigris forks` - List and create forks. A fork is a writable copy-on-write clone of a bucket, useful for testing or branching data +- `tigris forks` - (Deprecated, use "buckets create --fork-of" and "buckets list --forks-of") List and create forks - `tigris snapshots` - List and take snapshots. A snapshot is a point-in-time, read-only copy of a bucket's state - `tigris objects` - Low-level object operations for listing, downloading, uploading, and deleting individual objects in a bucket - `tigris iam` - Identity and Access Management - manage policies, users, and permissions @@ -53,9 +65,17 @@ Run `tigris help` to see all available commands, or `tigris help` for List all buckets (no arguments) or objects under a bucket/prefix path. Accepts bare names or t3:// URIs ``` -tigris ls [path] +tigris ls [path] [flags] ``` +| Flag | Description | +|------|-------------| +| `-snapshot, --snapshot-version` | Read from a specific bucket snapshot. Accepts a snapshot version string or any UNIX nanosecond-precision timestamp (e.g. 1765889000501544464) | +| `--format` | Output format | +| `--limit` | Maximum number of items to return per page | +| `-pt, --page-token` | Pagination token from a previous request to fetch the next page | +| `--source` | List objects from a specific storage source on buckets with shadow migration enabled | + **Examples:** ```bash tigris ls @@ -78,8 +98,11 @@ tigris mk [flags] | `--public` | Shorthand for --access public (only applies when creating a bucket) | | `-s, --enable-snapshots` | Enable snapshots for the bucket (only applies when creating a bucket) | | `-t, --default-tier` | Default storage tier (only applies when creating a bucket) | -| `-c, --consistency` | Consistency level (only applies when creating a bucket) | -| `-r, --region` | Region (only applies when creating a bucket) | +| `-c, --consistency` | (Deprecated, use --locations) Consistency level (only applies when creating a bucket) | +| `-r, --region` | (Deprecated, use --locations) Region (only applies when creating a bucket) | +| `-l, --locations` | Location for the bucket (only applies when creating a bucket) | +| `-fork, --fork-of` | Create this bucket as a fork (copy-on-write clone) of the named source bucket | +| `-source-snap, --source-snapshot` | Fork from a specific snapshot of the source bucket. Accepts a snapshot version string or any UNIX nanosecond-precision timestamp (e.g. 1765889000501544464). Requires --fork-of | **Examples:** ```bash @@ -87,6 +110,8 @@ tigris mk my-bucket tigris mk my-bucket --access public --region iad tigris mk my-bucket/images/ tigris mk t3://my-bucket +tigris mk my-fork --fork-of my-bucket +tigris mk my-fork --fork-of my-bucket --source-snapshot 1765889000501544464 ``` ### `touch` @@ -134,7 +159,7 @@ tigris mv [flags] | Flag | Description | |------|-------------| | `-r, --recursive` | Move directories recursively | -| `-f, --force` | Skip confirmation prompt | +| `-f, --force` | Skip confirmation prompts (alias for --yes) | **Examples:** ```bash @@ -154,7 +179,7 @@ tigris rm [flags] | Flag | Description | |------|-------------| | `-r, --recursive` | Remove directories recursively | -| `-f, --force` | Skip confirmation prompt | +| `-f, --force` | Skip confirmation prompts (alias for --yes) | **Examples:** ```bash @@ -174,7 +199,8 @@ tigris stat [path] [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format | +| `--format` | Output format | +| `-snapshot, --snapshot-version` | Read from a specific bucket snapshot. Accepts a snapshot version string or any UNIX nanosecond-precision timestamp (e.g. 1765889000501544464) | **Examples:** ```bash @@ -183,6 +209,53 @@ tigris stat t3://my-bucket tigris stat t3://my-bucket/my-object.json ``` +### `presign` + +Generate a presigned URL for temporary access to an object without credentials + +``` +tigris presign [flags] +``` + +| Flag | Description | +|------|-------------| +| `-m, --method` | HTTP method for the presigned URL | +| `-e, --expires-in` | URL expiry time in seconds | +| `--access-key` | Access key ID to use for signing. If not provided, resolved from credentials or auto-selected | +| `--select` | Interactively select an access key (OAuth only) | +| `--format` | Output format | + +**Examples:** +```bash +tigris presign my-bucket/file.txt +tigris presign t3://my-bucket/report.pdf --method put --expires-in 7200 +tigris presign my-bucket/image.png --format json +tigris presign my-bucket/data.csv --access-key tid_AaBb +``` + +### `bundle` + +Download multiple objects as a streaming tar archive in a single request. Designed for batch workloads that need many objects without per-object HTTP overhead + +``` +tigris bundle [flags] +``` + +| Flag | Description | +|------|-------------| +| `-k, --keys` | Comma-separated object keys, or path to a file with one key per line. If a local file matching the value exists, it is read as a keys file. If omitted, reads keys from stdin | +| `-o, --output` | Output file path. Defaults to stdout (for piping) | +| `--compression` | Compression algorithm for the archive. Auto-detected from output file extension when not specified | +| `--on-error` | How to handle missing objects. 'skip' omits them, 'fail' aborts the request | + +**Examples:** +```bash +tigris bundle my-bucket --keys key1.jpg,key2.jpg --output archive.tar +tigris bundle my-bucket --keys keys.txt --output archive.tar +tigris bundle t3://my-bucket --keys keys.txt --compression gzip -o archive.tar.gz +cat keys.txt | tigris bundle my-bucket > archive.tar +``` + ## Authentication ### `login` | `l` @@ -295,7 +368,7 @@ tigris organizations list [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format (default: select) | +| `--format` | Output format (default: select) | | `-i, --select` | Interactive selection mode | **Examples:** @@ -337,13 +410,23 @@ Create, list, inspect, delete, and assign roles to access keys. Access keys are | `access-keys delete` (d) | Permanently delete an access key by its ID. This revokes all access immediately | | `access-keys get` (g) | Show details for an access key including its name, creation date, and assigned bucket roles | | `access-keys assign` (a) | Assign per-bucket roles to an access key. Pair each --bucket with a --role (Editor or ReadOnly), or use --admin for org-wide access | +| `access-keys rotate` (r) | Rotate an access key's secret. The current secret is immediately invalidated and a new one is returned (shown only once) | +| `access-keys attach-policy` (ap) | Attach an IAM policy to an access key. If no policy ARN is provided, shows interactive selection of available policies | +| `access-keys detach-policy` (dp) | Detach an IAM policy from an access key. If no policy ARN is provided, shows interactive selection of attached policies | +| `access-keys list-policies` (lp) | List all IAM policies attached to an access key | #### `access-keys list` ``` -tigris access-keys list +tigris access-keys list [flags] ``` +| Flag | Description | +|------|-------------| +| `--format` | Output format (default: table) | +| `--limit` | Maximum number of items to return per page | +| `-pt, --page-token` | Pagination token from a previous request to fetch the next page | + **Examples:** ```bash tigris access-keys list @@ -363,12 +446,16 @@ tigris access-keys create my-ci-key #### `access-keys delete` ``` -tigris access-keys delete +tigris access-keys delete [flags] ``` +| Flag | Description | +|------|-------------| +| `--force` | Skip confirmation prompts (alias for --yes) | + **Examples:** ```bash -tigris access-keys delete tid_AaBbCcDdEeFf +tigris access-keys delete tid_AaBbCcDdEeFf --yes ``` #### `access-keys get` @@ -403,6 +490,71 @@ tigris access-keys assign tid_AaBb --admin tigris access-keys assign tid_AaBb --revoke-roles ``` +#### `access-keys rotate` + +``` +tigris access-keys rotate [flags] +``` + +| Flag | Description | +|------|-------------| +| `--force` | Skip confirmation prompts (alias for --yes) | + +**Examples:** +```bash +tigris access-keys rotate tid_AaBbCcDdEeFf --yes +``` + +#### `access-keys attach-policy` + +``` +tigris access-keys attach-policy [flags] +``` + +| Flag | Description | +|------|-------------| +| `--policy-arn` | ARN of the policy to attach | + +**Examples:** +```bash +tigris access-keys attach-policy tid_AaBb --policy-arn arn:aws:iam::org_id:policy/my-policy +tigris access-keys attach-policy tid_AaBb +``` + +#### `access-keys detach-policy` + +``` +tigris access-keys detach-policy [flags] +``` + +| Flag | Description | +|------|-------------| +| `--policy-arn` | ARN of the policy to detach | +| `--force` | Skip confirmation prompts (alias for --yes) | + +**Examples:** +```bash +tigris access-keys detach-policy tid_AaBb --policy-arn arn:aws:iam::org_id:policy/my-policy --yes +tigris access-keys detach-policy tid_AaBb +``` + +#### `access-keys list-policies` + +``` +tigris access-keys list-policies [flags] +``` + +| Flag | Description | +|------|-------------| +| `--format` | Output format (default: table) | +| `--limit` | Maximum number of items to return per page | +| `-pt, --page-token` | Pagination token from a previous request to fetch the next page | + +**Examples:** +```bash +tigris access-keys list-policies tid_AaBbCcDdEeFf +``` + ### `credentials` | `creds` Test whether your current credentials can reach Tigris and optionally verify access to a specific bucket @@ -438,10 +590,17 @@ Create, inspect, update, and delete buckets. Buckets are top-level containers th | Command | Description | |---------|-------------| | `buckets list` (l) | List all buckets in the current organization | -| `buckets create` (c) | Create a new bucket with optional access, tier, consistency, and region settings | +| `buckets create` (c) | Create a new bucket with optional access, tier, and location settings | | `buckets get` (g) | Show details for a bucket including access level, region, tier, and custom domain | | `buckets delete` (d) | Delete one or more buckets by name. The bucket must be empty or delete-protection must be off | -| `buckets set` (s) | Update settings on an existing bucket such as access level, region, caching, or custom domain | +| `buckets set` (s) | Update settings on an existing bucket such as access level, location, caching, or custom domain | +| `buckets set-ttl` | Configure object expiration (TTL) on a bucket. Objects expire after a number of days or on a specific date | +| `buckets set-locations` | Set the data locations for a bucket | +| `buckets set-migration` | Configure data migration from an external S3-compatible source bucket. Tigris will pull objects on demand from the source | +| `buckets migrate` | Actively migrate all objects from a shadow bucket to Tigris by scheduling server-side migration for unmigrated objects | +| `buckets set-transition` | Configure a lifecycle transition rule on a bucket. Automatically move objects to a different storage class after a number of days or on a specific date | +| `buckets set-notifications` | Configure object event notifications on a bucket. Sends webhook requests to a URL when objects are created, updated, or deleted | +| `buckets set-cors` | Configure CORS rules on a bucket. Each invocation adds a rule unless --override or --reset is used | ##### `buckets list` @@ -451,12 +610,16 @@ tigris buckets list [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | +| `--forks-of` | Only list buckets that are forks of the named source bucket | +| `--limit` | Maximum number of items to return per page | +| `-pt, --page-token` | Pagination token from a previous request to fetch the next page | **Examples:** ```bash tigris buckets list tigris buckets list --format json +tigris buckets list --forks-of my-bucket ``` ##### `buckets create` @@ -471,22 +634,31 @@ tigris buckets create [name] [flags] | `--public` | Shorthand for --access public | | `-s, --enable-snapshots` | Enable snapshots for the bucket (default: false) | | `-t, --default-tier` | Choose the default tier for the bucket (default: STANDARD) | -| `-c, --consistency` | Choose the consistency level for the bucket (default: default) | -| `-r, --region` | Region (default: global) | +| `-c, --consistency` | (Deprecated, use --locations) Choose the consistency level for the bucket | +| `-r, --region` | (Deprecated, use --locations) Region | +| `-l, --locations` | Location for the bucket (default: global) | +| `-fork, --fork-of` | Create this bucket as a fork (copy-on-write clone) of the named source bucket | +| `-source-snap, --source-snapshot` | Fork from a specific snapshot of the source bucket. Accepts a snapshot version string or any UNIX nanosecond-precision timestamp (e.g. 1765889000501544464). Requires --fork-of | **Examples:** ```bash tigris buckets create my-bucket -tigris buckets create my-bucket --access public --region iad +tigris buckets create my-bucket --access public --locations iad tigris buckets create my-bucket --enable-snapshots --default-tier STANDARD_IA +tigris buckets create my-fork --fork-of my-bucket +tigris buckets create my-fork --fork-of my-bucket --source-snapshot 1765889000501544464 ``` ##### `buckets get` ``` -tigris buckets get +tigris buckets get [flags] ``` +| Flag | Description | +|------|-------------| +| `--format` | Output format (default: table) | + **Examples:** ```bash tigris buckets get my-bucket @@ -495,13 +667,17 @@ tigris buckets get my-bucket ##### `buckets delete` ``` -tigris buckets delete +tigris buckets delete [flags] ``` +| Flag | Description | +|------|-------------| +| `--force` | Skip confirmation prompts (alias for --yes) | + **Examples:** ```bash -tigris buckets delete my-bucket -tigris buckets delete bucket-a,bucket-b +tigris buckets delete my-bucket --yes +tigris buckets delete bucket-a,bucket-b --yes ``` ##### `buckets set` @@ -513,28 +689,177 @@ tigris buckets set [flags] | Flag | Description | |------|-------------| | `--access` | Bucket access level | -| `--region` | Allowed regions (can specify multiple) | +| `--region` | (Deprecated, use --locations) Allowed regions (can specify multiple) | +| `--locations` | Bucket location (see https://www.tigrisdata.com/docs/buckets/locations/ for more details) | | `--allow-object-acl` | Enable object-level ACL | | `--disable-directory-listing` | Disable directory listing | | `--cache-control` | Default cache-control header value | | `--custom-domain` | Custom domain for the bucket | | `--enable-delete-protection` | Enable delete protection | +| `--enable-additional-headers` | Enable additional HTTP headers (X-Content-Type-Options nosniff) | **Examples:** ```bash tigris buckets set my-bucket --access public -tigris buckets set my-bucket --region iad,fra --cache-control 'max-age=3600' +tigris buckets set my-bucket --locations iad,fra --cache-control 'max-age=3600' tigris buckets set my-bucket --custom-domain assets.example.com ``` +##### `buckets set-ttl` + +``` +tigris buckets set-ttl [flags] +``` + +| Flag | Description | +|------|-------------| +| `-d, --days` | Expire objects after this many days | +| `--date` | Expire objects on this date (ISO-8601, e.g. 2026-06-01) | +| `--enable` | Enable TTL on the bucket (uses existing lifecycle rules) | +| `--disable` | Disable TTL on the bucket | + +**Examples:** +```bash +tigris buckets set-ttl my-bucket --days 30 +tigris buckets set-ttl my-bucket --date 2026-06-01 +tigris buckets set-ttl my-bucket --disable +``` + +##### `buckets set-locations` + +``` +tigris buckets set-locations [flags] +``` + +| Flag | Description | +|------|-------------| +| `-l, --locations` | Bucket location | + +**Examples:** +```bash +tigris buckets set-locations my-bucket --locations iad +tigris buckets set-locations my-bucket --locations iad,fra +tigris buckets set-locations my-bucket --locations global +``` + +##### `buckets set-migration` + +``` +tigris buckets set-migration [flags] +``` + +| Flag | Description | +|------|-------------| +| `-b, --bucket` | Name of the source bucket to migrate from | +| `-e, --endpoint` | Endpoint URL of the source S3-compatible service | +| `-r, --region` | Region of the source bucket | +| `-key, --access-key` | Access key for the source bucket | +| `-secret, --secret-key` | Secret key for the source bucket | +| `--write-through` | Enable write-through mode (writes go to both source and Tigris) | +| `--disable` | Disable migration and clear all migration settings | + +**Examples:** +```bash +tigris buckets set-migration my-bucket --bucket source-bucket --endpoint https://s3.amazonaws.com --region us-east-1 --access-key AKIA... --secret-key wJal... +tigris buckets set-migration my-bucket --bucket source-bucket --endpoint https://s3.amazonaws.com --region us-east-1 --access-key AKIA... --secret-key wJal... --write-through +tigris buckets set-migration my-bucket --disable +``` + +##### `buckets migrate` + +``` +tigris buckets migrate +``` + +**Examples:** +```bash +tigris buckets migrate my-bucket +tigris buckets migrate my-bucket/images/ +tigris buckets migrate t3://my-bucket/prefix/ +``` + +##### `buckets set-transition` + +``` +tigris buckets set-transition [flags] +``` + +| Flag | Description | +|------|-------------| +| `-s, --storage-class` | Target storage class to transition objects to | +| `-d, --days` | Transition objects after this many days | +| `--date` | Transition objects on this date (ISO-8601, e.g. 2026-06-01) | +| `--enable` | Enable lifecycle transition rules on the bucket | +| `--disable` | Disable lifecycle transition rules on the bucket | + +**Examples:** +```bash +tigris buckets set-transition my-bucket --storage-class STANDARD_IA --days 30 +tigris buckets set-transition my-bucket --storage-class GLACIER --date 2026-06-01 +tigris buckets set-transition my-bucket --enable +tigris buckets set-transition my-bucket --disable +``` + +##### `buckets set-notifications` + +``` +tigris buckets set-notifications [flags] +``` + +| Flag | Description | +|------|-------------| +| `-u, --url` | Webhook URL to send notifications to (must be http or https) | +| `-f, --filter` | SQL WHERE clause to filter events by key (e.g. WHERE `key` REGEXP "^images") | +| `-t, --token` | Token for webhook authentication | +| `--username` | Username for basic webhook authentication | +| `--password` | Password for basic webhook authentication | +| `--enable` | Enable notifications on the bucket (uses existing config) | +| `--disable` | Disable notifications on the bucket (preserves existing config) | +| `--reset` | Clear all notification settings on the bucket | + +**Examples:** +```bash +tigris buckets set-notifications my-bucket --url https://example.com/webhook +tigris buckets set-notifications my-bucket --url https://example.com/webhook --token secret123 +tigris buckets set-notifications my-bucket --url https://example.com/webhook --username admin --password secret +tigris buckets set-notifications my-bucket --url https://example.com/webhook --filter "WHERE `key` REGEXP \"^images\"" +tigris buckets set-notifications my-bucket --enable +tigris buckets set-notifications my-bucket --disable +tigris buckets set-notifications my-bucket --reset +``` + +##### `buckets set-cors` + +``` +tigris buckets set-cors [flags] +``` + +| Flag | Description | +|------|-------------| +| `-o, --origins` | Allowed origins (comma-separated, or '*' for all) | +| `-m, --methods` | Allowed HTTP methods (comma-separated, e.g. GET,POST,PUT) | +| `--headers` | Allowed request headers (comma-separated, or '*' for all) | +| `--expose-headers` | Response headers to expose (comma-separated) | +| `--max-age` | Preflight cache duration in seconds (default: 3600) | +| `--override` | Replace all existing CORS rules instead of appending | +| `--reset` | Clear all CORS rules on the bucket | + +**Examples:** +```bash +tigris buckets set-cors my-bucket --origins '*' --methods GET,HEAD +tigris buckets set-cors my-bucket --origins https://example.com --methods GET,POST --headers Content-Type,Authorization --max-age 3600 +tigris buckets set-cors my-bucket --origins https://example.com --override +tigris buckets set-cors my-bucket --reset +``` + #### `forks` | `f` -List and create forks. A fork is a writable copy-on-write clone of a bucket, useful for testing or branching data +(Deprecated, use "buckets create --fork-of" and "buckets list --forks-of") List and create forks | Command | Description | |---------|-------------| -| `forks list` (l) | List all forks created from the given source bucket | -| `forks create` (c) | Create a new fork (copy-on-write clone) of the source bucket. Optionally fork from a specific snapshot | +| `forks list` (l) | (Deprecated, use "buckets list --forks-of") List all forks created from the given source bucket | +| `forks create` (c) | (Deprecated, use "buckets create --fork-of") Create a new fork (copy-on-write clone) of the source bucket | ##### `forks list` @@ -544,7 +869,7 @@ tigris forks list [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | **Examples:** ```bash @@ -560,12 +885,12 @@ tigris forks create [flags] | Flag | Description | |------|-------------| -| `-s, --snapshot` | Create fork from a specific snapshot | +| `-s, --snapshot` | Create fork from a specific snapshot. Accepts a snapshot version string or any UNIX nanosecond-precision timestamp (e.g. 1765889000501544464) | **Examples:** ```bash tigris forks create my-bucket my-fork -tigris forks create my-bucket my-fork --snapshot snap-2025-01-01 +tigris forks create my-bucket my-fork --snapshot 1765889000501544464 ``` #### `snapshots` | `s` @@ -585,7 +910,9 @@ tigris snapshots list [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | +| `--limit` | Maximum number of items to return per page | +| `-pt, --page-token` | Pagination token from a previous request to fetch the next page | **Examples:** ```bash @@ -616,6 +943,7 @@ Low-level object operations for listing, downloading, uploading, and deleting in | `objects put` (p) | Upload a local file as an object. Content-type is auto-detected from extension unless overridden | | `objects delete` (d) | Delete one or more objects by key from the given bucket | | `objects set` (s) | Update settings on an existing object such as access level | +| `objects info` (i) | Show metadata for an object (content type, size, modified date) | #### `objects list` @@ -626,11 +954,17 @@ tigris objects list [flags] | Flag | Description | |------|-------------| | `-p, --prefix` | Filter objects by key prefix (e.g. "images/" to list only images) | -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | +| `-snapshot, --snapshot-version` | Read from a specific bucket snapshot. Accepts a snapshot version string or any UNIX nanosecond-precision timestamp (e.g. 1765889000501544464) | +| `--limit` | Maximum number of items to return per page | +| `-pt, --page-token` | Pagination token from a previous request to fetch the next page | +| `--source` | List objects from a specific storage source on buckets with shadow migration enabled | **Examples:** ```bash tigris objects list my-bucket +tigris objects list t3://my-bucket +tigris objects list t3://my-bucket/images/ tigris objects list my-bucket --prefix images/ tigris objects list my-bucket --format json ``` @@ -638,54 +972,62 @@ tigris objects list my-bucket --format json #### `objects get` ``` -tigris objects get [flags] +tigris objects get [key] [flags] ``` | Flag | Description | |------|-------------| | `-o, --output` | Output file path (if not specified, prints to stdout) | | `-m, --mode` | Response mode: "string" loads into memory, "stream" writes in chunks (auto-detected from extension if not specified) | +| `-snapshot, --snapshot-version` | Read from a specific bucket snapshot. Accepts a snapshot version string or any UNIX nanosecond-precision timestamp (e.g. 1765889000501544464) | **Examples:** ```bash tigris objects get my-bucket config.json +tigris objects get t3://my-bucket/config.json tigris objects get my-bucket archive.zip --output ./archive.zip --mode stream ``` #### `objects put` ``` -tigris objects put [file] [flags] +tigris objects put [key] [file] [flags] ``` | Flag | Description | |------|-------------| | `-a, --access` | Access level (default: private) | | `-t, --content-type` | Content type (auto-detected from extension if omitted) | -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | **Examples:** ```bash tigris objects put my-bucket report.pdf ./report.pdf +tigris objects put t3://my-bucket/report.pdf ./report.pdf tigris objects put my-bucket logo.png ./logo.png --access public --content-type image/png ``` #### `objects delete` ``` -tigris objects delete +tigris objects delete [key] [flags] ``` +| Flag | Description | +|------|-------------| +| `--force` | Skip confirmation prompts (alias for --yes) | + **Examples:** ```bash -tigris objects delete my-bucket old-file.txt -tigris objects delete my-bucket file-a.txt,file-b.txt +tigris objects delete my-bucket old-file.txt --yes +tigris objects delete t3://my-bucket/old-file.txt --yes +tigris objects delete my-bucket file-a.txt,file-b.txt --yes ``` #### `objects set` ``` -tigris objects set [flags] +tigris objects set [key] [flags] ``` | Flag | Description | @@ -696,9 +1038,28 @@ tigris objects set [flags] **Examples:** ```bash tigris objects set my-bucket my-file.txt --access public +tigris objects set t3://my-bucket/my-file.txt --access public tigris objects set my-bucket my-file.txt --access private ``` +#### `objects info` + +``` +tigris objects info [key] [flags] +``` + +| Flag | Description | +|------|-------------| +| `--format` | Output format (default: table) | +| `-snapshot, --snapshot-version` | Read from a specific bucket snapshot | + +**Examples:** +```bash +tigris objects info my-bucket report.pdf +tigris objects info t3://my-bucket/report.pdf +tigris objects info my-bucket report.pdf --format json +``` + ### `iam` Identity and Access Management - manage policies, users, and permissions @@ -719,6 +1080,9 @@ Manage IAM policies. Policies define permissions for access keys | `iam policies create` (c) | Create a new policy with the given name and policy document. Document can be provided via file, inline JSON, or stdin | | `iam policies edit` (e) | Update an existing policy's document. Document can be provided via file, inline JSON, or stdin. If no ARN provided, shows interactive selection | | `iam policies delete` (d) | Delete a policy. If no ARN provided, shows interactive selection | +| `iam policies link-key` (lnk) | Link an access key to a policy. If no policy ARN is provided, shows interactive selection. If no access key ID is provided, shows interactive selection of unlinked keys | +| `iam policies unlink-key` (ulnk) | Unlink an access key from a policy. If no policy ARN is provided, shows interactive selection. If no access key ID is provided, shows interactive selection of linked keys | +| `iam policies list-keys` (lk) | List all access keys attached to a policy. If no policy ARN is provided, shows interactive selection | ##### `iam policies list` @@ -728,7 +1092,9 @@ tigris iam policies list [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | +| `--limit` | Maximum number of items to return per page | +| `-pt, --page-token` | Pagination token from a previous request to fetch the next page | **Examples:** ```bash @@ -743,7 +1109,7 @@ tigris iam policies get [resource] [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | **Examples:** ```bash @@ -790,13 +1156,66 @@ cat policy.json | tigris iam policies edit arn:aws:iam::org_id:policy/my-policy ##### `iam policies delete` ``` -tigris iam policies delete [resource] +tigris iam policies delete [resource] [flags] ``` +| Flag | Description | +|------|-------------| +| `--force` | Skip confirmation prompts (alias for --yes) | + **Examples:** ```bash tigris iam policies delete -tigris iam policies delete arn:aws:iam::org_id:policy/my-policy +tigris iam policies delete arn:aws:iam::org_id:policy/my-policy --yes +``` + +##### `iam policies link-key` + +``` +tigris iam policies link-key [resource] [flags] +``` + +| Flag | Description | +|------|-------------| +| `--id` | Access key ID to attach | + +**Examples:** +```bash +tigris iam policies link-key arn:aws:iam::org_id:policy/my-policy --id tid_AaBb +tigris iam policies link-key +``` + +##### `iam policies unlink-key` + +``` +tigris iam policies unlink-key [resource] [flags] +``` + +| Flag | Description | +|------|-------------| +| `--id` | Access key ID to detach | +| `--force` | Skip confirmation prompts (alias for --yes) | + +**Examples:** +```bash +tigris iam policies unlink-key arn:aws:iam::org_id:policy/my-policy --id tid_AaBb --yes +tigris iam policies unlink-key +``` + +##### `iam policies list-keys` + +``` +tigris iam policies list-keys [resource] [flags] +``` + +| Flag | Description | +|------|-------------| +| `--format` | Output format (default: table) | + +**Examples:** +```bash +tigris iam policies list-keys arn:aws:iam::org_id:policy/my-policy +tigris iam policies list-keys ``` #### `iam users` | `u` @@ -819,7 +1238,7 @@ tigris iam users list [flags] | Flag | Description | |------|-------------| -| `-f, --format` | Output format (default: table) | +| `--format` | Output format (default: table) | **Examples:** ```bash @@ -847,14 +1266,18 @@ tigris iam users invite user1@example.com,user2@example.com ##### `iam users revoke-invitation` ``` -tigris iam users revoke-invitation [resource] +tigris iam users revoke-invitation [resource] [flags] ``` +| Flag | Description | +|------|-------------| +| `--force` | Skip confirmation prompts (alias for --yes) | + **Examples:** ```bash tigris iam users revoke-invitation -tigris iam users revoke-invitation invitation_id -tigris iam users revoke-invitation id1,id2,id3 +tigris iam users revoke-invitation invitation_id --yes +tigris iam users revoke-invitation id1,id2,id3 --yes ``` ##### `iam users update-role` @@ -878,14 +1301,33 @@ tigris iam users update-role id1,id2 --role admin,member ##### `iam users remove` ``` -tigris iam users remove [resource] +tigris iam users remove [resource] [flags] ``` +| Flag | Description | +|------|-------------| +| `--force` | Skip confirmation prompts (alias for --yes) | + **Examples:** ```bash tigris iam users remove -tigris iam users remove user@example.com -tigris iam users remove user@example.com,user@example.net +tigris iam users remove user@example.com --yes +tigris iam users remove user@example.com,user@example.net --yes +``` + +## Other + +### `update` + +Update the CLI to the latest version + +``` +tigris update +``` + +**Examples:** +```bash +tigris update ``` ## License diff --git a/SKILL.md b/SKILL.md index 5513429..2680971 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,6 +1,6 @@ --- name: tigris -description: "Tigris object storage CLI reference. Use when working with object storage, file uploads, S3-compatible buckets, or blob storage. Provides commands, conventions, and environment setup for using Tigris via the tigris (t3) CLI." +description: 'Tigris object storage CLI reference. Use when working with object storage, file uploads, S3-compatible buckets, or blob storage. Provides commands, conventions, and environment setup for using Tigris via the tigris (t3) CLI.' user-invocable: false --- @@ -13,17 +13,6 @@ Use Tigris for all object storage tasks. Prefer the Tigris CLI (`tigris` or shor - **Single endpoint**: `https://t3.storage.dev` - **Region**: `auto` (Tigris handles routing automatically) -## Environment Variables - -When configuring S3-compatible access (SDKs, Terraform, etc.): - -```sh -export AWS_ENDPOINT_URL_S3=https://t3.storage.dev -export AWS_REGION=auto -export AWS_ACCESS_KEY_ID= -export AWS_SECRET_ACCESS_KEY= -``` - ## Key Commands ### Authentication @@ -62,7 +51,6 @@ export AWS_SECRET_ACCESS_KEY= ## Conventions -- Always use `--dry-run` for mutating operations when available. - Use `t3://` URI prefix for remote paths (e.g., `t3://my-bucket/path/file.txt`). - The `t3` shorthand works for all commands: `t3 ls`, `t3 cp`, etc. - Paths support both `t3://` and `tigris://` prefixes. diff --git a/package-lock.json b/package-lock.json index 5a54e20..2c9d7d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,10 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@aws-sdk/credential-providers": "^3.1024.0", - "@smithy/shared-ini-file-loader": "^4.4.7", + "@aws-sdk/credential-providers": "^3.1035.0", + "@smithy/shared-ini-file-loader": "^4.4.9", "@tigrisdata/iam": "^2.1.0", - "@tigrisdata/storage": "^3.0.0", + "@tigrisdata/storage": "^3.2.0", "commander": "^14.0.3", "enquirer": "^2.4.1", "jose": "^6.2.2", @@ -29,18 +29,18 @@ "@commitlint/config-conventional": "^20.5.0", "@eslint/js": "^10.0.1", "@types/node": "^22.19.11", - "dotenv": "^17.4.1", - "eslint": "^10.2.0", - "eslint-plugin-simple-import-sort": "^12.1.1", + "dotenv": "^17.4.2", + "eslint": "^10.2.1", + "eslint-plugin-simple-import-sort": "^13.0.0", "husky": "^9.1.7", - "prettier": "^3.8.1", + "prettier": "^3.8.3", "publint": "^0.3.18", "semantic-release": "^25.0.3", "tsup": "^8.5.1", "tsx": "^4.21.0", "typescript": "^5.9.3", - "typescript-eslint": "^8.58.0", - "vitest": "^4.1.2" + "typescript-eslint": "^8.59.0", + "vitest": "^4.1.5" } }, "node_modules/@actions/core": { @@ -295,48 +295,48 @@ } }, "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.1024.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1024.0.tgz", - "integrity": "sha512-PhbZl7TT+SBAsNxeC4vjRCqnkKYadRPKpsX4s0CtsVZz3QJ6UWBO7nBCHV5Pdv1f+YJD+UbCxGBj389vOPLmsw==", + "version": "3.1035.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1035.0.tgz", + "integrity": "sha512-sHjCtR5GdKVXZ/bEXwqUMoGzak9fnI4Ny/NyG7+gAkYC1Z+CIg5Kr4QSrqGjA+N2iwCly8f2/rGAsNo+JGeaNA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/credential-provider-node": "^3.972.29", - "@aws-sdk/middleware-host-header": "^3.972.8", - "@aws-sdk/middleware-logger": "^3.972.8", - "@aws-sdk/middleware-recursion-detection": "^3.972.9", - "@aws-sdk/middleware-user-agent": "^3.972.28", - "@aws-sdk/region-config-resolver": "^3.972.10", - "@aws-sdk/types": "^3.973.6", - "@aws-sdk/util-endpoints": "^3.996.5", - "@aws-sdk/util-user-agent-browser": "^3.972.8", - "@aws-sdk/util-user-agent-node": "^3.973.14", - "@smithy/config-resolver": "^4.4.13", - "@smithy/core": "^3.23.13", - "@smithy/fetch-http-handler": "^5.3.15", - "@smithy/hash-node": "^4.2.12", - "@smithy/invalid-dependency": "^4.2.12", - "@smithy/middleware-content-length": "^4.2.12", - "@smithy/middleware-endpoint": "^4.4.28", - "@smithy/middleware-retry": "^4.4.46", - "@smithy/middleware-serde": "^4.2.16", - "@smithy/middleware-stack": "^4.2.12", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/node-http-handler": "^4.5.1", - "@smithy/protocol-http": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", - "@smithy/url-parser": "^4.2.12", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/credential-provider-node": "^3.972.35", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.34", + "@aws-sdk/region-config-resolver": "^3.972.13", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.8", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.20", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.16", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.31", + "@smithy/middleware-retry": "^4.5.4", + "@smithy/middleware-serde": "^4.2.19", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.6.0", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", - "@smithy/util-defaults-mode-browser": "^4.3.44", - "@smithy/util-defaults-mode-node": "^4.2.48", - "@smithy/util-endpoints": "^3.3.3", - "@smithy/util-middleware": "^4.2.12", - "@smithy/util-retry": "^4.2.13", + "@smithy/util-defaults-mode-browser": "^4.3.48", + "@smithy/util-defaults-mode-node": "^4.2.53", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.3", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -345,65 +345,65 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.1024.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1024.0.tgz", - "integrity": "sha512-8qdO5aLCzaf9l0RdrSBW1iIroRKP2QBqtZ6lkrtHKiaaH0B18xEn+lrEgiN/eCf3uRAYk4cqbnI2XcWzm+7dDQ==", + "version": "3.1035.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1035.0.tgz", + "integrity": "sha512-Bh1h96CjHMpxg6Rn2G4EE30YiiBh9w/7WmSZIfwLB0X/6lblaJcHggcryrq2uNN2Bx1/CNErMjTpGQzqhA7Rhg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/credential-provider-node": "^3.972.29", - "@aws-sdk/middleware-bucket-endpoint": "^3.972.8", - "@aws-sdk/middleware-expect-continue": "^3.972.8", - "@aws-sdk/middleware-flexible-checksums": "^3.974.6", - "@aws-sdk/middleware-host-header": "^3.972.8", - "@aws-sdk/middleware-location-constraint": "^3.972.8", - "@aws-sdk/middleware-logger": "^3.972.8", - "@aws-sdk/middleware-recursion-detection": "^3.972.9", - "@aws-sdk/middleware-sdk-s3": "^3.972.27", - "@aws-sdk/middleware-ssec": "^3.972.8", - "@aws-sdk/middleware-user-agent": "^3.972.28", - "@aws-sdk/region-config-resolver": "^3.972.10", - "@aws-sdk/signature-v4-multi-region": "^3.996.15", - "@aws-sdk/types": "^3.973.6", - "@aws-sdk/util-endpoints": "^3.996.5", - "@aws-sdk/util-user-agent-browser": "^3.972.8", - "@aws-sdk/util-user-agent-node": "^3.973.14", - "@smithy/config-resolver": "^4.4.13", - "@smithy/core": "^3.23.13", - "@smithy/eventstream-serde-browser": "^4.2.12", - "@smithy/eventstream-serde-config-resolver": "^4.3.12", - "@smithy/eventstream-serde-node": "^4.2.12", - "@smithy/fetch-http-handler": "^5.3.15", - "@smithy/hash-blob-browser": "^4.2.13", - "@smithy/hash-node": "^4.2.12", - "@smithy/hash-stream-node": "^4.2.12", - "@smithy/invalid-dependency": "^4.2.12", - "@smithy/md5-js": "^4.2.12", - "@smithy/middleware-content-length": "^4.2.12", - "@smithy/middleware-endpoint": "^4.4.28", - "@smithy/middleware-retry": "^4.4.46", - "@smithy/middleware-serde": "^4.2.16", - "@smithy/middleware-stack": "^4.2.12", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/node-http-handler": "^4.5.1", - "@smithy/protocol-http": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", - "@smithy/url-parser": "^4.2.12", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/credential-provider-node": "^3.972.35", + "@aws-sdk/middleware-bucket-endpoint": "^3.972.10", + "@aws-sdk/middleware-expect-continue": "^3.972.10", + "@aws-sdk/middleware-flexible-checksums": "^3.974.12", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-location-constraint": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-sdk-s3": "^3.972.33", + "@aws-sdk/middleware-ssec": "^3.972.10", + "@aws-sdk/middleware-user-agent": "^3.972.34", + "@aws-sdk/region-config-resolver": "^3.972.13", + "@aws-sdk/signature-v4-multi-region": "^3.996.21", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.8", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.20", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.16", + "@smithy/eventstream-serde-browser": "^4.2.14", + "@smithy/eventstream-serde-config-resolver": "^4.3.14", + "@smithy/eventstream-serde-node": "^4.2.14", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-blob-browser": "^4.2.15", + "@smithy/hash-node": "^4.2.14", + "@smithy/hash-stream-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/md5-js": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.31", + "@smithy/middleware-retry": "^4.5.4", + "@smithy/middleware-serde": "^4.2.19", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.6.0", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", - "@smithy/util-defaults-mode-browser": "^4.3.44", - "@smithy/util-defaults-mode-node": "^4.2.48", - "@smithy/util-endpoints": "^3.3.3", - "@smithy/util-middleware": "^4.2.12", - "@smithy/util-retry": "^4.2.13", - "@smithy/util-stream": "^4.5.21", + "@smithy/util-defaults-mode-browser": "^4.3.48", + "@smithy/util-defaults-mode-node": "^4.2.53", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.3", + "@smithy/util-stream": "^4.5.24", "@smithy/util-utf8": "^4.2.2", - "@smithy/util-waiter": "^4.2.14", + "@smithy/util-waiter": "^4.2.16", "tslib": "^2.6.2" }, "engines": { @@ -411,22 +411,23 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.973.26", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.26.tgz", - "integrity": "sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@aws-sdk/xml-builder": "^3.972.16", - "@smithy/core": "^3.23.13", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/property-provider": "^4.2.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/signature-v4": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", + "version": "3.974.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.4.tgz", + "integrity": "sha512-EbVgyzQ83/Lf6oh1O4vYY47tuYw3Aosthh865LNU77KyotKz+uvEBNmsl/bSVS/vG+IU39mCqcOHrnhmhF4lug==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/xml-builder": "^3.972.18", + "@smithy/core": "^3.23.16", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", - "@smithy/util-middleware": "^4.2.12", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.3", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -435,12 +436,12 @@ } }, "node_modules/@aws-sdk/crc64-nvme": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.5.tgz", - "integrity": "sha512-2VbTstbjKdT+yKi8m7b3a9CiVac+pL/IY2PHJwsaGkkHmuuqkJZIErPck1h6P3T9ghQMLSdMPyW6Qp7Di5swFg==", + "version": "3.972.7", + "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.7.tgz", + "integrity": "sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -448,15 +449,15 @@ } }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.972.21", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.21.tgz", - "integrity": "sha512-3ooy5gLnMLgWtkxz53P9R0RiSSCCHn576kyfy/L88QXOqS/G4wYTsqoNJBGZ0Kg46FlQ9jZHuZThbyeEeXgW/g==", + "version": "3.972.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.27.tgz", + "integrity": "sha512-ibA1vjaLhS1c/wNa9SSSOunjz5I72DBfAYrtM4G4sKQ3wPuk8ycfvU3AF8nEJBfefqPu2RhHxW7bEC9wiA/MTA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/nested-clients": "^3.996.18", - "@aws-sdk/types": "^3.973.6", - "@smithy/property-provider": "^4.2.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/nested-clients": "^3.997.2", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -464,15 +465,15 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.24", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.24.tgz", - "integrity": "sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w==", + "version": "3.972.30", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.30.tgz", + "integrity": "sha512-dHpeqa29a0cBYq/h59IC2EK3AphLY96nKy4F35kBtiz9GuKDc32UYRTgjZaF8uuJCnqgw9omUZKR+9myyDHC2A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/types": "^3.973.6", - "@smithy/property-provider": "^4.2.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -480,20 +481,20 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.26", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.26.tgz", - "integrity": "sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/types": "^3.973.6", - "@smithy/fetch-http-handler": "^5.3.15", - "@smithy/node-http-handler": "^4.5.1", - "@smithy/property-provider": "^4.2.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", - "@smithy/util-stream": "^4.5.21", + "version": "3.972.32", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.32.tgz", + "integrity": "sha512-A+ZTT//Mswkf9DFEM6XlngwOtYdD8X4CUcoZ2wdpgI8cCs9mcGeuhgTwbGJvealub/MeONOaUr3FbRPMKmTDjg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/types": "^3.973.8", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/node-http-handler": "^4.6.0", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", + "@smithy/util-stream": "^4.5.24", "tslib": "^2.6.2" }, "engines": { @@ -501,24 +502,24 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.28.tgz", - "integrity": "sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/credential-provider-env": "^3.972.24", - "@aws-sdk/credential-provider-http": "^3.972.26", - "@aws-sdk/credential-provider-login": "^3.972.28", - "@aws-sdk/credential-provider-process": "^3.972.24", - "@aws-sdk/credential-provider-sso": "^3.972.28", - "@aws-sdk/credential-provider-web-identity": "^3.972.28", - "@aws-sdk/nested-clients": "^3.996.18", - "@aws-sdk/types": "^3.973.6", - "@smithy/credential-provider-imds": "^4.2.12", - "@smithy/property-provider": "^4.2.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.34.tgz", + "integrity": "sha512-MoRc7tLnx3JpFkV2R826enEfBUVN8o9Cc7y3hnbMwiWzL/VJhgfxRQzHkEL9vWorMWP7tibltsRcLoid9fsVdw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/credential-provider-env": "^3.972.30", + "@aws-sdk/credential-provider-http": "^3.972.32", + "@aws-sdk/credential-provider-login": "^3.972.34", + "@aws-sdk/credential-provider-process": "^3.972.30", + "@aws-sdk/credential-provider-sso": "^3.972.34", + "@aws-sdk/credential-provider-web-identity": "^3.972.34", + "@aws-sdk/nested-clients": "^3.997.2", + "@aws-sdk/types": "^3.973.8", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -526,18 +527,18 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.28.tgz", - "integrity": "sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/nested-clients": "^3.996.18", - "@aws-sdk/types": "^3.973.6", - "@smithy/property-provider": "^4.2.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.34.tgz", + "integrity": "sha512-XVSklkRRQ/CQDmv3VVFdZRl5hTFgncFhZrLyi0Ai4LZk5o3jpY5HIfuTK7ad7tixPKa+iQmL9+vg9qNyYZB+nw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/nested-clients": "^3.997.2", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -545,22 +546,22 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.29", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.29.tgz", - "integrity": "sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.24", - "@aws-sdk/credential-provider-http": "^3.972.26", - "@aws-sdk/credential-provider-ini": "^3.972.28", - "@aws-sdk/credential-provider-process": "^3.972.24", - "@aws-sdk/credential-provider-sso": "^3.972.28", - "@aws-sdk/credential-provider-web-identity": "^3.972.28", - "@aws-sdk/types": "^3.973.6", - "@smithy/credential-provider-imds": "^4.2.12", - "@smithy/property-provider": "^4.2.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "version": "3.972.35", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.35.tgz", + "integrity": "sha512-nVrY7AdGfzYgAa/jd9m06p3ES7QQDaB7zN9c+vXnVXxBRkAs9MjRDPB5AKogWuC6phddltfvHGFqLDJmyU9u/A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.30", + "@aws-sdk/credential-provider-http": "^3.972.32", + "@aws-sdk/credential-provider-ini": "^3.972.34", + "@aws-sdk/credential-provider-process": "^3.972.30", + "@aws-sdk/credential-provider-sso": "^3.972.34", + "@aws-sdk/credential-provider-web-identity": "^3.972.34", + "@aws-sdk/types": "^3.973.8", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -568,16 +569,16 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.24", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.24.tgz", - "integrity": "sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw==", + "version": "3.972.30", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.30.tgz", + "integrity": "sha512-McJPomNTSEo+C6UA3Zq6pFrcyTUaVsoPPBOvbOHAoIFPc8Z2CMLndqFJOnB+9bVFiBTWQLutlVGmrocBbvv4MQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/types": "^3.973.6", - "@smithy/property-provider": "^4.2.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -585,18 +586,18 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.28.tgz", - "integrity": "sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/nested-clients": "^3.996.18", - "@aws-sdk/token-providers": "3.1021.0", - "@aws-sdk/types": "^3.973.6", - "@smithy/property-provider": "^4.2.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.34.tgz", + "integrity": "sha512-WngYb2K+/yhkDOmDfAOjoCa9Ja3he0DZiAraboKwgWoVRkajDIcDYBCVbUTxtTUldvQoe7VvHLTrBNxvftN1aQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/nested-clients": "^3.997.2", + "@aws-sdk/token-providers": "3.1035.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -604,17 +605,17 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.28.tgz", - "integrity": "sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ==", + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.34.tgz", + "integrity": "sha512-5KLUH+XmSNRj6amJiJSrPsCxU5l/PYDfxyqPa1MxWhHoQC3sxvGPrSib3IE+HQlfRA4e2kO0bnJy7HJdjvpuuA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/nested-clients": "^3.996.18", - "@aws-sdk/types": "^3.973.6", - "@smithy/property-provider": "^4.2.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/nested-clients": "^3.997.2", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -622,30 +623,30 @@ } }, "node_modules/@aws-sdk/credential-providers": { - "version": "3.1024.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1024.0.tgz", - "integrity": "sha512-5aVZ74iKJ3InT/s4H2tVzAjH48SdegJU0Y0RaAYToQbmrS1R17tipw0jVQrFzajX6W5sbG6xfLcTNIGL33ODMQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.1024.0", - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/credential-provider-cognito-identity": "^3.972.21", - "@aws-sdk/credential-provider-env": "^3.972.24", - "@aws-sdk/credential-provider-http": "^3.972.26", - "@aws-sdk/credential-provider-ini": "^3.972.28", - "@aws-sdk/credential-provider-login": "^3.972.28", - "@aws-sdk/credential-provider-node": "^3.972.29", - "@aws-sdk/credential-provider-process": "^3.972.24", - "@aws-sdk/credential-provider-sso": "^3.972.28", - "@aws-sdk/credential-provider-web-identity": "^3.972.28", - "@aws-sdk/nested-clients": "^3.996.18", - "@aws-sdk/types": "^3.973.6", - "@smithy/config-resolver": "^4.4.13", - "@smithy/core": "^3.23.13", - "@smithy/credential-provider-imds": "^4.2.12", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/property-provider": "^4.2.12", - "@smithy/types": "^4.13.1", + "version": "3.1035.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1035.0.tgz", + "integrity": "sha512-HimZ+jVYJzeD6+pwXvhKX2mvx2fScLbjC4+oz1HF9Vuls/3lAWKHssLLVpCIuXL8Ov6cWe1vQIbwpFajuTAmEA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.1035.0", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/credential-provider-cognito-identity": "^3.972.27", + "@aws-sdk/credential-provider-env": "^3.972.30", + "@aws-sdk/credential-provider-http": "^3.972.32", + "@aws-sdk/credential-provider-ini": "^3.972.34", + "@aws-sdk/credential-provider-login": "^3.972.34", + "@aws-sdk/credential-provider-node": "^3.972.35", + "@aws-sdk/credential-provider-process": "^3.972.30", + "@aws-sdk/credential-provider-sso": "^3.972.34", + "@aws-sdk/credential-provider-web-identity": "^3.972.34", + "@aws-sdk/nested-clients": "^3.997.2", + "@aws-sdk/types": "^3.973.8", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.16", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -653,15 +654,15 @@ } }, "node_modules/@aws-sdk/lib-storage": { - "version": "3.1024.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1024.0.tgz", - "integrity": "sha512-5zZSYI8VncyiatvEn+UqElvgX14NKEc+3a+aeMyMzqKuYgDCFd97KGdbqAXEgnfEiTNK0QgSecFC6PUMAsE3xg==", + "version": "3.1035.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1035.0.tgz", + "integrity": "sha512-VkC0kDql0qkv+h6nIZOAxmek3VMCNGsq2v74QT9Zf/WbPlyM5PqyGp1dsPxNSv2iMtoWXzHvqzkZ55ZiJCgq4Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-endpoint": "^4.4.28", - "@smithy/protocol-http": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", + "@smithy/middleware-endpoint": "^4.4.31", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", "buffer": "5.6.0", "events": "3.3.0", "stream-browserify": "3.0.0", @@ -671,20 +672,20 @@ "node": ">=20.0.0" }, "peerDependencies": { - "@aws-sdk/client-s3": "^3.1024.0" + "@aws-sdk/client-s3": "^3.1035.0" } }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.8.tgz", - "integrity": "sha512-WR525Rr2QJSETa9a050isktyWi/4yIGcmY3BQ1kpHqb0LqUglQHCS8R27dTJxxWNZvQ0RVGtEZjTCbZJpyF3Aw==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.10.tgz", + "integrity": "sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", + "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-arn-parser": "^3.972.3", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, @@ -693,14 +694,14 @@ } }, "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.8.tgz", - "integrity": "sha512-5DTBTiotEES1e2jOHAq//zyzCjeMB78lEHd35u15qnrid4Nxm7diqIf9fQQ3Ov0ChH1V3Vvt13thOnrACmfGVQ==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.10.tgz", + "integrity": "sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -708,23 +709,23 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.974.6", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.6.tgz", - "integrity": "sha512-YckB8k1ejbyCg/g36gUMFLNzE4W5cERIa4MtsdO+wpTmJEP0+TB7okWIt7d8TDOvnb7SwvxJ21E4TGOBxFpSWQ==", + "version": "3.974.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.12.tgz", + "integrity": "sha512-v7n0//P95g+UnmyjCpJkDJFB+EP/9Wx/fQJC5BEiK9Y7VHgmhh6RNPVbqDYz9gsz8mXnxzyYt3tCEVJ1kzo01w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/crc64-nvme": "^3.972.5", - "@aws-sdk/types": "^3.973.6", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/crc64-nvme": "^3.972.7", + "@aws-sdk/types": "^3.973.8", "@smithy/is-array-buffer": "^4.2.2", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", - "@smithy/util-middleware": "^4.2.12", - "@smithy/util-stream": "^4.5.21", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-stream": "^4.5.24", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -733,14 +734,14 @@ } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.8.tgz", - "integrity": "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.10.tgz", + "integrity": "sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -748,13 +749,13 @@ } }, "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.8.tgz", - "integrity": "sha512-KaUoFuoFPziIa98DSQsTPeke1gvGXlc5ZGMhy+b+nLxZ4A7jmJgLzjEF95l8aOQN2T/qlPP3MrAyELm8ExXucw==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.10.tgz", + "integrity": "sha512-rI3NZvJcEvjoD0+0PI0iUAwlPw2IlSlhyvgBK/3WkKJQE/YiKFedd9dMN2lVacdNxPNhxL/jzQaKQdrGtQagjQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -762,13 +763,13 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.8.tgz", - "integrity": "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.10.tgz", + "integrity": "sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -776,15 +777,15 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.972.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.9.tgz", - "integrity": "sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ==", + "version": "3.972.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.11.tgz", + "integrity": "sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", + "@aws-sdk/types": "^3.973.8", "@aws/lambda-invoke-store": "^0.2.2", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -792,23 +793,23 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.972.27", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.27.tgz", - "integrity": "sha512-gomO6DZwx+1D/9mbCpcqO5tPBqYBK7DtdgjTIjZ4yvfh/S7ETwAPS0XbJgP2JD8Ycr5CwVrEkV1sFtu3ShXeOw==", + "version": "3.972.33", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.33.tgz", + "integrity": "sha512-n8Eh/+kq3u/EodLr8n6sQupu03QGjf122RHXCTGLaHSkavz/2beSKpRlq2oDgfmJZNkAkWF113xbyaUmyOd+YA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/types": "^3.973.6", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-arn-parser": "^3.972.3", - "@smithy/core": "^3.23.13", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/signature-v4": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", + "@smithy/core": "^3.23.16", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", - "@smithy/util-middleware": "^4.2.12", - "@smithy/util-stream": "^4.5.21", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-stream": "^4.5.24", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -817,13 +818,13 @@ } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.8.tgz", - "integrity": "sha512-wqlK0yO/TxEC2UsY9wIlqeeutF6jjLe0f96Pbm40XscTo57nImUk9lBcw0dPgsm0sppFtAkSlDrfpK+pC30Wqw==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.10.tgz", + "integrity": "sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -831,18 +832,18 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.972.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.28.tgz", - "integrity": "sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/types": "^3.973.6", - "@aws-sdk/util-endpoints": "^3.996.5", - "@smithy/core": "^3.23.13", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", - "@smithy/util-retry": "^4.2.13", + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.34.tgz", + "integrity": "sha512-jrmJHyYlTQocR7H4VhvSFhaoedMb2rmlOTvFWD6tNBQ/EVQhTsrNfQUYFuPiOc2wUGxbm5LgCHtnvVmCPgODHw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.8", + "@smithy/core": "^3.23.16", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-retry": "^4.3.3", "tslib": "^2.6.2" }, "engines": { @@ -850,47 +851,48 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.996.18", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.18.tgz", - "integrity": "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA==", + "version": "3.997.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.2.tgz", + "integrity": "sha512-uGGQO08YetrqfInOKG5atRMrCDRQWRuZ9gGfKY6svPmuE4K7ac+XcbCkpWpjcA7yCYsBaKB/Nly4XKgPXUO1PA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/middleware-host-header": "^3.972.8", - "@aws-sdk/middleware-logger": "^3.972.8", - "@aws-sdk/middleware-recursion-detection": "^3.972.9", - "@aws-sdk/middleware-user-agent": "^3.972.28", - "@aws-sdk/region-config-resolver": "^3.972.10", - "@aws-sdk/types": "^3.973.6", - "@aws-sdk/util-endpoints": "^3.996.5", - "@aws-sdk/util-user-agent-browser": "^3.972.8", - "@aws-sdk/util-user-agent-node": "^3.973.14", - "@smithy/config-resolver": "^4.4.13", - "@smithy/core": "^3.23.13", - "@smithy/fetch-http-handler": "^5.3.15", - "@smithy/hash-node": "^4.2.12", - "@smithy/invalid-dependency": "^4.2.12", - "@smithy/middleware-content-length": "^4.2.12", - "@smithy/middleware-endpoint": "^4.4.28", - "@smithy/middleware-retry": "^4.4.46", - "@smithy/middleware-serde": "^4.2.16", - "@smithy/middleware-stack": "^4.2.12", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/node-http-handler": "^4.5.1", - "@smithy/protocol-http": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", - "@smithy/url-parser": "^4.2.12", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.34", + "@aws-sdk/region-config-resolver": "^3.972.13", + "@aws-sdk/signature-v4-multi-region": "^3.996.21", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.8", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.20", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.16", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.31", + "@smithy/middleware-retry": "^4.5.4", + "@smithy/middleware-serde": "^4.2.19", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.6.0", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", - "@smithy/util-defaults-mode-browser": "^4.3.44", - "@smithy/util-defaults-mode-node": "^4.2.48", - "@smithy/util-endpoints": "^3.3.3", - "@smithy/util-middleware": "^4.2.12", - "@smithy/util-retry": "^4.2.13", + "@smithy/util-defaults-mode-browser": "^4.3.48", + "@smithy/util-defaults-mode-node": "^4.2.53", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.3", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -899,15 +901,15 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.10.tgz", - "integrity": "sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.13.tgz", + "integrity": "sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/config-resolver": "^4.4.13", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/config-resolver": "^4.4.17", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -915,18 +917,18 @@ } }, "node_modules/@aws-sdk/s3-request-presigner": { - "version": "3.1024.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.1024.0.tgz", - "integrity": "sha512-KNoGsXnTfBxPqrtV2Owd4mrLnhTHRsOz6Hdaz+As5czGMQuPchoRvG1BJzn2NFRGLt/HSJAXVn+G6IhtRIDe+Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/signature-v4-multi-region": "^3.996.15", - "@aws-sdk/types": "^3.973.6", - "@aws-sdk/util-format-url": "^3.972.8", - "@smithy/middleware-endpoint": "^4.4.28", - "@smithy/protocol-http": "^5.3.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", + "version": "3.1035.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.1035.0.tgz", + "integrity": "sha512-zT+ulZy7/4mqSNL0toB5GuJIBm3nbeGyq/sHPOxIKR3g0bVi5CZupxGvt78yzQeBcXVNZz+orXvaw5ejQ0FGPw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/signature-v4-multi-region": "^3.996.21", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-format-url": "^3.972.10", + "@smithy/middleware-endpoint": "^4.4.31", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -934,16 +936,16 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.15", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.15.tgz", - "integrity": "sha512-Ukw2RpqvaL96CjfH/FgfBmy/ZosHBqoHBCFsN61qGg99F33vpntIVii8aNeh65XuOja73arSduskoa4OJea9RQ==", + "version": "3.996.21", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.21.tgz", + "integrity": "sha512-3EpT+C0QdmTMB5aVeJ5odWSLt9vg2oGzUXl1xvUazKGlkr9OBYnegNWqhhjGgZdv8RmSi5eS8nqqB+euNP2aqA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "^3.972.27", - "@aws-sdk/types": "^3.973.6", - "@smithy/protocol-http": "^5.3.12", - "@smithy/signature-v4": "^5.3.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/middleware-sdk-s3": "^3.972.33", + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -951,17 +953,17 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.1021.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1021.0.tgz", - "integrity": "sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA==", + "version": "3.1035.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1035.0.tgz", + "integrity": "sha512-E6IO3Cn+OzBe6Sb5pnubd5Y8qSUMAsVKkD5QSwFfIx5fV1g5SkYwUDRDyPlm90RuIVcCo28wpMJU6W8wXH46Aw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.26", - "@aws-sdk/nested-clients": "^3.996.18", - "@aws-sdk/types": "^3.973.6", - "@smithy/property-provider": "^4.2.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "@aws-sdk/core": "^3.974.4", + "@aws-sdk/nested-clients": "^3.997.2", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -969,12 +971,12 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.973.6", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.6.tgz", - "integrity": "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==", + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", + "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -994,15 +996,15 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.996.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.5.tgz", - "integrity": "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==", + "version": "3.996.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.8.tgz", + "integrity": "sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/types": "^4.13.1", - "@smithy/url-parser": "^4.2.12", - "@smithy/util-endpoints": "^3.3.3", + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-endpoints": "^3.4.2", "tslib": "^2.6.2" }, "engines": { @@ -1010,14 +1012,14 @@ } }, "node_modules/@aws-sdk/util-format-url": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.8.tgz", - "integrity": "sha512-J6DS9oocrgxM8xlUTTmQOuwRF6rnAGEujAN9SAzllcrQmwn5iJ58ogxy3SEhD0Q7JZvlA5jvIXBkpQRqEqlE9A==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.10.tgz", + "integrity": "sha512-DEKiHNJVtNxdyTeQspzY+15Po/kHm6sF0Cs4HV9Q2+lplB63+DrvdeiSoOSdWEWAoO2RcY1veoXVDz2tWxWCgQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/querystring-builder": "^4.2.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -1037,27 +1039,27 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.8.tgz", - "integrity": "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==", + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.10.tgz", + "integrity": "sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.6", - "@smithy/types": "^4.13.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.973.14", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.14.tgz", - "integrity": "sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw==", + "version": "3.973.20", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.20.tgz", + "integrity": "sha512-owEqyKr0z5hWwk+uHwudwNhyFMZ9f9eSWr/k/XD6yeDCI7hHyc56s4UOY1iBQmoramTbdAY4UCuLLEuKmjVXrg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "^3.972.28", - "@aws-sdk/types": "^3.973.6", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/types": "^4.13.1", + "@aws-sdk/middleware-user-agent": "^3.972.34", + "@aws-sdk/types": "^3.973.8", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, @@ -1074,12 +1076,12 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.16.tgz", - "integrity": "sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==", + "version": "3.972.18", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.18.tgz", + "integrity": "sha512-BMDNVG1ETXRhl1tnisQiYBef3RShJ1kfZA7x7afivTFMLirfHNTb6U71K569HNXhSXbQZsweHvSDZ6euBw8hPA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "fast-xml-parser": "5.5.8", "tslib": "^2.6.2" }, @@ -1416,21 +1418,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", - "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", - "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -1439,9 +1441,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -1934,13 +1936,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz", - "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^3.0.4", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" }, @@ -1949,22 +1951,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz", - "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.2.0" + "@eslint/core": "^1.2.1" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz", - "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1996,9 +1998,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz", - "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2006,13 +2008,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz", - "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.2.0", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { @@ -2111,9 +2113,9 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", - "integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, @@ -2287,9 +2289,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.123.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.123.0.tgz", - "integrity": "sha512-YtECP/y8Mj1lSHiUWGSRzy/C6teUKlS87dEfuVKT09LgQbUsBW1rNg+MiJ4buGu3yuADV60gbIvo9/HplA56Ew==", + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "dev": true, "license": "MIT", "funding": { @@ -2355,9 +2357,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.13.tgz", - "integrity": "sha512-5ZiiecKH2DXAVJTNN13gNMUcCDg4Jy8ZjbXEsPnqa248wgOVeYRX0iqXXD5Jz4bI9BFHgKsI2qmyJynstbmr+g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", "cpu": [ "arm64" ], @@ -2372,9 +2374,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.13.tgz", - "integrity": "sha512-tz/v/8G77seu8zAB3A5sK3UFoOl06zcshEzhUO62sAEtrEuW/H1CcyoupOrD+NbQJytYgA4CppXPzlrmp4JZKA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", "cpu": [ "arm64" ], @@ -2389,9 +2391,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.13.tgz", - "integrity": "sha512-8DakphqOz8JrMYWTJmWA+vDJxut6LijZ8Xcdc4flOlAhU7PNVwo2MaWBF9iXjJAPo5rC/IxEFZDhJ3GC7NHvug==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", "cpu": [ "x64" ], @@ -2406,9 +2408,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.13.tgz", - "integrity": "sha512-4wBQFfjDuXYN/SVI8inBF3Aa+isq40rc6VMFbk5jcpolUBTe5cYnMsHZ51nFWsx3PVyyNN3vgoESki0Hmr/4BA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", "cpu": [ "x64" ], @@ -2423,9 +2425,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.13.tgz", - "integrity": "sha512-JW/e4yPIXLms+jmnbwwy5LA/LxVwZUWLN8xug+V200wzaVi5TEGIWQlh8o91gWYFxW609euI98OCCemmWGuPrw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", "cpu": [ "arm" ], @@ -2440,9 +2442,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.13.tgz", - "integrity": "sha512-ZfKWpXiUymDnavepCaM6KG/uGydJ4l2nBmMxg60Ci4CbeefpqjPWpfaZM7PThOhk2dssqBAcwLc6rAyr0uTdXg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "cpu": [ "arm64" ], @@ -2457,9 +2459,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.13.tgz", - "integrity": "sha512-bmRg3O6Z0gq9yodKKWCIpnlH051sEfdVwt+6m5UDffAQMUUqU0xjnQqqAUm+Gu7ofAAly9DqiQDtKu2nPDEABA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", "cpu": [ "arm64" ], @@ -2474,9 +2476,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.13.tgz", - "integrity": "sha512-8Wtnbw4k7pMYN9B/mOEAsQ8HOiq7AZ31Ig4M9BKn2So4xRaFEhtCSa4ZJaOutOWq50zpgR4N5+L/opnlaCx8wQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", "cpu": [ "ppc64" ], @@ -2491,9 +2493,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.13.tgz", - "integrity": "sha512-D/0Nlo8mQuxSMohNJUF2lDXWRsFDsHldfRRgD9bRgktj+EndGPj4DOV37LqDKPYS+osdyhZEH7fTakTAEcW7qg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", "cpu": [ "s390x" ], @@ -2508,9 +2510,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.13.tgz", - "integrity": "sha512-eRrPvat2YaVQcwwKi/JzOP6MKf1WRnOCr+VaI3cTWz3ZoLcP/654z90lVCJ4dAuMEpPdke0n+qyAqXDZdIC4rA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "cpu": [ "x64" ], @@ -2525,9 +2527,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.13.tgz", - "integrity": "sha512-PsdONiFRp8hR8KgVjTWjZ9s7uA3uueWL0t74/cKHfM4dR5zXYv4AjB8BvA+QDToqxAFg4ZkcVEqeu5F7inoz5w==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", "cpu": [ "x64" ], @@ -2542,9 +2544,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.13.tgz", - "integrity": "sha512-hCNXgC5dI3TVOLrPT++PKFNZ+1EtS0mLQwfXXXSUD/+rGlB65gZDwN/IDuxLpQP4x8RYYHqGomlUXzpO8aVI2w==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", "cpu": [ "arm64" ], @@ -2559,9 +2561,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.13.tgz", - "integrity": "sha512-viLS5C5et8NFtLWw9Sw3M/w4vvnVkbWkO7wSNh3C+7G1+uCkGpr6PcjNDSFcNtmXY/4trjPBqUfcOL+P3sWy/g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", "cpu": [ "wasm32" ], @@ -2569,18 +2571,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.9.1", - "@emnapi/runtime": "1.9.1", - "@napi-rs/wasm-runtime": "^1.1.2" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.13.tgz", - "integrity": "sha512-Fqa3Tlt1xL4wzmAYxGNFV36Hb+VfPc9PYU+E25DAnswXv3ODDu/yyWjQDbXMo5AGWkQVjLgQExuVu8I/UaZhPQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", "cpu": [ "arm64" ], @@ -2595,9 +2597,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.13.tgz", - "integrity": "sha512-/pLI5kPkGEi44TDlnbio3St/5gUFeN51YWNAk/Gnv6mEQBOahRBh52qVFVBpmrnU01n2yysvBML9Ynu7K4kGAQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", "cpu": [ "x64" ], @@ -2612,9 +2614,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.13.tgz", - "integrity": "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", "dev": true, "license": "MIT" }, @@ -3306,16 +3308,16 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.13.tgz", - "integrity": "sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg==", + "version": "4.4.17", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.17.tgz", + "integrity": "sha512-TzDZcAnhTyAHbXVxWZo7/tEcrIeFq20IBk8So3OLOetWpR8EwY/yEqBMBFaJMeyEiREDq4NfEl+qO3OAUD+vbQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.12", - "@smithy/types": "^4.13.1", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", - "@smithy/util-endpoints": "^3.3.3", - "@smithy/util-middleware": "^4.2.12", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", "tslib": "^2.6.2" }, "engines": { @@ -3323,18 +3325,18 @@ } }, "node_modules/@smithy/core": { - "version": "3.23.13", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.13.tgz", - "integrity": "sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q==", + "version": "3.23.16", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.16.tgz", + "integrity": "sha512-JStomOrINQA1VqNEopLsgcdgwd42au7mykKqVr30XFw89wLt9sDxJDi4djVPRwQmmzyTGy/uOvTc2ultMpFi1w==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", - "@smithy/url-parser": "^4.2.12", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", - "@smithy/util-middleware": "^4.2.12", - "@smithy/util-stream": "^4.5.21", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-stream": "^4.5.24", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" @@ -3344,15 +3346,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.12.tgz", - "integrity": "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.14.tgz", + "integrity": "sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.12", - "@smithy/property-provider": "^4.2.12", - "@smithy/types": "^4.13.1", - "@smithy/url-parser": "^4.2.12", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", "tslib": "^2.6.2" }, "engines": { @@ -3360,13 +3362,13 @@ } }, "node_modules/@smithy/eventstream-codec": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.12.tgz", - "integrity": "sha512-FE3bZdEl62ojmy8x4FHqxq2+BuOHlcxiH5vaZ6aqHJr3AIZzwF5jfx8dEiU/X0a8RboyNDjmXjlbr8AdEyLgiA==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.14.tgz", + "integrity": "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" }, @@ -3375,13 +3377,13 @@ } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.12.tgz", - "integrity": "sha512-XUSuMxlTxV5pp4VpqZf6Sa3vT/Q75FVkLSpSSE3KkWBvAQWeuWt1msTv8fJfgA4/jcJhrbrbMzN1AC/hvPmm5A==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.14.tgz", + "integrity": "sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.2.12", - "@smithy/types": "^4.13.1", + "@smithy/eventstream-serde-universal": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3389,12 +3391,12 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.3.12", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.12.tgz", - "integrity": "sha512-7epsAZ3QvfHkngz6RXQYseyZYHlmWXSTPOfPmXkiS+zA6TBNo1awUaMFL9vxyXlGdoELmCZyZe1nQE+imbmV+Q==", + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.14.tgz", + "integrity": "sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3402,13 +3404,13 @@ } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.12.tgz", - "integrity": "sha512-D1pFuExo31854eAvg89KMn9Oab/wEeJR6Buy32B49A9Ogdtx5fwZPqBHUlDzaCDpycTFk2+fSQgX689Qsk7UGA==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.14.tgz", + "integrity": "sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.2.12", - "@smithy/types": "^4.13.1", + "@smithy/eventstream-serde-universal": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3416,13 +3418,13 @@ } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.12.tgz", - "integrity": "sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.14.tgz", + "integrity": "sha512-lWyt4T2XQZUZgK3tQ3Wn0w3XBvZsK/vjTuJl6bXbnGZBHH0ZUSONTYiK9TgjTTzU54xQr3DRFwpjmhp0oLm3gg==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-codec": "^4.2.12", - "@smithy/types": "^4.13.1", + "@smithy/eventstream-codec": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3430,14 +3432,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.15", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.15.tgz", - "integrity": "sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A==", + "version": "5.3.17", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz", + "integrity": "sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.12", - "@smithy/querystring-builder": "^4.2.12", - "@smithy/types": "^4.13.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" }, @@ -3446,14 +3448,14 @@ } }, "node_modules/@smithy/hash-blob-browser": { - "version": "4.2.13", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.13.tgz", - "integrity": "sha512-YrF4zWKh+ghLuquldj6e/RzE3xZYL8wIPfkt0MqCRphVICjyyjH8OwKD7LLlKpVEbk4FLizFfC1+gwK6XQdR3g==", + "version": "4.2.15", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.15.tgz", + "integrity": "sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA==", "license": "Apache-2.0", "dependencies": { "@smithy/chunked-blob-reader": "^5.2.2", "@smithy/chunked-blob-reader-native": "^4.2.3", - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3461,12 +3463,12 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.12.tgz", - "integrity": "sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.14.tgz", + "integrity": "sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" @@ -3476,12 +3478,12 @@ } }, "node_modules/@smithy/hash-stream-node": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.12.tgz", - "integrity": "sha512-O3YbmGExeafuM/kP7Y8r6+1y0hIh3/zn6GROx0uNlB54K9oihAL75Qtc+jFfLNliTi6pxOAYZrRKD9A7iA6UFw==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.14.tgz", + "integrity": "sha512-tw4GANWkZPb6+BdD4Fgucqzey2+r73Z/GRo9zklsCdwrnxxumUV83ZIaBDdudV4Ylazw3EPTiJZhpX42105ruQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -3490,12 +3492,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.12.tgz", - "integrity": "sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.14.tgz", + "integrity": "sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3515,12 +3517,12 @@ } }, "node_modules/@smithy/md5-js": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.12.tgz", - "integrity": "sha512-W/oIpHCpWU2+iAkfZYyGWE+qkpuf3vEXHLxQQDx9FPNZTTdnul0dZ2d/gUFrtQ5je1G2kp4cjG0/24YueG2LbQ==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.14.tgz", + "integrity": "sha512-V2v0vx+h0iUSNG1Alt+GNBMSLGCrl9iVsdd+Ap67HPM9PN479x12V8LkuMoKImNZxn3MXeuyUjls+/7ZACZghA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -3529,13 +3531,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.12.tgz", - "integrity": "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.14.tgz", + "integrity": "sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3543,18 +3545,18 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.4.28", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.28.tgz", - "integrity": "sha512-p1gfYpi91CHcs5cBq982UlGlDrxoYUX6XdHSo91cQ2KFuz6QloHosO7Jc60pJiVmkWrKOV8kFYlGFFbQ2WUKKQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.23.13", - "@smithy/middleware-serde": "^4.2.16", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", - "@smithy/url-parser": "^4.2.12", - "@smithy/util-middleware": "^4.2.12", + "version": "4.4.31", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.31.tgz", + "integrity": "sha512-KJPdCIN2kOE2aGmqZd7eUTr4WQwOGgtLWgUkswGJggs7rBcQYQjcZMEDa3C0DwbOiXS9L8/wDoQHkfxBYLfiLw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.16", + "@smithy/middleware-serde": "^4.2.19", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-middleware": "^4.2.14", "tslib": "^2.6.2" }, "engines": { @@ -3562,18 +3564,19 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.46", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.46.tgz", - "integrity": "sha512-SpvWNNOPOrKQGUqZbEPO+es+FRXMWvIyzUKUOYdDgdlA6BdZj/R58p4umoQ76c2oJC44PiM7mKizyyex1IJzow==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/service-error-classification": "^4.2.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", - "@smithy/util-middleware": "^4.2.12", - "@smithy/util-retry": "^4.2.13", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.5.4.tgz", + "integrity": "sha512-/z7nIFK+ZRW3Ie/l3NEVGdy34LvmEOzBrtBAvgWZ/4PrKX0xP3kWm8pkfcwUk523SqxZhdbQP9JSXgjF77Uhpw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.16", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/service-error-classification": "^4.3.0", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.3", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" }, @@ -3582,14 +3585,14 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.2.16", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.16.tgz", - "integrity": "sha512-beqfV+RZ9RSv+sQqor3xroUUYgRFCGRw6niGstPG8zO9LgTl0B0MCucxjmrH/2WwksQN7UUgI7KNANoZv+KALA==", + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.19.tgz", + "integrity": "sha512-Q6y+W9h3iYVMCKWDoVge+OC1LKFqbEKaq8SIWG2X2bWJRpd/6dDLyICcNLT6PbjH3Rr6bmg/SeDB25XFOFfeEw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.23.13", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", + "@smithy/core": "^3.23.16", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3597,12 +3600,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.12.tgz", - "integrity": "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.14.tgz", + "integrity": "sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3610,14 +3613,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.3.12", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.12.tgz", - "integrity": "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw==", + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.14.tgz", + "integrity": "sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.12", - "@smithy/shared-ini-file-loader": "^4.4.7", - "@smithy/types": "^4.13.1", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3625,14 +3628,14 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.1.tgz", - "integrity": "sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.6.0.tgz", + "integrity": "sha512-P734cAoTFtuGfWa/R3jgBnGlURt2w9bYEBwQNMKf58sRM9RShirB2mKwLsVP+jlG/wxpCu8abv8NxdUts8tdLA==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.12", - "@smithy/querystring-builder": "^4.2.12", - "@smithy/types": "^4.13.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3640,12 +3643,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.12.tgz", - "integrity": "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.14.tgz", + "integrity": "sha512-WuM31CgfsnQ/10i7NYr0PyxqknD72Y5uMfUMVSniPjbEPceiTErb4eIqJQ+pdxNEAUEWrewrGjIRjVbVHsxZiQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3653,12 +3656,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.3.12", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.12.tgz", - "integrity": "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.14.tgz", + "integrity": "sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3666,12 +3669,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.12.tgz", - "integrity": "sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.14.tgz", + "integrity": "sha512-XYA5Z0IqTeF+5XDdh4BBmSA0HvbgVZIyv4cmOoUheDNR57K1HgBp9ukUMx3Cr3XpDHHpLBnexPE3LAtDsZkj2A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" }, @@ -3680,12 +3683,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.12.tgz", - "integrity": "sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.14.tgz", + "integrity": "sha512-hr+YyqBD23GVvRxGGrcc/oOeNlK3PzT5Fu4dzrDXxzS1LpFiuL2PQQqKPs87M79aW7ziMs+nvB3qdw77SqE7Lw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3693,24 +3696,24 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.12.tgz", - "integrity": "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.3.0.tgz", + "integrity": "sha512-9jKsBYQRPR0xBLgc2415RsA5PIcP2sis4oBdN9s0D13cg1B1284mNTjx9Yc+BEERXzuPm5ObktI96OxsKh8E9A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1" + "@smithy/types": "^4.14.1" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.7.tgz", - "integrity": "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.9.tgz", + "integrity": "sha512-495/V2I15SHgedSJoDPD23JuSfKAp726ZI1V0wtjB07Wh7q/0tri/0e0DLefZCHgxZonrGKt/OCTpAtP1wE1kQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3718,16 +3721,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.3.12", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.12.tgz", - "integrity": "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.14.tgz", + "integrity": "sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.2", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", - "@smithy/util-middleware": "^4.2.12", + "@smithy/util-middleware": "^4.2.14", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" @@ -3737,17 +3740,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.12.8", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.8.tgz", - "integrity": "sha512-aJaAX7vHe5i66smoSSID7t4rKY08PbD8EBU7DOloixvhOozfYWdcSYE4l6/tjkZ0vBZhGjheWzB2mh31sLgCMA==", + "version": "4.12.12", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.12.tgz", + "integrity": "sha512-daO7SJn4eM6ArbmrEs+/BTbH7af8AEbSL3OMQdcRvvn8tuUcR5rU2n6DgxIV53aXMS42uwK8NgKKCh5XgqYOPQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.23.13", - "@smithy/middleware-endpoint": "^4.4.28", - "@smithy/middleware-stack": "^4.2.12", - "@smithy/protocol-http": "^5.3.12", - "@smithy/types": "^4.13.1", - "@smithy/util-stream": "^4.5.21", + "@smithy/core": "^3.23.16", + "@smithy/middleware-endpoint": "^4.4.31", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-stream": "^4.5.24", "tslib": "^2.6.2" }, "engines": { @@ -3755,9 +3758,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz", - "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.1.tgz", + "integrity": "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -3767,13 +3770,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.12.tgz", - "integrity": "sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.14.tgz", + "integrity": "sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^4.2.12", - "@smithy/types": "^4.13.1", + "@smithy/querystring-parser": "^4.2.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3844,14 +3847,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.44", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.44.tgz", - "integrity": "sha512-eZg6XzaCbVr2S5cAErU5eGBDaOVTuTo1I65i4tQcHENRcZ8rMWhQy1DaIYUSLyZjsfXvmCqZrstSMYyGFocvHA==", + "version": "4.3.48", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.48.tgz", + "integrity": "sha512-hxVRVPYaRDWa6YQdse1aWX1qrksmLsvNyGBKdc32q4jFzSjxYVNWfstknAfR228TnzS4tzgswXRuYIbhXBuXFQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", + "@smithy/property-provider": "^4.2.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3859,17 +3862,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.48", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.48.tgz", - "integrity": "sha512-FqOKTlqSaoV3nzO55pMs5NBnZX8EhoI0DGmn9kbYeXWppgHD6dchyuj2HLqp4INJDJbSrj6OFYJkAh/WhSzZPg==", + "version": "4.2.53", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.53.tgz", + "integrity": "sha512-ybgCk+9JdBq8pYC8Y6U5fjyS8e4sboyAShetxPNL0rRBtaVl56GSFAxsolVBIea1tXR4LPIzL8i6xqmcf0+DCQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.4.13", - "@smithy/credential-provider-imds": "^4.2.12", - "@smithy/node-config-provider": "^4.3.12", - "@smithy/property-provider": "^4.2.12", - "@smithy/smithy-client": "^4.12.8", - "@smithy/types": "^4.13.1", + "@smithy/config-resolver": "^4.4.17", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/smithy-client": "^4.12.12", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3877,13 +3880,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.3.tgz", - "integrity": "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.4.2.tgz", + "integrity": "sha512-a55Tr+3OKld4TTtnT+RhKOQHyPxm3j/xL4OR83WBUhLJaKDS9dnJ7arRMOp3t31dcLhApwG9bgvrRXBHlLdIkg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.12", - "@smithy/types": "^4.13.1", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3903,12 +3906,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.12.tgz", - "integrity": "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.14.tgz", + "integrity": "sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3916,13 +3919,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.2.13", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.13.tgz", - "integrity": "sha512-qQQsIvL0MGIbUjeSrg0/VlQ3jGNKyM3/2iU3FPNgy01z+Sp4OvcaxbgIoFOTvB61ZoohtutuOvOcgmhbD0katQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.3.3.tgz", + "integrity": "sha512-idjUvd4M9Jj6rXkhqw4H4reHoweuK4ZxYWyOrEp4N2rOF5VtaOlQGLDQJva/8WanNXk9ScQtsAb7o5UHGvFm4A==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.2.12", - "@smithy/types": "^4.13.1", + "@smithy/service-error-classification": "^4.3.0", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -3930,14 +3933,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.5.21", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.21.tgz", - "integrity": "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q==", + "version": "4.5.24", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.24.tgz", + "integrity": "sha512-na5vv2mBSDzXewLEEoWGI7LQQkfpmFEomBsmOpzLFjqGctm0iMwXY5lAwesY9pIaErkccW0qzEOUcYP+WKneXg==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.3.15", - "@smithy/node-http-handler": "^4.5.1", - "@smithy/types": "^4.13.1", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/node-http-handler": "^4.6.0", + "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", @@ -3974,12 +3977,12 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.14.tgz", - "integrity": "sha512-2zqq5o/oizvMaFUlNiTyZ7dbgYv1a893aGut2uaxtbzTx/VYYnRxWzDHuD/ftgcw94ffenua+ZNLrbqwUYE+Bg==", + "version": "4.2.16", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.16.tgz", + "integrity": "sha512-GtclrKoZ3Lt7jPQ7aTIYKfjY92OgceScftVnkTsG8e1KV8rkvZgN+ny6YSRhd9hxB8rZtwVbmln7NTvE5O3GmQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -4015,17 +4018,17 @@ } }, "node_modules/@tigrisdata/storage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@tigrisdata/storage/-/storage-3.0.0.tgz", - "integrity": "sha512-Rhw+aEOpl2bcgDhIymAguX2m178TYdco+lmX+zxYHw+P9jX8v4euwnZwRSb/+YwqmEawhBeapdNkCgIsBIVZ8g==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@tigrisdata/storage/-/storage-3.2.0.tgz", + "integrity": "sha512-sDBloJ+LrHA5+Ni3h545BFv+ZLwbxUvi9q1J6aoaFZEJwLX//RS9JFI5P5J3CT+A7rh8DM5LGj59E1iu5vdfqg==", "license": "MIT", "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", - "@aws-sdk/client-s3": "^3.1018.0", - "@aws-sdk/lib-storage": "^3.1018.0", - "@aws-sdk/s3-request-presigner": "^3.1018.0", - "@smithy/signature-v4": "^5.3.12", - "dotenv": "^17.3.1" + "@aws-sdk/client-s3": "^3.1030.0", + "@aws-sdk/lib-storage": "^3.1030.0", + "@aws-sdk/s3-request-presigner": "^3.1030.0", + "@smithy/signature-v4": "^5.3.13", + "dotenv": "^17.4.2" } }, "node_modules/@tybys/wasm-util": { @@ -4096,17 +4099,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz", - "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.0.tgz", + "integrity": "sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.58.0", - "@typescript-eslint/type-utils": "8.58.0", - "@typescript-eslint/utils": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0", + "@typescript-eslint/scope-manager": "8.59.0", + "@typescript-eslint/type-utils": "8.59.0", + "@typescript-eslint/utils": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -4119,7 +4122,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.58.0", + "@typescript-eslint/parser": "^8.59.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -4135,16 +4138,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz", - "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.0.tgz", + "integrity": "sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.58.0", - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/typescript-estree": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0", + "@typescript-eslint/scope-manager": "8.59.0", + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.0", "debug": "^4.4.3" }, "engines": { @@ -4160,14 +4163,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz", - "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.0.tgz", + "integrity": "sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.58.0", - "@typescript-eslint/types": "^8.58.0", + "@typescript-eslint/tsconfig-utils": "^8.59.0", + "@typescript-eslint/types": "^8.59.0", "debug": "^4.4.3" }, "engines": { @@ -4182,14 +4185,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz", - "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.0.tgz", + "integrity": "sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0" + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4200,9 +4203,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz", - "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.0.tgz", + "integrity": "sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg==", "dev": true, "license": "MIT", "engines": { @@ -4217,15 +4220,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz", - "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.0.tgz", + "integrity": "sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/typescript-estree": "8.58.0", - "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0", + "@typescript-eslint/utils": "8.59.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -4242,9 +4245,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz", - "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.0.tgz", + "integrity": "sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A==", "dev": true, "license": "MIT", "engines": { @@ -4256,16 +4259,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz", - "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.0.tgz", + "integrity": "sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.58.0", - "@typescript-eslint/tsconfig-utils": "8.58.0", - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/visitor-keys": "8.58.0", + "@typescript-eslint/project-service": "8.59.0", + "@typescript-eslint/tsconfig-utils": "8.59.0", + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -4284,16 +4287,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz", - "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.0.tgz", + "integrity": "sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.58.0", - "@typescript-eslint/types": "8.58.0", - "@typescript-eslint/typescript-estree": "8.58.0" + "@typescript-eslint/scope-manager": "8.59.0", + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4308,13 +4311,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz", - "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.0.tgz", + "integrity": "sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/types": "8.59.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -4326,16 +4329,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.2.tgz", - "integrity": "sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.2", - "@vitest/utils": "4.1.2", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -4344,13 +4347,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.2.tgz", - "integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.2", + "@vitest/spy": "4.1.5", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -4371,9 +4374,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.2.tgz", - "integrity": "sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", "dev": true, "license": "MIT", "dependencies": { @@ -4384,13 +4387,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.2.tgz", - "integrity": "sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.2", + "@vitest/utils": "4.1.5", "pathe": "^2.0.3" }, "funding": { @@ -4398,14 +4401,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.2.tgz", - "integrity": "sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.2", - "@vitest/utils": "4.1.2", + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -4414,9 +4417,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.2.tgz", - "integrity": "sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", "dev": true, "license": "MIT", "funding": { @@ -4424,13 +4427,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.2.tgz", - "integrity": "sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.2", + "@vitest/pretty-format": "4.1.5", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -5299,9 +5302,9 @@ } }, "node_modules/dotenv": { - "version": "17.4.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz", - "integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -5569,18 +5572,18 @@ } }, "node_modules/eslint": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", - "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", + "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.4", - "@eslint/config-helpers": "^0.5.4", - "@eslint/core": "^1.2.0", - "@eslint/plugin-kit": "^0.7.0", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -5625,9 +5628,9 @@ } }, "node_modules/eslint-plugin-simple-import-sort": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", - "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-13.0.0.tgz", + "integrity": "sha512-McAc+/Nlvcg4byY/CABGH8kqnefWBj8s3JA2okEtz8ixbECQgU46p0HkTUKa4YS7wvgGceimlc34p1nXqbWqtA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -5883,9 +5886,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz", + "integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==", "funding": [ { "type": "github", @@ -9777,9 +9780,9 @@ } }, "node_modules/path-expression-matcher": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.1.tgz", - "integrity": "sha512-d7gQQmLvAKXKXE2GeP9apIGbMYKz88zWdsn/BN2HRWVQsDFdUY36WSLTY0Jvd4HWi7Fb30gQ62oAOzdgJA6fZw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "funding": [ { "type": "github", @@ -9948,9 +9951,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "dev": true, "funding": [ { @@ -10042,9 +10045,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { @@ -10308,14 +10311,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.13.tgz", - "integrity": "sha512-bvVj8YJmf0rq4pSFmH7laLa6pYrhghv3PRzrCdRAr23g66zOKVJ4wkvFtgohtPLWmthgg8/rkaqRHrpUEh0Zbw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.123.0", - "@rolldown/pluginutils": "1.0.0-rc.13" + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" }, "bin": { "rolldown": "bin/cli.mjs" @@ -10324,21 +10327,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.13", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.13", - "@rolldown/binding-darwin-x64": "1.0.0-rc.13", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.13", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.13", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.13", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.13", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.13", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.13", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.13", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.13", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.13", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.13", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.13", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.13" + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" } }, "node_modules/rollup": { @@ -10964,9 +10967,9 @@ } }, "node_modules/strnum": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.2.tgz", - "integrity": "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", + "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", "funding": [ { "type": "github", @@ -11192,14 +11195,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -11455,16 +11458,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.58.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.0.tgz", - "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==", + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.0.tgz", + "integrity": "sha512-BU3ONW9X+v90EcCH9ZS6LMackcVtxRLlI3XrYyqZIwVSHIk7Qf7bFw1z0M9Q0IUxhTMZCf8piY9hTYaNEIASrw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.58.0", - "@typescript-eslint/parser": "8.58.0", - "@typescript-eslint/typescript-estree": "8.58.0", - "@typescript-eslint/utils": "8.58.0" + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0", + "@typescript-eslint/utils": "8.59.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -11610,17 +11613,17 @@ } }, "node_modules/vite": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.7.tgz", - "integrity": "sha512-P1PbweD+2/udplnThz3btF4cf6AgPky7kk23RtHUkJIU5BIxwPprhRGmOAHs6FTI7UiGbTNrgNP6jSYD6JaRnw==", + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.13", - "tinyglobby": "^0.2.15" + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" @@ -11701,19 +11704,19 @@ } }, "node_modules/vitest": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.2.tgz", - "integrity": "sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.2", - "@vitest/mocker": "4.1.2", - "@vitest/pretty-format": "4.1.2", - "@vitest/runner": "4.1.2", - "@vitest/snapshot": "4.1.2", - "@vitest/spy": "4.1.2", - "@vitest/utils": "4.1.2", + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -11741,10 +11744,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.2", - "@vitest/browser-preview": "4.1.2", - "@vitest/browser-webdriverio": "4.1.2", - "@vitest/ui": "4.1.2", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -11768,6 +11773,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, diff --git a/package.json b/package.json index 5e757f9..7a720d9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ }, "scripts": { "build": "tsc --noEmit && tsup", - "dev": "export $(grep -v '^#' .env | xargs) && (tsc --noEmit --watch --preserveWatchOutput & tsup --watch)", + "dev": "export $(grep -v '^#' .env.test | xargs) && (tsc --noEmit --watch --preserveWatchOutput & tsup --watch)", "cli": "node dist/cli.js", "lint": "eslint src test", "lint:fix": "eslint src test --fix", @@ -90,10 +90,10 @@ ] }, "dependencies": { - "@aws-sdk/credential-providers": "^3.1024.0", - "@smithy/shared-ini-file-loader": "^4.4.7", + "@aws-sdk/credential-providers": "^3.1035.0", + "@smithy/shared-ini-file-loader": "^4.4.9", "@tigrisdata/iam": "^2.1.0", - "@tigrisdata/storage": "^3.0.0", + "@tigrisdata/storage": "^3.2.0", "commander": "^14.0.3", "enquirer": "^2.4.1", "jose": "^6.2.2", @@ -105,17 +105,17 @@ "@commitlint/config-conventional": "^20.5.0", "@eslint/js": "^10.0.1", "@types/node": "^22.19.11", - "dotenv": "^17.4.1", - "eslint": "^10.2.0", - "eslint-plugin-simple-import-sort": "^12.1.1", + "dotenv": "^17.4.2", + "eslint": "^10.2.1", + "eslint-plugin-simple-import-sort": "^13.0.0", "husky": "^9.1.7", - "prettier": "^3.8.1", + "prettier": "^3.8.3", "publint": "^0.3.18", "semantic-release": "^25.0.3", "tsup": "^8.5.1", "tsx": "^4.21.0", "typescript": "^5.9.3", - "typescript-eslint": "^8.58.0", - "vitest": "^4.1.2" + "typescript-eslint": "^8.59.0", + "vitest": "^4.1.5" } } diff --git a/scripts/generate-registry.ts b/scripts/generate-registry.ts index 6735b8b..4535f37 100644 --- a/scripts/generate-registry.ts +++ b/scripts/generate-registry.ts @@ -9,7 +9,7 @@ * Run: npm run generate:registry */ -import { readFileSync, existsSync, writeFileSync } from 'fs'; +import { existsSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; import * as YAML from 'yaml'; diff --git a/scripts/update-docs.ts b/scripts/update-docs.ts index 2dd03b4..8b57fe8 100644 --- a/scripts/update-docs.ts +++ b/scripts/update-docs.ts @@ -1,7 +1,8 @@ -import { readFileSync, writeFileSync, existsSync } from 'fs'; -import { join, dirname } from 'path'; +import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; import * as yaml from 'yaml'; + import type { CommandSpec } from '../src/types.js'; const __filename = fileURLToPath(import.meta.url); @@ -226,7 +227,7 @@ function generateDocs(specs: Specs): string { lines.push(''); // Core commands (Unix-style) - only implemented ones - const coreCommands = ['ls', 'mk', 'touch', 'cp', 'mv', 'rm', 'stat'].filter((c) => isImplemented(c)); + const coreCommands = ['ls', 'mk', 'touch', 'cp', 'mv', 'rm', 'stat', 'presign', 'bundle'].filter((c) => isImplemented(c)); lines.push('### Core Commands'); lines.push(''); for (const cmdName of coreCommands) { @@ -254,6 +255,20 @@ function generateDocs(specs: Specs): string { } lines.push(''); + // Other commands (CLI management) + const otherCommands = ['update'].filter((c) => isImplemented(c)); + if (otherCommands.length > 0) { + lines.push('### Other'); + lines.push(''); + for (const cmdName of otherCommands) { + const cmd = specs.commands.find((c) => c.name === cmdName); + if (cmd) { + lines.push(`- \`tigris ${cmd.name}\` - ${cmd.description}`); + } + } + lines.push(''); + } + // Resource management const resourceCommands = ['organizations', 'access-keys', 'credentials', 'buckets', 'forks', 'snapshots', 'objects', 'iam']; const implementedResources = resourceCommands.filter((c) => { @@ -358,6 +373,34 @@ function generateDocs(specs: Specs): string { } } + // Other commands + if (otherCommands.length > 0) { + lines.push('## Other'); + lines.push(''); + for (const cmdName of otherCommands) { + const cmd = specs.commands.find((c) => c.name === cmdName); + if (cmd) { + lines.push(generateCommandSection(cmd)); + } + } + } + + // Warn about any specs commands that aren't in any category + const allCategorized = new Set([ + ...coreCommands, + ...authCommandNames, + ...resourceCommands, + ...otherCommands, + ]); + const unhandled = specs.commands + .filter((c) => !allCategorized.has(c.name) && hasImplementation(c)) + .map((c) => c.name); + if (unhandled.length > 0) { + console.warn( + `Warning: the following implemented commands are not in any docs category: ${unhandled.join(', ')}` + ); + } + return lines.join('\n'); } diff --git a/src/lib/buckets/migrate.ts b/src/lib/buckets/migrate.ts new file mode 100644 index 0000000..bfefeff --- /dev/null +++ b/src/lib/buckets/migrate.ts @@ -0,0 +1,464 @@ +import { getStorageConfig } from '@auth/provider.js'; +import type { ListItem } from '@tigrisdata/storage'; +import { + isMigrated, + list, + migrate as scheduleMigration, +} from '@tigrisdata/storage'; +import { executeWithConcurrency } from '@utils/concurrency.js'; +import { failWithError } from '@utils/exit.js'; +import { formatSize } from '@utils/format.js'; +import { msg, printFailure } from '@utils/messages.js'; +import { getOption } from '@utils/options.js'; +import { parseAnyPath } from '@utils/path.js'; + +const context = msg('buckets', 'migrate'); + +/** Max total bytes of in-flight (scheduled but not confirmed) migrations */ +const MAX_IN_FLIGHT_BYTES = 10 * 1024 * 1024 * 1024; // 10 GB + +/** Max concurrent migrate() or isMigrated() calls */ +const CONCURRENCY = 50; + +/** Seconds to wait between isMigrated polling rounds */ +const CHECK_INTERVAL_MS = 5_000; + +/** Batch size for scheduling migrate() calls before checking throttle */ +const SCHEDULE_BATCH_SIZE = 50; + +/** Max consecutive isMigrated failures before marking item as failed */ +const MAX_CHECK_FAILURES = 3; + +interface MigrationItem { + name: string; + size: number; +} + +interface InFlightItem extends MigrationItem { + checkFailures: number; +} + +interface MigrationState { + total: number; + totalBytes: number; + scheduled: number; + confirmed: number; + confirmedBytes: number; + failed: number; + inFlight: InFlightItem[]; + inFlightBytes: number; + errors: Array<{ name: string; error: string }>; + startTime: number; +} + +// --------------------------------------------------------------------------- +// PaginatedCursor: wraps list() with source-based pagination +// --------------------------------------------------------------------------- + +class PaginatedCursor { + private buffer: ListItem[] = []; + private index = 0; + private token: string | undefined; + private _done = false; + + constructor( + private bucket: string, + private source: 'tigris' | 'shadow', + private prefix: string | undefined, + private config: Record + ) {} + + get done(): boolean { + return this._done && this.index >= this.buffer.length; + } + + async current(): Promise { + if (this.index < this.buffer.length) { + return this.buffer[this.index]; + } + if (this._done) return null; + await this.fetchPage(); + return this.index < this.buffer.length ? this.buffer[this.index] : null; + } + + advance(): void { + this.index++; + } + + private async fetchPage(): Promise { + if (this._done) return; + + const { data, error } = await list({ + prefix: this.prefix, + source: this.source, + ...(this.token ? { paginationToken: this.token } : {}), + config: { + ...this.config, + bucket: this.bucket, + }, + }); + + if (error) { + throw error; + } + + this.buffer = data.items ?? []; + this.index = 0; + this.token = data.paginationToken; + + if (!data.paginationToken && !data.hasMore) { + this._done = true; + } + } +} + +// --------------------------------------------------------------------------- +// Discovery: sorted merge-diff +// --------------------------------------------------------------------------- + +async function discoverDiff( + bucket: string, + prefix: string | undefined, + config: Record +): Promise { + const shadow = new PaginatedCursor(bucket, 'shadow', prefix, config); + const tigris = new PaginatedCursor(bucket, 'tigris', prefix, config); + + const diff: MigrationItem[] = []; + + let shadowItem = await shadow.current(); + let tigrisItem = await tigris.current(); + + while (shadowItem !== null) { + if (tigrisItem === null) { + // Tigris exhausted — all remaining shadow items need migration + diff.push({ name: shadowItem.name, size: shadowItem.size }); + shadow.advance(); + shadowItem = await shadow.current(); + continue; + } + + if (shadowItem.name < tigrisItem.name) { + // In shadow but not in tigris + diff.push({ name: shadowItem.name, size: shadowItem.size }); + shadow.advance(); + shadowItem = await shadow.current(); + } else if (shadowItem.name > tigrisItem.name) { + // In tigris but not in shadow — skip + tigris.advance(); + tigrisItem = await tigris.current(); + } else { + // In both — already migrated + shadow.advance(); + tigris.advance(); + shadowItem = await shadow.current(); + tigrisItem = await tigris.current(); + } + } + + return diff; +} + +// --------------------------------------------------------------------------- +// Migration loop +// --------------------------------------------------------------------------- + +function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function formatElapsed(ms: number): string { + const totalSeconds = Math.floor(ms / 1000); + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + if (minutes === 0) return `${seconds}s`; + return `${minutes}m ${seconds}s`; +} + +function printProgress(state: MigrationState, bucket: string): void { + if (!process.stderr.isTTY || globalThis.__TIGRIS_JSON_MODE) return; + + const elapsed = formatElapsed(Date.now() - state.startTime); + const line = + `\rMigrating ${bucket}: ` + + `${state.confirmed.toLocaleString()} / ${state.total.toLocaleString()} objects | ` + + `In-flight: ${formatSize(state.inFlightBytes)} | ` + + `${elapsed}`; + + process.stderr.write(line + ' '.repeat(Math.max(0, 100 - line.length))); +} + +function clearProgress(): void { + if (!process.stderr.isTTY || globalThis.__TIGRIS_JSON_MODE) return; + process.stderr.write('\r' + ' '.repeat(100) + '\r'); +} + +async function flushScheduleBatch( + batch: MigrationItem[], + state: MigrationState, + config: Record, + bucket: string +): Promise { + const results = await executeWithConcurrency( + batch.map( + (item) => () => + scheduleMigration(item.name, { + config: { ...config, bucket }, + }) + ), + CONCURRENCY + ); + + for (let i = 0; i < results.length; i++) { + const result = results[i]; + const item = batch[i]; + + if (result.error) { + state.failed++; + state.errors.push({ + name: item.name, + error: result.error.message, + }); + } else { + state.inFlight.push({ ...item, checkFailures: 0 }); + state.inFlightBytes += item.size; + state.scheduled++; + } + } +} + +async function drainCompleted( + state: MigrationState, + config: Record, + bucket: string +): Promise { + if (state.inFlight.length === 0) return; + + // Check oldest items first (FIFO), up to CONCURRENCY at a time + const toCheck = state.inFlight.slice(0, CONCURRENCY); + + const results = await executeWithConcurrency( + toCheck.map( + (item) => () => + isMigrated(item.name, { + config: { ...config, bucket }, + }) + ), + CONCURRENCY + ); + + const completedKeys = new Set(); + for (let i = 0; i < results.length; i++) { + const result = results[i]; + const item = toCheck[i]; + + if (result.error) { + item.checkFailures++; + if (item.checkFailures >= MAX_CHECK_FAILURES) { + completedKeys.add(item.name); + state.failed++; + state.inFlightBytes -= item.size; + state.errors.push({ + name: item.name, + error: `Failed to verify migration status after ${MAX_CHECK_FAILURES} attempts`, + }); + } + } else if (result.data) { + completedKeys.add(item.name); + state.confirmed++; + state.confirmedBytes += item.size; + state.inFlightBytes -= item.size; + } + } + + if (completedKeys.size > 0) { + state.inFlight = state.inFlight.filter( + (item) => !completedKeys.has(item.name) + ); + } + + // If nothing completed, wait before next check + if (completedKeys.size === 0) { + await sleep(CHECK_INTERVAL_MS); + } +} + +// --------------------------------------------------------------------------- +// Main command +// --------------------------------------------------------------------------- + +export default async function migrate( + options: Record +): Promise { + const pathString = getOption(options, ['path']); + + if (!pathString) { + failWithError(context, 'Bucket name or path is required'); + } + + const { bucket, path: prefix } = parseAnyPath(pathString); + + if (!bucket) { + failWithError(context, 'Invalid path'); + } + + const config = await getStorageConfig(); + + // Handle SIGINT gracefully + let interrupted = false; + const sigintHandler = () => { + interrupted = true; + }; + process.on('SIGINT', sigintHandler); + + try { + // Phase 1: Discovery + if (process.stderr.isTTY && !globalThis.__TIGRIS_JSON_MODE) { + process.stderr.write('Discovering objects to migrate...'); + } + + let diff: MigrationItem[]; + try { + diff = await discoverDiff(bucket, prefix, config); + } catch (err) { + clearProgress(); + failWithError(context, err); + } + + clearProgress(); + + if (diff.length === 0) { + if (process.stderr.isTTY && !globalThis.__TIGRIS_JSON_MODE) { + console.error('All objects are already migrated.'); + } + if (globalThis.__TIGRIS_JSON_MODE) { + console.log( + JSON.stringify({ + action: 'migrate', + bucket, + toMigrate: 0, + confirmed: 0, + failed: 0, + }) + ); + } + return; + } + + const totalBytes = diff.reduce((sum, item) => sum + item.size, 0); + + if (process.stderr.isTTY && !globalThis.__TIGRIS_JSON_MODE) { + console.error( + `Found ${diff.length.toLocaleString()} objects to migrate (${formatSize(totalBytes)})` + ); + } + + // Phase 2: Migration loop + const state: MigrationState = { + total: diff.length, + totalBytes, + scheduled: 0, + confirmed: 0, + confirmedBytes: 0, + failed: 0, + inFlight: [], + inFlightBytes: 0, + errors: [], + startTime: Date.now(), + }; + + let batch: MigrationItem[] = []; + + for (const item of diff) { + if (interrupted) break; + + // Throttle: wait until capacity is available + while ( + state.inFlightBytes + item.size > MAX_IN_FLIGHT_BYTES && + state.inFlight.length > 0 && + !interrupted + ) { + await drainCompleted(state, config, bucket); + printProgress(state, bucket); + } + + if (interrupted) break; + + batch.push(item); + + if (batch.length >= SCHEDULE_BATCH_SIZE) { + await flushScheduleBatch(batch, state, config, bucket); + batch = []; + printProgress(state, bucket); + } + } + + // Flush remaining batch + if (batch.length > 0 && !interrupted) { + await flushScheduleBatch(batch, state, config, bucket); + printProgress(state, bucket); + } + + // Phase 3: Drain all remaining in-flight items + while (state.inFlight.length > 0 && !interrupted) { + await drainCompleted(state, config, bucket); + printProgress(state, bucket); + } + + clearProgress(); + + // Summary + const elapsed = formatElapsed(Date.now() - state.startTime); + + if (globalThis.__TIGRIS_JSON_MODE) { + console.log( + JSON.stringify({ + action: 'migrate', + bucket, + toMigrate: state.total, + scheduled: state.scheduled, + confirmed: state.confirmed, + failed: state.failed, + elapsed, + ...(state.errors.length > 0 + ? { errors: state.errors.slice(0, 20) } + : {}), + }) + ); + } + + if (interrupted) { + console.error( + `\nInterrupted. ${state.confirmed} confirmed, ${state.inFlight.length} still in-flight, ${state.total - state.scheduled} not yet scheduled.` + ); + process.exit(1); + } + + if (state.failed > 0) { + printFailure( + context, + `${state.failed} object(s) failed to migrate. ${state.confirmed} migrated successfully in ${elapsed}.` + ); + if ( + process.stderr.isTTY && + !globalThis.__TIGRIS_JSON_MODE && + state.errors.length > 0 + ) { + const shown = state.errors.slice(0, 10); + for (const err of shown) { + console.error(` ${err.name}: ${err.error}`); + } + if (state.errors.length > 10) { + console.error(` ... and ${state.errors.length - 10} more`); + } + } + process.exit(1); + } + + console.error( + `\nMigration complete: ${state.confirmed.toLocaleString()} object(s) migrated (${formatSize(state.confirmedBytes)}) in ${elapsed}` + ); + } finally { + process.removeListener('SIGINT', sigintHandler); + } +} diff --git a/src/lib/bundle.ts b/src/lib/bundle.ts new file mode 100644 index 0000000..351c14c --- /dev/null +++ b/src/lib/bundle.ts @@ -0,0 +1,156 @@ +import { getStorageConfig } from '@auth/provider.js'; +import { bundle } from '@tigrisdata/storage'; +import { exitWithError } from '@utils/exit.js'; +import { getFormat, getOption, readStdin } from '@utils/options.js'; +import { parseAnyPath } from '@utils/path.js'; +import { createWriteStream, existsSync, readFileSync } from 'fs'; +import { Readable } from 'stream'; +import { pipeline } from 'stream/promises'; + +const MAX_KEYS = 5000; + +function parseKeys(content: string): string[] { + return content + .split('\n') + .map((line) => line.trim()) + .filter((line) => line.length > 0 && !line.startsWith('#')); +} + +function detectCompression( + outputPath: string +): 'none' | 'gzip' | 'zstd' | undefined { + if (outputPath.endsWith('.tar.gz') || outputPath.endsWith('.tgz')) { + return 'gzip'; + } + if (outputPath.endsWith('.tar.zst')) { + return 'zstd'; + } + if (outputPath.endsWith('.tar')) { + return 'none'; + } + return undefined; +} + +export default async function bundleCommand(options: Record) { + const bucketArg = getOption(options, ['bucket']); + const keysArg = getOption(options, ['keys', 'k']); + const outputPath = getOption(options, ['output', 'o']); + const compressionArg = getOption(options, ['compression']); + const onError = getOption(options, ['on-error', 'onError'], 'skip'); + const format = getFormat(options); + const jsonMode = format === 'json'; + + // stdout carries binary data when no --output + const stdoutBinary = !outputPath; + + if (!bucketArg) { + exitWithError('Bucket is required'); + } + + const { bucket, path: prefix } = parseAnyPath(bucketArg); + + if (!bucket) { + exitWithError('Invalid bucket'); + } + + // Resolve keys: file, inline, or stdin + let keys: string[]; + + if (keysArg) { + if (keysArg.includes(',')) { + // Commas present → always treat as inline comma-separated keys + keys = keysArg + .split(',') + .map((k) => k.trim()) + .filter((k) => k.length > 0); + } else if (existsSync(keysArg)) { + // No commas and local file exists → read as keys file + keys = parseKeys(readFileSync(keysArg, 'utf-8')); + } else { + // Single key + keys = [keysArg.trim()]; + } + } else if (!process.stdin.isTTY) { + const input = await readStdin(); + keys = parseKeys(input); + } else { + exitWithError('Keys are required. Provide via --keys or pipe to stdin.'); + } + + // Prepend path prefix from bucket arg (e.g. t3://bucket/prefix) + if (prefix) { + const normalizedPrefix = prefix.endsWith('/') ? prefix : `${prefix}/`; + keys = keys.map((key) => `${normalizedPrefix}${key}`); + } + + if (keys.length === 0) { + exitWithError('No keys found'); + } + + if (keys.length > MAX_KEYS) { + exitWithError(`Too many keys (max ${MAX_KEYS}). Got ${keys.length}`); + } + + // Resolve compression: explicit flag > auto-detect from extension > default + let compression: 'none' | 'gzip' | 'zstd' = 'none'; + if (compressionArg) { + compression = compressionArg as 'none' | 'gzip' | 'zstd'; + } else if (outputPath) { + compression = detectCompression(outputPath) ?? 'none'; + } + + if (!stdoutBinary && !jsonMode) { + process.stderr.write(`Bundling ${keys.length} object(s)...\n`); + } + + const config = await getStorageConfig({ withCredentialProvider: true }); + + const { data, error } = await bundle(keys, { + config: { ...config, bucket }, + compression, + onError: onError as 'skip' | 'fail', + }); + + if (error) { + exitWithError(error); + } + + const nodeStream = Readable.fromWeb(data.body as ReadableStream); + + if (outputPath) { + const writeStream = createWriteStream(outputPath); + await pipeline(nodeStream, writeStream); + + if (jsonMode) { + console.log( + JSON.stringify({ + action: 'bundled', + bucket, + keys: keys.length, + compression, + output: outputPath, + }) + ); + } else { + console.log( + `Bundled ${keys.length} object(s) from '${bucket}' to ${outputPath}` + ); + } + } else { + await pipeline(nodeStream, process.stdout); + + if (jsonMode) { + console.error( + JSON.stringify({ + action: 'bundled', + bucket, + keys: keys.length, + compression, + output: 'stdout', + }) + ); + } + } + + process.exit(0); +} diff --git a/src/lib/iam/policies/utils.ts b/src/lib/iam/policies/utils.ts index 0e206b7..961c595 100644 --- a/src/lib/iam/policies/utils.ts +++ b/src/lib/iam/policies/utils.ts @@ -1,12 +1,6 @@ import type { PolicyDocument } from '@tigrisdata/iam'; -export async function readStdin(): Promise { - const chunks: Buffer[] = []; - for await (const chunk of process.stdin) { - chunks.push(chunk); - } - return Buffer.concat(chunks).toString('utf-8'); -} +export { readStdin } from '@utils/options.js'; export function parseDocument(jsonString: string): PolicyDocument { const raw = JSON.parse(jsonString); diff --git a/src/lib/ls.ts b/src/lib/ls.ts index 2bfb789..90cf3ec 100644 --- a/src/lib/ls.ts +++ b/src/lib/ls.ts @@ -14,6 +14,7 @@ export default async function ls(options: Record) { 'snapshot', ]); const format = getFormat(options); + const source = getOption<'tigris' | 'shadow'>(options, ['source']); const { limit, pageToken } = getPaginationOptions(options); if (!pathString) { @@ -72,7 +73,9 @@ export default async function ls(options: Record) { const { data, error } = await list({ prefix, + delimiter: '/', ...(snapshotVersion ? { snapshotVersion } : {}), + ...(source ? { source } : {}), ...(limit !== undefined ? { limit } : {}), ...(pageToken ? { paginationToken: pageToken } : {}), config: { @@ -85,28 +88,29 @@ export default async function ls(options: Record) { exitWithError(error); } - const objects = (data.items || []) - .map((item) => { - // Strip the prefix from the name for cleaner display - const name = prefix ? item.name.slice(prefix.length) : item.name; - - // For immediate children only: if name contains /, only show up to first / - const firstSlash = name.indexOf('/'); - const displayName = - firstSlash === -1 ? name : name.slice(0, firstSlash + 1); - const isFolder = displayName.endsWith('/'); + // Common prefixes are "folders" returned by S3 when using a delimiter + const folders = (data.commonPrefixes || []).map((p) => { + const displayName = prefix ? p.slice(prefix.length) : p; + return { + key: displayName, + size: '-', + modified: '', + }; + }); + // Items are files at this level (filter out empty keys from folder marker objects) + const files = (data.items || []) + .map((item) => { + const displayName = prefix ? item.name.slice(prefix.length) : item.name; return { key: displayName, - size: isFolder ? '-' : formatSize(item.size), + size: formatSize(item.size), modified: item.lastModified, }; }) - // Filter out empty keys and deduplicate folders - .filter( - (item, index, arr) => - item.key !== '' && arr.findIndex((i) => i.key === item.key) === index - ); + .filter((item) => item.key !== ''); + + const objects = [...folders, ...files]; const columns = [ { key: 'key', header: 'Key' }, diff --git a/src/lib/objects/list.ts b/src/lib/objects/list.ts index f9ff4b0..812a51a 100644 --- a/src/lib/objects/list.ts +++ b/src/lib/objects/list.ts @@ -25,6 +25,7 @@ export default async function listObjects(options: Record) { 'snapshotVersion', 'snapshot', ]); + const source = getOption<'tigris' | 'shadow'>(options, ['source']); const { limit, pageToken } = getPaginationOptions(options); if (!bucketArg) { @@ -40,6 +41,7 @@ export default async function listObjects(options: Record) { const { data, error } = await list({ prefix, ...(snapshotVersion ? { snapshotVersion } : {}), + ...(source ? { source } : {}), ...(limit !== undefined ? { limit } : {}), ...(pageToken ? { paginationToken: pageToken } : {}), config: { diff --git a/src/specs.yaml b/src/specs.yaml index 3c8b1ee..1205e57 100644 --- a/src/specs.yaml +++ b/src/specs.yaml @@ -297,6 +297,9 @@ commands: - name: page-token description: Pagination token from a previous request to fetch the next page alias: pt + - name: source + description: List objects from a specific storage source on buckets with shadow migration enabled + options: [tigris, shadow] # mk - name: mk @@ -546,6 +549,40 @@ commands: alias: f description: Skip confirmation prompts (alias for --yes) + # bundle + - name: bundle + description: Download multiple objects as a streaming tar archive in a single request. Designed for batch workloads that need many objects without per-object HTTP overhead + examples: + - "tigris bundle my-bucket --keys key1.jpg,key2.jpg --output archive.tar" + - "tigris bundle my-bucket --keys keys.txt --output archive.tar" + - "tigris bundle t3://my-bucket --keys keys.txt --compression gzip -o archive.tar.gz" + - "cat keys.txt | tigris bundle my-bucket > archive.tar" + messages: + onStart: '' + onSuccess: '' + onFailure: 'Bundle failed. Verify the bucket exists and credentials have read access' + arguments: + - name: bucket + required: true + type: positional + description: Bucket name or t3:// path containing the objects to bundle + examples: + - my-bucket + - t3://my-bucket + - name: keys + description: "Comma-separated object keys, or path to a file with one key per line. If a local file matching the value exists, it is read as a keys file. If omitted, reads keys from stdin" + alias: k + - name: output + description: Output file path. Defaults to stdout (for piping) + alias: o + - name: compression + description: Compression algorithm for the archive. Auto-detected from output file extension when not specified + options: [none, gzip, zstd] + - name: on-error + description: How to handle missing objects. 'skip' omits them, 'fail' aborts the request + options: [skip, fail] + default: skip + ######################### # Manage organizations ######################### @@ -906,6 +943,26 @@ commands: - name: disable description: Disable migration and clear all migration settings type: flag + # migrate + - name: migrate + description: Actively migrate all objects from a shadow bucket to Tigris by scheduling server-side migration for unmigrated objects + examples: + - "tigris buckets migrate my-bucket" + - "tigris buckets migrate my-bucket/images/" + - "tigris buckets migrate t3://my-bucket/prefix/" + messages: + onStart: '' + onSuccess: '' + onFailure: 'Migration failed' + arguments: + - name: path + description: Bucket name or path with optional prefix. Supports t3:// and tigris:// prefixes + type: positional + required: true + examples: + - my-bucket + - my-bucket/images/ + - t3://my-bucket/prefix/ # set-transition - name: set-transition description: Configure a lifecycle transition rule on a bucket. Automatically move objects to a different storage class after a number of days or on a specific date @@ -1202,6 +1259,9 @@ commands: - name: page-token description: Pagination token from a previous request to fetch the next page alias: pt + - name: source + description: List objects from a specific storage source on buckets with shadow migration enabled + options: [tigris, shadow] # get - name: get description: Download an object by key. Prints to stdout by default, or saves to a file with --output diff --git a/src/utils/messages.ts b/src/utils/messages.ts index 5c9359d..e785d4e 100644 --- a/src/utils/messages.ts +++ b/src/utils/messages.ts @@ -174,7 +174,7 @@ export function printDeprecated(message: string): void { */ export function printPaginationHint(paginationToken?: string): void { if (!paginationToken) return; - console.error(`\nNext page: --page-token ${paginationToken}`); + console.error(`\nNext page: --page-token "${paginationToken}"`); } /** diff --git a/src/utils/options.ts b/src/utils/options.ts index 79046ed..7e1858a 100644 --- a/src/utils/options.ts +++ b/src/utils/options.ts @@ -73,3 +73,15 @@ export function parseBoolean( if (typeof value === 'boolean') return value; return value === 'true'; } + +/** + * Read all of stdin as a UTF-8 string. + * Use when stdin is piped (i.e. `!process.stdin.isTTY`). + */ +export async function readStdin(): Promise { + const chunks: Buffer[] = []; + for await (const chunk of process.stdin) { + chunks.push(chunk); + } + return Buffer.concat(chunks).toString('utf-8'); +} diff --git a/src/utils/update-check.ts b/src/utils/update-check.ts index 7911e53..756e2fe 100644 --- a/src/utils/update-check.ts +++ b/src/utils/update-check.ts @@ -1,5 +1,4 @@ -import { execSync } from 'child_process'; -import { mkdirSync, readFileSync, writeFileSync } from 'fs'; +import { mkdirSync, readFileSync, realpathSync, writeFileSync } from 'fs'; import https from 'https'; import { homedir } from 'os'; import { join } from 'path'; @@ -96,8 +95,8 @@ export function isNewerVersion(current: string, latest: string): boolean { function isHomebrewInstall(): boolean { if (process.platform === 'win32') return false; try { - execSync('brew list tigris', { stdio: 'ignore' }); - return true; + const resolved = realpathSync(process.execPath); + return resolved.includes('/Cellar/') || resolved.includes('/Caskroom/'); } catch { return false; } @@ -109,15 +108,23 @@ function isHomebrewInstall(): boolean { export function getUpdateCommand(): string { const isBinary = (globalThis as { __TIGRIS_BINARY?: boolean }).__TIGRIS_BINARY === true; - const isWindows = process.platform === 'win32'; + // npm install — process.execPath is Node, not our binary. + // Must come before isHomebrewInstall() to avoid false positives + // when Node itself was installed via Homebrew. if (!isBinary) { return 'npm install -g @tigrisdata/cli'; - } else if (isHomebrewInstall()) { + } + // Standalone binary installed via Homebrew (execPath resolves to /Cellar/ or /Caskroom/) + else if (isHomebrewInstall()) { return 'brew upgrade tigris'; - } else if (isWindows) { + } + // Standalone binary on Windows + else if (process.platform === 'win32') { return 'irm https://github.com/tigrisdata/cli/releases/latest/download/install.ps1 | iex'; - } else { + } + // Standalone binary on macOS/Linux (installed via curl) + else { return 'curl -fsSL https://github.com/tigrisdata/cli/releases/latest/download/install.sh | sh'; } } diff --git a/test/auth/fly.test.ts b/test/auth/fly.test.ts new file mode 100644 index 0000000..7a29289 --- /dev/null +++ b/test/auth/fly.test.ts @@ -0,0 +1,45 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +vi.mock('../../src/auth/storage.js', () => ({ + getSelectedOrganization: vi.fn(), +})); + +import { isFlyOrganization } from '../../src/auth/fly.js'; +import { getSelectedOrganization } from '../../src/auth/storage.js'; + +describe('isFlyOrganization', () => { + const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); + + beforeEach(() => { + logSpy.mockClear(); + }); + + afterEach(() => { + vi.mocked(getSelectedOrganization).mockReset(); + }); + + it('returns true when org starts with flyio_', () => { + vi.mocked(getSelectedOrganization).mockReturnValue('flyio_my-org'); + expect(isFlyOrganization('User management')).toBe(true); + }); + + it('prints message when org is Fly', () => { + vi.mocked(getSelectedOrganization).mockReturnValue('flyio_my-org'); + isFlyOrganization('User management'); + expect(logSpy).toHaveBeenCalledTimes(1); + expect(logSpy.mock.calls[0][0]).toContain('User management'); + expect(logSpy.mock.calls[0][0]).toContain('fly.io'); + }); + + it('returns false when org does not start with flyio_', () => { + vi.mocked(getSelectedOrganization).mockReturnValue('my-regular-org'); + expect(isFlyOrganization('User management')).toBe(false); + expect(logSpy).not.toHaveBeenCalled(); + }); + + it('returns false when getSelectedOrganization returns null', () => { + vi.mocked(getSelectedOrganization).mockReturnValue(null); + expect(isFlyOrganization('User management')).toBe(false); + expect(logSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/test/auth/iam.test.ts b/test/auth/iam.test.ts new file mode 100644 index 0000000..732b0a4 --- /dev/null +++ b/test/auth/iam.test.ts @@ -0,0 +1,155 @@ +import { describe, expect, it, vi } from 'vitest'; + +// Mock dependencies before importing module under test +vi.mock('../../src/auth/client.js', () => ({ + getAuthClient: vi.fn(() => ({ + isAuthenticated: vi.fn(), + getAccessToken: vi.fn(), + })), + getAuth0Config: () => ({ + domain: 'test.auth0.com', + clientId: 'test-client-id', + audience: 'test-audience', + }), +})); + +vi.mock('../../src/auth/provider.js', () => ({ + resolveAuthMethod: vi.fn(), + getTigrisConfig: vi.fn(() => ({ + iamEndpoint: 'https://iam.test', + mgmtEndpoint: 'https://mgmt.test', + })), +})); + +vi.mock('../../src/auth/storage.js', () => ({ + getLoginMethod: vi.fn(), + getSelectedOrganization: vi.fn(), +})); + +vi.mock('../../src/utils/exit.js', () => ({ + failWithError: vi.fn((_ctx: unknown, msg: unknown) => { + throw new Error(String(msg)); + }), +})); + +vi.mock('../../src/utils/messages.js', () => ({ + msg: vi.fn(() => ({})), +})); + +import { getAuthClient } from '../../src/auth/client.js'; +import { getIAMConfig, getOAuthIAMConfig } from '../../src/auth/iam.js'; +import { resolveAuthMethod } from '../../src/auth/provider.js'; +import { + getLoginMethod, + getSelectedOrganization, +} from '../../src/auth/storage.js'; +import { msg } from '../../src/utils/messages.js'; + +const context = msg('test'); + +describe('getOAuthIAMConfig', () => { + it('throws when login method is not oauth', async () => { + vi.mocked(getLoginMethod).mockReturnValue('credentials'); + await expect(getOAuthIAMConfig(context)).rejects.toThrow( + 'requires OAuth login' + ); + }); + + it('throws when not authenticated', async () => { + vi.mocked(getLoginMethod).mockReturnValue('oauth'); + const mockClient = { + isAuthenticated: vi.fn().mockResolvedValue(false), + getAccessToken: vi.fn(), + }; + vi.mocked(getAuthClient).mockReturnValue( + mockClient as ReturnType + ); + + await expect(getOAuthIAMConfig(context)).rejects.toThrow( + 'Not authenticated' + ); + }); + + it('returns config on success', async () => { + vi.mocked(getLoginMethod).mockReturnValue('oauth'); + vi.mocked(getSelectedOrganization).mockReturnValue('my-org'); + const mockClient = { + isAuthenticated: vi.fn().mockResolvedValue(true), + getAccessToken: vi.fn().mockResolvedValue('tok-123'), + }; + vi.mocked(getAuthClient).mockReturnValue( + mockClient as ReturnType + ); + + const config = await getOAuthIAMConfig(context); + expect(config).toEqual({ + sessionToken: 'tok-123', + organizationId: 'my-org', + iamEndpoint: 'https://iam.test', + mgmtEndpoint: 'https://mgmt.test', + }); + }); + + it('returns undefined organizationId when no org selected', async () => { + vi.mocked(getLoginMethod).mockReturnValue('oauth'); + vi.mocked(getSelectedOrganization).mockReturnValue(null); + const mockClient = { + isAuthenticated: vi.fn().mockResolvedValue(true), + getAccessToken: vi.fn().mockResolvedValue('tok-123'), + }; + vi.mocked(getAuthClient).mockReturnValue( + mockClient as ReturnType + ); + + const config = await getOAuthIAMConfig(context); + expect(config.organizationId).toBeUndefined(); + }); +}); + +describe('getIAMConfig', () => { + it('delegates to getOAuthIAMConfig when type is oauth', async () => { + vi.mocked(resolveAuthMethod).mockResolvedValue({ + type: 'oauth', + } as Awaited>); + vi.mocked(getLoginMethod).mockReturnValue('oauth'); + const mockClient = { + isAuthenticated: vi.fn().mockResolvedValue(true), + getAccessToken: vi.fn().mockResolvedValue('tok-456'), + }; + vi.mocked(getAuthClient).mockReturnValue( + mockClient as ReturnType + ); + vi.mocked(getSelectedOrganization).mockReturnValue('org-1'); + + const config = await getIAMConfig(context); + expect(config).toHaveProperty('sessionToken', 'tok-456'); + }); + + it.each(['credentials', 'environment', 'configured', 'aws-profile'] as const)( + 'returns credential config when type is %s', + async (type) => { + vi.mocked(resolveAuthMethod).mockResolvedValue({ + type, + accessKeyId: 'ak-123', + secretAccessKey: 'sk-456', + } as Awaited>); + vi.mocked(getSelectedOrganization).mockReturnValue('org-2'); + + const config = await getIAMConfig(context); + expect(config).toEqual({ + accessKeyId: 'ak-123', + secretAccessKey: 'sk-456', + organizationId: 'org-2', + iamEndpoint: 'https://iam.test', + }); + } + ); + + it('throws when type is none', async () => { + vi.mocked(resolveAuthMethod).mockResolvedValue({ + type: 'none', + } as Awaited>); + + await expect(getIAMConfig(context)).rejects.toThrow('Not authenticated'); + }); +}); diff --git a/test/cli.test.ts b/test/cli.test.ts index e0b06cc..a71cda5 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -4,9 +4,14 @@ import { tmpdir } from 'os'; import { join } from 'path'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -import { getTestPrefix, shouldSkipIntegrationTests } from './setup.js'; +import { + getTestPrefix, + shouldSkipIntegrationTests, + shouldSkipOAuthTests, +} from './setup.js'; const skipTests = shouldSkipIntegrationTests(); +const skipOAuth = shouldSkipOAuthTests(); // Helper to run CLI commands with env vars for auth function runCli(args: string): { @@ -126,6 +131,16 @@ describe('CLI Help Commands', () => { expect(result.stdout).toContain('path'); }); + it('should show bundle help', () => { + const result = runCli('bundle help'); + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain('bundle'); + expect(result.stdout).toContain('--keys'); + expect(result.stdout).toContain('--output'); + expect(result.stdout).toContain('--compression'); + expect(result.stdout).toContain('--on-error'); + }); + it('should show configure help', () => { const result = runCli('configure help'); expect(result.exitCode).toBe(0); @@ -452,6 +467,129 @@ describe.skipIf(skipTests)('CLI Integration Tests', () => { }); }); + describe('bundle command', () => { + const bundleDir = 'bundle-test'; + const rootTxt = 'bundle-root.txt'; + const rootJson = 'bundle-root.json'; + const nestedTxt = `${bundleDir}/nested.txt`; + const nestedJson = `${bundleDir}/nested.json`; + const tmpDir = join(tmpdir(), `tigris-bundle-test-${Date.now()}`); + + beforeAll(() => { + mkdirSync(tmpDir, { recursive: true }); + + // Create test files at bucket root + const txtFile = join(tmpDir, 'root.txt'); + const jsonFile = join(tmpDir, 'root.json'); + writeFileSync(txtFile, 'hello from txt'); + writeFileSync(jsonFile, JSON.stringify({ hello: 'from json' })); + + runCli(`objects put ${testBucket} ${rootTxt} ${txtFile}`); + runCli(`objects put ${testBucket} ${rootJson} ${jsonFile}`); + + // Create test files in a folder + const nestedTxtFile = join(tmpDir, 'nested.txt'); + const nestedJsonFile = join(tmpDir, 'nested.json'); + writeFileSync(nestedTxtFile, 'nested txt content'); + writeFileSync(nestedJsonFile, JSON.stringify({ nested: true })); + + runCli(`mk ${testBucket}/${bundleDir}/`); + runCli(`objects put ${testBucket} ${nestedTxt} ${nestedTxtFile}`); + runCli(`objects put ${testBucket} ${nestedJson} ${nestedJsonFile}`); + }); + + afterAll(() => { + rmSync(tmpDir, { recursive: true, force: true }); + runCli(`rm ${t3(testBucket)}/${bundleDir} -r -f`); + runCli(`rm ${t3(testBucket)}/${rootTxt} -f`); + runCli(`rm ${t3(testBucket)}/${rootJson} -f`); + }); + + it('should bundle root objects with inline keys', () => { + const output = join(tmpDir, 'root-bundle.tar'); + const result = runCli( + `bundle ${testBucket} --keys ${rootTxt},${rootJson} --output ${output}` + ); + expect(result.exitCode).toBe(0); + expect(existsSync(output)).toBe(true); + + // Verify tar contents + const tarList = execSync(`tar tf ${output}`, { encoding: 'utf-8' }); + expect(tarList).toContain(rootTxt); + expect(tarList).toContain(rootJson); + }); + + it('should bundle with keys from file', () => { + const keysFile = join(tmpDir, 'keys.txt'); + writeFileSync(keysFile, `${rootTxt}\n${rootJson}\n`); + + const output = join(tmpDir, 'from-file.tar'); + const result = runCli( + `bundle ${testBucket} --keys ${keysFile} --output ${output}` + ); + expect(result.exitCode).toBe(0); + + const tarList = execSync(`tar tf ${output}`, { encoding: 'utf-8' }); + expect(tarList).toContain(rootTxt); + expect(tarList).toContain(rootJson); + }); + + it('should bundle nested objects with path prefix', () => { + const output = join(tmpDir, 'nested-bundle.tar'); + const result = runCli( + `bundle ${t3(testBucket)}/${bundleDir} --keys nested.txt,nested.json --output ${output}` + ); + expect(result.exitCode).toBe(0); + + const tarList = execSync(`tar tf ${output}`, { encoding: 'utf-8' }); + expect(tarList).toContain('nested.txt'); + expect(tarList).toContain('nested.json'); + }); + + it('should bundle with gzip compression', () => { + const output = join(tmpDir, 'compressed.tar.gz'); + const result = runCli( + `bundle ${testBucket} --keys ${rootTxt},${rootJson} --output ${output}` + ); + expect(result.exitCode).toBe(0); + + // tar should be able to decompress gzip + const tarList = execSync(`tar tzf ${output}`, { encoding: 'utf-8' }); + expect(tarList).toContain(rootTxt); + expect(tarList).toContain(rootJson); + }); + + it('should bundle with explicit compression flag', () => { + const output = join(tmpDir, 'explicit-gzip.tar'); + const result = runCli( + `bundle ${testBucket} --keys ${rootTxt} --compression gzip --output ${output}` + ); + expect(result.exitCode).toBe(0); + + // Despite .tar extension, content is gzip-compressed + const tarList = execSync(`tar tzf ${output}`, { encoding: 'utf-8' }); + expect(tarList).toContain(rootTxt); + }); + + it('should output JSON with --json flag', () => { + const output = join(tmpDir, 'json-mode.tar'); + const result = runCli( + `bundle ${testBucket} --keys ${rootTxt},${rootJson} --output ${output} --json` + ); + expect(result.exitCode).toBe(0); + + const parsed = JSON.parse(result.stdout.trim()); + expect(parsed.action).toBe('bundled'); + expect(parsed.bucket).toBe(testBucket); + expect(parsed.keys).toBe(2); + }); + + it('should fail with no keys provided', () => { + const result = runCli(`bundle ${testBucket}`); + expect(result.exitCode).not.toBe(0); + }); + }); + describe('folder auto-detection', () => { const autoFolder = 'autodetect'; const copiedFolder = 'copied'; @@ -1891,4 +2029,204 @@ describe.skipIf(skipTests)('CLI Integration Tests', () => { expect(result.stdout).toContain('Access verified'); }); }); + + describe('access-keys lifecycle', () => { + let createdKeyId: string | undefined; + const keyName = `${testPrefix}-ak`; + + afterAll(() => { + if (createdKeyId) { + runCli(`access-keys delete ${createdKeyId} --yes`); + } + }); + + it('should create an access key', () => { + const result = runCli(`access-keys create ${keyName} --format json`); + expect(result.exitCode).toBe(0); + const parsed = JSON.parse(result.stdout.trim()); + createdKeyId = parsed.id; + expect(parsed.name).toBe(keyName); + expect(parsed.secret).toBeTruthy(); + }); + + it('should get the access key', () => { + if (!createdKeyId) return; + const result = runCli(`access-keys get ${createdKeyId} --format json`); + expect(result.exitCode).toBe(0); + const parsed = JSON.parse(result.stdout.trim()); + expect(parsed.name).toBe(keyName); + expect(parsed.id).toBe(createdKeyId); + }); + + it('should list access keys and include the created one', () => { + if (!createdKeyId) return; + const result = runCli('access-keys list --format json'); + expect(result.exitCode).toBe(0); + const parsed = JSON.parse(result.stdout.trim()); + const found = parsed.items.some( + (k: { id: string }) => k.id === createdKeyId + ); + expect(found).toBe(true); + }); + + it('should assign bucket-specific role', () => { + if (!createdKeyId) return; + const result = runCli( + `access-keys assign ${createdKeyId} --bucket ${testBucket} --role Editor` + ); + expect(result.exitCode).toBe(0); + }); + + it('should assign admin role', () => { + if (!createdKeyId) return; + // Revoke bucket roles first, then assign admin + runCli(`access-keys assign ${createdKeyId} --revoke-roles`); + const result = runCli(`access-keys assign ${createdKeyId} --admin`); + expect(result.exitCode).toBe(0); + }); + + it('should revoke all roles', () => { + if (!createdKeyId) return; + const result = runCli( + `access-keys assign ${createdKeyId} --revoke-roles` + ); + expect(result.exitCode).toBe(0); + }); + + it('should rotate the access key', () => { + if (!createdKeyId) return; + const result = runCli( + `access-keys rotate ${createdKeyId} --yes --format json` + ); + expect(result.exitCode).toBe(0); + const parsed = JSON.parse(result.stdout.trim()); + expect(parsed.secret).toBeTruthy(); + }); + + it('should delete the access key', () => { + if (!createdKeyId) return; + const result = runCli(`access-keys delete ${createdKeyId} --yes`); + expect(result.exitCode).toBe(0); + createdKeyId = undefined; + }); + }); + + describe('access-keys error cases', () => { + it('should error on create without name', () => { + const result = runCli('access-keys create'); + expect(result.exitCode).not.toBe(0); + }); + + it('should error on get without id', () => { + const result = runCli('access-keys get'); + expect(result.exitCode).not.toBe(0); + }); + + it('should error on delete without --yes in non-TTY', () => { + const result = runCli('access-keys delete fake-id'); + expect(result.exitCode).toBe(1); + }); + + it('should error on rotate without --yes in non-TTY', () => { + const result = runCli('access-keys rotate fake-id'); + expect(result.exitCode).toBe(1); + }); + }); + + describe('whoami command', () => { + it('should show auth info', () => { + const result = runCli('whoami'); + expect(result.exitCode).toBe(0); + }); + + it('should show auth info with --format json', () => { + const result = runCli('whoami --format json'); + expect(result.exitCode).toBe(0); + expect(() => JSON.parse(result.stdout.trim())).not.toThrow(); + }); + }); +}); + +describe.skipIf(skipTests || skipOAuth)('OAuth Integration Tests', () => { + const testPrefix = getTestPrefix(); + + describe('iam policies lifecycle', () => { + let policyArn: string | undefined; + const policyName = `${testPrefix}-policy`; + + afterAll(() => { + if (policyArn) { + runCli(`iam policies delete --resource ${policyArn} --yes`); + } + }); + + it('should create a policy', () => { + const doc = JSON.stringify({ + Version: '2012-10-17', + Statement: [ + { Effect: 'Allow', Action: ['s3:GetObject'], Resource: ['*'] }, + ], + }); + const result = runCli( + `iam policies create --name ${policyName} --document '${doc}' --format json` + ); + expect(result.exitCode).toBe(0); + const parsed = JSON.parse(result.stdout.trim()); + policyArn = parsed.arn; + expect(parsed.name).toBe(policyName); + }); + + it('should list policies and include the created one', () => { + if (!policyArn) return; + const result = runCli('iam policies list --format json'); + expect(result.exitCode).toBe(0); + const parsed = JSON.parse(result.stdout.trim()); + const found = parsed.items.some( + (p: { resource: string }) => p.resource === policyArn + ); + expect(found).toBe(true); + }); + + it('should get the policy', () => { + if (!policyArn) return; + const result = runCli( + `iam policies get --resource ${policyArn} --format json` + ); + expect(result.exitCode).toBe(0); + }); + + it('should delete the policy', () => { + if (!policyArn) return; + const result = runCli( + `iam policies delete --resource ${policyArn} --yes` + ); + expect(result.exitCode).toBe(0); + policyArn = undefined; + }); + }); + + describe('iam users', () => { + it('should list users', () => { + const result = runCli('iam users list --format json'); + // May fail for Fly orgs — that's expected + if (result.exitCode === 0 && result.stdout.trim()) { + expect(() => JSON.parse(result.stdout.trim())).not.toThrow(); + } + }); + }); + + describe('organizations', () => { + it('should list organizations with --format table', () => { + const result = runCli('organizations list --format table'); + expect(result.exitCode).toBe(0); + }); + + it('should list organizations with --format json', () => { + const result = runCli('organizations list --format json'); + expect(result.exitCode).toBe(0); + if (result.stdout.trim()) { + expect(() => JSON.parse(result.stdout.trim())).not.toThrow(); + } + }); + }); }); diff --git a/test/setup.ts b/test/setup.ts index 68d2f19..7c30782 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -38,6 +38,20 @@ export function shouldSkipIntegrationTests(): boolean { return false; } +/** + * Check if OAuth-dependent integration tests should run. + * Set TIGRIS_OAUTH_TEST=true in the environment to enable. + */ +export function shouldSkipOAuthTests(): boolean { + if (!process.env.TIGRIS_OAUTH_TEST) { + console.warn( + 'Skipping OAuth integration tests - set TIGRIS_OAUTH_TEST=true to enable' + ); + return true; + } + return false; +} + /** * Generate a unique test prefix using nanosecond timestamp * Format: tigris-cli-test-{timestamp} diff --git a/test/utils/bucket-info.test.ts b/test/utils/bucket-info.test.ts new file mode 100644 index 0000000..c2f9ded --- /dev/null +++ b/test/utils/bucket-info.test.ts @@ -0,0 +1,381 @@ +import { describe, expect, it } from 'vitest'; + +import { buildBucketInfo } from '../../src/utils/bucket-info.js'; + +function makeResponse(overrides: Record = {}) { + return { + isSnapshotEnabled: false, + forkInfo: undefined, + sizeInfo: { + numberOfObjects: 10, + size: 1024, + numberOfObjectsAllVersions: 15, + }, + settings: { + defaultTier: 'STANDARD', + deleteProtection: false, + allowObjectAcl: false, + corsRules: [], + customDomain: undefined, + lifecycleRules: undefined, + ttlConfig: undefined, + notifications: undefined, + dataMigration: undefined, + }, + ...overrides, + } as Parameters[0]; +} + +function findValue( + info: { label: string; value: string }[], + label: string +): string | undefined { + return info.find((i) => i.label === label)?.value; +} + +describe('buildBucketInfo', () => { + describe('base fields', () => { + it('returns all base fields', () => { + const info = buildBucketInfo(makeResponse()); + const labels = info.map((i) => i.label); + expect(labels).toContain('Number of Objects'); + expect(labels).toContain('Total Size'); + expect(labels).toContain('All Versions Count'); + expect(labels).toContain('Default Tier'); + expect(labels).toContain('Snapshots Enabled'); + expect(labels).toContain('Delete Protection'); + expect(labels).toContain('Allow Object ACL'); + expect(labels).toContain('Custom Domain'); + expect(labels).toContain('Has Forks'); + }); + + it('formats number of objects', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'Number of Objects')).toBe('10'); + }); + + it('uses N/A when numberOfObjects is undefined', () => { + const info = buildBucketInfo( + makeResponse({ sizeInfo: { size: 0, numberOfObjectsAllVersions: 0 } }) + ); + expect(findValue(info, 'Number of Objects')).toBe('N/A'); + }); + + it('uses N/A when size is undefined', () => { + const info = buildBucketInfo( + makeResponse({ sizeInfo: { numberOfObjects: 0 } }) + ); + expect(findValue(info, 'Total Size')).toBe('N/A'); + }); + + it('formats size when defined', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'Total Size')).toBe('1.0 KB'); + }); + + it('uses N/A when numberOfObjectsAllVersions is undefined', () => { + const info = buildBucketInfo( + makeResponse({ sizeInfo: { numberOfObjects: 0, size: 0 } }) + ); + expect(findValue(info, 'All Versions Count')).toBe('N/A'); + }); + + it('shows custom domain as None when undefined', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'Custom Domain')).toBe('None'); + }); + + it('shows custom domain when defined', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + customDomain: 'cdn.example.com', + }, + }) + ); + expect(findValue(info, 'Custom Domain')).toBe('cdn.example.com'); + }); + + it('shows boolean fields as Yes/No', () => { + const info = buildBucketInfo( + makeResponse({ + isSnapshotEnabled: true, + settings: { + ...makeResponse().settings, + deleteProtection: true, + allowObjectAcl: true, + }, + }) + ); + expect(findValue(info, 'Snapshots Enabled')).toBe('Yes'); + expect(findValue(info, 'Delete Protection')).toBe('Yes'); + expect(findValue(info, 'Allow Object ACL')).toBe('Yes'); + }); + }); + + describe('fork info', () => { + it('shows Has Forks as No when forkInfo is undefined', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'Has Forks')).toBe('No'); + }); + + it('shows Has Forks as Yes when hasChildren is true', () => { + const info = buildBucketInfo( + makeResponse({ forkInfo: { hasChildren: true, parents: [] } }) + ); + expect(findValue(info, 'Has Forks')).toBe('Yes'); + }); + + it('adds Forked From and Fork Snapshot when parents exist', () => { + const info = buildBucketInfo( + makeResponse({ + forkInfo: { + hasChildren: false, + parents: [{ bucketName: 'parent-bucket', snapshot: 'snap-123' }], + }, + }) + ); + expect(findValue(info, 'Forked From')).toBe('parent-bucket'); + expect(findValue(info, 'Fork Snapshot')).toBe('snap-123'); + }); + + it('does not add fork fields when parents is empty', () => { + const info = buildBucketInfo( + makeResponse({ forkInfo: { hasChildren: false, parents: [] } }) + ); + expect(findValue(info, 'Forked From')).toBeUndefined(); + }); + }); + + describe('TTL config', () => { + it('does not add TTL when ttlConfig is undefined', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'TTL')).toBeUndefined(); + }); + + it('shows Disabled when ttlConfig.enabled is false', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + ttlConfig: { enabled: false }, + }, + }) + ); + expect(findValue(info, 'TTL')).toBe('Disabled'); + }); + + it('shows days when enabled with days', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + ttlConfig: { enabled: true, days: 30 }, + }, + }) + ); + expect(findValue(info, 'TTL')).toBe('30 days'); + }); + + it('shows date when enabled without days', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + ttlConfig: { enabled: true, date: '2025-12-31' }, + }, + }) + ); + expect(findValue(info, 'TTL')).toBe('2025-12-31'); + }); + + it('shows Enabled when enabled without days or date', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + ttlConfig: { enabled: true }, + }, + }) + ); + expect(findValue(info, 'TTL')).toBe('Enabled'); + }); + }); + + describe('lifecycle rules', () => { + it('does not add lifecycle rules when undefined', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'Lifecycle Rules')).toBeUndefined(); + }); + + it('does not add lifecycle rules when empty', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { ...makeResponse().settings, lifecycleRules: [] }, + }) + ); + expect(findValue(info, 'Lifecycle Rules')).toBeUndefined(); + }); + + it('formats rule with storage class and days', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + lifecycleRules: [ + { storageClass: 'GLACIER', days: 90, enabled: true }, + ], + }, + }) + ); + expect(findValue(info, 'Lifecycle Rules')).toBe('GLACIER after 90d'); + }); + + it('marks disabled rules', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + lifecycleRules: [ + { storageClass: 'GLACIER', days: 90, enabled: false }, + ], + }, + }) + ); + expect(findValue(info, 'Lifecycle Rules')).toBe( + 'GLACIER after 90d (disabled)' + ); + }); + + it('joins multiple rules with commas', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + lifecycleRules: [ + { storageClass: 'STANDARD_IA', days: 30, enabled: true }, + { storageClass: 'GLACIER', days: 90, enabled: true }, + ], + }, + }) + ); + expect(findValue(info, 'Lifecycle Rules')).toBe( + 'STANDARD_IA after 30d, GLACIER after 90d' + ); + }); + }); + + describe('CORS rules', () => { + it('does not add CORS when empty', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'CORS Rules')).toBeUndefined(); + }); + + it('shows rule count when corsRules has entries', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + corsRules: [{}, {}], + }, + }) + ); + expect(findValue(info, 'CORS Rules')).toBe('2 rule(s)'); + }); + }); + + describe('notifications', () => { + it('does not add notifications when undefined', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'Notifications')).toBeUndefined(); + }); + + it('shows Enabled when notifications.enabled is not false', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + notifications: { enabled: true }, + }, + }) + ); + expect(findValue(info, 'Notifications')).toBe('Enabled'); + }); + + it('shows Enabled when notifications.enabled is undefined', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { ...makeResponse().settings, notifications: {} }, + }) + ); + expect(findValue(info, 'Notifications')).toBe('Enabled'); + }); + + it('shows Disabled when notifications.enabled is false', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + notifications: { enabled: false }, + }, + }) + ); + expect(findValue(info, 'Notifications')).toBe('Disabled'); + }); + }); + + describe('data migration', () => { + it('does not add data migration when undefined', () => { + const info = buildBucketInfo(makeResponse()); + expect(findValue(info, 'Data Migration')).toBeUndefined(); + }); + + it('shows name and endpoint when both present', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + dataMigration: { name: 'aws-s3', endpoint: 's3.amazonaws.com' }, + }, + }) + ); + expect(findValue(info, 'Data Migration')).toBe( + 'aws-s3 (s3.amazonaws.com)' + ); + }); + + it('shows name when endpoint is absent', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + dataMigration: { name: 'aws-s3' }, + }, + }) + ); + expect(findValue(info, 'Data Migration')).toBe('aws-s3'); + }); + + it('shows Configured when both name and endpoint are absent', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { ...makeResponse().settings, dataMigration: {} }, + }) + ); + expect(findValue(info, 'Data Migration')).toBe('Configured'); + }); + + it('shows N/A for name when only endpoint is present', () => { + const info = buildBucketInfo( + makeResponse({ + settings: { + ...makeResponse().settings, + dataMigration: { endpoint: 's3.amazonaws.com' }, + }, + }) + ); + expect(findValue(info, 'Data Migration')).toBe('N/A (s3.amazonaws.com)'); + }); + }); +}); diff --git a/test/utils/concurrency.test.ts b/test/utils/concurrency.test.ts new file mode 100644 index 0000000..0a13225 --- /dev/null +++ b/test/utils/concurrency.test.ts @@ -0,0 +1,77 @@ +import { describe, expect, it } from 'vitest'; + +import { executeWithConcurrency } from '../../src/utils/concurrency.js'; + +describe('executeWithConcurrency', () => { + it('returns empty array for empty tasks', async () => { + const results = await executeWithConcurrency([], 4); + expect(results).toEqual([]); + }); + + it('executes a single task', async () => { + const tasks = [() => Promise.resolve('a')]; + const results = await executeWithConcurrency(tasks, 1); + expect(results).toEqual(['a']); + }); + + it('preserves result order', async () => { + const tasks = [ + () => new Promise((r) => setTimeout(() => r(3), 30)), + () => new Promise((r) => setTimeout(() => r(1), 10)), + () => new Promise((r) => setTimeout(() => r(2), 20)), + ]; + const results = await executeWithConcurrency(tasks, 3); + expect(results).toEqual([3, 1, 2]); + }); + + it('floors concurrency to 1 when 0', async () => { + const tasks = [() => Promise.resolve('ok')]; + const results = await executeWithConcurrency(tasks, 0); + expect(results).toEqual(['ok']); + }); + + it('floors concurrency to 1 when negative', async () => { + const tasks = [() => Promise.resolve('ok')]; + const results = await executeWithConcurrency(tasks, -5); + expect(results).toEqual(['ok']); + }); + + it('floors fractional concurrency', async () => { + const tasks = [() => Promise.resolve('a'), () => Promise.resolve('b')]; + const results = await executeWithConcurrency(tasks, 0.5); + expect(results).toEqual(['a', 'b']); + }); + + it('works when concurrency exceeds number of tasks', async () => { + const tasks = [() => Promise.resolve(1), () => Promise.resolve(2)]; + const results = await executeWithConcurrency(tasks, 100); + expect(results).toEqual([1, 2]); + }); + + it('limits concurrent execution to the specified concurrency', async () => { + let running = 0; + let maxRunning = 0; + + const makeTask = () => async () => { + running++; + maxRunning = Math.max(maxRunning, running); + await new Promise((r) => setTimeout(r, 20)); + running--; + return true; + }; + + const tasks = Array.from({ length: 8 }, makeTask); + await executeWithConcurrency(tasks, 3); + expect(maxRunning).toBeLessThanOrEqual(3); + expect(maxRunning).toBeGreaterThan(1); + }); + + it('propagates error from a failing task', async () => { + const tasks = [ + () => Promise.resolve('ok'), + () => Promise.reject(new Error('boom')), + () => Promise.resolve('ok'), + ]; + await expect(executeWithConcurrency(tasks, 2)).rejects.toThrow('boom'); + }); +}); diff --git a/test/utils/interactive.test.ts b/test/utils/interactive.test.ts new file mode 100644 index 0000000..fa5d5f0 --- /dev/null +++ b/test/utils/interactive.test.ts @@ -0,0 +1,55 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { requireInteractive } from '../../src/utils/interactive.js'; + +describe('requireInteractive', () => { + const originalIsTTY = process.stdin.isTTY; + const exitSpy = vi + .spyOn(process, 'exit') + .mockImplementation(() => undefined as never); + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + beforeEach(() => { + exitSpy.mockClear(); + errorSpy.mockClear(); + }); + + afterEach(() => { + Object.defineProperty(process.stdin, 'isTTY', { + value: originalIsTTY, + writable: true, + }); + }); + + it('does nothing when stdin is a TTY', () => { + Object.defineProperty(process.stdin, 'isTTY', { + value: true, + writable: true, + }); + requireInteractive('use --yes flag'); + expect(exitSpy).not.toHaveBeenCalled(); + expect(errorSpy).not.toHaveBeenCalled(); + }); + + it('prints error and exits when stdin is not a TTY', () => { + Object.defineProperty(process.stdin, 'isTTY', { + value: false, + writable: true, + }); + requireInteractive('use --yes flag'); + expect(errorSpy).toHaveBeenCalledTimes(2); + expect(exitSpy).toHaveBeenCalledWith(1); + }); + + it('includes the hint in the error message', () => { + Object.defineProperty(process.stdin, 'isTTY', { + value: false, + writable: true, + }); + requireInteractive('use --format json'); + const hintCall = errorSpy.mock.calls.find((call) => + String(call[0]).includes('use --format json') + ); + expect(hintCall).toBeTruthy(); + }); +}); diff --git a/test/utils/upload.test.ts b/test/utils/upload.test.ts new file mode 100644 index 0000000..102092f --- /dev/null +++ b/test/utils/upload.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, it } from 'vitest'; + +import { calculateUploadParams } from '../../src/utils/upload.js'; + +const MB = 1024 * 1024; +const GB = 1024 * MB; +const DEFAULT_PART_SIZE = 5 * MB; + +describe('calculateUploadParams', () => { + it.each([ + { fileSize: undefined, label: 'undefined' }, + { fileSize: 0, label: '0' }, + { fileSize: 1, label: '1 byte' }, + { fileSize: DEFAULT_PART_SIZE, label: '5 MB (exactly)' }, + ])('returns { multipart: false } when fileSize is $label', ({ fileSize }) => { + expect(calculateUploadParams(fileSize)).toEqual({ multipart: false }); + }); + + it('returns multipart config when fileSize exceeds 5 MB', () => { + const result = calculateUploadParams(DEFAULT_PART_SIZE + 1); + expect(result).toEqual({ + multipart: true, + partSize: DEFAULT_PART_SIZE, + queueSize: 10, + }); + }); + + it('keeps default partSize for files under 50 GB', () => { + const result = calculateUploadParams(10 * GB); + expect(result).toEqual({ + multipart: true, + partSize: DEFAULT_PART_SIZE, + queueSize: 10, + }); + }); + + it('recalculates partSize when file exceeds MAX_PARTS * DEFAULT_PART_SIZE', () => { + const fileSize = DEFAULT_PART_SIZE * 10_000 + 1; // just over 50 GB + const result = calculateUploadParams(fileSize); + expect(result.multipart).toBe(true); + if (result.multipart) { + expect(result.partSize).toBe(Math.ceil(fileSize / 10_000)); + expect(result.partSize).toBeGreaterThan(DEFAULT_PART_SIZE); + expect(result.queueSize).toBe(10); + } + }); + + it('handles very large files (1 TB)', () => { + const fileSize = 1024 * GB; + const result = calculateUploadParams(fileSize); + expect(result.multipart).toBe(true); + if (result.multipart) { + expect(result.partSize).toBe(Math.ceil(fileSize / 10_000)); + // Verify we stay within S3 part limit + expect(Math.ceil(fileSize / result.partSize)).toBeLessThanOrEqual(10_000); + } + }); +}); diff --git a/vitest.config.ts b/vitest.config.ts index 84dac24..335550f 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,9 +1,9 @@ -import { defineConfig } from 'vitest/config'; -import path from 'path'; import dotenv from 'dotenv'; +import path from 'path'; +import { defineConfig } from 'vitest/config'; -// Load .env for integration tests -dotenv.config({ path: path.resolve(__dirname, '.env') }); +// Load .env.test for integration tests +dotenv.config({ path: path.resolve(__dirname, '.env.test') }); export default defineConfig({ resolve: { @@ -15,7 +15,7 @@ export default defineConfig({ test: { globals: true, environment: 'node', - reporter: 'verbose', + reporters: 'verbose', include: ['test/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], exclude: ['node_modules', 'dist'], setupFiles: ['test/setup.ts'],