From 2cf41f3d77a2cf0c78675811c700663dfd96c36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Tue, 3 Feb 2026 12:06:33 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0s3=E5=AD=98=E5=82=A8=20#1?= =?UTF-8?q?146?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + packages/filesystem/factory.ts | 19 +- packages/filesystem/s3/rw.ts | 116 ++ packages/filesystem/s3/s3.ts | 227 +++ pnpm-lock.yaml | 1250 +++++++++++++++++ src/locales/ach-UG/translation.json | 5 + src/locales/de-DE/translation.json | 5 + src/locales/en-US/translation.json | 5 + src/locales/ja-JP/translation.json | 5 + src/locales/ru-RU/translation.json | 5 + src/locales/vi-VN/translation.json | 5 + src/locales/zh-CN/translation.json | 5 + src/locales/zh-TW/translation.json | 5 + .../components/FileSystemParams/index.tsx | 4 + 14 files changed, 1656 insertions(+), 1 deletion(-) create mode 100644 packages/filesystem/s3/rw.ts create mode 100644 packages/filesystem/s3/s3.ts diff --git a/package.json b/package.json index 7d851ce21..251dd01aa 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ }, "dependencies": { "@arco-design/web-react": "^2.66.7", + "@aws-sdk/client-s3": "^3.981.0", "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", diff --git a/packages/filesystem/factory.ts b/packages/filesystem/factory.ts index 24aca3e4c..bdeb26e16 100644 --- a/packages/filesystem/factory.ts +++ b/packages/filesystem/factory.ts @@ -5,10 +5,11 @@ import OneDriveFileSystem from "./onedrive/onedrive"; import DropboxFileSystem from "./dropbox/dropbox"; import WebDAVFileSystem from "./webdav/webdav"; import ZipFileSystem from "./zip/zip"; +import S3FileSystem from "./s3/s3"; import { t } from "@App/locales/locales"; import LimiterFileSystem from "./limiter"; -export type FileSystemType = "zip" | "webdav" | "baidu-netdsik" | "onedrive" | "googledrive" | "dropbox"; +export type FileSystemType = "zip" | "webdav" | "baidu-netdsik" | "onedrive" | "googledrive" | "dropbox" | "s3"; export type FileSystemParams = { [key: string]: { @@ -40,6 +41,15 @@ export default class FileSystemFactory { case "dropbox": fs = new DropboxFileSystem(); break; + case "s3": + fs = new S3FileSystem( + params.bucket, + params.region, + params.accessKeyId, + params.secretAccessKey, + params.endpoint + ); + break; default: throw new Error("not found filesystem"); } @@ -63,6 +73,13 @@ export default class FileSystemFactory { onedrive: {}, googledrive: {}, dropbox: {}, + s3: { + bucket: { title: t("s3_bucket_name") }, + region: { title: t("s3_region") }, + accessKeyId: { title: t("s3_access_key_id") }, + secretAccessKey: { title: t("s3_secret_access_key"), type: "password" }, + endpoint: { title: t("s3_custom_endpoint") }, + }, }; } diff --git a/packages/filesystem/s3/rw.ts b/packages/filesystem/s3/rw.ts new file mode 100644 index 000000000..b7e8fe198 --- /dev/null +++ b/packages/filesystem/s3/rw.ts @@ -0,0 +1,116 @@ +import { GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; +import type { S3Client } from "@aws-sdk/client-s3"; +import type { FileReader, FileWriter } from "../filesystem"; + +/** + * FileReader implementation for Amazon S3. + * Downloads and reads file content from S3. + */ +export class S3FileReader implements FileReader { + client: S3Client; + + bucket: string; + + key: string; + + constructor(client: S3Client, bucket: string, key: string) { + this.client = client; + this.bucket = bucket; + this.key = key; + } + + /** + * Reads file content from S3. + * @param type - Output format: "string" for text, "blob" for binary (default) + * @returns File content as string or Blob + * @throws {Error} If file not found or read fails + */ + async read(type?: "string" | "blob"): Promise { + try { + const command = new GetObjectCommand({ + Bucket: this.bucket, + Key: this.key, + }); + + const response = await this.client.send(command); + + if (!response.Body) { + throw new Error("Empty response body from S3"); + } + + // Convert the stream to the requested format + const chunks: Uint8Array[] = []; + const reader = response.Body.transformToWebStream().getReader(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + chunks.push(value); + } + + const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0); + const result = new Uint8Array(totalLength); + let offset = 0; + for (const chunk of chunks) { + result.set(chunk, offset); + offset += chunk.length; + } + + switch (type) { + case "string": + return new TextDecoder().decode(result); + default: + return new Blob([result]); + } + } catch (error: any) { + if (error.name === "NoSuchKey") { + throw new Error(`File not found: ${this.key}`); + } + throw error; + } + } +} + +/** + * FileWriter implementation for Amazon S3. + * Uploads file content to S3 with optional metadata. + */ +export class S3FileWriter implements FileWriter { + client: S3Client; + + bucket: string; + + key: string; + + modifiedDate?: number; + + constructor(client: S3Client, bucket: string, key: string, modifiedDate?: number) { + this.client = client; + this.bucket = bucket; + this.key = key; + this.modifiedDate = modifiedDate; + } + + /** + * Writes content to S3. + * @param content - File content as string or Blob + * @throws {Error} If upload fails + */ + async write(content: string | Blob): Promise { + const body = content instanceof Blob ? new Uint8Array(await content.arrayBuffer()) : content; + + const metadata: Record = {}; + if (this.modifiedDate) { + metadata.createtime = this.modifiedDate.toString(); + } + + const command = new PutObjectCommand({ + Bucket: this.bucket, + Key: this.key, + Body: body, + Metadata: Object.keys(metadata).length > 0 ? metadata : undefined, + }); + + await this.client.send(command); + } +} diff --git a/packages/filesystem/s3/s3.ts b/packages/filesystem/s3/s3.ts new file mode 100644 index 000000000..8f5310135 --- /dev/null +++ b/packages/filesystem/s3/s3.ts @@ -0,0 +1,227 @@ +import { + S3Client, + HeadBucketCommand, + ListObjectsV2Command, + DeleteObjectCommand, + type S3ClientConfig, +} from "@aws-sdk/client-s3"; +import type FileSystem from "../filesystem"; +import type { FileInfo, FileCreateOptions, FileReader, FileWriter } from "../filesystem"; +import { joinPath } from "../utils"; +import { S3FileReader, S3FileWriter } from "./rw"; +import { WarpTokenError } from "../error"; + +/** + * Amazon S3 implementation of the FileSystem interface. + * Supports AWS S3 and S3-compatible services (MinIO, Wasabi, etc.). + */ +export default class S3FileSystem implements FileSystem { + client: S3Client; + + bucket: string; + + region: string; + + basePath: string = "/"; + + /** + * Creates a new S3FileSystem instance. + * + * @param bucket - S3 bucket name + * @param region - AWS region (e.g., "us-east-1") + * @param accessKeyId - AWS access key ID + * @param secretAccessKey - AWS secret access key + * @param endpoint - Optional custom endpoint for S3-compatible services + * @param basePath - Optional base path for directory scoping + */ + constructor( + bucket: string, + region: string, + accessKeyId: string, + secretAccessKey: string, + endpoint?: string, + basePath?: string + ) { + this.bucket = bucket; + this.region = region; + this.basePath = basePath || "/"; + + const config: S3ClientConfig = { + region, + credentials: { + accessKeyId, + secretAccessKey, + }, + forcePathStyle: true, + }; + + if (endpoint) { + config.endpoint = endpoint; + } + + this.client = new S3Client(config); + } + + /** + * Verifies bucket access and credentials. + * @throws {WarpTokenError} If authentication fails + * @throws {Error} If bucket not found or network error + */ + async verify(): Promise { + try { + const command = new HeadBucketCommand({ + Bucket: this.bucket, + }); + await this.client.send(command); + } catch (error: any) { + if ( + error.name === "InvalidAccessKeyId" || + error.name === "SignatureDoesNotMatch" || + error.name === "InvalidClientTokenId" + ) { + throw new WarpTokenError(error); + } + if (error.name === "NoSuchBucket") { + throw new Error(`Bucket not found: ${this.bucket}`); + } + if (error.message?.includes("getaddrinfo") || error.message?.includes("fetch failed")) { + throw new Error("Network connection failed. Please check your internet connection."); + } + throw error; + } + } + + /** + * Opens a file for reading. + * @param file - File information + * @returns FileReader instance for reading file content + */ + async open(file: FileInfo): Promise { + const key = joinPath(file.path, file.name).substring(1); // Remove leading / + return new S3FileReader(this.client, this.bucket, key); + } + + /** + * Opens a directory (returns a new FileSystem scoped to that directory). + * @param path - Directory path relative to current basePath + * @returns New S3FileSystem instance scoped to the directory + */ + async openDir(path: string): Promise { + const newBasePath = joinPath(this.basePath, path); + return new S3FileSystem( + this.bucket, + this.region, + "", // These won't be used since we're reusing the client + "", + undefined, + newBasePath + ); + } + + /** + * Creates a file for writing. + * @param path - File path relative to current basePath + * @param opts - Optional file creation options (modifiedDate) + * @returns FileWriter instance for writing file content + */ + async create(path: string, opts?: FileCreateOptions): Promise { + const key = joinPath(this.basePath, path).substring(1); // Remove leading / + return new S3FileWriter(this.client, this.bucket, key, opts?.modifiedDate); + } + + /** + * Creates a directory (no-op for S3, directories are implicit). + * @param _path - Directory path (unused) + * @param _opts - Optional creation options (unused) + */ + async createDir(_path: string, _opts?: FileCreateOptions): Promise { + // No-op: S3 doesn't require explicit directory creation + return Promise.resolve(); + } + + /** + * Deletes a file from S3. + * This operation is idempotent - deleting a non-existent file succeeds. + * @param path - File path relative to current basePath + */ + async delete(path: string): Promise { + try { + const key = joinPath(this.basePath, path).substring(1); // Remove leading / + const command = new DeleteObjectCommand({ + Bucket: this.bucket, + Key: key, + }); + await this.client.send(command); + } catch (error: any) { + // S3 delete is idempotent - if the key doesn't exist, it succeeds + if (error.name === "NoSuchKey") { + return; + } + throw error; + } + } + + /** + * Lists files in the current directory. + * Handles pagination automatically for large directories. + * @returns Array of FileInfo objects for files in current directory + * @throws {Error} If permission denied or other S3 error + */ + async list(): Promise { + const prefix = this.basePath === "/" ? "" : this.basePath.substring(1); + const files: FileInfo[] = []; + let continuationToken: string | undefined; + + try { + do { + const command = new ListObjectsV2Command({ + Bucket: this.bucket, + Prefix: prefix, + Delimiter: "/", + ContinuationToken: continuationToken, + }); + + const response = await this.client.send(command); + + if (response.Contents) { + for (const object of response.Contents) { + if (!object.Key) continue; + + // Skip the directory marker itself + if (object.Key === prefix || object.Key.endsWith("/")) continue; + + const name = object.Key.substring(prefix.length); + const lastModified = object.LastModified?.getTime() || Date.now(); + + files.push({ + name, + path: this.basePath, + size: object.Size || 0, + digest: object.ETag?.replace(/"/g, "") || "", + createtime: lastModified, + updatetime: lastModified, + }); + } + } + + continuationToken = response.NextContinuationToken; + } while (continuationToken); + + return files; + } catch (error: any) { + if (error.name === "AccessDenied") { + throw new Error(`Permission denied. Check your IAM permissions for bucket: ${this.bucket}`); + } + throw error; + } + } + + /** + * Gets the S3 console URL for the current directory. + * @returns URL to S3 console for this bucket/prefix + */ + async getDirUrl(): Promise { + const prefix = this.basePath === "/" ? "" : this.basePath.substring(1); + return `https://s3.console.aws.amazon.com/s3/buckets/${this.bucket}?prefix=${encodeURIComponent(prefix)}®ion=${this.region}`; + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5ee772c7..1d2d31566 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@arco-design/web-react': specifier: ^2.66.7 version: 2.66.7(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@aws-sdk/client-s3': + specifier: ^3.981.0 + version: 3.981.0 '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -238,6 +241,173 @@ packages: '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/crc32c@5.2.0': + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + + '@aws-crypto/sha1-browser@5.2.0': + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-s3@3.981.0': + resolution: {integrity: sha512-zX3Xqm7V30J1D2II7WBL23SyqIIMD0wMzpiE+VosBxH6fAeXgrjIwSudCypNgnE1EK9OZoZMT3mJtkbUqUDdaA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/client-sso@3.980.0': + resolution: {integrity: sha512-AhNXQaJ46C1I+lQ+6Kj+L24il5K9lqqIanJd8lMszPmP7bLnmX0wTKK0dxywcvrLdij3zhWttjAKEBNgLtS8/A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.973.5': + resolution: {integrity: sha512-IMM7xGfLGW6lMvubsA4j6BHU5FPgGAxoQ/NA63KqNLMwTS+PeMBcx8DPHL12Vg6yqOZnqok9Mu4H2BdQyq7gSA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/crc64-nvme@3.972.0': + resolution: {integrity: sha512-ThlLhTqX68jvoIVv+pryOdb5coP1cX1/MaTbB9xkGDCbWbsqQcLqzPxuSoW1DCnAAIacmXCWpzUNOB9pv+xXQw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.3': + resolution: {integrity: sha512-OBYNY4xQPq7Rx+oOhtyuyO0AQvdJSpXRg7JuPNBJH4a1XXIzJQl4UHQTPKZKwfJXmYLpv4+OkcFen4LYmDPd3g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.5': + resolution: {integrity: sha512-GpvBgEmSZPvlDekd26Zi+XsI27Qz7y0utUx0g2fSTSiDzhnd1FSa1owuodxR0BcUKNL7U2cOVhhDxgZ4iSoPVg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.3': + resolution: {integrity: sha512-rMQAIxstP7cLgYfsRGrGOlpyMl0l8JL2mcke3dsIPLWke05zKOFyR7yoJzWCsI/QiIxjRbxpvPiAeKEA6CoYkg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.3': + resolution: {integrity: sha512-Gc3O91iVvA47kp2CLIXOwuo5ffo1cIpmmyIewcYjAcvurdFHQ8YdcBe1KHidnbbBO4/ZtywGBACsAX5vr3UdoA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.4': + resolution: {integrity: sha512-UwerdzosMSY7V5oIZm3NsMDZPv2aSVzSkZxYxIOWHBeKTZlUqW7XpHtJMZ4PZpJ+HMRhgP+MDGQx4THndgqJfQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.3': + resolution: {integrity: sha512-xkSY7zjRqeVc6TXK2xr3z1bTLm0wD8cj3lAkproRGaO4Ku7dPlKy843YKnHrUOUzOnMezdZ4xtmFc0eKIDTo2w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.3': + resolution: {integrity: sha512-8Ww3F5Ngk8dZ6JPL/V5LhCU1BwMfQd3tLdoEuzaewX8FdnT633tPr+KTHySz9FK7fFPcz5qG3R5edVEhWQD4AA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.3': + resolution: {integrity: sha512-62VufdcH5rRfiRKZRcf1wVbbt/1jAntMj1+J0qAd+r5pQRg2t0/P9/Rz16B1o5/0Se9lVL506LRjrhIJAhYBfA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-bucket-endpoint@3.972.3': + resolution: {integrity: sha512-fmbgWYirF67YF1GfD7cg5N6HHQ96EyRNx/rDIrTF277/zTWVuPI2qS/ZHgofwR1NZPe/NWvoppflQY01LrbVLg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-expect-continue@3.972.3': + resolution: {integrity: sha512-4msC33RZsXQpUKR5QR4HnvBSNCPLGHmB55oDiROqqgyOc+TOfVu2xgi5goA7ms6MdZLeEh2905UfWMnMMF4mRg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-flexible-checksums@3.972.3': + resolution: {integrity: sha512-MkNGJ6qB9kpsLwL18kC/ZXppsJbftHVGCisqpEVbTQsum8CLYDX1Bmp/IvhRGNxsqCO2w9/4PwhDKBjG3Uvr4Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-host-header@3.972.3': + resolution: {integrity: sha512-aknPTb2M+G3s+0qLCx4Li/qGZH8IIYjugHMv15JTYMe6mgZO8VBpYgeGYsNMGCqCZOcWzuf900jFBG5bopfzmA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-location-constraint@3.972.3': + resolution: {integrity: sha512-nIg64CVrsXp67vbK0U1/Is8rik3huS3QkRHn2DRDx4NldrEFMgdkZGI/+cZMKD9k4YOS110Dfu21KZLHrFA/1g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-logger@3.972.3': + resolution: {integrity: sha512-Ftg09xNNRqaz9QNzlfdQWfpqMCJbsQdnZVJP55jfhbKi1+FTWxGuvfPoBhDHIovqWKjqbuiew3HuhxbJ0+OjgA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.972.3': + resolution: {integrity: sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-sdk-s3@3.972.5': + resolution: {integrity: sha512-3IgeIDiQ15tmMBFIdJ1cTy3A9rXHGo+b9p22V38vA3MozeMyVC8VmCYdDLA0iMWo4VHA9LDJTgCM0+xU3wjBOg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-ssec@3.972.3': + resolution: {integrity: sha512-dU6kDuULN3o3jEHcjm0c4zWJlY1zWVkjG9NPe9qxYLLpcbdj5kRYBS2DdWYD+1B9f910DezRuws7xDEqKkHQIg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-user-agent@3.972.5': + resolution: {integrity: sha512-TVZQ6PWPwQbahUI8V+Er+gS41ctIawcI/uMNmQtQ7RMcg3JYn6gyKAFKUb3HFYx2OjYlx1u11sETSwwEUxVHTg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/nested-clients@3.980.0': + resolution: {integrity: sha512-/dONY5xc5/CCKzOqHZCTidtAR4lJXWkGefXvTRKdSKMGaYbbKsxDckisd6GfnvPSLxWtvQzwgRGRutMRoYUApQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/region-config-resolver@3.972.3': + resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.981.0': + resolution: {integrity: sha512-T/+h9df0DALAXXP+YfZ8bgmH6cEN7HAg6BqHe3t38GhHgQ1HULXwK5XMhiLWiHpytDdhLqiVH41SRgW8ynBl6Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.980.0': + resolution: {integrity: sha512-1nFileg1wAgDmieRoj9dOawgr2hhlh7xdvcH57b1NnqfPaVlcqVJyPc6k3TLDUFPY69eEwNxdGue/0wIz58vjA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.1': + resolution: {integrity: sha512-DwHBiMNOB468JiX6+i34c+THsKHErYUdNQ3HexeXZvVn4zouLjgaS4FejiGSi2HyBuzuyHg7SuOPmjSvoU9NRg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-arn-parser@3.972.2': + resolution: {integrity: sha512-VkykWbqMjlSgBFDyrY3nOSqupMc6ivXuGmvci6Q3NnLq5kC+mKQe2QBZ4nrWRE/jqOxeFP2uYzLtwncYYcvQDg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-endpoints@3.980.0': + resolution: {integrity: sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-endpoints@3.981.0': + resolution: {integrity: sha512-a8nXh/H3/4j+sxhZk+N3acSDlgwTVSZbX9i55dx41gI1H+geuonuRG+Shv3GZsCb46vzc08RK2qC78ypO8uRlg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.4': + resolution: {integrity: sha512-H1onv5SkgPBK2P6JR2MjGgbOnttoNzSPIRoeZTNPZYyaplwGg50zS3amXvXqF0/qfXpWEC9rLWU564QTB9bSog==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-user-agent-browser@3.972.3': + resolution: {integrity: sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==} + + '@aws-sdk/util-user-agent-node@3.972.3': + resolution: {integrity: sha512-gqG+02/lXQtO0j3US6EVnxtwwoXQC5l2qkhLCrqUrqdtcQxV7FDMbm9wLjKqoronSHyELGTjbFKK/xV5q1bZNA==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/xml-builder@3.972.3': + resolution: {integrity: sha512-bCk63RsBNCWW4tt5atv5Sbrh+3J3e8YzgyF6aZb1JeXcdzG4k5SlPLeTMFOIXFuuFHIwgphUhn4i3uS/q49eww==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.3': + resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -905,56 +1075,67 @@ packages: resolution: {integrity: sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.44.2': resolution: {integrity: sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.44.2': resolution: {integrity: sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.44.2': resolution: {integrity: sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.44.2': resolution: {integrity: sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.44.2': resolution: {integrity: sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.44.2': resolution: {integrity: sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.44.2': resolution: {integrity: sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.44.2': resolution: {integrity: sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.44.2': resolution: {integrity: sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.44.2': resolution: {integrity: sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.44.2': resolution: {integrity: sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==} @@ -985,21 +1166,25 @@ packages: resolution: {integrity: sha512-n7UGSBzv7PiX+V1Q2bY3S1XWyN3RCykCQUgfhZ+xWietCM/1349jgN7DoXKPllqlof1GPGBjziHU0sQZTC4tag==} cpu: [arm64] os: [linux] + libc: [glibc] '@rspack/binding-linux-arm64-musl@1.6.1': resolution: {integrity: sha512-P7nx0jsKxx7g3QAnH9UnJDGVgs1M2H7ZQl68SRyrs42TKOd9Md22ynoMIgCK1zoy+skssU6MhWptluSggXqSrA==} cpu: [arm64] os: [linux] + libc: [musl] '@rspack/binding-linux-x64-gnu@1.6.1': resolution: {integrity: sha512-SdiurC1bV/QHnj7rmrBYJLdsat3uUDWl9KjkVjEbtc8kQV0Ri4/vZRH0nswgzx7hZNY2j0jYuCm5O8+3qeJEMg==} cpu: [x64] os: [linux] + libc: [glibc] '@rspack/binding-linux-x64-musl@1.6.1': resolution: {integrity: sha512-JoSJu29nV+auOePhe8x2Fzqxiga1YGNcOMWKJ5Uj8rHBZ8FPAiiE+CpLG8TwfpHsivojrY/sy6fE8JldYLV5TQ==} cpu: [x64] os: [linux] + libc: [musl] '@rspack/binding-wasm32-wasi@1.6.1': resolution: {integrity: sha512-u5NiSHxM7LtIo4cebq/hQPJ9o39u127am3eVJHDzdmBVhTYYO5l7XVUnFmcU8hNHuj/4lJzkFviWFbf3SaRSYA==} @@ -1048,6 +1233,222 @@ packages: resolution: {integrity: sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==} engines: {node: '>=16.0.0'} + '@smithy/abort-controller@4.2.8': + resolution: {integrity: sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader-native@4.2.1': + resolution: {integrity: sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader@5.2.0': + resolution: {integrity: sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@4.4.6': + resolution: {integrity: sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.22.1': + resolution: {integrity: sha512-x3ie6Crr58MWrm4viHqqy2Du2rHYZjwu8BekasrQx4ca+Y24dzVAwq3yErdqIbc2G3I0kLQA13PQ+/rde+u65g==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.2.8': + resolution: {integrity: sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.2.8': + resolution: {integrity: sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.2.8': + resolution: {integrity: sha512-MTfQT/CRQz5g24ayXdjg53V0mhucZth4PESoA5IhvaWVDTOQLfo8qI9vzqHcPsdd2v6sqfTYqF5L/l+pea5Uyw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.3.8': + resolution: {integrity: sha512-ah12+luBiDGzBruhu3efNy1IlbwSEdNiw8fOZksoKoWW1ZHvO/04MQsdnws/9Aj+5b0YXSSN2JXKy/ClIsW8MQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.2.8': + resolution: {integrity: sha512-cYpCpp29z6EJHa5T9WL0KAlq3SOKUQkcgSoeRfRVwjGgSFl7Uh32eYGt7IDYCX20skiEdRffyDpvF2efEZPC0A==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.2.8': + resolution: {integrity: sha512-iJ6YNJd0bntJYnX6s52NC4WFYcZeKrPUr1Kmmr5AwZcwCSzVpS7oavAmxMR7pMq7V+D1G4s9F5NJK0xwOsKAlQ==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.3.9': + resolution: {integrity: sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-blob-browser@4.2.9': + resolution: {integrity: sha512-m80d/iicI7DlBDxyQP6Th7BW/ejDGiF0bgI754+tiwK0lgMkcaIBgvwwVc7OFbY4eUzpGtnig52MhPAEJ7iNYg==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.2.8': + resolution: {integrity: sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-stream-node@4.2.8': + resolution: {integrity: sha512-v0FLTXgHrTeheYZFGhR+ehX5qUm4IQsjAiL9qehad2cyjMWcN2QG6/4mSwbSgEQzI7jwfoXj7z4fxZUx/Mhj2w==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.2.8': + resolution: {integrity: sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.2.0': + resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} + engines: {node: '>=18.0.0'} + + '@smithy/md5-js@4.2.8': + resolution: {integrity: sha512-oGMaLj4tVZzLi3itBa9TCswgMBr7k9b+qKYowQ6x1rTyTuO1IU2YHdHUa+891OsOH+wCsH7aTPRsTJO3RMQmjQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.2.8': + resolution: {integrity: sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.4.13': + resolution: {integrity: sha512-x6vn0PjYmGdNuKh/juUJJewZh7MoQ46jYaJ2mvekF4EesMuFfrl4LaW/k97Zjf8PTCPQmPgMvwewg7eNoH9n5w==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.4.30': + resolution: {integrity: sha512-CBGyFvN0f8hlnqKH/jckRDz78Snrp345+PVk8Ux7pnkUCW97Iinse59lY78hBt04h1GZ6hjBN94BRwZy1xC8Bg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.9': + resolution: {integrity: sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.2.8': + resolution: {integrity: sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.3.8': + resolution: {integrity: sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.4.9': + resolution: {integrity: sha512-KX5Wml5mF+luxm1szW4QDz32e3NObgJ4Fyw+irhph4I/2geXwUy4jkIMUs5ZPGflRBeR6BUkC2wqIab4Llgm3w==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.8': + resolution: {integrity: sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.3.8': + resolution: {integrity: sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.2.8': + resolution: {integrity: sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.2.8': + resolution: {integrity: sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.2.8': + resolution: {integrity: sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.4.3': + resolution: {integrity: sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.8': + resolution: {integrity: sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.11.2': + resolution: {integrity: sha512-SCkGmFak/xC1n7hKRsUr6wOnBTJ3L22Qd4e8H1fQIuKTAjntwgU8lrdMe7uHdiT2mJAOWA/60qaW9tiMu69n1A==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.12.0': + resolution: {integrity: sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.8': + resolution: {integrity: sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.3.0': + resolution: {integrity: sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.2.0': + resolution: {integrity: sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.2.1': + resolution: {integrity: sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.0': + resolution: {integrity: sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.2.0': + resolution: {integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.3.29': + resolution: {integrity: sha512-nIGy3DNRmOjaYaaKcQDzmWsro9uxlaqUOhZDHQed9MW/GmkBZPtnU70Pu1+GT9IBmUXwRdDuiyaeiy9Xtpn3+Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.2.32': + resolution: {integrity: sha512-7dtFff6pu5fsjqrVve0YMhrnzJtccCWDacNKOkiZjJ++fmjGExmmSu341x+WU6Oc1IccL7lDuaUj7SfrHpWc5Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.2.8': + resolution: {integrity: sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.0': + resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.8': + resolution: {integrity: sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.2.8': + resolution: {integrity: sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.11': + resolution: {integrity: sha512-lKmZ0S/3Qj2OF5H1+VzvDLb6kRxGzZHq6f3rAsoSu5cTLGsn3v3VQBA8czkNNXlLjoFEtVu3OQT2jEeOtOE2CA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.2.0': + resolution: {integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.0': + resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-waiter@4.2.8': + resolution: {integrity: sha512-n+lahlMWk+aejGuax7DPWtqav8HYnWxQwR+LCG2BgCUmaGcTe9qZCFsmw8TMg9iG75HOwhrJCX9TCJRLH+Yzqg==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.1.0': + resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} + engines: {node: '>=18.0.0'} + '@swc/helpers@0.5.17': resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} @@ -1646,6 +2047,9 @@ packages: bonjour-service@1.3.0: resolution: {integrity: sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==} + bowser@2.13.1: + resolution: {integrity: sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -2275,6 +2679,10 @@ packages: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true + fast-xml-parser@5.3.4: + resolution: {integrity: sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==} + hasBin: true + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -3780,6 +4188,9 @@ packages: strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + strnum@2.1.2: + resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -4394,6 +4805,499 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 10.4.3 + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.1 + tslib: 2.8.1 + + '@aws-crypto/crc32c@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.1 + tslib: 2.8.1 + + '@aws-crypto/sha1-browser@5.2.0': + dependencies: + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-locate-window': 3.965.4 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-locate-window': 3.965.4 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.1 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-s3@3.981.0': + dependencies: + '@aws-crypto/sha1-browser': 5.2.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.5 + '@aws-sdk/credential-provider-node': 3.972.4 + '@aws-sdk/middleware-bucket-endpoint': 3.972.3 + '@aws-sdk/middleware-expect-continue': 3.972.3 + '@aws-sdk/middleware-flexible-checksums': 3.972.3 + '@aws-sdk/middleware-host-header': 3.972.3 + '@aws-sdk/middleware-location-constraint': 3.972.3 + '@aws-sdk/middleware-logger': 3.972.3 + '@aws-sdk/middleware-recursion-detection': 3.972.3 + '@aws-sdk/middleware-sdk-s3': 3.972.5 + '@aws-sdk/middleware-ssec': 3.972.3 + '@aws-sdk/middleware-user-agent': 3.972.5 + '@aws-sdk/region-config-resolver': 3.972.3 + '@aws-sdk/signature-v4-multi-region': 3.981.0 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.981.0 + '@aws-sdk/util-user-agent-browser': 3.972.3 + '@aws-sdk/util-user-agent-node': 3.972.3 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.22.1 + '@smithy/eventstream-serde-browser': 4.2.8 + '@smithy/eventstream-serde-config-resolver': 4.3.8 + '@smithy/eventstream-serde-node': 4.2.8 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-blob-browser': 4.2.9 + '@smithy/hash-node': 4.2.8 + '@smithy/hash-stream-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/md5-js': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.13 + '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.9 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.29 + '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-stream': 4.5.11 + '@smithy/util-utf8': 4.2.0 + '@smithy/util-waiter': 4.2.8 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.980.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.5 + '@aws-sdk/middleware-host-header': 3.972.3 + '@aws-sdk/middleware-logger': 3.972.3 + '@aws-sdk/middleware-recursion-detection': 3.972.3 + '@aws-sdk/middleware-user-agent': 3.972.5 + '@aws-sdk/region-config-resolver': 3.972.3 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.980.0 + '@aws-sdk/util-user-agent-browser': 3.972.3 + '@aws-sdk/util-user-agent-node': 3.972.3 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.22.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.13 + '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.9 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.29 + '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.973.5': + dependencies: + '@aws-sdk/types': 3.973.1 + '@aws-sdk/xml-builder': 3.972.3 + '@smithy/core': 3.22.1 + '@smithy/node-config-provider': 4.3.8 + '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/signature-v4': 5.3.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/crc64-nvme@3.972.0': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.3': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.5': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/types': 3.973.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/node-http-handler': 4.4.9 + '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + '@smithy/util-stream': 4.5.11 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.3': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/credential-provider-env': 3.972.3 + '@aws-sdk/credential-provider-http': 3.972.5 + '@aws-sdk/credential-provider-login': 3.972.3 + '@aws-sdk/credential-provider-process': 3.972.3 + '@aws-sdk/credential-provider-sso': 3.972.3 + '@aws-sdk/credential-provider-web-identity': 3.972.3 + '@aws-sdk/nested-clients': 3.980.0 + '@aws-sdk/types': 3.973.1 + '@smithy/credential-provider-imds': 4.2.8 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-login@3.972.3': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/nested-clients': 3.980.0 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.972.4': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.3 + '@aws-sdk/credential-provider-http': 3.972.5 + '@aws-sdk/credential-provider-ini': 3.972.3 + '@aws-sdk/credential-provider-process': 3.972.3 + '@aws-sdk/credential-provider-sso': 3.972.3 + '@aws-sdk/credential-provider-web-identity': 3.972.3 + '@aws-sdk/types': 3.973.1 + '@smithy/credential-provider-imds': 4.2.8 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.972.3': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.3': + dependencies: + '@aws-sdk/client-sso': 3.980.0 + '@aws-sdk/core': 3.973.5 + '@aws-sdk/token-providers': 3.980.0 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.972.3': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/nested-clients': 3.980.0 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/middleware-bucket-endpoint@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-arn-parser': 3.972.2 + '@smithy/node-config-provider': 4.3.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-config-provider': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-expect-continue@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-flexible-checksums@3.972.3': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/core': 3.973.5 + '@aws-sdk/crc64-nvme': 3.972.0 + '@aws-sdk/types': 3.973.1 + '@smithy/is-array-buffer': 4.2.0 + '@smithy/node-config-provider': 4.3.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-stream': 4.5.11 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-host-header@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-location-constraint@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@aws/lambda-invoke-store': 0.2.3 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-s3@3.972.5': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-arn-parser': 3.972.2 + '@smithy/core': 3.22.1 + '@smithy/node-config-provider': 4.3.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/signature-v4': 5.3.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + '@smithy/util-config-provider': 4.2.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-stream': 4.5.11 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-ssec@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.972.5': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.980.0 + '@smithy/core': 3.22.1 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.980.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.5 + '@aws-sdk/middleware-host-header': 3.972.3 + '@aws-sdk/middleware-logger': 3.972.3 + '@aws-sdk/middleware-recursion-detection': 3.972.3 + '@aws-sdk/middleware-user-agent': 3.972.5 + '@aws-sdk/region-config-resolver': 3.972.3 + '@aws-sdk/types': 3.973.1 + '@aws-sdk/util-endpoints': 3.980.0 + '@aws-sdk/util-user-agent-browser': 3.972.3 + '@aws-sdk/util-user-agent-node': 3.972.3 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.22.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.13 + '@smithy/middleware-retry': 4.4.30 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.9 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.29 + '@smithy/util-defaults-mode-node': 4.2.32 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/config-resolver': 4.4.6 + '@smithy/node-config-provider': 4.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.981.0': + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.972.5 + '@aws-sdk/types': 3.973.1 + '@smithy/protocol-http': 5.3.8 + '@smithy/signature-v4': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.980.0': + dependencies: + '@aws-sdk/core': 3.973.5 + '@aws-sdk/nested-clients': 3.980.0 + '@aws-sdk/types': 3.973.1 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.973.1': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/util-arn-parser@3.972.2': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.980.0': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-endpoints': 3.2.8 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.981.0': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-endpoints': 3.2.8 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.4': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.972.3': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + bowser: 2.13.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.972.3': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.5 + '@aws-sdk/types': 3.973.1 + '@smithy/node-config-provider': 4.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.3': + dependencies: + '@smithy/types': 4.12.0 + fast-xml-parser: 5.3.4 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.3': {} + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -5056,6 +5960,344 @@ snapshots: '@rspack/lite-tapable@1.0.1': {} + '@smithy/abort-controller@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader-native@4.2.1': + dependencies: + '@smithy/util-base64': 4.3.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader@5.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/config-resolver@4.4.6': + dependencies: + '@smithy/node-config-provider': 4.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-config-provider': 4.2.0 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + tslib: 2.8.1 + + '@smithy/core@3.22.1': + dependencies: + '@smithy/middleware-serde': 4.2.9 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-stream': 4.5.11 + '@smithy/util-utf8': 4.2.0 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.2.8': + dependencies: + '@smithy/node-config-provider': 4.3.8 + '@smithy/property-provider': 4.2.8 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + tslib: 2.8.1 + + '@smithy/eventstream-codec@4.2.8': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.12.0 + '@smithy/util-hex-encoding': 4.2.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@4.2.8': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@4.3.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@4.2.8': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@4.2.8': + dependencies: + '@smithy/eventstream-codec': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.3.9': + dependencies: + '@smithy/protocol-http': 5.3.8 + '@smithy/querystring-builder': 4.2.8 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + tslib: 2.8.1 + + '@smithy/hash-blob-browser@4.2.9': + dependencies: + '@smithy/chunked-blob-reader': 5.2.0 + '@smithy/chunked-blob-reader-native': 4.2.1 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/hash-node@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/hash-stream-node@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/md5-js@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.2.8': + dependencies: + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.4.13': + dependencies: + '@smithy/core': 3.22.1 + '@smithy/middleware-serde': 4.2.9 + '@smithy/node-config-provider': 4.3.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-middleware': 4.2.8 + tslib: 2.8.1 + + '@smithy/middleware-retry@4.4.30': + dependencies: + '@smithy/node-config-provider': 4.3.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/service-error-classification': 4.2.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.2.9': + dependencies: + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.3.8': + dependencies: + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.4.9': + dependencies: + '@smithy/abort-controller': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/querystring-builder': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.3.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + '@smithy/util-uri-escape': 4.2.0 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/service-error-classification@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + + '@smithy/shared-ini-file-loader@4.4.3': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.3.8': + dependencies: + '@smithy/is-array-buffer': 4.2.0 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-uri-escape': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/smithy-client@4.11.2': + dependencies: + '@smithy/core': 3.22.1 + '@smithy/middleware-endpoint': 4.4.13 + '@smithy/middleware-stack': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-stream': 4.5.11 + tslib: 2.8.1 + + '@smithy/types@4.12.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.2.8': + dependencies: + '@smithy/querystring-parser': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.3.0': + dependencies: + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.2.0': + dependencies: + '@smithy/is-array-buffer': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-config-provider@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@4.3.29': + dependencies: + '@smithy/property-provider': 4.2.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.2.32': + dependencies: + '@smithy/config-resolver': 4.4.6 + '@smithy/credential-provider-imds': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/property-provider': 4.2.8 + '@smithy/smithy-client': 4.11.2 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/util-endpoints@3.2.8': + dependencies: + '@smithy/node-config-provider': 4.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@4.2.8': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/util-retry@4.2.8': + dependencies: + '@smithy/service-error-classification': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.5.11': + dependencies: + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/node-http-handler': 4.4.9 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-uri-escape@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.2.0': + dependencies: + '@smithy/util-buffer-from': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-waiter@4.2.8': + dependencies: + '@smithy/abort-controller': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + + '@smithy/uuid@1.1.0': + dependencies: + tslib: 2.8.1 + '@swc/helpers@0.5.17': dependencies: tslib: 2.8.1 @@ -5888,6 +7130,8 @@ snapshots: fast-deep-equal: 3.1.3 multicast-dns: 7.2.5 + bowser@2.13.1: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -6649,6 +7893,10 @@ snapshots: dependencies: strnum: 1.1.2 + fast-xml-parser@5.3.4: + dependencies: + strnum: 2.1.2 + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -8260,6 +9508,8 @@ snapshots: strnum@1.1.2: {} + strnum@2.1.2: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 diff --git a/src/locales/ach-UG/translation.json b/src/locales/ach-UG/translation.json index 25b2dbed3..476b452f2 100644 --- a/src/locales/ach-UG/translation.json +++ b/src/locales/ach-UG/translation.json @@ -373,6 +373,11 @@ "url": "crwdns8544:0crwdne8544:0", "username": "crwdns8546:0crwdne8546:0", "password": "crwdns8548:0crwdne8548:0", + "s3_bucket_name": "Bucket Name", + "s3_region": "Region", + "s3_access_key_id": "Access Key ID", + "s3_secret_access_key": "Secret Access Key", + "s3_custom_endpoint": "Custom Endpoint (Optional)", "skip": "crwdns8550:0crwdne8550:0", "next": "crwdns8552:0crwdne8552:0", "next_with_progress": "crwdns8920:0{step}crwdnd8920:0{steps}crwdne8920:0", diff --git a/src/locales/de-DE/translation.json b/src/locales/de-DE/translation.json index d18264195..6f0610f6d 100644 --- a/src/locales/de-DE/translation.json +++ b/src/locales/de-DE/translation.json @@ -382,6 +382,11 @@ "url": "URL", "username": "Benutzername", "password": "Passwort", + "s3_bucket_name": "Bucket-Name", + "s3_region": "Region", + "s3_access_key_id": "Zugriffs-Schlüssel-ID", + "s3_secret_access_key": "Geheimer Zugriffsschlüssel", + "s3_custom_endpoint": "Benutzerdefinierter Endpunkt (optional)", "skip": "Überspringen", "next": "Weiter", "next_with_progress": "Nächster Schritt (Schritt {step} von {steps})", diff --git a/src/locales/en-US/translation.json b/src/locales/en-US/translation.json index a5df027f6..1035e511c 100644 --- a/src/locales/en-US/translation.json +++ b/src/locales/en-US/translation.json @@ -382,6 +382,11 @@ "url": "URL", "username": "Username", "password": "Password", + "s3_bucket_name": "Bucket Name", + "s3_region": "Region", + "s3_access_key_id": "Access Key ID", + "s3_secret_access_key": "Secret Access Key", + "s3_custom_endpoint": "Custom Endpoint (Optional)", "skip": "Skip", "next": "Next", "next_with_progress": "Next (Step {step} of {steps})", diff --git a/src/locales/ja-JP/translation.json b/src/locales/ja-JP/translation.json index 1b7a04b01..2ebfd7262 100644 --- a/src/locales/ja-JP/translation.json +++ b/src/locales/ja-JP/translation.json @@ -382,6 +382,11 @@ "url": "URL", "username": "ユーザー名", "password": "パスワード", + "s3_bucket_name": "バケット名", + "s3_region": "リージョン", + "s3_access_key_id": "アクセスキーID", + "s3_secret_access_key": "シークレットアクセスキー", + "s3_custom_endpoint": "カスタムエンドポイント(オプション)", "skip": "スキップ", "next": "次へ", "next_with_progress": "次へ(ステップ{step}の全{steps}ステップ中)", diff --git a/src/locales/ru-RU/translation.json b/src/locales/ru-RU/translation.json index b41776979..6720d5173 100644 --- a/src/locales/ru-RU/translation.json +++ b/src/locales/ru-RU/translation.json @@ -382,6 +382,11 @@ "url": "URL", "username": "Имя пользователя", "password": "Пароль", + "s3_bucket_name": "Имя корзины", + "s3_region": "Регион", + "s3_access_key_id": "Идентификатор ключа доступа", + "s3_secret_access_key": "Секретный ключ доступа", + "s3_custom_endpoint": "Пользовательская конечная точка (необязательно)", "skip": "Пропустить", "next": "Далее", "next_with_progress": "Следующий шаг (шаг {step} из {steps})", diff --git a/src/locales/vi-VN/translation.json b/src/locales/vi-VN/translation.json index 9b35e23ec..6c10e5274 100644 --- a/src/locales/vi-VN/translation.json +++ b/src/locales/vi-VN/translation.json @@ -382,6 +382,11 @@ "url": "Url", "username": "Tên người dùng", "password": "Mật khẩu", + "s3_bucket_name": "Tên Bucket", + "s3_region": "Vùng", + "s3_access_key_id": "ID Khóa Truy Cập", + "s3_secret_access_key": "Khóa Truy Cập Bí Mật", + "s3_custom_endpoint": "Điểm Cuối Tùy Chỉnh (Tùy Chọn)", "skip": "Bỏ qua", "next": "Tiếp theo", "next_with_progress": "Tiếp theo (bước {step} trên {steps})", diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json index 2409e2e52..6d78cd5dd 100644 --- a/src/locales/zh-CN/translation.json +++ b/src/locales/zh-CN/translation.json @@ -382,6 +382,11 @@ "url": "URL", "username": "用户名", "password": "密码", + "s3_bucket_name": "存储桶名称", + "s3_region": "区域", + "s3_access_key_id": "访问密钥 ID", + "s3_secret_access_key": "访问密钥密文", + "s3_custom_endpoint": "自定义端点(可选)", "skip": "跳过", "next": "下一步", "next_with_progress": "下一步(第 {step} 步 / 共 {steps} 步)", diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json index fa6b99483..a9b98bd0d 100644 --- a/src/locales/zh-TW/translation.json +++ b/src/locales/zh-TW/translation.json @@ -382,6 +382,11 @@ "url": "網址", "username": "使用者名稱", "password": "密碼", + "s3_bucket_name": "儲存貯體名稱", + "s3_region": "區域", + "s3_access_key_id": "存取金鑰 ID", + "s3_secret_access_key": "私密存取金鑰", + "s3_custom_endpoint": "自訂端點(選用)", "skip": "跳過", "next": "下一步", "next_with_progress": "下一步(第 {step} 步 / 共 {steps} 步)", diff --git a/src/pages/components/FileSystemParams/index.tsx b/src/pages/components/FileSystemParams/index.tsx index f05dd5e28..8e7549985 100644 --- a/src/pages/components/FileSystemParams/index.tsx +++ b/src/pages/components/FileSystemParams/index.tsx @@ -47,6 +47,10 @@ const FileSystemParams: React.FC<{ key: "dropbox", name: "Dropbox", }, + { + key: "s3", + name: "Amazon S3", + }, ]; const netDiskType = netDiskTypeMap[fileSystemType]; From ba73e4a9fbed06afc1b152f14ad345ca5b3b39ab Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:20:48 +0900 Subject: [PATCH 2/8] fix --- packages/filesystem/s3/rw.ts | 44 ++++++++++++++++++------------------ packages/filesystem/s3/s3.ts | 14 +++++++++--- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/filesystem/s3/rw.ts b/packages/filesystem/s3/rw.ts index b7e8fe198..acd310d3d 100644 --- a/packages/filesystem/s3/rw.ts +++ b/packages/filesystem/s3/rw.ts @@ -25,7 +25,7 @@ export class S3FileReader implements FileReader { * @returns File content as string or Blob * @throws {Error} If file not found or read fails */ - async read(type?: "string" | "blob"): Promise { + async read(type: "string" | "blob" = "blob"): Promise { try { const command = new GetObjectCommand({ Bucket: this.bucket, @@ -40,28 +40,27 @@ export class S3FileReader implements FileReader { // Convert the stream to the requested format const chunks: Uint8Array[] = []; - const reader = response.Body.transformToWebStream().getReader(); - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - chunks.push(value); - } - - const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0); - const result = new Uint8Array(totalLength); - let offset = 0; - for (const chunk of chunks) { - result.set(chunk, offset); - offset += chunk.length; + const stream = response.Body.transformToWebStream(); + + if (type === "string") { + // Streaming decode to string (省内存) + const reader = stream.getReader(); + const decoder = new TextDecoder(); + let result = ""; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + result += decoder.decode(value, { stream: true }); + } + // 最后 flush + result += decoder.decode(); + return result; + + } else { + // 返回 Blob,避免 JS 层缓冲与拼接,走底层最优路径 + return new Response(stream).blob(); } - switch (type) { - case "string": - return new TextDecoder().decode(result); - default: - return new Blob([result]); - } } catch (error: any) { if (error.name === "NoSuchKey") { throw new Error(`File not found: ${this.key}`); @@ -101,7 +100,8 @@ export class S3FileWriter implements FileWriter { const metadata: Record = {}; if (this.modifiedDate) { - metadata.createtime = this.modifiedDate.toString(); + // 用 ISO 8601 格式 + metadata.createtime = new Date(this.modifiedDate).toISOString(); // 规范格式 } const command = new PutObjectCommand({ diff --git a/packages/filesystem/s3/s3.ts b/packages/filesystem/s3/s3.ts index 8f5310135..c98a9e840 100644 --- a/packages/filesystem/s3/s3.ts +++ b/packages/filesystem/s3/s3.ts @@ -40,7 +40,8 @@ export default class S3FileSystem implements FileSystem { accessKeyId: string, secretAccessKey: string, endpoint?: string, - basePath?: string + basePath?: string, + usePathStyle: boolean = true // 默认兼容S3 ) { this.bucket = bucket; this.region = region; @@ -52,11 +53,14 @@ export default class S3FileSystem implements FileSystem { accessKeyId, secretAccessKey, }, - forcePathStyle: true, + // forcePathStyle: true 对 AWS 官方 S3 不是最佳实践(会用 path-style URL,已被逐渐弃用),对 MinIO 等兼容服务则是必须的。硬编码会导致部分用户配置失败。 + forcePathStyle: usePathStyle, }; if (endpoint) { config.endpoint = endpoint; + // 自动检测:如果 endpoint 包含 amazonaws.com,设为 false。 + if (endpoint.includes("amazonaws.com")) config.forcePathStyle = false; } this.client = new S3Client(config); @@ -108,7 +112,7 @@ export default class S3FileSystem implements FileSystem { */ async openDir(path: string): Promise { const newBasePath = joinPath(this.basePath, path); - return new S3FileSystem( + const fs = new S3FileSystem( this.bucket, this.region, "", // These won't be used since we're reusing the client @@ -116,6 +120,10 @@ export default class S3FileSystem implements FileSystem { undefined, newBasePath ); + // openDir 又 new 一个 S3FileSystem,但传了空字符串的 AK/SK,导致逻辑不清晰。 + // 复用原有 client,只修改 basePath。 + fs.client = this.client; // 复用 client + return fs; } /** From 66194284a9c6a078207e3a35c7b920f5ad682619 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:24:23 +0900 Subject: [PATCH 3/8] fix --- packages/filesystem/s3/rw.ts | 5 +---- packages/filesystem/s3/s3.ts | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/filesystem/s3/rw.ts b/packages/filesystem/s3/rw.ts index acd310d3d..409f7f965 100644 --- a/packages/filesystem/s3/rw.ts +++ b/packages/filesystem/s3/rw.ts @@ -39,7 +39,6 @@ export class S3FileReader implements FileReader { } // Convert the stream to the requested format - const chunks: Uint8Array[] = []; const stream = response.Body.transformToWebStream(); if (type === "string") { @@ -55,12 +54,10 @@ export class S3FileReader implements FileReader { // 最后 flush result += decoder.decode(); return result; - } else { // 返回 Blob,避免 JS 层缓冲与拼接,走底层最优路径 return new Response(stream).blob(); } - } catch (error: any) { if (error.name === "NoSuchKey") { throw new Error(`File not found: ${this.key}`); @@ -101,7 +98,7 @@ export class S3FileWriter implements FileWriter { const metadata: Record = {}; if (this.modifiedDate) { // 用 ISO 8601 格式 - metadata.createtime = new Date(this.modifiedDate).toISOString(); // 规范格式 + metadata.createtime = new Date(this.modifiedDate).toISOString(); // 规范格式 } const command = new PutObjectCommand({ diff --git a/packages/filesystem/s3/s3.ts b/packages/filesystem/s3/s3.ts index c98a9e840..4708f96e0 100644 --- a/packages/filesystem/s3/s3.ts +++ b/packages/filesystem/s3/s3.ts @@ -41,7 +41,7 @@ export default class S3FileSystem implements FileSystem { secretAccessKey: string, endpoint?: string, basePath?: string, - usePathStyle: boolean = true // 默认兼容S3 + usePathStyle: boolean = true // 默认兼容S3 ) { this.bucket = bucket; this.region = region; From 3a4e4fa3a566bacd7cade7367b779effd4160a41 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:41:00 +0900 Subject: [PATCH 4/8] fix 02 --- packages/filesystem/s3/s3.ts | 58 ++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/packages/filesystem/s3/s3.ts b/packages/filesystem/s3/s3.ts index 4708f96e0..8cc487511 100644 --- a/packages/filesystem/s3/s3.ts +++ b/packages/filesystem/s3/s3.ts @@ -58,6 +58,12 @@ export default class S3FileSystem implements FileSystem { }; if (endpoint) { + // AWS SDK v3 要求 endpoint 是完整 URL(带 https://)。缺少协议会导致 InvalidEndpoint 或连接失败。 + // 自动补全协议(常见兼容做法) + let fixedEndpoint = `${endpoint}`.trim(); + if (!fixedEndpoint.startsWith("http://") && !fixedEndpoint.startsWith("https://")) { + fixedEndpoint = `https://${fixedEndpoint}`; + } config.endpoint = endpoint; // 自动检测:如果 endpoint 包含 amazonaws.com,设为 false。 if (endpoint.includes("amazonaws.com")) config.forcePathStyle = false; @@ -78,18 +84,27 @@ export default class S3FileSystem implements FileSystem { }); await this.client.send(command); } catch (error: any) { + if (error.name === "NotFound") { + throw new Error("NotFound"); // Bucket 不存在 + } if ( error.name === "InvalidAccessKeyId" || error.name === "SignatureDoesNotMatch" || error.name === "InvalidClientTokenId" ) { - throw new WarpTokenError(error); + throw new WarpTokenError(error); // AccessKey 或 SecretKey 无效 + } + if (error.name === "AccessDenied") { + throw new Error("Access Denied"); // 无权限访问该 Bucket(Access Denied) + } + if (error.name === "PermanentRedirect") { + throw new Error("Access Denied"); // Region 设置错误,请检查 region 是否匹配 Bucket 所在区域 } if (error.name === "NoSuchBucket") { throw new Error(`Bucket not found: ${this.bucket}`); } if (error.message?.includes("getaddrinfo") || error.message?.includes("fetch failed")) { - throw new Error("Network connection failed. Please check your internet connection."); + throw new Error("Network connection failed. Please check your internet connection."); // 网络连接失败,请检查 endpoint 或网络 } throw error; } @@ -115,10 +130,11 @@ export default class S3FileSystem implements FileSystem { const fs = new S3FileSystem( this.bucket, this.region, - "", // These won't be used since we're reusing the client + "", // 占位: These won't be used since we're reusing the client "", undefined, - newBasePath + newBasePath, + true // forcePathStyle 同父 ); // openDir 又 new 一个 S3FileSystem,但传了空字符串的 AK/SK,导致逻辑不清晰。 // 复用原有 client,只修改 basePath。 @@ -187,25 +203,37 @@ export default class S3FileSystem implements FileSystem { Prefix: prefix, Delimiter: "/", ContinuationToken: continuationToken, + MaxKeys: 1000, // ← 每次最多 1000,防滥用 }); const response = await this.client.send(command); + // 处理 CommonPrefixes(子目录) + // if (response.CommonPrefixes) { + // for (const prefix of response.CommonPrefixes) { + // if (prefix.Prefix && prefix.Prefix !== this.basePath) { + // } + // } + // } + + // 处理 Contents(文件) if (response.Contents) { - for (const object of response.Contents) { - if (!object.Key) continue; + for (const obj of response.Contents) { + if (!obj.Key) continue; + if (obj.Key && obj.Key.endsWith("/")) continue; // 跳过目录占位符 + if (obj.Key === this.basePath.slice(1)) continue; // 跳过 prefix 本身 - // Skip the directory marker itself - if (object.Key === prefix || object.Key.endsWith("/")) continue; + // const name = obj.Key.substring(prefix.length); + const relativeKey = obj.Key.slice(this.basePath.length); + if (!relativeKey) continue; - const name = object.Key.substring(prefix.length); - const lastModified = object.LastModified?.getTime() || Date.now(); + const lastModified = obj.LastModified?.getTime() || Date.now(); files.push({ - name, + name: relativeKey, path: this.basePath, - size: object.Size || 0, - digest: object.ETag?.replace(/"/g, "") || "", + size: obj.Size || 0, + digest: obj.ETag?.replace(/"/g, "") || "", createtime: lastModified, updatetime: lastModified, }); @@ -215,6 +243,10 @@ export default class S3FileSystem implements FileSystem { continuationToken = response.NextContinuationToken; } while (continuationToken); + if (files.length > 10000) { + console.warn(`Directory listing truncated: >10000 items under ${this.basePath}`); + } + return files; } catch (error: any) { if (error.name === "AccessDenied") { From 1f82929c4f817d99db63d136022daec84bbc4d03 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:42:30 +0900 Subject: [PATCH 5/8] lint --- packages/filesystem/s3/s3.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/filesystem/s3/s3.ts b/packages/filesystem/s3/s3.ts index 8cc487511..4431dd999 100644 --- a/packages/filesystem/s3/s3.ts +++ b/packages/filesystem/s3/s3.ts @@ -203,7 +203,7 @@ export default class S3FileSystem implements FileSystem { Prefix: prefix, Delimiter: "/", ContinuationToken: continuationToken, - MaxKeys: 1000, // ← 每次最多 1000,防滥用 + MaxKeys: 1000, // ← 每次最多 1000,防滥用 }); const response = await this.client.send(command); From 0815b9dce9f2c0f33b75266e805b3a96df89f5bc Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:56:11 +0900 Subject: [PATCH 6/8] =?UTF-8?q?PutObjectCommand=20=E7=9A=84=20Body=20?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E7=9B=B4=E6=8E=A5=E5=86=99=E5=85=A5=20Blob?= =?UTF-8?q?=20content?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/filesystem/s3/rw.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/filesystem/s3/rw.ts b/packages/filesystem/s3/rw.ts index 409f7f965..d71409078 100644 --- a/packages/filesystem/s3/rw.ts +++ b/packages/filesystem/s3/rw.ts @@ -93,7 +93,6 @@ export class S3FileWriter implements FileWriter { * @throws {Error} If upload fails */ async write(content: string | Blob): Promise { - const body = content instanceof Blob ? new Uint8Array(await content.arrayBuffer()) : content; const metadata: Record = {}; if (this.modifiedDate) { @@ -104,7 +103,7 @@ export class S3FileWriter implements FileWriter { const command = new PutObjectCommand({ Bucket: this.bucket, Key: this.key, - Body: body, + Body: content, Metadata: Object.keys(metadata).length > 0 ? metadata : undefined, }); From f9233388a56e186fe336a8475186da3ceff5031d Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:06:42 +0900 Subject: [PATCH 7/8] added comment --- packages/filesystem/s3/rw.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/filesystem/s3/rw.ts b/packages/filesystem/s3/rw.ts index d71409078..f4526fd4e 100644 --- a/packages/filesystem/s3/rw.ts +++ b/packages/filesystem/s3/rw.ts @@ -103,7 +103,7 @@ export class S3FileWriter implements FileWriter { const command = new PutObjectCommand({ Bucket: this.bucket, Key: this.key, - Body: content, + Body: content, // API 的 Body 接受 string | Blob | Uint8Array | Buffer | Readable | ReadableStream Metadata: Object.keys(metadata).length > 0 ? metadata : undefined, }); From 65361891ed27d66bb496476409c1f48785d25257 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:15:20 +0900 Subject: [PATCH 8/8] lint --- packages/filesystem/s3/rw.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/filesystem/s3/rw.ts b/packages/filesystem/s3/rw.ts index f4526fd4e..008d0bb8d 100644 --- a/packages/filesystem/s3/rw.ts +++ b/packages/filesystem/s3/rw.ts @@ -93,7 +93,6 @@ export class S3FileWriter implements FileWriter { * @throws {Error} If upload fails */ async write(content: string | Blob): Promise { - const metadata: Record = {}; if (this.modifiedDate) { // 用 ISO 8601 格式