diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e9953a6..14fbbfb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,6 +27,7 @@ include: - shopware-action - twilio-action - stripe-action + - s3-action - smtp-action - github-action diff --git a/actions/s3-action/.gitignore b/actions/s3-action/.gitignore new file mode 100644 index 0000000..ddc3c2a --- /dev/null +++ b/actions/s3-action/.gitignore @@ -0,0 +1,3 @@ +.env +node_modules/ +dist/ diff --git a/actions/s3-action/Dockerfile b/actions/s3-action/Dockerfile new file mode 100644 index 0000000..08c4e6b --- /dev/null +++ b/actions/s3-action/Dockerfile @@ -0,0 +1,13 @@ +FROM node:24-alpine + +WORKDIR /app + +COPY package.json package-lock.json* ./ + +RUN npm ci + +COPY . . + +RUN npm run build + +CMD ["npm", "run", "start"] diff --git a/actions/s3-action/README.md b/actions/s3-action/README.md new file mode 100644 index 0000000..79cdc2a --- /dev/null +++ b/actions/s3-action/README.md @@ -0,0 +1,64 @@ +# S3 Action + +S3 / object storage integration for the **Hercules** automation platform. + +Works against AWS S3 and any S3-compatible provider (MinIO, Cloudflare R2, +DigitalOcean Spaces, ...) by pointing the `endpoint` config at that provider. + +## Functions + +The action exposes two parallel function sets. The **object** set is the +S3-native primitive: you give an explicit key and exchange the body as raw +(UTF-8 text) data. The **file** set works with hercules' standard `FILE` value +(base64 content plus a file name/content type), deriving object keys from the +file name — so a file downloaded from S3 can be piped directly into, say, an +HTTP upload, and vice versa. Pick the set that matches the data you have. + +### Object functions (raw data, explicit key) + +| Function | Description | +|----------|-------------| +| `uploadObject` | Upload raw text `Data` to an explicit `Key`, creating or overwriting the object. | +| `downloadObject` | Download an object's body as raw UTF-8 text, plus metadata. | +| `deleteObject` | Delete an object. | +| `listObjects` | List objects in a bucket, optionally filtered by prefix. | +| `createObjectPresignedUrl` | Generate a temporary signed URL for direct GET or PUT access. | + +### File functions (hercules `FILE` values) + +| Function | Description | +|----------|-------------| +| `uploadFiles` | Upload one or more `FILE` values, creating or overwriting them. Each file's key is its own name, optionally under a `KeyPrefix`. | +| `downloadFile` | Download an object's content as a `FILE` value (base64), plus metadata. | +| `deleteFile` | Delete a file. | +| `listFiles` | List files in a bucket, optionally filtered by prefix. | +| `createFilePresignedUrl` | Generate a temporary signed URL for direct GET or PUT access. | + +## Configuration + +| Config | Required | Description | +|--------|----------|-------------| +| `access_key_id` | no | Access key ID. Leave empty to fall back to the AWS SDK's default credential provider chain (env vars, shared config file, or an IAM role). | +| `secret_access_key` | no | Secret access key. Leave empty for the same default credential provider chain fallback. | +| `region` | no | Region to connect to. Defaults to `us-east-1`. | +| `endpoint` | no | Custom endpoint URL for S3-compatible providers. Empty uses AWS S3. | +| `bucket` | no | Default bucket used when a function call does not specify one. | + +Leaving both `access_key_id` and `secret_access_key` empty is the expected +setup when this action runs inside AWS (EC2/ECS/EKS) with an IAM role, rather +than a static key pair. + +When `endpoint` is set, requests use path-style addressing (required by most +S3-compatible providers); AWS S3 keeps using virtual-hosted-style requests. + +All API calls use the official +[`@aws-sdk/client-s3`](https://www.npmjs.com/package/@aws-sdk/client-s3) and +[`@aws-sdk/s3-request-presigner`](https://www.npmjs.com/package/@aws-sdk/s3-request-presigner) +packages. + +## Data types + +The `@Schema` data types are manually defined zod schemas covering the fields +each function needs — there is no vendor OpenAPI spec for the S3 API to +generate from. `S3_OBJECT_CONTENT`'s `File` field reuses hercules' built-in +`fileSchema`/`FILE` data type rather than inventing a bespoke one. diff --git a/actions/s3-action/manifest.json b/actions/s3-action/manifest.json new file mode 100644 index 0000000..5687e82 --- /dev/null +++ b/actions/s3-action/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "s3", + "identifier": "s3-action", + "description": "S3 / object storage integration: upload, download, list, and delete objects, and generate presigned URLs, against AWS S3 or any S3-compatible provider.", + "deployment": { + "docker": { + "image": "ghcr.io/code0-tech/centaurus/ci-builds/s3-action" + } + } +} diff --git a/actions/s3-action/package-lock.json b/actions/s3-action/package-lock.json new file mode 100644 index 0000000..aaf27ce --- /dev/null +++ b/actions/s3-action/package-lock.json @@ -0,0 +1,3793 @@ +{ + "name": "@code0-tech/s3-action", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@code0-tech/s3-action", + "version": "1.0.0", + "dependencies": { + "@aws-sdk/client-s3": "^3.700.0", + "@aws-sdk/s3-request-presigner": "^3.700.0", + "@code0-tech/hercules": "^1.1.1" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "tsx": "^4.0.0", + "typescript": "^5.9.3", + "vite": "^8.0.3", + "vitest": "^4.1.10" + } + }, + "node_modules/@aws-sdk/checksums": { + "version": "3.1002.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1002.1.tgz", + "integrity": "sha512-CXNESwkQC9jdrUG6cKXBfudVt1frGcYQykcCYbNclVrsewuGMbo3PlFjRteMe4OftNAqhyc3xC2jTz7SUqLasQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.1161.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1161.0.tgz", + "integrity": "sha512-iRZGMsJnYRrI98O+U6o5fHeLPQTP+Dc/w0mWLcBLQcEQ10DA06+XQj0WmdRiCM7vIso7QEtN1fsj9Vzo5/R3LQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/checksums": "^3.1002.1", + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/credential-provider-node": "^3.972.92", + "@aws-sdk/middleware-sdk-s3": "^3.972.85", + "@aws-sdk/signature-v4-multi-region": "^3.996.51", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.14.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.979.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.979.1.tgz", + "integrity": "sha512-ayOlV1VhLNMiq8PW9ZkVobG4gkldnUoHjG69yy2b8j+VYFlhz/uAL7ZdYQAoQ+eShtGUdNDnnG5rxDg6yUJrOg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.975.0", + "@aws-sdk/xml-builder": "^3.972.42", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.38.0", + "@smithy/signature-v4": "^5.7.5", + "@smithy/types": "^4.19.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.80", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.80.tgz", + "integrity": "sha512-uO5TiSvb6j1w9RTe5z28OaOmsrOxVQUPaC5+wZl50RfOXcrYD/KgnS8I9lfyGXc7sGbkCopK6VnhNIAoLqfewQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.82", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.82.tgz", + "integrity": "sha512-vQzlDHlC24Yz42p+rT4NBoP/5VdetkBoujbOLq9h6QYWC8THuZSPYnXIR9OP3XcOrdMgPBBipOrdssfxnIiWUg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.14.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.25", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.25.tgz", + "integrity": "sha512-b5xl71uCRdWsu7P1VeGpiGuCf6zfYETsSNOv8AmYVTrsgbvTJRXdmmOPVfxkvGGVNsiKkGctClQW3jAn0SZLug==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/credential-provider-env": "^3.972.80", + "@aws-sdk/credential-provider-http": "^3.972.82", + "@aws-sdk/credential-provider-login": "^3.972.87", + "@aws-sdk/credential-provider-process": "^3.972.80", + "@aws-sdk/credential-provider-sso": "^3.973.24", + "@aws-sdk/credential-provider-web-identity": "^3.972.86", + "@aws-sdk/nested-clients": "^3.997.54", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.87", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.87.tgz", + "integrity": "sha512-C4ZFmcwM+Zj14Z8huVUk54Gv4uzT1ZdzG9cY3Gdh8FePakq7Bss1OFsgZjAhWFOkFOGpBvFBeu0OWjWf8HNKRQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/nested-clients": "^3.997.54", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.92", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.92.tgz", + "integrity": "sha512-jC3zmOo7Qxlk+oBivvSsS1Ph7sFGm0QfuhqDGbqgRXi4cxUYMG+dWtBwS2XYYXgc8TIVXJiwgQ65sbNpbYupTA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.80", + "@aws-sdk/credential-provider-http": "^3.972.82", + "@aws-sdk/credential-provider-ini": "^3.973.25", + "@aws-sdk/credential-provider-process": "^3.972.80", + "@aws-sdk/credential-provider-sso": "^3.973.24", + "@aws-sdk/credential-provider-web-identity": "^3.972.86", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.80", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.80.tgz", + "integrity": "sha512-xqfixO5aclje7tbQJDias+iNND5wp/3QZixCdZcVQpgWPTZ0V5DfTW9A804A5Z7ezu7sH3WRO+vzUjtiJBA8yg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.24", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.24.tgz", + "integrity": "sha512-nlg3BKG03Cgzvv/dMnhxvDJPhAhQSpaN0RUdwgU7ziwkasoev7iI8el8Xy4Rd5sqzgaDUbV269fOXck5SargqA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/nested-clients": "^3.997.54", + "@aws-sdk/token-providers": "3.1161.0", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.86", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.86.tgz", + "integrity": "sha512-zKTyLJBEyfQBVlYqT6Jt+mYV4r8kGbWM7dn6v4Y4MRARizhYafjDXP/iMu76UMRhToSPNmIKX1XAb24gtpBFIA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/nested-clients": "^3.997.54", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.972.85", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.85.tgz", + "integrity": "sha512-Kyl2G6zhIS9qFoeLdlxvXFrWyc6g9D9ZCIRJnGkkfX6JZhxCZB5ebXBc7GKEeetrnhXcail6ALZT0lKbojcaNA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/signature-v4-multi-region": "^3.996.51", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.54", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.54.tgz", + "integrity": "sha512-/OczlavsS7U5sOodRO10Ug4R/AKFVZiXTstKipWe68EfjPkmdDFNXNl9FCJyXWkg1DG6RBm3qAuVB8FNW9O8KQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/signature-v4-multi-region": "^3.996.51", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.14.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner": { + "version": "3.1161.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.1161.0.tgz", + "integrity": "sha512-ACJ3DWmniBWI4mppBd9ro4aHwF68ImxyZnh/2fgDJHsZesNSByOU2tC/E9uhHX2FPhxrdzfRGnA2REgiNeIwwA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/signature-v4-multi-region": "^3.996.51", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.51", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.51.tgz", + "integrity": "sha512-+aHvUugVBuMPXxgkPfWnTMyGdE/yWS8GHi5+qQ37HowS0YqzrbuaDLznj+Dtmtu5jgCdqz36gXmujOToUhNNWw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.975.0", + "@smithy/signature-v4": "^5.7.5", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1161.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1161.0.tgz", + "integrity": "sha512-ypbXSofNcSHwf/KA40bFCXJb0MLaAKrfT7sot4dFaA+2lsuXNah4zLRJIAU7Qmvs9PFJ6rnY0bZFEC+mE7attA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.979.1", + "@aws-sdk/nested-clients": "^3.997.54", + "@aws-sdk/types": "^3.975.0", + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.975.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.975.0.tgz", + "integrity": "sha512-WQlhs6juByzWOzj5fwxOx0mPJaEqMcG/sDpl3Id61B3XhKE63xY+0QWcnG+sWR/sCfprmreyUo1lM7IKZmHMzw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.42", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.42.tgz", + "integrity": "sha512-smX8/gNP8Kjq+CWTBMZQLQ912vOQjiWExzwzvMO+eujPB5RY8IbtF0AGdUUXHKN7KoDWK9dIcuW0WG269kiP6w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@clack/core": { + "version": "1.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.0.0-alpha.4.tgz", + "integrity": "sha512-VCtU+vjyKPMSakVrB9q1bOnXN7QW/w4+YQDQCOF59GrzydW+169i0fVx/qzRRXJgt8KGj/pZZ/JxXroFZIDByg==", + "license": "MIT", + "peer": true, + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@clack/prompts": { + "version": "1.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.0.0-alpha.4.tgz", + "integrity": "sha512-KnmtDF2xQGoI5AlBme9akHtvCRV0RKAARUXHBQO2tMwnY8B08/4zPWigT7uLK25UPrMCEqnyQPkKRjNdhPbf8g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@clack/core": "1.0.0-alpha.4", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@code0-tech/hercules": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@code0-tech/hercules/-/hercules-1.7.2.tgz", + "integrity": "sha512-xRfolLdKOWC+oiNa7XRo8EeQSylwgq6XkcLhB0YocU8XeEc7qSaHWKJSNnhIDLOmAZzpa7OmpxZj6YFeweUqJg==", + "license": "ISC", + "bin": { + "hercules": "bin/hercules.js" + }, + "peerDependencies": { + "@code0-tech/tucana": "0.0.83", + "@grpc/grpc-js": "^1.14.3", + "@protobuf-ts/grpc-backend": "^2.11.1", + "@protobuf-ts/grpc-transport": "^2.11.1", + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1", + "reflect-metadata": "^0.2.2", + "ts-morph": "^28.0.0", + "ts-to-zod": "^5.1.0", + "zod": "^4.4.3", + "zod-to-ts": "^2.1.0" + } + }, + "node_modules/@code0-tech/tucana": { + "version": "0.0.83", + "resolved": "https://registry.npmjs.org/@code0-tech/tucana/-/tucana-0.0.83.tgz", + "integrity": "sha512-scBOjgf3oIQF8pUlskqPHqfzPvgCJgG1+/tt9RAKWZ1IdCdSqTRG768uEVeTjpuryiGRiO0p8r4bCXNEQNRtRg==", + "license": "MIT", + "peer": true + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.7.tgz", + "integrity": "sha512-W4W/fcBMGRVtG6dW2c7cw2mnpS3hvbBd+oQXjh2iYFTZDk1JJmcNqkM5KSaPubQpamlUUurrlb7G1s9NJeERmQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.1.tgz", + "integrity": "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@oclif/core": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.14.0.tgz", + "integrity": "sha512-QCJIZoVJxV7jywgVAUlsQwl3dr3Sa21kfi5z9KrYolbexWJUtFSEtMoNiBWojD05mYycLnB50gp/VxlGdaOCRA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-escapes": "^4.3.2", + "ansis": "^3.17.0", + "clean-stack": "^3.0.1", + "cli-spinners": "^2.9.2", + "debug": "^4.4.3", + "ejs": "^6", + "get-package-type": "^0.1.0", + "indent-string": "^4.0.0", + "lilconfig": "^3.1.3", + "minimatch": "^10.2.5", + "semver": "^7.8.1", + "string-width": "^4.2.3", + "supports-color": "^8", + "tinyglobby": "^0.2.17", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0", + "wsl-utils": "^0.4.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.156.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.156.0.tgz", + "integrity": "sha512-1Duyg48TdJNdyhEB8Xn1L36bT9Pv6GUtlKjHxOys8xkaF/rQq3XJE+bAurSK/AgIz5mGFsb77cn9Pb20+WCScw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@protobuf-ts/grpc-backend": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/grpc-backend/-/grpc-backend-2.11.1.tgz", + "integrity": "sha512-llAkJ03SlR/+p70YBTMOAQqdkXWghsTWwlPuGXC+Hj99hDQq6fa2CoVePPqbcn7A7/aLBcPG/9Ag3yqlltldxw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1" + }, + "peerDependencies": { + "@grpc/grpc-js": "^1.8.22" + } + }, + "node_modules/@protobuf-ts/grpc-transport": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/grpc-transport/-/grpc-transport-2.11.1.tgz", + "integrity": "sha512-l6wrcFffY+tuNnuyrNCkRM8hDIsAZVLA8Mn7PKdVyYxITosYh60qW663p9kL6TWXYuDCL3oxH8ih3vLKTDyhtg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1" + }, + "peerDependencies": { + "@grpc/grpc-js": "^1.6.0" + } + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz", + "integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)", + "peer": true + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz", + "integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.16.tgz", + "integrity": "sha512-ia3DwAs0OsMGS7+IConptSiyk9pEXkOx/AbJ2n/lAGxH3QkWQus1t8d7gnAT38FCU2sQu8lUbeR6AiZFv4JxaA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.16.tgz", + "integrity": "sha512-kx5wBiMB6E7TEvpl2B9gjLU004BkvEm2Dr941BFjx/SontPwSzNuQUIoVKxHHoSjpFIfHMmcguyLOtyn0hObRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.16.tgz", + "integrity": "sha512-qslZrXnKJU4cUpjoAmtAo/KQM9e2IRMlmpig6Zpwj+8KWxW8v+nkAf9216Bsek9lOC1jvg2yCjygCFo2f83msQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.16.tgz", + "integrity": "sha512-FdF+y48ND13eAyM2mQn+85kvAqNlvRWROy2rhgA463X/0Gv4vGtazZtfaF1mRBLscYvtOlh4QnLjOWiFzX69OQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.16.tgz", + "integrity": "sha512-ddjqFM5e95AgLbUPtKIS7V1KTVlA0RUgCVr5mn+/IEhsdy3pr+Vuj/HZ7nlMN2FyxIwUktOH1LEPIQXO1v9y1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.16.tgz", + "integrity": "sha512-tHdKWbFkFBI687iim3LIyIvyL7j66VvQYkDPss5Stn/qyE2tWkR1YD0dXmXPFKKqT/o5ZEJVsaRsWS2meQwGOA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.16.tgz", + "integrity": "sha512-FJiLGAblPBMlBEdbOqw6kW6QcXDWAf/oJu7gYs9ZJZwmg+K+/zjFLxPTIY9izJUzxzc24FHvmseyA0IvJSl17w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.16.tgz", + "integrity": "sha512-hrJpblMsrQ58U9veWpbXzkhV5zStunds6HWLprqq1qauvgBr1E6P+24kLj6lSLI9vjRn/RYpjprhkHQPKGWpNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.16.tgz", + "integrity": "sha512-qJd/dC6j6CwLG9/s/RP2nb1RZ0GIgj7Ioj7x/SYa3RzjVrlzrmH0fhIOpfvqQDeIsdP0loi+kHaMhJzY1PBIaA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.16.tgz", + "integrity": "sha512-Vx7Xg5uUJuNcujJjI70OICaH0EYj80BtOLZTSN7uOYg8QOLlyKnaG0IW7Fn/J0IpJsaKzmDKMhOQv1JBM9m9vg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.16.tgz", + "integrity": "sha512-TNKhgE3uJTsTzatUSSYt0Kgo+Oa2uSlSjz4r1aEIea7HX6ULBym4fAlYUhG1i6pjNf2njfCUAfKwr6C3E9Xg1w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.16.tgz", + "integrity": "sha512-7chXdpjXZ8qG0+mIxECN3cT9kvhZ3/oZhMX6Pp876P7CDrIy8nJswva6Mq357JR7eYXfuskwZxMeV1SzoZdHrA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.16.tgz", + "integrity": "sha512-Kwjt+7uNTJK5/MDkGWGVO2KQPnj8yAV75dMpfwyHZrJSXWHrniOB0aUEWlVYf3H1hOqFLIStLdM5QXq6bnKmOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.16.tgz", + "integrity": "sha512-/LH6WfjDRXXJz/p5xl4TmU+jpcnwcxbKEQBW/GZE0JHfN0lGIyTtsUEGaQ/q/GikkGJ2yLKe6pwm7AnEWO8pdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.16.tgz", + "integrity": "sha512-1lv1KvX0Z871zfk7vw+dnXMMnHNyDwMzWG8Kv3HxDXMOhzCX4SHc7HK319fInP0i+0p9D8brkfzL7pJOaGl+tw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@smithy/core": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.38.1.tgz", + "integrity": "sha512-U/mB2XiwTLaf+NSgLSWwJfptsMT/H8aBi0aTAA/E5e2/TagFeGCqAyhKGG0w0A9IWTkm4qYEmLoD/HB6aYfnRA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.8.0.tgz", + "integrity": "sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.18.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.14.1.tgz", + "integrity": "sha512-/T6E1jzCL0fErS9uq8JqES/5yYQQ4ppVmmYHwXw2nlov8KFzLb+3QqHR5iAun1BsuAB50IPxZliV8YMgghLwhA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.38.1", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.7.5", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.5.tgz", + "integrity": "sha512-WPjdr5oWOk1LArpI4pavu+fSo+/evi0Re1olxGvqwuZopd4gYR1UGCi+Soyn/IjmafqbWs+ZC+3AKxJS3ZpwUg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.38.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.19.0.tgz", + "integrity": "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ts-morph/common": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.29.0.tgz", + "integrity": "sha512-35oUmphHbJvQ/+UTwFNme/t2p3FoKiGJ5auTjjpNTop2dyREspirjMy82PLSC1pnDJ8ah1GU98hwpVt64YXQsg==", + "license": "MIT", + "peer": true, + "dependencies": { + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1", + "tinyglobby": "^0.2.14" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.10.tgz", + "integrity": "sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.5.tgz", + "integrity": "sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@typescript/vfs": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.5.tgz", + "integrity": "sha512-gobLHQLmvQGJInFk31NvgMd1uYzRXsd8qgnOssyLD055R2QPnw1ubRbBQ4+T+5qC7IQVuYXdvNDE2G7tMDVHgw==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.3" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.12.tgz", + "integrity": "sha512-vFlTt+YEu9WBpNjdGayNmlMVzrWPi1+sv853/7t2FU7hpO5gAFBKHzQmkCq5Xjpr+evegF2994LQT3hF3mRlqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.12", + "@vitest/utils": "4.1.12", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.12.tgz", + "integrity": "sha512-fKShNpKZzupWZuY0z7egydvL0sqW4INEZBEExMBMAa6izlENEVHwoXgdaTCaBZ5fwlr4xf2o1wXC83n9RpO+NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.12", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.12.tgz", + "integrity": "sha512-XW9O8+Mxx4VpCtkYdMJLZQQwsVryP9wk7cPKDxtXFfwSak6yRh5+2fep/Y0XF/ElBvJHq8bcYdi6aeuai0opZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.12.tgz", + "integrity": "sha512-NKlVKCr5QnCe8jijdMnmkpHHU+WTqiLFR6G0pHji9uRjXK9xJl1k1nTw6F3pOOj2PDcsDt2GKQMI7wIsaT491w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.12", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.12.tgz", + "integrity": "sha512-ko1y1Qgb/slzQ9mr+b89Cuqud8WG1TKtsPD8r7ZUBdvVOGt85Af2HwCqHujrhwJq95hs/9RM7fcAPg57o1vlzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.12", + "@vitest/utils": "4.1.12", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.12.tgz", + "integrity": "sha512-RGq9x4JNGNTZHEJxvN0oSiJjeSCExm0n2gZKKJZHY9cX5AVA6M7VJILBT3ZJ/tJ/0J9uWT7fETV9/btoi//vSg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.12.tgz", + "integrity": "sha512-Q3awXrwOfEV+qc3WmO5ONyE0yO7Q1gQ9/oyHxGLZ/pl7N3NO/ZztqQwKLuwMkV+CA1JYSIeO3gkHnRDIo4AVaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.12", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz", + "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "peer": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bowser": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.15.0.tgz", + "integrity": "sha512-xic6KSZglg/I4ymp45fdM4GWfYpBK79Fxd/TOvJktlaPgQqqDxvmGwOPZl2V0dyeS3Lj5c180bLhXF43iyAjZQ==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/chai": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "license": "MIT", + "peer": true, + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "peer": true, + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "license": "MIT", + "peer": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT", + "peer": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT", + "peer": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/ejs": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-6.0.1.tgz", + "integrity": "sha512-UaaM14yby8U3k02ihS1Bmj5Kz2d7CCQM1scxpgs4Mhkq8F1wR2gl3+Ts4h5Ne4Mnt7M9m4Dw7jsuMr3+xO4vZA==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.12.18" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "peer": true + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT", + "peer": true + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "peer": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.4.tgz", + "integrity": "sha512-zJZyBmQhArDRefuWTypZxwDpFDIYmrj8ypSBvwGD5P13Y95s6DjzKgu4DVdGbeQa5PDEsAOCAPNk4X+QOR006w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "license": "MIT", + "peer": true, + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT", + "peer": true + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT", + "peer": true + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "license": "MIT", + "peer": true, + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT", + "peer": true + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "peer": true + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/obug": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT", + "peer": true + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.32.tgz", + "integrity": "sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/protobufjs": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", + "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "peer": true, + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT", + "peer": true + }, + "node_modules/rolldown": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.16.tgz", + "integrity": "sha512-bWvlMpFKiTfDKfnK7FC2MPgPeWCf/Kpwsq49ApdW+FQaBZb6O6dZ4MAPbPUjp7hYQrw/RobqCzn64BRrQecGHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.156.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.16", + "@rolldown/binding-android-arm64": "1.2.16", + "@rolldown/binding-darwin-arm64": "1.2.16", + "@rolldown/binding-darwin-x64": "1.2.16", + "@rolldown/binding-freebsd-x64": "1.2.16", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.16", + "@rolldown/binding-linux-arm64-gnu": "1.2.16", + "@rolldown/binding-linux-arm64-musl": "1.2.16", + "@rolldown/binding-linux-ppc64-gnu": "1.2.16", + "@rolldown/binding-linux-s390x-gnu": "1.2.16", + "@rolldown/binding-linux-x64-gnu": "1.2.16", + "@rolldown/binding-linux-x64-musl": "1.2.16", + "@rolldown/binding-openharmony-arm64": "1.2.16", + "@rolldown/binding-win32-arm64-msvc": "1.2.16", + "@rolldown/binding-win32-x64-msvc": "1.2.16" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT", + "peer": true + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.3.0.tgz", + "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/text-camel-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-camel-case/-/text-camel-case-1.2.11.tgz", + "integrity": "sha512-2ZsM/gOlB1tyza+8lGLvs6gtPuZ9qEYuKPa+gwo38m65wkY4k323SK4hT7ku8r5wIKyspUYIWSk1aB9/Jjxr7A==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-pascal-case": "^1.2.11" + } + }, + "node_modules/text-capital-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-capital-case/-/text-capital-case-1.2.11.tgz", + "integrity": "sha512-30A7B7+VUvevEmPE0xWK1Z2z0ncl/JTjSUBLfjpoXrkwuPpmNTVbjHShRTN3cX9GIuZn/P3jvR+TO9JiTZcl8A==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-no-case": "^1.2.11", + "text-upper-case-first": "^1.2.11" + } + }, + "node_modules/text-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-case/-/text-case-1.2.11.tgz", + "integrity": "sha512-LbdWNQeuXWbfav+pxBxvaefkziffMYeSA53BHp52cgJa9rjiC0dkjum9AKrH8iQWoQJ4InGPSGexLeerGFaZ1Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-camel-case": "^1.2.11", + "text-capital-case": "^1.2.11", + "text-constant-case": "^1.2.11", + "text-dot-case": "^1.2.11", + "text-header-case": "^1.2.11", + "text-is-lower-case": "^1.2.11", + "text-is-upper-case": "^1.2.11", + "text-kebab-case": "^1.2.11", + "text-lower-case": "^1.2.11", + "text-lower-case-first": "^1.2.11", + "text-no-case": "^1.2.11", + "text-param-case": "^1.2.11", + "text-pascal-case": "^1.2.11", + "text-path-case": "^1.2.11", + "text-sentence-case": "^1.2.11", + "text-snake-case": "^1.2.11", + "text-swap-case": "^1.2.11", + "text-title-case": "^1.2.11", + "text-upper-case": "^1.2.11", + "text-upper-case-first": "^1.2.11" + } + }, + "node_modules/text-constant-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-constant-case/-/text-constant-case-1.2.11.tgz", + "integrity": "sha512-XnTBILsa7UpMWncUCchqIybZlg15FUcrlyNaWIJ8ybPy54qcoN513EXFswueyizuAgyJFXPCwwSFbSji6kw/Uw==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-no-case": "^1.2.11", + "text-upper-case": "^1.2.11" + } + }, + "node_modules/text-dot-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-dot-case/-/text-dot-case-1.2.11.tgz", + "integrity": "sha512-7SLKiT45KZO0qad0+p+GvC0+F+6pZ851HJcTcBJiSF88HsK/e1qErlGLtVBT6hkTHIaAj48WfSyQr4lZRv1xJQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-no-case": "^1.2.11" + } + }, + "node_modules/text-header-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-header-case/-/text-header-case-1.2.11.tgz", + "integrity": "sha512-7OBHd2g7X+aH6rXMC3cANFh6yvhXjXkyumw2NaRwJRIk343pP2e1SQCTCfowPDmmi8wkZVqz1fdWNq5LwvcBOQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-capital-case": "^1.2.11" + } + }, + "node_modules/text-is-lower-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-is-lower-case/-/text-is-lower-case-1.2.11.tgz", + "integrity": "sha512-dBqPAkNmX7eTM7ZbS3D/UBCQ5i9EXt5tujF2wIGGbZ1+aN8bY7Qda4mDpxgd6Hbzf/z10uQWRNzupl99wFQ8CQ==", + "license": "MIT", + "peer": true + }, + "node_modules/text-is-upper-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-is-upper-case/-/text-is-upper-case-1.2.11.tgz", + "integrity": "sha512-MZeUIYEYfKZ2FSeg0vnHCH4mHXLgGzes+iz2K+4BYnhnkEa2svKA1nNjQAqTUiVNHOPqPCuzmUr1LsyQZ73uyA==", + "license": "MIT", + "peer": true + }, + "node_modules/text-kebab-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-kebab-case/-/text-kebab-case-1.2.11.tgz", + "integrity": "sha512-RIg9iN6VwH+JrX9dFdm1nd1efPGR9LjNc0CiQz496sQETeKGkDEzxES/ZzxbkerrAL2DFEMGdLXckzDz1OEDBQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-no-case": "^1.2.11" + } + }, + "node_modules/text-lower-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-lower-case/-/text-lower-case-1.2.11.tgz", + "integrity": "sha512-txTy6y0y8M23Lhf0mk8WcvXTqlf4OQ3AGnDsRB6o3uMNfIa0CJDol2s1PdKNa63rt5B2277zkZCCn6Xeq//big==", + "license": "MIT", + "peer": true + }, + "node_modules/text-lower-case-first": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-lower-case-first/-/text-lower-case-first-1.2.11.tgz", + "integrity": "sha512-QR483XLyuyIpq8tKu1ds3Q1jfsgfaa/p9rtoQKHe6Rv5ah9ic/SUzTGN0MQ7UIS9APADd8SUPn5TTh1Z2/ACyg==", + "license": "MIT", + "peer": true + }, + "node_modules/text-no-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-no-case/-/text-no-case-1.2.11.tgz", + "integrity": "sha512-wazS7FEq0Ct3aJzeE8MEMcSs0eW4+/X/fwdotv/rG66bLS+g1T0pa0gUsbBGjjLFs191AIXVIry+bYE0uaaBBQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-lower-case": "^1.2.11" + } + }, + "node_modules/text-param-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-param-case/-/text-param-case-1.2.11.tgz", + "integrity": "sha512-3EMMAMLSz/mJXOnATNnrS+dZAvghpq09VhOVYDOkUnbm5zlYc6iU5AZOKVDpiAVVllQ9P1h5IKVZzsEYrdIRGw==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-dot-case": "^1.2.11" + } + }, + "node_modules/text-pascal-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-pascal-case/-/text-pascal-case-1.2.11.tgz", + "integrity": "sha512-BNhQ1O/g/Q4dH5gPyLIJLDLDknl2dipBwV629ScsiZCKJaCLGXYhTXp23rp9Htg3O5OSSsiU3mqDKq+pBmwTSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-no-case": "^1.2.11" + } + }, + "node_modules/text-path-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-path-case/-/text-path-case-1.2.11.tgz", + "integrity": "sha512-FsJU4BmMdtLtmnBK/XRJPqTwLF8yFiTEClHjxlQjSAG5Xt9R4p6D1WNaM1CI2dG5Lr4rsFM4jiVC620m0AsRbw==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-dot-case": "^1.2.11" + } + }, + "node_modules/text-sentence-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-sentence-case/-/text-sentence-case-1.2.11.tgz", + "integrity": "sha512-ApiVsvdLy+Wb8x7mZRVuoy8VO12jJ22G2djVM3ZZbUhXVIkqGgHxmiXRwdhRPoWGojK9n53m7jviJgBVNdRn+g==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-no-case": "^1.2.11", + "text-upper-case-first": "^1.2.11" + } + }, + "node_modules/text-snake-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-snake-case/-/text-snake-case-1.2.11.tgz", + "integrity": "sha512-NOEQvjyyVABB41SS8dUx423Y6hWS+Z4TrAAJg1xzCkOD3q9y0JtdJjCvCA1FWI8oDu+HiIOp/N446uDM8j54XQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-dot-case": "^1.2.11" + } + }, + "node_modules/text-swap-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-swap-case/-/text-swap-case-1.2.11.tgz", + "integrity": "sha512-PBmC5xvZdDZ4suikydpeXH0s4JV2XHelMj9/OEXEbA3oLpdV2A+B4BspVDWVw7C2Gi5eCareqk/7EE8I1/WwgQ==", + "license": "MIT", + "peer": true + }, + "node_modules/text-title-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-title-case/-/text-title-case-1.2.11.tgz", + "integrity": "sha512-V1GZy0XlqdkYUQm0tqm1jqtYlXJqFVMreBCTUReOaz8d/JbozTSpZrcakIeV8+1bN7LsvfhPFhA5zREiax6YIA==", + "license": "MIT", + "peer": true, + "dependencies": { + "text-no-case": "^1.2.11", + "text-upper-case-first": "^1.2.11" + } + }, + "node_modules/text-upper-case": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-upper-case/-/text-upper-case-1.2.11.tgz", + "integrity": "sha512-BfTL7yB1YIRlVGNdZUvno013hOq2cRs07fDR2ApppOXRDuKrEmsLDEY82xXlDzQHELp0jexqkI+NeyPIl6MtMw==", + "license": "MIT", + "peer": true + }, + "node_modules/text-upper-case-first": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/text-upper-case-first/-/text-upper-case-first-1.2.11.tgz", + "integrity": "sha512-vgfbwKo8TEJbRsapR9LWWvIJRnv8u9aXVa6cyYOAQQmurCx54Cnt59x5fKdiq+hFaBJ51AbzCgMpbP3p65/pHQ==", + "license": "MIT", + "peer": true + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ts-morph": { + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-28.0.0.tgz", + "integrity": "sha512-Wp3tnZ2bzwxyTZMtgWVzXDfm7lB1Drz+y9DmmYH/L702PQhPyVrp3pkou3yIz4qjS14GY9kcpmLiOOMvl8oG1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@ts-morph/common": "~0.29.0", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/ts-to-zod": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ts-to-zod/-/ts-to-zod-5.1.0.tgz", + "integrity": "sha512-giqqlvRHunlJqG9tBL/KAO3wWIVZGF//mZiWLKm/fdQnKnz4EN2mtiK5cugN9slytBkdMEXQIaLvMzIScbhhFw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@clack/prompts": "1.0.0-alpha.4", + "@oclif/core": "^4.5.4", + "@typescript/vfs": "^1.5.0", + "chokidar": "^4.0.3", + "listr2": "^9.0.4", + "slash": "^5.1.0", + "text-case": "^1.2.4", + "tslib": "^2.3.1", + "tsutils": "^3.21.0", + "typescript": "^5.2.2", + "zod": "^4.1.5" + }, + "bin": { + "ts-to-zod": "bin/run" + } + }, + "node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD", + "peer": true + }, + "node_modules/tsx": { + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/vite": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz", + "integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.30", + "rolldown": "~1.2.14", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1 || ^0.8.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.12.tgz", + "integrity": "sha512-5eWdz2yb3ajxWF3C8C4TjkXl7FGm3n2E/VlazALrQHzK7nYMSGFnCZto0bbPNl77AwkOZVLk0YnBAejUu0NiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.12", + "@vitest/mocker": "4.1.12", + "@vitest/pretty-format": "4.1.12", + "@vitest/runner": "4.1.12", + "@vitest/snapshot": "4.1.12", + "@vitest/spy": "4.1.12", + "@vitest/utils": "4.1.12", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.12", + "@vitest/browser-preview": "4.1.12", + "@vitest/browser-webdriverio": "^4.1.11", + "@vitest/coverage-istanbul": "4.1.12", + "@vitest/coverage-v8": "4.1.12", + "@vitest/ui": "4.1.12", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "license": "MIT", + "peer": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT", + "peer": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wsl-utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.4.0.tgz", + "integrity": "sha512-9YmF+2sFEd+T7TkwlmE337F0IVzfDvDknhtpBQxxXzEOfgPphGlFYpyx0cTuCIFj8/p+sqwBYAeGxOMNSzPPDA==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "license": "MIT", + "peer": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/zod": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-ts": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-2.1.0.tgz", + "integrity": "sha512-jZP1GokTqR99FLmtGU+B9acjD9u/R++b++Vxe1sWpBQDd82/9/j5LyLZZ7/Oy3h2nxcz5NihikgX4D0hhdu3+g==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "typescript": "^5 || ^6", + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/actions/s3-action/package.json b/actions/s3-action/package.json new file mode 100644 index 0000000..9d164f2 --- /dev/null +++ b/actions/s3-action/package.json @@ -0,0 +1,26 @@ +{ + "name": "@code0-tech/s3-action", + "version": "1.0.0", + "private": true, + "type": "module", + "main": "dist/index.js", + "scripts": { + "dev": "tsx watch src/index.ts", + "typecheck": "tsc --noEmit", + "build": "vite build", + "test": "vitest run", + "start": "node dist/index.js" + }, + "dependencies": { + "@aws-sdk/client-s3": "^3.700.0", + "@aws-sdk/s3-request-presigner": "^3.700.0", + "@code0-tech/hercules": "^1.1.1" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "tsx": "^4.0.0", + "typescript": "^5.9.3", + "vite": "^8.0.3", + "vitest": "^4.1.10" + } +} diff --git a/actions/s3-action/src/data_types/s3DeleteResult.ts b/actions/s3-action/src/data_types/s3DeleteResult.ts new file mode 100644 index 0000000..f061ccf --- /dev/null +++ b/actions/s3-action/src/data_types/s3DeleteResult.ts @@ -0,0 +1,17 @@ +import { DisplayMessage, Identifier, Name, Schema } from "@code0-tech/hercules"; +import { z } from "zod"; + +export const S3DeleteResultSchema = z.object({ + Key: z.string(), + Bucket: z.string(), + Deleted: z.boolean(), + DeleteMarker: z.boolean().optional(), + VersionId: z.string().optional(), +}); +export type S3DeleteResult = z.infer; + +@Identifier("S3_DELETE_RESULT") +@Name({ code: "en-US", content: "S3 delete result" }) +@DisplayMessage({ code: "en-US", content: "Deleted S3 object ${Key}" }) +@Schema(S3DeleteResultSchema) +export class S3DeleteResultDataType {} diff --git a/actions/s3-action/src/data_types/s3Object.ts b/actions/s3-action/src/data_types/s3Object.ts new file mode 100644 index 0000000..e686e89 --- /dev/null +++ b/actions/s3-action/src/data_types/s3Object.ts @@ -0,0 +1,17 @@ +import { DisplayMessage, Identifier, Name, Schema } from "@code0-tech/hercules"; +import { z } from "zod"; + +export const S3ObjectSchema = z.object({ + Key: z.string(), + Bucket: z.string(), + ETag: z.string().optional(), + Location: z.string(), + VersionId: z.string().optional(), +}); +export type S3Object = z.infer; + +@Identifier("S3_OBJECT") +@Name({ code: "en-US", content: "S3 object" }) +@DisplayMessage({ code: "en-US", content: "S3 object ${Key}" }) +@Schema(S3ObjectSchema) +export class S3ObjectDataType {} diff --git a/actions/s3-action/src/data_types/s3ObjectContent.ts b/actions/s3-action/src/data_types/s3ObjectContent.ts new file mode 100644 index 0000000..9e6f747 --- /dev/null +++ b/actions/s3-action/src/data_types/s3ObjectContent.ts @@ -0,0 +1,23 @@ +import { DisplayMessage, fileSchema, Identifier, Name, Schema } from "@code0-tech/hercules"; +import { z } from "zod"; + +/** + * File carries the downloaded body as a std FILE value (base64 content plus + * file name/content type) from hercules' `taurus-file` module, so it can be + * passed directly into any other function/action that accepts a FILE. + */ +export const S3ObjectContentSchema = z.object({ + Key: z.string(), + Bucket: z.string(), + File: fileSchema, + ContentLength: z.number().optional(), + ETag: z.string().optional(), + LastModified: z.string().optional(), +}); +export type S3ObjectContent = z.infer; + +@Identifier("S3_OBJECT_CONTENT") +@Name({ code: "en-US", content: "S3 object content" }) +@DisplayMessage({ code: "en-US", content: "S3 object content ${Key}" }) +@Schema(S3ObjectContentSchema) +export class S3ObjectContentDataType {} diff --git a/actions/s3-action/src/data_types/s3ObjectData.ts b/actions/s3-action/src/data_types/s3ObjectData.ts new file mode 100644 index 0000000..26fe4bd --- /dev/null +++ b/actions/s3-action/src/data_types/s3ObjectData.ts @@ -0,0 +1,26 @@ +import { DisplayMessage, Identifier, Name, Schema } from "@code0-tech/hercules"; +import { z } from "zod"; + +/** + * The raw (textual) body of an S3 object, used by the "object" function set. + * Unlike {@link S3_OBJECT_CONTENT} (the "file" set), this does not wrap a std + * FILE value: `Data` is the object body decoded as UTF-8 text, so it can be + * fed straight into text-oriented functions. Binary payloads should use the + * file set instead, which exchanges content as base64 FILE values. + */ +export const S3ObjectDataSchema = z.object({ + Key: z.string(), + Bucket: z.string(), + Data: z.string(), + ContentType: z.string().optional(), + ContentLength: z.number().optional(), + ETag: z.string().optional(), + LastModified: z.string().optional(), +}); +export type S3ObjectData = z.infer; + +@Identifier("S3_OBJECT_DATA") +@Name({ code: "en-US", content: "S3 object data" }) +@DisplayMessage({ code: "en-US", content: "S3 object data ${Key}" }) +@Schema(S3ObjectDataSchema) +export class S3ObjectDataDataType {} diff --git a/actions/s3-action/src/data_types/s3ObjectList.ts b/actions/s3-action/src/data_types/s3ObjectList.ts new file mode 100644 index 0000000..82e5b22 --- /dev/null +++ b/actions/s3-action/src/data_types/s3ObjectList.ts @@ -0,0 +1,25 @@ +import { DisplayMessage, Identifier, Name, Schema } from "@code0-tech/hercules"; +import { z } from "zod"; + +export const S3ObjectListSchema = z.object({ + Bucket: z.string(), + Prefix: z.string().optional(), + Objects: z.array( + z.object({ + Key: z.string(), + Size: z.number().optional(), + ETag: z.string().optional(), + LastModified: z.string().optional(), + StorageClass: z.string().optional(), + }) + ), + IsTruncated: z.boolean().optional(), + NextContinuationToken: z.string().optional(), +}); +export type S3ObjectList = z.infer; + +@Identifier("S3_OBJECT_LIST") +@Name({ code: "en-US", content: "S3 object list" }) +@DisplayMessage({ code: "en-US", content: "S3 objects in ${Bucket}" }) +@Schema(S3ObjectListSchema) +export class S3ObjectListDataType {} diff --git a/actions/s3-action/src/data_types/s3PresignedUrl.ts b/actions/s3-action/src/data_types/s3PresignedUrl.ts new file mode 100644 index 0000000..4dc15dc --- /dev/null +++ b/actions/s3-action/src/data_types/s3PresignedUrl.ts @@ -0,0 +1,17 @@ +import { DisplayMessage, Identifier, Name, Schema } from "@code0-tech/hercules"; +import { z } from "zod"; + +export const S3PresignedUrlSchema = z.object({ + Url: z.string(), + Key: z.string(), + Bucket: z.string(), + Operation: z.enum(["get", "put"]), + ExpiresInSeconds: z.number(), +}); +export type S3PresignedUrl = z.infer; + +@Identifier("S3_PRESIGNED_URL") +@Name({ code: "en-US", content: "S3 presigned URL" }) +@DisplayMessage({ code: "en-US", content: "Presigned URL for ${Key}" }) +@Schema(S3PresignedUrlSchema) +export class S3PresignedUrlDataType {} diff --git a/actions/s3-action/src/functions/files/createPresignedUrlFunction.ts b/actions/s3-action/src/functions/files/createPresignedUrlFunction.ts new file mode 100644 index 0000000..5bac0f3 --- /dev/null +++ b/actions/s3-action/src/functions/files/createPresignedUrlFunction.ts @@ -0,0 +1,90 @@ +import { GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; +import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + RuntimeError, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3PresignedUrl, S3PresignedUrlSchema } from "../../data_types/s3PresignedUrl.js"; + +@Identifier("createFilePresignedUrl") +@DisplayIcon("tabler:bucket") +@Signature('(Key: string, Operation?: "get"|"put", ExpiresInSeconds?: number, Bucket?: string): S3_PRESIGNED_URL') +@Name({ code: "en-US", content: "Create file presigned URL" }) +@DisplayMessage({ code: "en-US", content: "Create file presigned URL for ${Key}" }) +@Documentation({ + code: "en-US", + content: + "Generates a temporary, signed URL that grants direct GET or PUT access to a file without sharing the configured credentials. The URL expires after ExpiresInSeconds (default 900, i.e. 15 minutes).", +}) +@Description({ + code: "en-US", + content: "Generates a temporary presigned URL for a file.", +}) +@Parameter({ + runtimeName: "Key", + name: [{ code: "en-US", content: "Key" }], + description: [{ code: "en-US", content: "The object key (path) to grant access to within the bucket." }], +}) +@Parameter({ + runtimeName: "Operation", + name: [{ code: "en-US", content: "Operation" }], + description: [{ code: "en-US", content: "Whether the URL grants read ('get') or write ('put') access. Defaults to 'get'." }], + optional: true, +}) +@Parameter({ + runtimeName: "ExpiresInSeconds", + name: [{ code: "en-US", content: "Expires in (seconds)" }], + description: [{ code: "en-US", content: "How long the URL stays valid, in seconds. Defaults to 900 (15 minutes)." }], + optional: true, +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket the object lives in. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class CreateFilePresignedUrlFunction { + async run( + context: FunctionContext, + Key: string, + Operation?: "get" | "put", + ExpiresInSeconds?: number, + Bucket?: string + ): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + const operation = Operation ?? "get"; + const expiresIn = ExpiresInSeconds ?? 900; + + if (operation !== "get" && operation !== "put") { + throw new RuntimeError("S3_INVALID_PRESIGNED_URL_OPERATION", `Operation must be 'get' or 'put', got '${operation}'.`); + } + + try { + const command = + operation === "get" ? new GetObjectCommand({ Bucket: bucket, Key }) : new PutObjectCommand({ Bucket: bucket, Key }); + const url = await getSignedUrl(client, command, { expiresIn }); + + return S3PresignedUrlSchema.parse({ + Url: url, + Key, + Bucket: bucket, + Operation: operation, + ExpiresInSeconds: expiresIn, + }); + } catch (error) { + throw toRuntimeError("S3_CREATE_FILE_PRESIGNED_URL_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/files/deleteFileFunction.ts b/actions/s3-action/src/functions/files/deleteFileFunction.ts new file mode 100644 index 0000000..17706f7 --- /dev/null +++ b/actions/s3-action/src/functions/files/deleteFileFunction.ts @@ -0,0 +1,61 @@ +import { DeleteObjectCommand } from "@aws-sdk/client-s3"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3DeleteResult, S3DeleteResultSchema } from "../../data_types/s3DeleteResult.js"; + +@Identifier("deleteFile") +@DisplayIcon("tabler:bucket") +@Signature("(Key: string, Bucket?: string): S3_DELETE_RESULT") +@Name({ code: "en-US", content: "Delete file" }) +@DisplayMessage({ code: "en-US", content: "Delete file ${Key}" }) +@Documentation({ + code: "en-US", + content: "Deletes a file from S3 by its key. Deleting a key that does not exist is not an error.", +}) +@Description({ + code: "en-US", + content: "Deletes a file from S3.", +}) +@Parameter({ + runtimeName: "Key", + name: [{ code: "en-US", content: "Key" }], + description: [{ code: "en-US", content: "The object key (path) to delete within the bucket." }], +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to delete from. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class DeleteFileFunction { + async run(context: FunctionContext, Key: string, Bucket?: string): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + + try { + const result = await client.send(new DeleteObjectCommand({ Bucket: bucket, Key })); + + return S3DeleteResultSchema.parse({ + Key, + Bucket: bucket, + Deleted: true, + DeleteMarker: result.DeleteMarker, + VersionId: result.VersionId, + }); + } catch (error) { + throw toRuntimeError("S3_DELETE_FILE_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/files/downloadFileFunction.ts b/actions/s3-action/src/functions/files/downloadFileFunction.ts new file mode 100644 index 0000000..7aef070 --- /dev/null +++ b/actions/s3-action/src/functions/files/downloadFileFunction.ts @@ -0,0 +1,69 @@ +import { GetObjectCommand } from "@aws-sdk/client-s3"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3ObjectContent, S3ObjectContentSchema } from "../../data_types/s3ObjectContent.js"; + +@Identifier("downloadFile") +@DisplayIcon("tabler:bucket") +@Signature("(Key: string, Bucket?: string): S3_OBJECT_CONTENT") +@Name({ code: "en-US", content: "Download file" }) +@DisplayMessage({ code: "en-US", content: "Download file ${Key}" }) +@Documentation({ + code: "en-US", + content: + "Downloads an object from S3 and returns its content as a standard hercules FILE value (base64-encoded content plus content type), so it can be passed directly to other functions/actions that accept a FILE. To receive the body as raw text, use `Download object` instead.", +}) +@Description({ + code: "en-US", + content: "Downloads a file from S3.", +}) +@Parameter({ + runtimeName: "Key", + name: [{ code: "en-US", content: "Key" }], + description: [{ code: "en-US", content: "The object key (path) to read within the bucket." }], +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to read from. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class DownloadFileFunction { + async run(context: FunctionContext, Key: string, Bucket?: string): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + + try { + const result = await client.send(new GetObjectCommand({ Bucket: bucket, Key })); + const bytes = (await result.Body?.transformToByteArray()) ?? new Uint8Array(); + + return S3ObjectContentSchema.parse({ + Key, + Bucket: bucket, + File: { + contentType: result.ContentType, + fileName: Key.split("/").pop() || Key, + valueType: "base64", + value: Buffer.from(bytes).toString("base64"), + }, + ContentLength: result.ContentLength, + ETag: result.ETag, + LastModified: result.LastModified?.toISOString(), + }); + } catch (error) { + throw toRuntimeError("S3_DOWNLOAD_FILE_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/files/listFilesFunction.ts b/actions/s3-action/src/functions/files/listFilesFunction.ts new file mode 100644 index 0000000..3d17703 --- /dev/null +++ b/actions/s3-action/src/functions/files/listFilesFunction.ts @@ -0,0 +1,94 @@ +import { ListObjectsV2Command } from "@aws-sdk/client-s3"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3ObjectList, S3ObjectListSchema } from "../../data_types/s3ObjectList.js"; + +@Identifier("listFiles") +@DisplayIcon("tabler:bucket") +@Signature("(Prefix?: string, Bucket?: string, MaxKeys?: number, ContinuationToken?: string): S3_OBJECT_LIST") +@Name({ code: "en-US", content: "List files" }) +@DisplayMessage({ code: "en-US", content: "List files in ${Bucket}" }) +@Documentation({ + code: "en-US", + content: + "Lists files in a bucket, optionally filtered by key prefix. Results are paginated; pass the returned NextContinuationToken back in as ContinuationToken to fetch the next page.", +}) +@Description({ + code: "en-US", + content: "Lists files in a bucket.", +}) +@Parameter({ + runtimeName: "Prefix", + name: [{ code: "en-US", content: "Prefix" }], + description: [{ code: "en-US", content: "Only return files whose key starts with this prefix." }], + optional: true, +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to list. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +@Parameter({ + runtimeName: "MaxKeys", + name: [{ code: "en-US", content: "Max keys" }], + description: [{ code: "en-US", content: "The maximum number of keys to return in one page. Defaults to 1000." }], + optional: true, +}) +@Parameter({ + runtimeName: "ContinuationToken", + name: [{ code: "en-US", content: "Continuation token" }], + description: [{ code: "en-US", content: "Token from a previous call's NextContinuationToken, to fetch the next page." }], + optional: true, +}) +export class ListFilesFunction { + async run( + context: FunctionContext, + Prefix?: string, + Bucket?: string, + MaxKeys?: number, + ContinuationToken?: string + ): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + + try { + const result = await client.send( + new ListObjectsV2Command({ + Bucket: bucket, + ...(Prefix ? { Prefix } : {}), + ...(MaxKeys ? { MaxKeys } : {}), + ...(ContinuationToken ? { ContinuationToken } : {}), + }) + ); + + return S3ObjectListSchema.parse({ + Bucket: bucket, + Prefix, + Objects: (result.Contents ?? []).map((object) => ({ + Key: object.Key, + Size: object.Size, + ETag: object.ETag, + LastModified: object.LastModified?.toISOString(), + StorageClass: object.StorageClass, + })), + IsTruncated: result.IsTruncated, + NextContinuationToken: result.NextContinuationToken, + }); + } catch (error) { + throw toRuntimeError("S3_LIST_FILES_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/files/uploadFilesFunction.ts b/actions/s3-action/src/functions/files/uploadFilesFunction.ts new file mode 100644 index 0000000..f938490 --- /dev/null +++ b/actions/s3-action/src/functions/files/uploadFilesFunction.ts @@ -0,0 +1,98 @@ +import { PutObjectCommand } from "@aws-sdk/client-s3"; +import type { File } from "@code0-tech/hercules"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, resolveObjectKey, toRuntimeError } from "../../helpers.js"; +import { S3Object, S3ObjectSchema } from "../../data_types/s3Object.js"; + +@Identifier("uploadFiles") +@DisplayIcon("tabler:bucket") +@Signature('(Files: FILE<"*/*">[], KeyPrefix?: string, Bucket?: string): S3_OBJECT[]') +@Name({ code: "en-US", content: "Upload files" }) +@DisplayMessage({ code: "en-US", content: "Upload files under ${KeyPrefix}" }) +@Documentation({ + code: "en-US", + content: + "Uploads one or more files (standard hercules FILE values: base64 content plus a file name and optional content type) to S3, creating them or overwriting existing objects with the same key. Each file's key is its own name, optionally placed under `KeyPrefix` (e.g. `reports/`). To upload raw data at an explicit key, use `Upload object` instead.", +}) +@Description({ + code: "en-US", + content: "Uploads one or more files to S3.", +}) +@Parameter({ + runtimeName: "Files", + name: [{ code: "en-US", content: "Files" }], + description: [ + { + code: "en-US", + content: "The files to upload, as standard FILE values. Each file's name becomes its object key.", + }, + ], +}) +@Parameter({ + runtimeName: "KeyPrefix", + name: [{ code: "en-US", content: "Key prefix" }], + description: [ + { + code: "en-US", + content: + "Optional key prefix (folder) the files are uploaded under, e.g. `reports/`. Joined to each file name with a `/`. Omit to upload at the bucket root under each file's name.", + }, + ], + optional: true, +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to upload to. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class UploadFilesFunction { + async run(context: FunctionContext, Files: File<"*/*">[], KeyPrefix?: string, Bucket?: string): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + const files = Files ?? []; + + try { + return await Promise.all( + files.map(async (file) => { + const key = resolveObjectKey(file.fileName, KeyPrefix); + const body = Buffer.from(file.value, "base64"); + // `file.contentType` is generic/unknown at the schema level (hercules' + // FILE value doesn't parameterize it), but it's a string at runtime. + const contentType = typeof file.contentType === "string" ? file.contentType : undefined; + + const result = await client.send( + new PutObjectCommand({ + Bucket: bucket, + Key: key, + Body: body, + ...(contentType ? { ContentType: contentType } : {}), + }) + ); + + return S3ObjectSchema.parse({ + Key: key, + Bucket: bucket, + ETag: result.ETag, + Location: `${bucket}/${key}`, + VersionId: result.VersionId, + }); + }) + ); + } catch (error) { + throw toRuntimeError("S3_UPLOAD_FILES_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/objects/createPresignedUrlFunction.ts b/actions/s3-action/src/functions/objects/createPresignedUrlFunction.ts new file mode 100644 index 0000000..0982bc9 --- /dev/null +++ b/actions/s3-action/src/functions/objects/createPresignedUrlFunction.ts @@ -0,0 +1,90 @@ +import { GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; +import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + RuntimeError, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3PresignedUrl, S3PresignedUrlSchema } from "../../data_types/s3PresignedUrl.js"; + +@Identifier("createObjectPresignedUrl") +@DisplayIcon("tabler:bucket") +@Signature('(Key: string, Operation?: "get"|"put", ExpiresInSeconds?: number, Bucket?: string): S3_PRESIGNED_URL') +@Name({ code: "en-US", content: "Create object presigned URL" }) +@DisplayMessage({ code: "en-US", content: "Create object presigned URL for ${Key}" }) +@Documentation({ + code: "en-US", + content: + "Generates a temporary, signed URL that grants direct GET or PUT access to an object without sharing the configured credentials. The URL expires after ExpiresInSeconds (default 900, i.e. 15 minutes).", +}) +@Description({ + code: "en-US", + content: "Generates a temporary presigned URL for an object.", +}) +@Parameter({ + runtimeName: "Key", + name: [{ code: "en-US", content: "Key" }], + description: [{ code: "en-US", content: "The object key (path) to grant access to within the bucket." }], +}) +@Parameter({ + runtimeName: "Operation", + name: [{ code: "en-US", content: "Operation" }], + description: [{ code: "en-US", content: "Whether the URL grants read ('get') or write ('put') access. Defaults to 'get'." }], + optional: true, +}) +@Parameter({ + runtimeName: "ExpiresInSeconds", + name: [{ code: "en-US", content: "Expires in (seconds)" }], + description: [{ code: "en-US", content: "How long the URL stays valid, in seconds. Defaults to 900 (15 minutes)." }], + optional: true, +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket the object lives in. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class CreateObjectPresignedUrlFunction { + async run( + context: FunctionContext, + Key: string, + Operation?: "get" | "put", + ExpiresInSeconds?: number, + Bucket?: string + ): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + const operation = Operation ?? "get"; + const expiresIn = ExpiresInSeconds ?? 900; + + if (operation !== "get" && operation !== "put") { + throw new RuntimeError("S3_INVALID_PRESIGNED_URL_OPERATION", `Operation must be 'get' or 'put', got '${operation}'.`); + } + + try { + const command = + operation === "get" ? new GetObjectCommand({ Bucket: bucket, Key }) : new PutObjectCommand({ Bucket: bucket, Key }); + const url = await getSignedUrl(client, command, { expiresIn }); + + return S3PresignedUrlSchema.parse({ + Url: url, + Key, + Bucket: bucket, + Operation: operation, + ExpiresInSeconds: expiresIn, + }); + } catch (error) { + throw toRuntimeError("S3_CREATE_OBJECT_PRESIGNED_URL_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/objects/deleteObjectFunction.ts b/actions/s3-action/src/functions/objects/deleteObjectFunction.ts new file mode 100644 index 0000000..4a74d12 --- /dev/null +++ b/actions/s3-action/src/functions/objects/deleteObjectFunction.ts @@ -0,0 +1,61 @@ +import { DeleteObjectCommand } from "@aws-sdk/client-s3"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3DeleteResult, S3DeleteResultSchema } from "../../data_types/s3DeleteResult.js"; + +@Identifier("deleteObject") +@DisplayIcon("tabler:bucket") +@Signature("(Key: string, Bucket?: string): S3_DELETE_RESULT") +@Name({ code: "en-US", content: "Delete object" }) +@DisplayMessage({ code: "en-US", content: "Delete object ${Key}" }) +@Documentation({ + code: "en-US", + content: "Deletes an object from S3 by its key. Deleting a key that does not exist is not an error.", +}) +@Description({ + code: "en-US", + content: "Deletes an object from S3.", +}) +@Parameter({ + runtimeName: "Key", + name: [{ code: "en-US", content: "Key" }], + description: [{ code: "en-US", content: "The object key (path) to delete within the bucket." }], +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to delete from. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class DeleteObjectFunction { + async run(context: FunctionContext, Key: string, Bucket?: string): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + + try { + const result = await client.send(new DeleteObjectCommand({ Bucket: bucket, Key })); + + return S3DeleteResultSchema.parse({ + Key, + Bucket: bucket, + Deleted: true, + DeleteMarker: result.DeleteMarker, + VersionId: result.VersionId, + }); + } catch (error) { + throw toRuntimeError("S3_DELETE_OBJECT_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/objects/downloadObjectFunction.ts b/actions/s3-action/src/functions/objects/downloadObjectFunction.ts new file mode 100644 index 0000000..f053440 --- /dev/null +++ b/actions/s3-action/src/functions/objects/downloadObjectFunction.ts @@ -0,0 +1,65 @@ +import { GetObjectCommand } from "@aws-sdk/client-s3"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3ObjectData, S3ObjectDataSchema } from "../../data_types/s3ObjectData.js"; + +@Identifier("downloadObject") +@DisplayIcon("tabler:bucket") +@Signature("(Key: string, Bucket?: string): S3_OBJECT_DATA") +@Name({ code: "en-US", content: "Download object" }) +@DisplayMessage({ code: "en-US", content: "Download object ${Key}" }) +@Documentation({ + code: "en-US", + content: + "Downloads an object from S3 and returns its body as raw UTF-8 text. This is the object-storage primitive; to receive the content as a hercules FILE value (base64, for binary content or chaining into FILE-consuming functions), use `Download file` instead.", +}) +@Description({ + code: "en-US", + content: "Downloads an object from S3 as raw data.", +}) +@Parameter({ + runtimeName: "Key", + name: [{ code: "en-US", content: "Key" }], + description: [{ code: "en-US", content: "The object key (path) to read within the bucket." }], +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to read from. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class DownloadObjectFunction { + async run(context: FunctionContext, Key: string, Bucket?: string): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + + try { + const result = await client.send(new GetObjectCommand({ Bucket: bucket, Key })); + const data = (await result.Body?.transformToString("utf-8")) ?? ""; + + return S3ObjectDataSchema.parse({ + Key, + Bucket: bucket, + Data: data, + ContentType: result.ContentType, + ContentLength: result.ContentLength, + ETag: result.ETag, + LastModified: result.LastModified?.toISOString(), + }); + } catch (error) { + throw toRuntimeError("S3_DOWNLOAD_OBJECT_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/objects/listObjectsFunction.ts b/actions/s3-action/src/functions/objects/listObjectsFunction.ts new file mode 100644 index 0000000..aff6053 --- /dev/null +++ b/actions/s3-action/src/functions/objects/listObjectsFunction.ts @@ -0,0 +1,94 @@ +import { ListObjectsV2Command } from "@aws-sdk/client-s3"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3ObjectList, S3ObjectListSchema } from "../../data_types/s3ObjectList.js"; + +@Identifier("listObjects") +@DisplayIcon("tabler:bucket") +@Signature("(Prefix?: string, Bucket?: string, MaxKeys?: number, ContinuationToken?: string): S3_OBJECT_LIST") +@Name({ code: "en-US", content: "List objects" }) +@DisplayMessage({ code: "en-US", content: "List objects in ${Bucket}" }) +@Documentation({ + code: "en-US", + content: + "Lists objects in a bucket, optionally filtered by key prefix. Results are paginated; pass the returned NextContinuationToken back in as ContinuationToken to fetch the next page.", +}) +@Description({ + code: "en-US", + content: "Lists objects in a bucket.", +}) +@Parameter({ + runtimeName: "Prefix", + name: [{ code: "en-US", content: "Prefix" }], + description: [{ code: "en-US", content: "Only return objects whose key starts with this prefix." }], + optional: true, +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to list. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +@Parameter({ + runtimeName: "MaxKeys", + name: [{ code: "en-US", content: "Max keys" }], + description: [{ code: "en-US", content: "The maximum number of keys to return in one page. Defaults to 1000." }], + optional: true, +}) +@Parameter({ + runtimeName: "ContinuationToken", + name: [{ code: "en-US", content: "Continuation token" }], + description: [{ code: "en-US", content: "Token from a previous call's NextContinuationToken, to fetch the next page." }], + optional: true, +}) +export class ListObjectsFunction { + async run( + context: FunctionContext, + Prefix?: string, + Bucket?: string, + MaxKeys?: number, + ContinuationToken?: string + ): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + + try { + const result = await client.send( + new ListObjectsV2Command({ + Bucket: bucket, + ...(Prefix ? { Prefix } : {}), + ...(MaxKeys ? { MaxKeys } : {}), + ...(ContinuationToken ? { ContinuationToken } : {}), + }) + ); + + return S3ObjectListSchema.parse({ + Bucket: bucket, + Prefix, + Objects: (result.Contents ?? []).map((object) => ({ + Key: object.Key, + Size: object.Size, + ETag: object.ETag, + LastModified: object.LastModified?.toISOString(), + StorageClass: object.StorageClass, + })), + IsTruncated: result.IsTruncated, + NextContinuationToken: result.NextContinuationToken, + }); + } catch (error) { + throw toRuntimeError("S3_LIST_OBJECTS_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/functions/objects/uploadObjectFunction.ts b/actions/s3-action/src/functions/objects/uploadObjectFunction.ts new file mode 100644 index 0000000..3e7004a --- /dev/null +++ b/actions/s3-action/src/functions/objects/uploadObjectFunction.ts @@ -0,0 +1,83 @@ +import { PutObjectCommand } from "@aws-sdk/client-s3"; +import { + Description, + DisplayIcon, + DisplayMessage, + Documentation, + FunctionContext, + Identifier, + Name, + Parameter, + Signature, +} from "@code0-tech/hercules"; +import { getS3Client, resolveBucket, toRuntimeError } from "../../helpers.js"; +import { S3Object, S3ObjectSchema } from "../../data_types/s3Object.js"; + +@Identifier("uploadObject") +@DisplayIcon("tabler:bucket") +@Signature("(Key: string, Data: string, ContentType?: string, Bucket?: string): S3_OBJECT") +@Name({ code: "en-US", content: "Upload object" }) +@DisplayMessage({ code: "en-US", content: "Upload object ${Key}" }) +@Documentation({ + code: "en-US", + content: + "Uploads a single object to S3 (or an S3-compatible provider) at the exact `Key` given, from raw textual `Data`. This is the object-storage primitive: the key is explicit and the body is a UTF-8 string. To upload binary content or hercules FILE values, use `Upload files` instead.", +}) +@Description({ + code: "en-US", + content: "Uploads raw data to S3 at an explicit key.", +}) +@Parameter({ + runtimeName: "Key", + name: [{ code: "en-US", content: "Key" }], + description: [{ code: "en-US", content: "The object key (path) to write within the bucket." }], +}) +@Parameter({ + runtimeName: "Data", + name: [{ code: "en-US", content: "Data" }], + description: [{ code: "en-US", content: "The object body, as UTF-8 text." }], +}) +@Parameter({ + runtimeName: "ContentType", + name: [{ code: "en-US", content: "Content type" }], + description: [ + { code: "en-US", content: "Optional MIME type stored with the object. Defaults to 'text/plain; charset=utf-8'." }, + ], + optional: true, +}) +@Parameter({ + runtimeName: "Bucket", + name: [{ code: "en-US", content: "Bucket" }], + description: [ + { code: "en-US", content: "The bucket to upload to. Falls back to the configured default bucket when omitted." }, + ], + optional: true, +}) +export class UploadObjectFunction { + async run(context: FunctionContext, Key: string, Data: string, ContentType?: string, Bucket?: string): Promise { + const bucket = resolveBucket(context, Bucket); + const client = getS3Client(context); + const contentType = ContentType || "text/plain; charset=utf-8"; + + try { + const result = await client.send( + new PutObjectCommand({ + Bucket: bucket, + Key, + Body: Buffer.from(Data ?? "", "utf-8"), + ContentType: contentType, + }) + ); + + return S3ObjectSchema.parse({ + Key, + Bucket: bucket, + ETag: result.ETag, + Location: `${bucket}/${Key}`, + VersionId: result.VersionId, + }); + } catch (error) { + throw toRuntimeError("S3_UPLOAD_OBJECT_FAILED", error); + } + } +} diff --git a/actions/s3-action/src/helpers.ts b/actions/s3-action/src/helpers.ts new file mode 100644 index 0000000..b4d54dc --- /dev/null +++ b/actions/s3-action/src/helpers.ts @@ -0,0 +1,82 @@ +import { S3Client } from "@aws-sdk/client-s3"; +import { FunctionContext, RuntimeError } from "@code0-tech/hercules"; + +/** + * Builds an S3 client from the action configuration. + * + * A fresh client is built per call: a single action process serves many flows, + * each with its own matched config (different credentials, region or endpoint), + * so there is no single client that can be safely reused across invocations. + * Uses the official `@aws-sdk/client-s3`, which works against AWS S3 and any + * S3-compatible provider (MinIO, Cloudflare R2, DigitalOcean Spaces, ...) by + * pointing `endpoint` at that provider. + * + * access_key_id / secret_access_key are optional: when either is left + * unconfigured, the AWS SDK's default credential provider chain is used + * instead (environment variables, shared config/credentials file, or an + * IAM role), which is the common setup when this action runs inside AWS + * (EC2/ECS/EKS) rather than with a static key pair. + */ +export function getS3Client(context: FunctionContext): S3Client { + const accessKeyId = (context.matchedConfig.findConfig("access_key_id") as string) || ""; + const secretAccessKey = (context.matchedConfig.findConfig("secret_access_key") as string) || ""; + const region = (context.matchedConfig.findConfig("region") as string) || "us-east-1"; + const endpoint = (context.matchedConfig.findConfig("endpoint") as string) || ""; + + return new S3Client({ + region, + ...(accessKeyId && secretAccessKey ? { credentials: { accessKeyId, secretAccessKey } } : {}), + // A custom endpoint is only set for S3-compatible providers (MinIO, + // R2, Spaces, ...), which virtually always require path-style + // addressing. Real AWS S3 keeps using virtual-hosted-style requests. + ...(endpoint ? { endpoint, forcePathStyle: true } : {}), + }); +} + +/** + * Resolves the bucket to operate on: an explicit per-call override, falling + * back to the action's configured default bucket. + */ +export function resolveBucket(context: FunctionContext, bucket?: string): string { + const resolved = bucket || (context.matchedConfig.findConfig("bucket") as string) || ""; + if (!resolved) { + throw new RuntimeError( + "S3_MISSING_BUCKET", + "No bucket provided. Pass a Bucket value or configure a default 'bucket' for the action." + ); + } + return resolved; +} + +/** + * Builds the object key for an uploaded file. The key is the file's own + * `fileName` (the FILE value always carries one), optionally placed under a + * key prefix so several files can be uploaded into the same "folder". The + * prefix and file name are joined with a single `/` unless the prefix is empty + * or already ends with one. + */ +export function resolveObjectKey(fileName: string, prefix?: string): string { + const name = fileName || ""; + if (!name) { + throw new RuntimeError( + "S3_MISSING_FILE_NAME", + "A file to upload is missing its file name; cannot derive an object key for it." + ); + } + const normalizedPrefix = prefix || ""; + if (!normalizedPrefix) { + return name; + } + return normalizedPrefix.endsWith("/") ? `${normalizedPrefix}${name}` : `${normalizedPrefix}/${name}`; +} + +/** + * Maps an error thrown by the AWS SDK (or anything else) into a Hercules + * RuntimeError with a stable code and a human readable message. + */ +export function toRuntimeError(code: string, error: unknown): RuntimeError { + if (error instanceof Error) { + return new RuntimeError(code, error.message); + } + return new RuntimeError(code, "An unexpected error occurred while calling the S3 API."); +} diff --git a/actions/s3-action/src/index.ts b/actions/s3-action/src/index.ts new file mode 100644 index 0000000..bbe2900 --- /dev/null +++ b/actions/s3-action/src/index.ts @@ -0,0 +1,144 @@ +import "reflect-metadata"; +import { Action, CodeZeroEvent } from "@code0-tech/hercules"; + +import { S3ObjectDataType } from "./data_types/s3Object.js"; +import { S3ObjectContentDataType } from "./data_types/s3ObjectContent.js"; +import { S3ObjectDataDataType } from "./data_types/s3ObjectData.js"; +import { S3DeleteResultDataType } from "./data_types/s3DeleteResult.js"; +import { S3ObjectListDataType } from "./data_types/s3ObjectList.js"; +import { S3PresignedUrlDataType } from "./data_types/s3PresignedUrl.js"; + +// Object function set: S3-native primitives (explicit key + raw data). +import { UploadObjectFunction } from "./functions/objects/uploadObjectFunction.js"; +import { DownloadObjectFunction } from "./functions/objects/downloadObjectFunction.js"; +import { DeleteObjectFunction } from "./functions/objects/deleteObjectFunction.js"; +import { ListObjectsFunction } from "./functions/objects/listObjectsFunction.js"; +import { CreateObjectPresignedUrlFunction } from "./functions/objects/createPresignedUrlFunction.js"; + +// File function set: hercules FILE values (keys derived from file names). +import { UploadFilesFunction } from "./functions/files/uploadFilesFunction.js"; +import { DownloadFileFunction } from "./functions/files/downloadFileFunction.js"; +import { DeleteFileFunction } from "./functions/files/deleteFileFunction.js"; +import { ListFilesFunction } from "./functions/files/listFilesFunction.js"; +import { CreateFilePresignedUrlFunction } from "./functions/files/createPresignedUrlFunction.js"; + +const action = new Action( + process.env.ACTION_ID ?? "s3-action", + process.env.VERSION ?? "1.0.0", + process.env.AQUILA_URL ?? "127.0.0.1:8081", + "CodeZero", + "tabler:bucket", + "S3 / object storage integration against AWS S3 or any S3-compatible provider. Offers a parallel object set (raw data at an explicit key) and file set (hercules FILE values keyed by file name): upload, download, list, delete, and presigned URLs.", + [{ code: "en-US", content: "S3" }], + [ + { + identifier: "access_key_id", + type: "TEXT", + optional: true, + name: [{ code: "en-US", content: "Access key ID" }], + description: [ + { + code: "en-US", + content: + "The access key ID used to authenticate with the S3 API. Leave empty to fall back to the AWS SDK's default credential provider chain (environment variables, shared config file, or an IAM role).", + }, + ], + linkedDataTypes: ["TEXT"], + }, + { + identifier: "secret_access_key", + type: "TEXT", + optional: true, + name: [{ code: "en-US", content: "Secret access key" }], + description: [ + { + code: "en-US", + content: + "The secret access key used to authenticate with the S3 API. Leave empty to fall back to the AWS SDK's default credential provider chain.", + }, + ], + linkedDataTypes: ["TEXT"], + }, + { + identifier: "region", + type: "TEXT", + defaultValue: "us-east-1", + name: [{ code: "en-US", content: "Region" }], + description: [ + { + code: "en-US", + content: "The region to connect to, e.g. us-east-1. S3-compatible providers may require a placeholder such as 'auto'.", + }, + ], + linkedDataTypes: ["TEXT"], + }, + { + identifier: "endpoint", + type: "TEXT", + defaultValue: "", + name: [{ code: "en-US", content: "Endpoint" }], + description: [ + { + code: "en-US", + content: + "Optional custom endpoint URL for S3-compatible providers (MinIO, Cloudflare R2, DigitalOcean Spaces, ...). Leave empty to use AWS S3.", + }, + ], + linkedDataTypes: ["TEXT"], + }, + { + identifier: "bucket", + type: "TEXT", + defaultValue: "", + name: [{ code: "en-US", content: "Default bucket" }], + description: [ + { code: "en-US", content: "Optional default bucket used when a function call does not specify one." }, + ], + linkedDataTypes: ["TEXT"], + }, + ] +); + +action.registerDataTypeClass(S3ObjectDataType); +action.registerDataTypeClass(S3ObjectContentDataType); +action.registerDataTypeClass(S3ObjectDataDataType); +action.registerDataTypeClass(S3DeleteResultDataType); +action.registerDataTypeClass(S3ObjectListDataType); +action.registerDataTypeClass(S3PresignedUrlDataType); + +action.registerRuntimeFunction(UploadObjectFunction); +action.registerRuntimeFunction(DownloadObjectFunction); +action.registerRuntimeFunction(DeleteObjectFunction); +action.registerRuntimeFunction(ListObjectsFunction); +action.registerRuntimeFunction(CreateObjectPresignedUrlFunction); + +action.registerRuntimeFunction(UploadFilesFunction); +action.registerRuntimeFunction(DownloadFileFunction); +action.registerRuntimeFunction(DeleteFileFunction); +action.registerRuntimeFunction(ListFilesFunction); +action.registerRuntimeFunction(CreateFilePresignedUrlFunction); + +action.on(CodeZeroEvent.connected, () => { + console.log("Connected to aquila"); +}); + +action.on(CodeZeroEvent.error, (error: Error) => { + console.error("Stream error:", error.message); + console.log("Attempting to reconnect in 5s..."); + setTimeout(() => { + action.connect(process.env.AUTH_TOKEN ?? "your_auth_token_here").catch((err: Error) => { + action.emit(CodeZeroEvent.error, err); + }); + }, 5000); +}); + +action.connect(process.env.AUTH_TOKEN ?? "your_auth_token_here").catch((err: Error) => { + action.emit(CodeZeroEvent.error, err); +}); + +action.on(CodeZeroEvent.moduleUpdated, (message: any) => { + console.dir(message, { depth: null }); + console.dir(action.configs.values(), { depth: null }); +}); + +export { action }; diff --git a/actions/s3-action/test/index.test.ts b/actions/s3-action/test/index.test.ts new file mode 100644 index 0000000..c6c26de --- /dev/null +++ b/actions/s3-action/test/index.test.ts @@ -0,0 +1,149 @@ +import "reflect-metadata"; +import { describe, expect, it } from "vitest"; +import type { FunctionContext } from "@code0-tech/hercules"; +import { RuntimeError } from "@code0-tech/hercules"; +import { S3ObjectSchema } from "../src/data_types/s3Object.js"; +import { S3ObjectContentSchema } from "../src/data_types/s3ObjectContent.js"; +import { S3ObjectDataSchema } from "../src/data_types/s3ObjectData.js"; +import { S3DeleteResultSchema } from "../src/data_types/s3DeleteResult.js"; +import { S3ObjectListSchema } from "../src/data_types/s3ObjectList.js"; +import { S3PresignedUrlSchema } from "../src/data_types/s3PresignedUrl.js"; +import { getS3Client, resolveBucket, resolveObjectKey } from "../src/helpers.js"; + +function makeContext(configValues: Record): FunctionContext { + return { + projectId: 1, + executionId: "test-execution", + matchedConfig: { + projectId: 1, + configValues: Object.entries(configValues).map(([identifier, value]) => ({ identifier, value: value as any })), + findConfig: (identifier: string) => configValues[identifier] as any, + }, + executeFlow: async () => null, + }; +} + +describe("S3ObjectSchema", () => { + it("parses a representative put-object result", () => { + const parsed = S3ObjectSchema.parse({ + Key: "reports/2026-11-01.json", + Bucket: "my-bucket", + ETag: '"d41d8cd98f00b204e9800998ecf8427e"', + Location: "my-bucket/reports/2026-11-01.json", + }); + expect(parsed.Key).toEqual("reports/2026-11-01.json"); + }); +}); + +describe("S3ObjectContentSchema", () => { + it("parses a representative get-object result with a base64 FILE value", () => { + const parsed = S3ObjectContentSchema.parse({ + Key: "reports/2026-11-01.json", + Bucket: "my-bucket", + File: { + contentType: "application/json", + fileName: "2026-11-01.json", + valueType: "base64", + value: Buffer.from('{"status":"ok"}').toString("base64"), + }, + ContentLength: 16, + }); + expect(Buffer.from(parsed.File.value, "base64").toString("utf-8")).toEqual('{"status":"ok"}'); + }); +}); + +describe("S3ObjectDataSchema", () => { + it("parses a representative get-object result with a raw text body", () => { + const parsed = S3ObjectDataSchema.parse({ + Key: "reports/2026-11-01.json", + Bucket: "my-bucket", + Data: '{"status":"ok"}', + ContentType: "application/json", + ContentLength: 16, + }); + expect(parsed.Data).toEqual('{"status":"ok"}'); + }); +}); + +describe("S3DeleteResultSchema", () => { + it("parses a representative delete result", () => { + const parsed = S3DeleteResultSchema.parse({ Key: "obsolete.txt", Bucket: "my-bucket", Deleted: true }); + expect(parsed.Bucket).toEqual("my-bucket"); + expect(parsed.Deleted).toBe(true); + }); +}); + +describe("S3ObjectListSchema", () => { + it("parses a representative list-objects result", () => { + const parsed = S3ObjectListSchema.parse({ + Bucket: "my-bucket", + Prefix: "reports/", + Objects: [{ Key: "reports/2026-11-01.json", Size: 16 }], + IsTruncated: false, + }); + expect(parsed.Objects).toHaveLength(1); + }); +}); + +describe("S3PresignedUrlSchema", () => { + it("parses a representative presigned-url result", () => { + const parsed = S3PresignedUrlSchema.parse({ + Url: "https://my-bucket.s3.amazonaws.com/key?X-Amz-Signature=...", + Key: "reports/2026-11-01.json", + Bucket: "my-bucket", + Operation: "get", + ExpiresInSeconds: 900, + }); + expect(parsed.Operation).toEqual("get"); + }); +}); + +describe("resolveBucket", () => { + it("prefers an explicit bucket override", () => { + const context = makeContext({ bucket: "default-bucket" }); + expect(resolveBucket(context, "override-bucket")).toEqual("override-bucket"); + }); + + it("falls back to the configured default bucket", () => { + const context = makeContext({ bucket: "default-bucket" }); + expect(resolveBucket(context)).toEqual("default-bucket"); + }); + + it("throws when no bucket is available", () => { + const context = makeContext({}); + expect(() => resolveBucket(context)).toThrow(RuntimeError); + }); +}); + +describe("resolveObjectKey", () => { + it("uses the file name alone when no prefix is given", () => { + expect(resolveObjectKey("report.json")).toEqual("report.json"); + }); + + it("joins a prefix and file name with a single slash", () => { + expect(resolveObjectKey("report.json", "reports")).toEqual("reports/report.json"); + }); + + it("does not double the slash when the prefix already ends with one", () => { + expect(resolveObjectKey("report.json", "reports/")).toEqual("reports/report.json"); + }); + + it("throws when the file has no name to derive a key from", () => { + expect(() => resolveObjectKey("", "reports/")).toThrow(RuntimeError); + }); +}); + +describe("getS3Client", () => { + it("builds a client via the default credential provider chain when none are configured", () => { + // access_key_id/secret_access_key are optional: with neither set, the + // AWS SDK falls back to its default credential provider chain (env + // vars, shared config, or an IAM role) instead of throwing. + const context = makeContext({}); + expect(() => getS3Client(context)).not.toThrow(); + }); + + it("builds a client when credentials are configured", () => { + const context = makeContext({ access_key_id: "AKIA...", secret_access_key: "secret" }); + expect(() => getS3Client(context)).not.toThrow(); + }); +}); diff --git a/actions/s3-action/tsconfig.json b/actions/s3-action/tsconfig.json new file mode 100644 index 0000000..65d780f --- /dev/null +++ b/actions/s3-action/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "declaration": true, + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "allowImportingTsExtensions": true, + "noEmit": true, + "baseUrl": ".", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "types": ["node", "vite/client"] + }, + "include": [ + "src/**/*", + "test/**/*", + "vite.config.ts" + ] +} diff --git a/actions/s3-action/vite.config.ts b/actions/s3-action/vite.config.ts new file mode 100644 index 0000000..ae8b973 --- /dev/null +++ b/actions/s3-action/vite.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vite'; +import { resolve } from 'path'; + +export default defineConfig({ + build: { + target: "node18", + ssr: resolve(__dirname, 'src/index.ts'), + rollupOptions: { + external: (id) => + [ + 'fs', + 'path', + 'typescript', + '@code0-tech/hercules', + '@aws-sdk/client-s3', + '@aws-sdk/s3-request-presigner' + ].includes(id) || id.startsWith('node:') + } + } +});