diff --git a/.github/workflows/qa-windows-node.yml b/.github/workflows/qa-windows-node.yml index 0c2a072..3f9bf95 100644 --- a/.github/workflows/qa-windows-node.yml +++ b/.github/workflows/qa-windows-node.yml @@ -2,7 +2,6 @@ name: Ubuntu + Windows on: workflow_dispatch: - concurrency: group: ${{ github.workflow }}-${{ github.ref }}-windows-node diff --git a/package-lock.json b/package-lock.json index 34315bd..77d651c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "express": "^5.1.0", "node-fetch": "^3.3.2", "rimraf": "^6.1.2", + "tsdown": "^0.15.12", "tsx": "^4.20.6", "typescript": "^5.9.3", "vite": "^7.2.4", @@ -234,32 +235,32 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.937.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.937.0.tgz", - "integrity": "sha512-ioeNe6HSc7PxjsUQY7foSHmgesxM5KwAeUtPhIHgKx99nrM+7xYCfW4FMvHypUzz7ZOvqlCdH7CEAZ8ParBvVg==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.940.0.tgz", + "integrity": "sha512-Wi4qnBT6shRRMXuuTgjMFTU5mu2KFWisgcigEMPptjPGUtJvBVi4PTGgS64qsLoUk/obqDAyOBOfEtRZ2ddC2w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.936.0", - "@aws-sdk/credential-provider-node": "3.936.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/middleware-bucket-endpoint": "3.936.0", "@aws-sdk/middleware-expect-continue": "3.936.0", - "@aws-sdk/middleware-flexible-checksums": "3.936.0", + "@aws-sdk/middleware-flexible-checksums": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-location-constraint": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", - "@aws-sdk/middleware-sdk-s3": "3.936.0", + "@aws-sdk/middleware-sdk-s3": "3.940.0", "@aws-sdk/middleware-ssec": "3.936.0", - "@aws-sdk/middleware-user-agent": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", - "@aws-sdk/signature-v4-multi-region": "3.936.0", + "@aws-sdk/signature-v4-multi-region": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", - "@aws-sdk/util-user-agent-node": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/eventstream-serde-browser": "^4.2.5", @@ -300,23 +301,23 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.936.0.tgz", - "integrity": "sha512-0G73S2cDqYwJVvqL08eakj79MZG2QRaB56Ul8/Ps9oQxllr7DMI1IQ/N3j3xjxgpq/U36pkoFZ8aK1n7Sbr3IQ==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz", + "integrity": "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", - "@aws-sdk/middleware-user-agent": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", - "@aws-sdk/util-user-agent-node": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", @@ -349,9 +350,9 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.936.0.tgz", - "integrity": "sha512-eGJ2ySUMvgtOziHhDRDLCrj473RJoL4J1vPjVM3NrKC/fF3/LoHjkut8AAnKmrW6a2uTzNKubigw8dEnpmpERw==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.940.0.tgz", + "integrity": "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.936.0", @@ -373,12 +374,12 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.936.0.tgz", - "integrity": "sha512-dKajFuaugEA5i9gCKzOaVy9uTeZcApE+7Z5wdcZ6j40523fY1a56khDAUYkCfwqa7sHci4ccmxBkAo+fW1RChA==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz", + "integrity": "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", @@ -389,12 +390,12 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.936.0.tgz", - "integrity": "sha512-5FguODLXG1tWx/x8fBxH+GVrk7Hey2LbXV5h9SFzYCx/2h50URBm0+9hndg0Rd23+xzYe14F6SI9HA9c1sPnjg==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz", + "integrity": "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", @@ -410,19 +411,19 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.936.0.tgz", - "integrity": "sha512-TbUv56ERQQujoHcLMcfL0Q6bVZfYF83gu/TjHkVkdSlHPOIKaG/mhE2XZSQzXv1cud6LlgeBbfzVAxJ+HPpffg==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz", + "integrity": "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", - "@aws-sdk/credential-provider-env": "3.936.0", - "@aws-sdk/credential-provider-http": "3.936.0", - "@aws-sdk/credential-provider-login": "3.936.0", - "@aws-sdk/credential-provider-process": "3.936.0", - "@aws-sdk/credential-provider-sso": "3.936.0", - "@aws-sdk/credential-provider-web-identity": "3.936.0", - "@aws-sdk/nested-clients": "3.936.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-login": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", @@ -435,13 +436,13 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.936.0.tgz", - "integrity": "sha512-8DVrdRqPyUU66gfV7VZNToh56ZuO5D6agWrkLQE/xbLJOm2RbeRgh6buz7CqV8ipRd6m+zCl9mM4F3osQLZn8Q==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz", + "integrity": "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", - "@aws-sdk/nested-clients": "3.936.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", @@ -454,17 +455,17 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.936.0.tgz", - "integrity": "sha512-rk/2PCtxX9xDsQW8p5Yjoca3StqmQcSfkmD7nQ61AqAHL1YgpSQWqHE+HjfGGiHDYKG7PvE33Ku2GyA7lEIJAw==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz", + "integrity": "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.936.0", - "@aws-sdk/credential-provider-http": "3.936.0", - "@aws-sdk/credential-provider-ini": "3.936.0", - "@aws-sdk/credential-provider-process": "3.936.0", - "@aws-sdk/credential-provider-sso": "3.936.0", - "@aws-sdk/credential-provider-web-identity": "3.936.0", + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-ini": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", @@ -477,12 +478,12 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.936.0.tgz", - "integrity": "sha512-GpA4AcHb96KQK2PSPUyvChvrsEKiLhQ5NWjeef2IZ3Jc8JoosiedYqp6yhZR+S8cTysuvx56WyJIJc8y8OTrLA==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz", + "integrity": "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", @@ -494,14 +495,14 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.936.0.tgz", - "integrity": "sha512-wHlEAJJvtnSyxTfNhN98JcU4taA1ED2JvuI2eePgawqBwS/Tzi0mhED1lvNIaWOkjfLd+nHALwszGrtJwEq4yQ==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz", + "integrity": "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.936.0", - "@aws-sdk/core": "3.936.0", - "@aws-sdk/token-providers": "3.936.0", + "@aws-sdk/client-sso": "3.940.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", @@ -513,13 +514,13 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.936.0.tgz", - "integrity": "sha512-v3qHAuoODkoRXsAF4RG+ZVO6q2P9yYBT4GMpMEfU9wXVNn7AIfwZgTwzSUfnjNiGva5BKleWVpRpJ9DeuLFbUg==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz", + "integrity": "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", - "@aws-sdk/nested-clients": "3.936.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", @@ -531,9 +532,9 @@ } }, "node_modules/@aws-sdk/lib-storage": { - "version": "3.937.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.937.0.tgz", - "integrity": "sha512-G+AxZX14MaVUT93BGeG17yBC+rR5yOOvE0QLpSViSARjPLI7el1zEEpOzC18OKIchFoM81VfC0xavfNMIp/bfw==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.940.0.tgz", + "integrity": "sha512-4pHgz9tuFJNSy/qoTbW5FqXPjoR4B18jB656UsE+TP5GWd7EPx7m4F0EUwIsD3OF5+KPiiyICi8zkxOs7erfQw==", "license": "Apache-2.0", "dependencies": { "@smithy/abort-controller": "^4.2.5", @@ -548,7 +549,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-s3": "^3.937.0" + "@aws-sdk/client-s3": "^3.940.0" } }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { @@ -585,15 +586,15 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.936.0.tgz", - "integrity": "sha512-l3GG6CrSQtMCM6fWY7foV3JQv0WJWT+3G6PSP3Ceb/KEE/5Lz5PrYFXTBf+bVoYL1b0bGjGajcgAXpstBmtHtQ==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.940.0.tgz", + "integrity": "sha512-WdsxDAVj5qaa5ApAP+JbpCOMHFGSmzjs2Y2OBSbWPeR9Ew7t/Okj+kUub94QJPsgzhvU1/cqNejhsw5VxeFKSQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.5", @@ -668,12 +669,12 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.936.0.tgz", - "integrity": "sha512-UQs/pVq4cOygsnKON0pOdSKIWkfgY0dzq4h+fR+xHi/Ng3XzxPJhWeAE6tDsKrcyQc1X8UdSbS70XkfGYr5hng==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.940.0.tgz", + "integrity": "sha512-JYkLjgS1wLoKHJ40G63+afM1ehmsPsjcmrHirKh8+kSCx4ip7+nL1e/twV4Zicxr8RJi9Y0Ahq5mDvneilDDKQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.5", @@ -707,12 +708,12 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.936.0.tgz", - "integrity": "sha512-YB40IPa7K3iaYX0lSnV9easDOLPLh+fJyUDF3BH8doX4i1AOSsYn86L4lVldmOaSX+DwiaqKHpvk4wPBdcIPWw==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.940.0.tgz", + "integrity": "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", @@ -725,23 +726,23 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.936.0.tgz", - "integrity": "sha512-eyj2tz1XmDSLSZQ5xnB7cLTVKkSJnYAEoNDSUNhzWPxrBDYeJzIbatecOKceKCU8NBf8gWWZCK/CSY0mDxMO0A==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.940.0.tgz", + "integrity": "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.936.0", + "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", - "@aws-sdk/middleware-user-agent": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", - "@aws-sdk/util-user-agent-node": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", @@ -790,12 +791,12 @@ } }, "node_modules/@aws-sdk/s3-request-presigner": { - "version": "3.937.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.937.0.tgz", - "integrity": "sha512-AvsCt6FnnKTpkmzDA1pFzmXPyxbGBdtllOIY0mL1iNSVZ3d7SoJKZH4NaqlcgUtbYG9zVh6QfLWememj1yEAmw==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.940.0.tgz", + "integrity": "sha512-TgTUDM2H7revReDfkVwVtIqxV3K0cJLdyuLDIkefVHRUNKwU1Vd5FB2TaFrs6STO0kx5pTckDCOLh0iy7nW5WQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/signature-v4-multi-region": "3.936.0", + "@aws-sdk/signature-v4-multi-region": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-format-url": "3.936.0", "@smithy/middleware-endpoint": "^4.3.12", @@ -809,12 +810,12 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.936.0.tgz", - "integrity": "sha512-8qS0GFUqkmwO7JZ0P8tdluBmt1UTfYUah8qJXGzNh9n1Pcb0AIeT117cCSiCUtwk+gDbJvd4hhRIhJCNr5wgjg==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.940.0.tgz", + "integrity": "sha512-ugHZEoktD/bG6mdgmhzLDjMP2VrYRAUPRPF1DpCyiZexkH7DCU7XrSJyXMvkcf0DHV+URk0q2sLf/oqn1D2uYw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.936.0", + "@aws-sdk/middleware-sdk-s3": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", @@ -826,13 +827,13 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.936.0.tgz", - "integrity": "sha512-vvw8+VXk0I+IsoxZw0mX9TMJawUJvEsg3EF7zcCSetwhNPAU8Xmlhv7E/sN/FgSmm7b7DsqKoW6rVtQiCs1PWQ==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz", + "integrity": "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.936.0", - "@aws-sdk/nested-clients": "3.936.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", @@ -900,9 +901,9 @@ } }, "node_modules/@aws-sdk/util-locate-window": { - "version": "3.804.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.804.0.tgz", - "integrity": "sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A==", + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.893.0.tgz", + "integrity": "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -924,12 +925,12 @@ } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.936.0.tgz", - "integrity": "sha512-XOEc7PF9Op00pWV2AYCGDSu5iHgYjIO53Py2VUQTIvP7SRCaCsXmA33mjBvC2Ms6FhSyWNa4aK4naUGIz0hQcw==", + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.940.0.tgz", + "integrity": "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", @@ -961,36 +962,6 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/xml-builder/node_modules/fast-xml-parser": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", - "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "strnum": "^2.1.0" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/@aws-sdk/xml-builder/node_modules/strnum": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", - "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" - }, "node_modules/@aws/lambda-invoke-store": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz", @@ -1086,9 +1057,9 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.1.tgz", - "integrity": "sha512-UVZlVLfLyz6g3Hy7GNDpooMQonUygH7ghdiSASOOHy97fKj/mPLqgDX7aidOijn+sCMU+WU8NjlPlNTgnvbcGA==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", + "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", "license": "MIT", "dependencies": { "@azure/abort-controller": "^2.1.2", @@ -1130,48 +1101,18 @@ } }, "node_modules/@azure/core-xml": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.4.5.tgz", - "integrity": "sha512-gT4H8mTaSXRz7eGTuQyq1aIJnJqeXzpOe9Ay7Z3FrCouer14CbV3VzjnJrNrQfbBpGBLO9oy8BmrY75A0p53cA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.5.0.tgz", + "integrity": "sha512-D/sdlJBMJfx7gqoj66PKVmhDDaU6TKA49ptcolxdas29X7AfvLTmfAGLjAcIMBK7UZ2o4lygHIqVckOlQU3xWw==", "license": "MIT", "dependencies": { "fast-xml-parser": "^5.0.7", "tslib": "^2.8.1" }, "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-xml/node_modules/fast-xml-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.3.tgz", - "integrity": "sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "strnum": "^2.1.0" - }, - "bin": { - "fxparser": "src/cli/cli.js" + "node": ">=20.0.0" } }, - "node_modules/@azure/core-xml/node_modules/strnum": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", - "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" - }, "node_modules/@azure/logger": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", @@ -1230,6 +1171,73 @@ "node": ">=20.0.0" } }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@borewit/text-codec": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.1.1.tgz", @@ -1240,6 +1248,40 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@epic-web/invariant": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz", @@ -1248,9 +1290,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -1265,9 +1307,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -1282,9 +1324,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -1299,9 +1341,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -1316,9 +1358,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -1333,9 +1375,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -1350,9 +1392,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -1367,9 +1409,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -1384,9 +1426,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -1401,9 +1443,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -1418,9 +1460,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -1435,9 +1477,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -1452,9 +1494,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -1469,9 +1511,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -1486,9 +1528,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -1503,9 +1545,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -1520,9 +1562,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -1537,9 +1579,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], @@ -1554,9 +1596,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -1571,9 +1613,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -1588,9 +1630,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -1604,10 +1646,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -1622,9 +1681,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -1639,9 +1698,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -1656,9 +1715,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -1766,50 +1825,393 @@ "uuid": "^8.0.0" }, "engines": { - "node": ">=14" + "node": ">=14" + } + }, + "node_modules/@google-cloud/storage/node_modules/fast-xml-parser": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.1.1" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/@google-cloud/storage/node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.95.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.95.0.tgz", + "integrity": "sha512-vACy7vhpMPhjEJhULNxrdR0D943TkA/MigMpJCHmBHvMXxRStRi/dPtTlfQ3uDwWSzRpT8z+7ImjZVf8JWBocQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@quansync/fs": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-0.1.5.tgz", + "integrity": "sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.11" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.45.tgz", + "integrity": "sha512-bfgKYhFiXJALeA/riil908+2vlyWGdwa7Ju5S+JgWZYdR4jtiPOGdM6WLfso1dojCh+4ZWeiTwPeV9IKQEX+4g==", + "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.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.45.tgz", + "integrity": "sha512-xjCv4CRVsSnnIxTuyH1RDJl5OEQ1c9JYOwfDAHddjJDxCw46ZX9q80+xq7Eok7KC4bRSZudMJllkvOKv0T9SeA==", + "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.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.45.tgz", + "integrity": "sha512-ddcO9TD3D/CLUa/l8GO8LHzBOaZqWg5ClMy3jICoxwCuoz47h9dtqPsIeTiB6yR501LQTeDsjA4lIFd7u3Ljfw==", + "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.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.45.tgz", + "integrity": "sha512-MBTWdrzW9w+UMYDUvnEuh0pQvLENkl2Sis15fHTfHVW7ClbGuez+RWopZudIDEGkpZXdeI4CkRXk+vdIIebrmg==", + "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.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.45.tgz", + "integrity": "sha512-4YgoCFiki1HR6oSg+GxxfzfnVCesQxLF1LEnw9uXS/MpBmuog0EOO2rYfy69rWP4tFZL9IWp6KEfGZLrZ7aUog==", + "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.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.45.tgz", + "integrity": "sha512-LE1gjAwQRrbCOorJJ7LFr10s5vqYf5a00V5Ea9wXcT2+56n5YosJkcp8eQ12FxRBv2YX8dsdQJb+ZTtYJwb6XQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.45.tgz", + "integrity": "sha512-tdy8ThO/fPp40B81v0YK3QC+KODOmzJzSUOO37DinQxzlTJ026gqUSOM8tzlVixRbQJltgVDCTYF8HNPRErQTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.45.tgz", + "integrity": "sha512-lS082ROBWdmOyVY/0YB3JmsiClaWoxvC+dA8/rbhyB9VLkvVEaihLEOr4CYmrMse151C4+S6hCw6oa1iewox7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.45.tgz", + "integrity": "sha512-Hi73aYY0cBkr1/SvNQqH8Cd+rSV6S9RB5izCv0ySBcRnd/Wfn5plguUoGYwBnhHgFbh6cPw9m2dUVBR6BG1gxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.45.tgz", + "integrity": "sha512-fljEqbO7RHHogNDxYtTzr+GNjlfOx21RUyGmF+NrkebZ8emYYiIqzPxsaMZuRx0rgZmVmliOzEp86/CQFDKhJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.45.tgz", + "integrity": "sha512-ZJDB7lkuZE9XUnWQSYrBObZxczut+8FZ5pdanm8nNS1DAo8zsrPuvGwn+U3fwU98WaiFsNrA4XHngesCGr8tEQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.7" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.45.tgz", + "integrity": "sha512-zyzAjItHPUmxg6Z8SyRhLdXlJn3/D9KL5b9mObUrBHhWS/GwRH4665xCiFqeuktAhhWutqfc+rOV2LjK4VYQGQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.45.tgz", + "integrity": "sha512-wODcGzlfxqS6D7BR0srkJk3drPwXYLu7jPHN27ce2c4PUnVVmJnp9mJzUQGT4LpmHmmVdMZ+P6hKvyTGBzc1CA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.45.tgz", + "integrity": "sha512-wiU40G1nQo9rtfvF9jLbl79lUgjfaD/LTyUEw2Wg/gdF5OhjzpKMVugZQngO+RNdwYaNj+Fs+kWBWfp4VXPMHA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.45.tgz", + "integrity": "sha512-Le9ulGCrD8ggInzWw/k2J8QcbPz7eGIOWqfJ2L+1R0Opm7n6J37s2hiDWlh6LJN0Lk9L5sUzMvRHKW7UxBZsQA==", "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", - "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", "cpu": [ "arm" ], @@ -1821,9 +2223,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", - "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", "cpu": [ "arm64" ], @@ -1835,9 +2237,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", - "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", "cpu": [ "arm64" ], @@ -1849,9 +2251,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", - "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", "cpu": [ "x64" ], @@ -1863,9 +2265,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", - "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", "cpu": [ "arm64" ], @@ -1877,9 +2279,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", - "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", "cpu": [ "x64" ], @@ -1891,9 +2293,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", - "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", "cpu": [ "arm" ], @@ -1905,9 +2307,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", - "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", "cpu": [ "arm" ], @@ -1919,9 +2321,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", - "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", "cpu": [ "arm64" ], @@ -1933,9 +2335,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", - "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", "cpu": [ "arm64" ], @@ -1946,10 +2348,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", - "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", "cpu": [ "loong64" ], @@ -1961,9 +2363,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", - "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", "cpu": [ "ppc64" ], @@ -1975,9 +2377,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", - "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", "cpu": [ "riscv64" ], @@ -1989,9 +2391,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", - "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", "cpu": [ "riscv64" ], @@ -2003,9 +2405,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", - "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", "cpu": [ "s390x" ], @@ -2017,9 +2419,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", - "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", "cpu": [ "x64" ], @@ -2031,9 +2433,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", - "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", "cpu": [ "x64" ], @@ -2044,10 +2446,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", - "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", "cpu": [ "arm64" ], @@ -2059,9 +2475,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", - "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", "cpu": [ "ia32" ], @@ -2072,10 +2488,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", + "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", - "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", + "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", "cpu": [ "x64" ], @@ -3083,10 +3513,21 @@ "node": ">= 10" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, "license": "MIT", "dependencies": { @@ -3148,9 +3589,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", - "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", "dev": true, "license": "MIT", "dependencies": { @@ -3161,9 +3602,9 @@ } }, "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "dev": true, "license": "MIT" }, @@ -3178,13 +3619,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-3.0.1.tgz", "integrity": "sha512-xRMsfuQbnRq1Ef+C+RKaENOxXX87Ygl38W1vDfPHRku02TgQr+Qd8iivLtAMcR0KF5/29xlnFihkTlbqFrGOVQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/multer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } @@ -3213,15 +3656,15 @@ "license": "MIT" }, "node_modules/@types/request": { - "version": "2.48.12", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", - "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", + "version": "2.48.13", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz", + "integrity": "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==", "license": "MIT", "dependencies": { "@types/caseless": "*", "@types/node": "*", "@types/tough-cookie": "*", - "form-data": "^2.5.0" + "form-data": "^2.5.5" } }, "node_modules/@types/request/node_modules/form-data": { @@ -3263,26 +3706,36 @@ } }, "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", - "@types/send": "*" + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" } }, "node_modules/@types/tough-cookie": { @@ -3292,9 +3745,9 @@ "license": "MIT" }, "node_modules/@typespec/ts-http-runtime": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.1.tgz", - "integrity": "sha512-SnbaqayTVFEA6/tYumdF0UmybY0KHyKwGPBXnyckFlrrKdhWFrL3a2HIPXHjht5ZOElKGcXfD2D63P36btb+ww==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.2.tgz", + "integrity": "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==", "license": "MIT", "dependencies": { "http-proxy-agent": "^7.0.0", @@ -3465,14 +3918,24 @@ } }, "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { "node": ">= 14" } }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3489,6 +3952,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -3514,6 +3987,23 @@ "node": ">=12" } }, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/async-retry": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", @@ -3550,39 +4040,53 @@ "license": "MIT" }, "node_modules/bignumber.js": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", - "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", "license": "MIT", "engines": { "node": "*" } }, + "node_modules/birpc": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.8.0.tgz", + "integrity": "sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/bowser": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.0.tgz", - "integrity": "sha512-yHAbSRuT6LTeKi6k2aS40csueHqgAsFEgmrOsfRyFpJnFv5O2hl9FYmWEUZ97gZ/dG17U4IQQcTx4YAFYPuWRQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", + "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==", "license": "MIT" }, "node_modules/buffer": { @@ -3604,7 +4108,8 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" }, "node_modules/busboy": { "version": "1.6.0", @@ -3627,6 +4132,16 @@ "node": ">= 0.8" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -3697,6 +4212,22 @@ "node": ">=8" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3712,69 +4243,6 @@ "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/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==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/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==", - "dev": true, - "license": "MIT", - "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/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3814,6 +4282,7 @@ "engines": [ "node >= 6.0" ], + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -3847,16 +4316,17 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -3949,6 +4419,13 @@ } } }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3968,6 +4445,16 @@ "node": ">= 0.8" } }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dotenv": { "version": "17.2.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", @@ -3980,6 +4467,27 @@ "url": "https://dotenvx.com" } }, + "node_modules/dts-resolver": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/dts-resolver/-/dts-resolver-2.1.3.tgz", + "integrity": "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "oxc-resolver": ">=11.0.0" + }, + "peerDependenciesMeta": { + "oxc-resolver": { + "optional": true + } + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4022,6 +4530,23 @@ "dev": true, "license": "MIT" }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -4033,9 +4558,9 @@ } }, "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -4094,9 +4619,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4107,31 +4632,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -4249,22 +4775,18 @@ "license": "MIT" }, "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", + "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" } ], "license": "MIT", "dependencies": { - "strnum": "^1.0.5" + "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" @@ -4570,9 +5092,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4707,6 +5229,13 @@ "node": ">= 0.4" } }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, "node_modules/html-entities": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", @@ -4724,20 +5253,24 @@ "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-proxy-agent": { @@ -4767,9 +5300,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4777,6 +5310,10 @@ }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ieee754": { @@ -4851,6 +5388,29 @@ "dev": true, "license": "ISC" }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -5105,6 +5665,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5277,13 +5838,14 @@ } }, "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=16" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/pathe": { @@ -5297,7 +5859,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", @@ -5331,6 +5894,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5370,6 +5934,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -5381,19 +5962,19 @@ } }, "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/readable-stream": { @@ -5410,6 +5991,20 @@ "node": ">= 6" } }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5473,10 +6068,88 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rolldown": { + "version": "1.0.0-beta.45", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.45.tgz", + "integrity": "sha512-iMmuD72XXLf26Tqrv1cryNYLX6NNPLhZ3AmNkSf8+xda0H+yijjGJ+wVT9UdBUHOpKzq9RjKtQKRCWoEKQQBZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.95.0", + "@rolldown/pluginutils": "1.0.0-beta.45" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.45", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.45", + "@rolldown/binding-darwin-x64": "1.0.0-beta.45", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.45", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.45", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.45", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.45", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.45", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.45", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.45", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.45", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.45", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.45", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.45" + } + }, + "node_modules/rolldown-plugin-dts": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/rolldown-plugin-dts/-/rolldown-plugin-dts-0.17.8.tgz", + "integrity": "sha512-76EEBlhF00yeY6M7VpMkWKI4r9WjuoMiOGey7j4D6zf3m0BR+ZrrY9hvSXdueJ3ljxSLq4DJBKFpX/X9+L7EKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.5", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "ast-kit": "^2.2.0", + "birpc": "^2.8.0", + "dts-resolver": "^2.1.3", + "get-tsconfig": "^4.13.0", + "magic-string": "^0.30.21", + "obug": "^2.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@ts-macro/tsc": "^0.3.6", + "@typescript/native-preview": ">=7.0.0-dev.20250601.1", + "rolldown": "^1.0.0-beta.44", + "typescript": "^5.0.0", + "vue-tsc": "~3.1.0" + }, + "peerDependenciesMeta": { + "@ts-macro/tsc": { + "optional": true + }, + "@typescript/native-preview": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + } + } + }, "node_modules/rollup": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", - "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", + "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, "license": "MIT", "dependencies": { @@ -5490,26 +6163,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.46.2", - "@rollup/rollup-android-arm64": "4.46.2", - "@rollup/rollup-darwin-arm64": "4.46.2", - "@rollup/rollup-darwin-x64": "4.46.2", - "@rollup/rollup-freebsd-arm64": "4.46.2", - "@rollup/rollup-freebsd-x64": "4.46.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", - "@rollup/rollup-linux-arm-musleabihf": "4.46.2", - "@rollup/rollup-linux-arm64-gnu": "4.46.2", - "@rollup/rollup-linux-arm64-musl": "4.46.2", - "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", - "@rollup/rollup-linux-ppc64-gnu": "4.46.2", - "@rollup/rollup-linux-riscv64-gnu": "4.46.2", - "@rollup/rollup-linux-riscv64-musl": "4.46.2", - "@rollup/rollup-linux-s390x-gnu": "4.46.2", - "@rollup/rollup-linux-x64-gnu": "4.46.2", - "@rollup/rollup-linux-x64-musl": "4.46.2", - "@rollup/rollup-win32-arm64-msvc": "4.46.2", - "@rollup/rollup-win32-ia32-msvc": "4.46.2", - "@rollup/rollup-win32-x64-msvc": "4.46.2", + "@rollup/rollup-android-arm-eabi": "4.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" } }, @@ -5567,6 +6242,19 @@ "dev": true, "license": "MIT" }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", @@ -5752,6 +6440,7 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -5764,9 +6453,9 @@ "license": "MIT" }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { @@ -5822,10 +6511,38 @@ "safe-buffer": "~5.2.0" } }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strnum": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", - "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", "funding": [ { "type": "github", @@ -5968,11 +6685,14 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/tinyglobby": { "version": "0.2.15", @@ -6056,9 +6776,9 @@ } }, "node_modules/tsconfck": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.5.tgz", - "integrity": "sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", "dev": true, "license": "MIT", "bin": { @@ -6076,6 +6796,66 @@ } } }, + "node_modules/tsdown": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.15.12.tgz", + "integrity": "sha512-c8VLlQm8/lFrOAg5VMVeN4NAbejZyVQkzd+ErjuaQgJFI/9MhR9ivr0H/CM7UlOF1+ELlF6YaI7sU/4itgGQ8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^4.2.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "debug": "^4.4.3", + "diff": "^8.0.2", + "empathic": "^2.0.0", + "hookable": "^5.5.3", + "rolldown": "1.0.0-beta.45", + "rolldown-plugin-dts": "^0.17.2", + "semver": "^7.7.3", + "tinyexec": "^1.0.1", + "tinyglobby": "^0.2.15", + "tree-kill": "^1.2.2", + "unconfig": "^7.3.3" + }, + "bin": { + "tsdown": "dist/run.mjs" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@arethetypeswrong/core": "^0.18.1", + "publint": "^0.3.0", + "typescript": "^5.0.0", + "unplugin-lightningcss": "^0.4.0", + "unplugin-unused": "^0.5.0", + "unrun": "^0.2.1" + }, + "peerDependenciesMeta": { + "@arethetypeswrong/core": { + "optional": true + }, + "publint": { + "optional": true + }, + "typescript": { + "optional": true + }, + "unplugin-lightningcss": { + "optional": true + }, + "unplugin-unused": { + "optional": true + }, + "unrun": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -6120,7 +6900,8 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" }, "node_modules/typescript": { "version": "5.9.3", @@ -6137,9 +6918,9 @@ } }, "node_modules/uint8array-extras": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.4.0.tgz", - "integrity": "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", "license": "MIT", "engines": { "node": ">=18" @@ -6148,6 +6929,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unconfig": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-7.4.1.tgz", + "integrity": "sha512-uyQ7LElcGizrOGZyIq9KU+xkuEjcRf9IpmDTkCSYv5mEeZzrXSj6rb51C0L+WTedsmAoVxW9WKrLWhSwebIM9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^0.1.5", + "defu": "^6.1.4", + "jiti": "^2.6.1", + "quansync": "^0.2.11", + "unconfig-core": "7.4.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unconfig-core": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/unconfig-core/-/unconfig-core-7.4.1.tgz", + "integrity": "sha512-Bp/bPZjV2Vl/fofoA2OYLSnw1Z0MOhCX7zHnVCYrazpfZvseBbGhwcNQMxsg185Mqh7VZQqK3C8hFG/Dyng+yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^0.1.5", + "quansync": "^0.2.11" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -6362,6 +7174,13 @@ } } }, + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -6421,6 +7240,24 @@ "node": ">=8" } }, + "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==", + "dev": true, + "license": "MIT", + "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/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6475,51 +7312,6 @@ "node": ">=12" } }, - "node_modules/yargs/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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/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==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -6571,7 +7363,7 @@ }, "packages/file-storage": { "name": "@flystorage/file-storage", - "version": "1.2.0", + "version": "1.2.1", "license": "MIT" }, "packages/google-cloud-storage": { diff --git a/package.json b/package.json index 09eb8bf..bf8644b 100644 --- a/package.json +++ b/package.json @@ -2,19 +2,14 @@ "private": true, "type": "module", "scripts": { - "build": "npm run compile -ws --if-present && npm run patch -ws --if-present", - "build:only": "npm run compile -ws --if-present", - "clean:build": "npm run clean && npm run build", - "watch": "concurrently npm:watch:*", - "watch:file-storage": "npm run watch -w ./packages/file-storage", - "watch:stream-mime-type": "npm run watch -w ./packages/stream-mime-type", - "watch:local": "npm run watch -w ./packages/local-fs", - "watch:aws-s3": "npm run watch -w ./packages/aws-s3", + "build": "tsdown && npm run patch -ws --if-present", + "build:only": "tsdown", "clean": "rm -rf ./packages/*/dist/", "ts": "node --import tsx/esm", "lint": "tsc --noEmit --incremental false", "test": "npm run lint && npm run vitest", - "vitest": "vitest run" + "vitest": "vitest run", + "pack": "npm pack -ws --pack-destination ./packed" }, "workspaces": [ "./packages/stream-mime-type", @@ -33,6 +28,7 @@ "express": "^5.1.0", "node-fetch": "^3.3.2", "rimraf": "^6.1.2", + "tsdown": "^0.15.12", "tsx": "^4.20.6", "typescript": "^5.9.3", "vite": "^7.2.4", diff --git a/packages/aws-s3/package.json b/packages/aws-s3/package.json index 80a7da1..b467ae1 100644 --- a/packages/aws-s3/package.json +++ b/packages/aws-s3/package.json @@ -12,27 +12,20 @@ "mime-types": "^3.0.2" }, "description": "", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, - "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" - }, "keywords": [ "s3", "file", diff --git a/packages/aws-s3/src/aws-s3-storage-adapter.ts b/packages/aws-s3/src/aws-s3-storage-adapter.ts deleted file mode 100644 index b48e95d..0000000 --- a/packages/aws-s3/src/aws-s3-storage-adapter.ts +++ /dev/null @@ -1,820 +0,0 @@ -import { - _Object, - CommonPrefix, - CopyObjectCommand, - CopyObjectRequest, - DeleteObjectCommand, - DeleteObjectsCommand, - GetObjectAclCommand, - GetObjectAclOutput, - GetObjectCommand, - GetObjectCommandInput, - GetObjectCommandOutput, - HeadObjectCommand, - ListObjectsV2Command, - ListObjectsV2Output, - ObjectCannedACL, - PutObjectAclCommand, - PutObjectCommand, - PutObjectCommandInput, - S3Client, - S3ServiceException, -} from '@aws-sdk/client-s3'; -import {Configuration, Upload} from '@aws-sdk/lib-storage'; -import {getSignedUrl} from '@aws-sdk/s3-request-presigner'; -import {posix} from 'node:path'; -import { - AdapterListOptions, - ChecksumIsNotAvailable, - ChecksumOptions, - closeReadable, - CopyFileOptions, - CreateDirectoryOptions, - FileContents, - FileWasNotFound, - MimeTypeOptions, - MiscellaneousOptions, - MoveFileOptions, - normalizeExpiryToMilliseconds, - PathPrefixer, - PublicUrlOptions, - StatEntry, - StorageAdapter, - TemporaryUrlOptions, - UploadRequest, - UploadRequestHeaders, - UploadRequestOptions, - Visibility, - WriteOptions, -} from '@flystorage/file-storage'; -import {resolveMimeType} from '@flystorage/stream-mime-type'; -import {Readable} from 'stream'; -import {lookup} from 'mime-types'; - -type PutObjectOptions = Omit; -export type WriteOptionsForS3 = Omit; -const possibleChecksumAlgos = ['SHA1', 'SHA256', 'CRC32', 'CRC32C', 'ETAG'] as const; -type ChecksumAlgo = typeof possibleChecksumAlgos[number]; - -function isSupportedAlgo(algo: string): algo is ChecksumAlgo { - return possibleChecksumAlgos.includes(algo as ChecksumAlgo); -} - -export type AwsS3StorageAdapterOptions = Readonly<{ - bucket: string, - prefix?: string, - region?: string, - publicUrlOptions?: PublicUrlOptions, - uploadRequestOptions?: UploadRequestOptions, - putObjectOptions?: PutObjectOptions, - uploadConfiguration?: Partial>, - defaultChecksumAlgo?: ChecksumAlgo, -}>; - -export type AwsPublicUrlOptions = PublicUrlOptions & { - bucket: string, - region?: string, - forcePathStyle?: boolean, - baseUrl?: string, -} - -export type AwsPublicUrlGenerator = { - publicUrl(path: string, options: AwsPublicUrlOptions): Promise; -}; - -export class DefaultAwsPublicUrlGenerator implements AwsPublicUrlGenerator { - async publicUrl(path: string, options: AwsPublicUrlOptions): Promise { - const baseUrl = options.baseUrl ?? 'https://{subdomain}.amazonaws.com/{uri}'; - const subdomain = options.forcePathStyle !== true - ? `${options.bucket}.s3` - : options.region === undefined - ? 's3' - : `s3-${options.region}`; - const uri = options.forcePathStyle !== true - ? encodePath(path) - : `${options.bucket}/${encodePath(path)}`; - - return baseUrl.replace('{subdomain}', subdomain).replace('{uri}', uri); - } -} - -/** - * BC extension - */ -export class HostStyleAwsPublicUrlGenerator extends DefaultAwsPublicUrlGenerator { -} - -export type TimestampResolver = () => number; -type AclOptions = Pick; - -/** - * Some commands need URI encoded paths to work ¯\_(ツ)_/¯ - */ -function encodePath(path: string): string { - return path.split('/').map(encodeURIComponent).join('/'); -} - -function maybeAbort(signal?: AbortSignal) { - if (signal?.aborted) { - throw signal.reason; - } -} - -export class AwsS3StorageAdapter implements StorageAdapter { - private readonly prefixer: PathPrefixer; - - constructor( - private readonly client: S3Client, - private readonly options: AwsS3StorageAdapterOptions, - private readonly publicUrlGenerator: AwsPublicUrlGenerator = new DefaultAwsPublicUrlGenerator(), - private readonly timestampResolver: TimestampResolver = () => Date.now(), - ) { - this.prefixer = new PathPrefixer(options.prefix ?? '', '/', (...paths) => { - const path = posix.join(...paths); - - if (path === "." || path === "/") { - // 1) https://nodejs.org/api/path.html#pathjoinpaths - // Zero-length path segments are ignored. If the joined path string is a zero-length string then '.' will be - // returned, representing the current working directory. - // 2) In S3 we use delimiter:"/". In that case we need to remove the root-slash in order to list the - // root-directory contents. - return ""; - } else { - return path; - } - }); - } - - async copyFile(from: string, to: string, options: CopyFileOptions): Promise { - maybeAbort(options.abortSignal); - let visibility: string | undefined = options.visibility; - - if (visibility === undefined && options.retainVisibility) { - visibility = await this.visibility(from, options); - maybeAbort(options.abortSignal); - } - - let acl: AclOptions = (visibility !== undefined && options.useVisibility !== false) - ? {ACL: this.visibilityToAcl(visibility)} - : {}; - - await this.client.send(new CopyObjectCommand({ - Bucket: this.options.bucket, - CopySource: posix.join('/', this.options.bucket, encodePath(this.prefixer.prefixFilePath(from))), - Key: this.prefixer.prefixFilePath(to), - ...acl, - }), {abortSignal: options.abortSignal}); - } - async moveFile(from: string, to: string, options: MoveFileOptions): Promise { - await this.copyFile(from, to, options); - await this.deleteFile(from, options); - } - - async prepareUpload(path: string, options: UploadRequestOptions): Promise { - maybeAbort(options.abortSignal); - const expiry = normalizeExpiryToMilliseconds(options.expiresAt); - const now = (this.timestampResolver)(); - - const putObjectParams: PutObjectCommandInput = { - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - }; - - const headers: UploadRequestHeaders = {}; - const contentType = options['Content-Type'] ?? options.contentType; - - if (typeof contentType === 'string') { - putObjectParams.ContentType = contentType; - headers['Content-Type'] = contentType; - } - - const url = await getSignedUrl(this.client, new PutObjectCommand(putObjectParams), { - expiresIn: Math.floor((expiry - now) / 1000), - }); - - return { - url, - method: 'PUT', - provider: 'aws-s3', - headers, - }; - } - - async temporaryUrl(path: string, options: TemporaryUrlOptions): Promise { - maybeAbort(options.abortSignal); - const expiry = normalizeExpiryToMilliseconds(options.expiresAt); - const now = (this.timestampResolver)(); - - const getObjectParams: GetObjectCommandInput = { - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - }; - - if (options.responseHeaders) { - if (options.responseHeaders['Cache-Control']) { - getObjectParams.ResponseCacheControl = options.responseHeaders['Cache-Control']; - } - - if (options.responseHeaders['Content-Disposition']) { - getObjectParams.ResponseContentDisposition = options.responseHeaders['Content-Disposition']; - } - - if (options.responseHeaders['Content-Encoding']) { - getObjectParams.ResponseContentEncoding = options.responseHeaders['Content-Encoding']; - } - - if (options.responseHeaders['Content-Language']) { - getObjectParams.ResponseContentLanguage = options.responseHeaders['Content-Language']; - } - - if (options.responseHeaders['Content-Type']) { - getObjectParams.ResponseContentType = options.responseHeaders['Content-Type']; - } - - if (options.responseHeaders['Expires']) { - getObjectParams.ResponseExpires = new Date(options.responseHeaders['Expires']); - } - } - - return await getSignedUrl(this.client, new GetObjectCommand(getObjectParams), { - expiresIn: Math.floor((expiry - now) / 1000), - }); - } - - async lastModified(path: string, options: MiscellaneousOptions): Promise { - const stat = await this.stat(path, options); - - if (stat.lastModifiedMs === undefined) { - throw new Error('Last modified is not available in stat'); - } - - return stat.lastModifiedMs; - } - - async fileSize(path: string, options: MiscellaneousOptions): Promise { - const stat = await this.stat(path, options); - - if (stat.isFile === false) { - throw new Error('Path is not a file'); - } - - if (stat.size === undefined) { - throw new Error('File size is not available in stat.') - } - - return stat.size; - } - - async mimeType(path: string, options: MimeTypeOptions): Promise { - const response = await this.stat(path, options); - - if (!response.isFile) { - throw new Error(`Path "${path} is not a file.`); - } - - if (response.mimeType) { - return response.mimeType; - } - - if (options.disallowFallback) { - throw new Error('Mime-type not available via HeadObject'); - } - - maybeAbort(options.abortSignal); - const method = options.fallbackMethod ?? 'path'; - const mimeType = method === 'path' - ? lookup(path) - : await this.lookupMimeTypeFromStream(path, options); - - if (mimeType === undefined || mimeType === false) { - throw new Error('Unable to resolve mime-type'); - } - - return mimeType; - } - - async visibility(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - const response: GetObjectAclOutput = await this.client.send(new GetObjectAclCommand({ - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - }), { - abortSignal: options.abortSignal, - }); - - const publicRead = response.Grants?.some(grant => - grant.Grantee?.URI === 'http://acs.amazonaws.com/groups/global/AllUsers' - && grant.Permission === 'READ' - ) ?? false; - - return publicRead ? Visibility.PUBLIC : Visibility.PRIVATE; - } - - async* list(path: string, options: AdapterListOptions): AsyncGenerator { - const listing = this.listObjects(path, { - deep: options.deep, - includePrefixes: true, - includeSelf: false, - abortSignal: options.abortSignal, - }); - - for await (const {type, item} of listing) { - if (type === 'prefix') { - yield { - type: 'directory', - isFile: false, - isDirectory: true, - path: this.prefixer.stripDirectoryPath(item.Prefix!), - }; - } else { - const path = item.Key!; - - if (path.endsWith('/')) { - yield { - type: 'directory', - isFile: false, - isDirectory: true, - path: this.prefixer.stripDirectoryPath(path), - }; - } else { - yield { - type: 'file', - isFile: true, - isDirectory: false, - path: this.prefixer.stripFilePath(path), - size: item.Size ?? 0, - lastModifiedMs: item.LastModified?.getTime(), - }; - } - } - } - } - - async * listObjects( - path: string, - options: { - deep: boolean, - includePrefixes: boolean, - includeSelf: boolean, - maxKeys?: number, - abortSignal?: AbortSignal, - }, - ): AsyncGenerator<{ type: 'prefix', item: CommonPrefix } | { type: 'object', item: _Object }, any, unknown> { - maybeAbort(options.abortSignal); - const prefix = this.prefixer.prefixDirectoryPath(path); - let collectedKeys = 0; - let shouldContinue = true; - let continuationToken: string | undefined = undefined; - - while (shouldContinue && (options.maxKeys === undefined || collectedKeys < options.maxKeys)) { - maybeAbort(options.abortSignal); - const response: ListObjectsV2Output = await this.client.send(new ListObjectsV2Command({ - Bucket: this.options.bucket, - Prefix: prefix, - Delimiter: options.deep ? undefined : '/', - ContinuationToken: continuationToken, - MaxKeys: options.maxKeys, - })); - - continuationToken = response.NextContinuationToken; - shouldContinue = response.IsTruncated ?? false; - const prefixes = options.includePrefixes ? response.CommonPrefixes ?? [] : []; - - for (const item of prefixes) { - if ((!options.includeSelf && item.Prefix === prefix) || item.Prefix === undefined) { - continue; - } - - collectedKeys++; - yield {type: 'prefix', item}; - } - - for (const item of response.Contents ?? []) { - if ((!options.includeSelf && item.Key === prefix) || item.Key === undefined) { - // not interested in itself - // not interested in empty prefixes - continue; - } - - collectedKeys++; - yield {type: 'object', item}; - } - } - } - - async read(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - - let response: GetObjectCommandOutput; - - try { - response = await this.client.send(new GetObjectCommand({ - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - }), { - abortSignal: options.abortSignal, - }); - } catch (err) { - if (err instanceof S3ServiceException && err.$metadata.httpStatusCode === 404) { - throw FileWasNotFound.atLocation(path, { - context: {path, options}, - cause: err, - }); - } - - throw err; - } - - if (response.Body instanceof Readable || response.Body instanceof ReadableStream) { - return response.Body; - } - - throw new Error('No response body was provided'); - } - - async stat(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - const response = await this.client.send(new HeadObjectCommand({ - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - }), { - abortSignal: options.abortSignal, - }); - - return { - path, - type: 'file', - isDirectory: false, - isFile: true, - size: response.ContentLength ?? 0, - lastModifiedMs: response.LastModified?.getTime(), - mimeType: response.ContentType, - }; - } - - async createDirectory(path: string, options: CreateDirectoryOptions): Promise { - const key = this.prefixer.prefixDirectoryPath(path); - const abortSignal = options.abortSignal; - const abortController = new AbortController(); - - if (abortSignal) { - if (abortSignal.aborted) { - throw abortSignal.reason; - } - - abortSignal.addEventListener('abort', () => { - abortController.abort(abortSignal.reason); - }); - } - const params = this.createPutObjectParams(key, '', { - ContentLength: 0, - ACL: options.directoryVisibility ? this.visibilityToAcl(options.directoryVisibility) : undefined, - }); - - maybeAbort(abortSignal); - await this.client.send(new PutObjectCommand(params), { - abortSignal, - }); - } - - async deleteDirectory(path: string): Promise { - // @ts-ignore because we know it will only be objects - let itemsToDelete: AsyncGenerator<{ item: _Object }> = this.listObjects(path, { - deep: true, - includeSelf: true, - includePrefixes: false, - }); - - const flush = async (keys: { Key: string }[]) => this.client.send(new DeleteObjectsCommand({ - Bucket: this.options.bucket, - Delete: { - Objects: keys, - }, - })); - - let bucket: { Key: string }[] = []; - let promises: Promise[] = []; - - for await (const {item} of itemsToDelete) { - bucket.push({Key: item.Key!}); - - if (bucket.length > 1000) { - promises.push(flush(bucket)); - bucket = []; - } - } - - if (bucket.length > 0) { - promises.push(flush(bucket)); - } - - await Promise.all(promises); - } - - async write(path: string, contents: Readable, options: WriteOptions): Promise { - let mimeType = options.mimeType; - - if (mimeType === undefined) { - [mimeType, contents] = await resolveMimeType(path, contents); - } - - const writeOptions: PutObjectOptions = { - ACL: options.visibility ? this.visibilityToAcl(options.visibility) : undefined, - ContentType: mimeType, - ContentLength: options.size, - CacheControl: options.cacheControl, - } - - for (const option of Object.keys(options)) { - if (isWriteOptionKey(option)) { - const resolver = (writeOptionResolvers as any)[option]; - const value = options[option]; - - if (resolver(value)) { - (writeOptions as any)[option] = value; - } - } - } - - const abortController = new AbortController(); - - if (options.abortSignal) { - const abortSignal = options.abortSignal; - if (abortSignal.aborted) { - throw abortSignal.reason; - } - - abortSignal.addEventListener('abort', () => { - abortController.abort(abortSignal.reason); - }); - } - - const upload = new Upload({ - client: this.client, - params: this.createPutObjectParams( - this.prefixer.prefixFilePath(path), - contents, - writeOptions, - ), - abortController, - ...this.options.uploadConfiguration, - }); - - await upload.done(); - } - - private createPutObjectParams( - key: string, - contents: Readable | '', - options: PutObjectOptions, - ): PutObjectCommandInput { - const params: PutObjectCommandInput = { - Bucket: this.options.bucket, - Key: key, - ...Object.assign({}, this.options.putObjectOptions, options), - }; - - if (contents !== '') { - params.Body = contents; - } - - return params; - } - - async deleteFile(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - const key = this.prefixer.prefixFilePath(path); - await this.client.send(new DeleteObjectCommand({ - Bucket: this.options.bucket, - Key: key, - }), { - abortSignal: options.abortSignal, - }); - } - - private visibilityToAcl(visibility: string): ObjectCannedACL { - if (visibility === Visibility.PUBLIC) { - return 'public-read'; - } else if (visibility === Visibility.PRIVATE) { - return 'private'; - } - - throw new Error(`Unrecognized visibility provided; ${visibility}`); - } - - async changeVisibility(path: string, visibility: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - await this.client.send(new PutObjectAclCommand({ - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - ACL: this.visibilityToAcl(visibility), - }), { - abortSignal: options.abortSignal, - }); - } - - async fileExists(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - try { - await this.client.send(new HeadObjectCommand({ - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - }), { - abortSignal: options.abortSignal, - }); - - return true; - } catch (e) { - if (e instanceof S3ServiceException && e.$metadata.httpStatusCode === 404) { - return false; - } - - throw e; - } - } - - async directoryExists(path: string, options: MiscellaneousOptions): Promise { - const listing = this.listObjects(path, { - deep: true, - includePrefixes: true, - includeSelf: true, - maxKeys: 1, - abortSignal: options.abortSignal, - }); - - for await (const _item of listing) { - return true; - } - - return false; - } - - async publicUrl(path: string, options: PublicUrlOptions): Promise { - maybeAbort(options.abortSignal); - return this.publicUrlGenerator.publicUrl(this.prefixer.prefixFilePath(path), { - bucket: this.options.bucket, - ...options, - ...this.options.publicUrlOptions, - }); - } - - async checksum(path: string, options: ChecksumOptions): Promise { - maybeAbort(options.abortSignal); - const algo = (options.algo || this.options.defaultChecksumAlgo || 'SHA256').toUpperCase(); - - if (!isSupportedAlgo(algo)) { - throw ChecksumIsNotAvailable.checksumNotSupported(algo); - } - - const responseKey = algo === 'ETAG' ? 'ETag' : `Checksum${algo}` as const; - - const response = await this.client.send(new HeadObjectCommand({ - Bucket: this.options.bucket, - Key: this.prefixer.prefixFilePath(path), - ...algo === 'ETAG' ? {} : {ChecksumMode: 'ENABLED'}, - }), { - abortSignal: options.abortSignal, - }); - - const checksum = response[responseKey]; - - if (checksum === undefined) { - throw new Error(`Unable to retrieve checksum with algo ${algo}`); - } - - return checksum.replace(/^"(.+)"$/, '$1'); - } - - private async lookupMimeTypeFromStream(path: string, options: MimeTypeOptions) { - const [mimetype, stream] = await resolveMimeType(path, Readable.from(await this.read(path, options))); - await closeReadable(stream); - - return mimetype; - } -} - -/** - * BC export - * - * @deprecated - */ -export class AwsS3FileStorage extends AwsS3StorageAdapter {} - -type ResolversForWriteOptions = { - [K in keyof WriteOptionsForS3]-?: (value: any) => value is WriteOptionsForS3[K] -} - -function isWriteOptionKey(key: string): key is string & keyof ResolversForWriteOptions { - return Object.hasOwn(writeOptionResolvers, key); -} - -export const writeOptionResolvers: ResolversForWriteOptions = { - ChecksumCRC64NVME: function (value: any): value is PutObjectOptions['ChecksumCRC64NVME'] { - return typeof value === 'string'; - }, - IfMatch: function (value: any): value is PutObjectOptions['IfMatch'] { - return typeof value === 'string'; - }, - WriteOffsetBytes: function (value: any): value is PutObjectOptions['WriteOffsetBytes'] { - return typeof value === 'string'; - }, - ChecksumSHA1: function (value: any): value is PutObjectOptions['ChecksumSHA1'] { - return typeof value === 'string'; - }, - ChecksumSHA256: function (value: any): value is PutObjectOptions['ChecksumSHA256'] { - return typeof value === 'string'; - }, - ChecksumCRC32: function (value: any): value is PutObjectOptions['ChecksumCRC32'] { - return typeof value === 'string'; - }, - ChecksumCRC32C: function (value: any): value is PutObjectOptions['ChecksumCRC32C'] { - return typeof value === 'string'; - }, - CacheControl: function (value: any): value is PutObjectOptions['CacheControl'] { - return typeof value === 'string'; - }, - ContentDisposition: function (value: any): value is PutObjectOptions['ContentDisposition'] { - return typeof value === 'string'; - }, - ContentEncoding: function (value: any): value is PutObjectOptions['ContentEncoding'] { - return typeof value === 'string'; - }, - ContentLanguage: function (value: any): value is PutObjectOptions['ContentLanguage'] { - return typeof value === 'string'; - }, - ContentMD5: function (value: any): value is PutObjectOptions['ContentMD5'] { - return typeof value === 'string'; - }, - ContentType: function (value: any): value is PutObjectOptions['ContentType'] { - return typeof value === 'string'; - }, - ChecksumAlgorithm: function (value: any): value is PutObjectOptions['ChecksumAlgorithm'] { - return typeof value === 'string'; - }, - Expires: function (value: any): value is PutObjectOptions['Expires'] { - return value instanceof Date; - }, - GrantFullControl: function (value: any): value is PutObjectOptions['GrantFullControl'] { - return typeof value === 'string'; - }, - GrantRead: function (value: any): value is PutObjectOptions['GrantRead'] { - return typeof value === 'string'; - }, - GrantReadACP: function (value: any): value is PutObjectOptions['GrantReadACP'] { - return typeof value === 'string'; - }, - GrantWriteACP: function (value: any): value is PutObjectOptions['GrantWriteACP'] { - return typeof value === 'string'; - }, - Metadata: function (value: any): value is PutObjectOptions['Metadata'] { - return typeof value === 'object'; - }, - ServerSideEncryption: function (value: any): value is PutObjectOptions['ServerSideEncryption'] { - return typeof value === 'string'; - }, - StorageClass: function (value: any): value is PutObjectOptions['StorageClass'] { - return typeof value === 'string'; - }, - WebsiteRedirectLocation: function (value: any): value is PutObjectOptions['WebsiteRedirectLocation'] { - return typeof value === 'string'; - }, - SSECustomerAlgorithm: function (value: any): value is PutObjectOptions['SSECustomerAlgorithm'] { - return typeof value === 'string'; - }, - SSECustomerKey: function (value: any): value is PutObjectOptions['SSECustomerKey'] { - return typeof value === 'string'; - }, - SSECustomerKeyMD5: function (value: any): value is PutObjectOptions['SSECustomerKeyMD5'] { - return typeof value === 'string'; - }, - SSEKMSKeyId: function (value: any): value is PutObjectOptions['SSEKMSKeyId'] { - return typeof value === 'string'; - }, - SSEKMSEncryptionContext: function (value: any): value is PutObjectOptions['SSEKMSEncryptionContext'] { - return typeof value === 'string'; - }, - BucketKeyEnabled: function (value: any): value is PutObjectOptions['BucketKeyEnabled'] { - return typeof value === 'string'; - }, - RequestPayer: function (value: any): value is PutObjectOptions['RequestPayer'] { - return typeof value === 'string'; - }, - Tagging: function (value: any): value is PutObjectOptions['Tagging'] { - return typeof value === 'string'; - }, - ObjectLockMode: function (value: any): value is PutObjectOptions['ObjectLockMode'] { - return typeof value === 'string'; - }, - ObjectLockRetainUntilDate: function (value: any): value is PutObjectOptions['ObjectLockRetainUntilDate'] { - return value instanceof Date; - }, - ObjectLockLegalHoldStatus: function (value: any): value is PutObjectOptions['ObjectLockLegalHoldStatus'] { - return typeof value === 'string'; - }, - ExpectedBucketOwner: function (value: any): value is PutObjectOptions['ExpectedBucketOwner'] { - return typeof value === 'string'; - }, - IfNoneMatch: function (value: any): value is WriteOptionsForS3['IfNoneMatch'] { - return typeof value === 'string'; - }, -}; diff --git a/packages/aws-s3/src/aws-s3-file-storage.test.ts b/packages/aws-s3/src/index.test.ts similarity index 99% rename from packages/aws-s3/src/aws-s3-file-storage.test.ts rename to packages/aws-s3/src/index.test.ts index e840dff..42286c8 100644 --- a/packages/aws-s3/src/aws-s3-file-storage.test.ts +++ b/packages/aws-s3/src/index.test.ts @@ -10,7 +10,7 @@ import { } from '@flystorage/file-storage'; import {BinaryToTextEncoding, createHash, randomBytes} from 'crypto'; import * as https from 'https'; -import {AwsS3StorageAdapter} from './aws-s3-storage-adapter.js'; +import {AwsS3StorageAdapter} from './index.js'; import {createReadStream} from "node:fs"; import * as path from "node:path"; import 'dotenv/config'; diff --git a/packages/aws-s3/src/index.ts b/packages/aws-s3/src/index.ts index aef9f6b..b48e95d 100644 --- a/packages/aws-s3/src/index.ts +++ b/packages/aws-s3/src/index.ts @@ -1 +1,820 @@ -export * from './aws-s3-storage-adapter.js'; \ No newline at end of file +import { + _Object, + CommonPrefix, + CopyObjectCommand, + CopyObjectRequest, + DeleteObjectCommand, + DeleteObjectsCommand, + GetObjectAclCommand, + GetObjectAclOutput, + GetObjectCommand, + GetObjectCommandInput, + GetObjectCommandOutput, + HeadObjectCommand, + ListObjectsV2Command, + ListObjectsV2Output, + ObjectCannedACL, + PutObjectAclCommand, + PutObjectCommand, + PutObjectCommandInput, + S3Client, + S3ServiceException, +} from '@aws-sdk/client-s3'; +import {Configuration, Upload} from '@aws-sdk/lib-storage'; +import {getSignedUrl} from '@aws-sdk/s3-request-presigner'; +import {posix} from 'node:path'; +import { + AdapterListOptions, + ChecksumIsNotAvailable, + ChecksumOptions, + closeReadable, + CopyFileOptions, + CreateDirectoryOptions, + FileContents, + FileWasNotFound, + MimeTypeOptions, + MiscellaneousOptions, + MoveFileOptions, + normalizeExpiryToMilliseconds, + PathPrefixer, + PublicUrlOptions, + StatEntry, + StorageAdapter, + TemporaryUrlOptions, + UploadRequest, + UploadRequestHeaders, + UploadRequestOptions, + Visibility, + WriteOptions, +} from '@flystorage/file-storage'; +import {resolveMimeType} from '@flystorage/stream-mime-type'; +import {Readable} from 'stream'; +import {lookup} from 'mime-types'; + +type PutObjectOptions = Omit; +export type WriteOptionsForS3 = Omit; +const possibleChecksumAlgos = ['SHA1', 'SHA256', 'CRC32', 'CRC32C', 'ETAG'] as const; +type ChecksumAlgo = typeof possibleChecksumAlgos[number]; + +function isSupportedAlgo(algo: string): algo is ChecksumAlgo { + return possibleChecksumAlgos.includes(algo as ChecksumAlgo); +} + +export type AwsS3StorageAdapterOptions = Readonly<{ + bucket: string, + prefix?: string, + region?: string, + publicUrlOptions?: PublicUrlOptions, + uploadRequestOptions?: UploadRequestOptions, + putObjectOptions?: PutObjectOptions, + uploadConfiguration?: Partial>, + defaultChecksumAlgo?: ChecksumAlgo, +}>; + +export type AwsPublicUrlOptions = PublicUrlOptions & { + bucket: string, + region?: string, + forcePathStyle?: boolean, + baseUrl?: string, +} + +export type AwsPublicUrlGenerator = { + publicUrl(path: string, options: AwsPublicUrlOptions): Promise; +}; + +export class DefaultAwsPublicUrlGenerator implements AwsPublicUrlGenerator { + async publicUrl(path: string, options: AwsPublicUrlOptions): Promise { + const baseUrl = options.baseUrl ?? 'https://{subdomain}.amazonaws.com/{uri}'; + const subdomain = options.forcePathStyle !== true + ? `${options.bucket}.s3` + : options.region === undefined + ? 's3' + : `s3-${options.region}`; + const uri = options.forcePathStyle !== true + ? encodePath(path) + : `${options.bucket}/${encodePath(path)}`; + + return baseUrl.replace('{subdomain}', subdomain).replace('{uri}', uri); + } +} + +/** + * BC extension + */ +export class HostStyleAwsPublicUrlGenerator extends DefaultAwsPublicUrlGenerator { +} + +export type TimestampResolver = () => number; +type AclOptions = Pick; + +/** + * Some commands need URI encoded paths to work ¯\_(ツ)_/¯ + */ +function encodePath(path: string): string { + return path.split('/').map(encodeURIComponent).join('/'); +} + +function maybeAbort(signal?: AbortSignal) { + if (signal?.aborted) { + throw signal.reason; + } +} + +export class AwsS3StorageAdapter implements StorageAdapter { + private readonly prefixer: PathPrefixer; + + constructor( + private readonly client: S3Client, + private readonly options: AwsS3StorageAdapterOptions, + private readonly publicUrlGenerator: AwsPublicUrlGenerator = new DefaultAwsPublicUrlGenerator(), + private readonly timestampResolver: TimestampResolver = () => Date.now(), + ) { + this.prefixer = new PathPrefixer(options.prefix ?? '', '/', (...paths) => { + const path = posix.join(...paths); + + if (path === "." || path === "/") { + // 1) https://nodejs.org/api/path.html#pathjoinpaths + // Zero-length path segments are ignored. If the joined path string is a zero-length string then '.' will be + // returned, representing the current working directory. + // 2) In S3 we use delimiter:"/". In that case we need to remove the root-slash in order to list the + // root-directory contents. + return ""; + } else { + return path; + } + }); + } + + async copyFile(from: string, to: string, options: CopyFileOptions): Promise { + maybeAbort(options.abortSignal); + let visibility: string | undefined = options.visibility; + + if (visibility === undefined && options.retainVisibility) { + visibility = await this.visibility(from, options); + maybeAbort(options.abortSignal); + } + + let acl: AclOptions = (visibility !== undefined && options.useVisibility !== false) + ? {ACL: this.visibilityToAcl(visibility)} + : {}; + + await this.client.send(new CopyObjectCommand({ + Bucket: this.options.bucket, + CopySource: posix.join('/', this.options.bucket, encodePath(this.prefixer.prefixFilePath(from))), + Key: this.prefixer.prefixFilePath(to), + ...acl, + }), {abortSignal: options.abortSignal}); + } + async moveFile(from: string, to: string, options: MoveFileOptions): Promise { + await this.copyFile(from, to, options); + await this.deleteFile(from, options); + } + + async prepareUpload(path: string, options: UploadRequestOptions): Promise { + maybeAbort(options.abortSignal); + const expiry = normalizeExpiryToMilliseconds(options.expiresAt); + const now = (this.timestampResolver)(); + + const putObjectParams: PutObjectCommandInput = { + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + }; + + const headers: UploadRequestHeaders = {}; + const contentType = options['Content-Type'] ?? options.contentType; + + if (typeof contentType === 'string') { + putObjectParams.ContentType = contentType; + headers['Content-Type'] = contentType; + } + + const url = await getSignedUrl(this.client, new PutObjectCommand(putObjectParams), { + expiresIn: Math.floor((expiry - now) / 1000), + }); + + return { + url, + method: 'PUT', + provider: 'aws-s3', + headers, + }; + } + + async temporaryUrl(path: string, options: TemporaryUrlOptions): Promise { + maybeAbort(options.abortSignal); + const expiry = normalizeExpiryToMilliseconds(options.expiresAt); + const now = (this.timestampResolver)(); + + const getObjectParams: GetObjectCommandInput = { + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + }; + + if (options.responseHeaders) { + if (options.responseHeaders['Cache-Control']) { + getObjectParams.ResponseCacheControl = options.responseHeaders['Cache-Control']; + } + + if (options.responseHeaders['Content-Disposition']) { + getObjectParams.ResponseContentDisposition = options.responseHeaders['Content-Disposition']; + } + + if (options.responseHeaders['Content-Encoding']) { + getObjectParams.ResponseContentEncoding = options.responseHeaders['Content-Encoding']; + } + + if (options.responseHeaders['Content-Language']) { + getObjectParams.ResponseContentLanguage = options.responseHeaders['Content-Language']; + } + + if (options.responseHeaders['Content-Type']) { + getObjectParams.ResponseContentType = options.responseHeaders['Content-Type']; + } + + if (options.responseHeaders['Expires']) { + getObjectParams.ResponseExpires = new Date(options.responseHeaders['Expires']); + } + } + + return await getSignedUrl(this.client, new GetObjectCommand(getObjectParams), { + expiresIn: Math.floor((expiry - now) / 1000), + }); + } + + async lastModified(path: string, options: MiscellaneousOptions): Promise { + const stat = await this.stat(path, options); + + if (stat.lastModifiedMs === undefined) { + throw new Error('Last modified is not available in stat'); + } + + return stat.lastModifiedMs; + } + + async fileSize(path: string, options: MiscellaneousOptions): Promise { + const stat = await this.stat(path, options); + + if (stat.isFile === false) { + throw new Error('Path is not a file'); + } + + if (stat.size === undefined) { + throw new Error('File size is not available in stat.') + } + + return stat.size; + } + + async mimeType(path: string, options: MimeTypeOptions): Promise { + const response = await this.stat(path, options); + + if (!response.isFile) { + throw new Error(`Path "${path} is not a file.`); + } + + if (response.mimeType) { + return response.mimeType; + } + + if (options.disallowFallback) { + throw new Error('Mime-type not available via HeadObject'); + } + + maybeAbort(options.abortSignal); + const method = options.fallbackMethod ?? 'path'; + const mimeType = method === 'path' + ? lookup(path) + : await this.lookupMimeTypeFromStream(path, options); + + if (mimeType === undefined || mimeType === false) { + throw new Error('Unable to resolve mime-type'); + } + + return mimeType; + } + + async visibility(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + const response: GetObjectAclOutput = await this.client.send(new GetObjectAclCommand({ + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + }), { + abortSignal: options.abortSignal, + }); + + const publicRead = response.Grants?.some(grant => + grant.Grantee?.URI === 'http://acs.amazonaws.com/groups/global/AllUsers' + && grant.Permission === 'READ' + ) ?? false; + + return publicRead ? Visibility.PUBLIC : Visibility.PRIVATE; + } + + async* list(path: string, options: AdapterListOptions): AsyncGenerator { + const listing = this.listObjects(path, { + deep: options.deep, + includePrefixes: true, + includeSelf: false, + abortSignal: options.abortSignal, + }); + + for await (const {type, item} of listing) { + if (type === 'prefix') { + yield { + type: 'directory', + isFile: false, + isDirectory: true, + path: this.prefixer.stripDirectoryPath(item.Prefix!), + }; + } else { + const path = item.Key!; + + if (path.endsWith('/')) { + yield { + type: 'directory', + isFile: false, + isDirectory: true, + path: this.prefixer.stripDirectoryPath(path), + }; + } else { + yield { + type: 'file', + isFile: true, + isDirectory: false, + path: this.prefixer.stripFilePath(path), + size: item.Size ?? 0, + lastModifiedMs: item.LastModified?.getTime(), + }; + } + } + } + } + + async * listObjects( + path: string, + options: { + deep: boolean, + includePrefixes: boolean, + includeSelf: boolean, + maxKeys?: number, + abortSignal?: AbortSignal, + }, + ): AsyncGenerator<{ type: 'prefix', item: CommonPrefix } | { type: 'object', item: _Object }, any, unknown> { + maybeAbort(options.abortSignal); + const prefix = this.prefixer.prefixDirectoryPath(path); + let collectedKeys = 0; + let shouldContinue = true; + let continuationToken: string | undefined = undefined; + + while (shouldContinue && (options.maxKeys === undefined || collectedKeys < options.maxKeys)) { + maybeAbort(options.abortSignal); + const response: ListObjectsV2Output = await this.client.send(new ListObjectsV2Command({ + Bucket: this.options.bucket, + Prefix: prefix, + Delimiter: options.deep ? undefined : '/', + ContinuationToken: continuationToken, + MaxKeys: options.maxKeys, + })); + + continuationToken = response.NextContinuationToken; + shouldContinue = response.IsTruncated ?? false; + const prefixes = options.includePrefixes ? response.CommonPrefixes ?? [] : []; + + for (const item of prefixes) { + if ((!options.includeSelf && item.Prefix === prefix) || item.Prefix === undefined) { + continue; + } + + collectedKeys++; + yield {type: 'prefix', item}; + } + + for (const item of response.Contents ?? []) { + if ((!options.includeSelf && item.Key === prefix) || item.Key === undefined) { + // not interested in itself + // not interested in empty prefixes + continue; + } + + collectedKeys++; + yield {type: 'object', item}; + } + } + } + + async read(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + + let response: GetObjectCommandOutput; + + try { + response = await this.client.send(new GetObjectCommand({ + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + }), { + abortSignal: options.abortSignal, + }); + } catch (err) { + if (err instanceof S3ServiceException && err.$metadata.httpStatusCode === 404) { + throw FileWasNotFound.atLocation(path, { + context: {path, options}, + cause: err, + }); + } + + throw err; + } + + if (response.Body instanceof Readable || response.Body instanceof ReadableStream) { + return response.Body; + } + + throw new Error('No response body was provided'); + } + + async stat(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + const response = await this.client.send(new HeadObjectCommand({ + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + }), { + abortSignal: options.abortSignal, + }); + + return { + path, + type: 'file', + isDirectory: false, + isFile: true, + size: response.ContentLength ?? 0, + lastModifiedMs: response.LastModified?.getTime(), + mimeType: response.ContentType, + }; + } + + async createDirectory(path: string, options: CreateDirectoryOptions): Promise { + const key = this.prefixer.prefixDirectoryPath(path); + const abortSignal = options.abortSignal; + const abortController = new AbortController(); + + if (abortSignal) { + if (abortSignal.aborted) { + throw abortSignal.reason; + } + + abortSignal.addEventListener('abort', () => { + abortController.abort(abortSignal.reason); + }); + } + const params = this.createPutObjectParams(key, '', { + ContentLength: 0, + ACL: options.directoryVisibility ? this.visibilityToAcl(options.directoryVisibility) : undefined, + }); + + maybeAbort(abortSignal); + await this.client.send(new PutObjectCommand(params), { + abortSignal, + }); + } + + async deleteDirectory(path: string): Promise { + // @ts-ignore because we know it will only be objects + let itemsToDelete: AsyncGenerator<{ item: _Object }> = this.listObjects(path, { + deep: true, + includeSelf: true, + includePrefixes: false, + }); + + const flush = async (keys: { Key: string }[]) => this.client.send(new DeleteObjectsCommand({ + Bucket: this.options.bucket, + Delete: { + Objects: keys, + }, + })); + + let bucket: { Key: string }[] = []; + let promises: Promise[] = []; + + for await (const {item} of itemsToDelete) { + bucket.push({Key: item.Key!}); + + if (bucket.length > 1000) { + promises.push(flush(bucket)); + bucket = []; + } + } + + if (bucket.length > 0) { + promises.push(flush(bucket)); + } + + await Promise.all(promises); + } + + async write(path: string, contents: Readable, options: WriteOptions): Promise { + let mimeType = options.mimeType; + + if (mimeType === undefined) { + [mimeType, contents] = await resolveMimeType(path, contents); + } + + const writeOptions: PutObjectOptions = { + ACL: options.visibility ? this.visibilityToAcl(options.visibility) : undefined, + ContentType: mimeType, + ContentLength: options.size, + CacheControl: options.cacheControl, + } + + for (const option of Object.keys(options)) { + if (isWriteOptionKey(option)) { + const resolver = (writeOptionResolvers as any)[option]; + const value = options[option]; + + if (resolver(value)) { + (writeOptions as any)[option] = value; + } + } + } + + const abortController = new AbortController(); + + if (options.abortSignal) { + const abortSignal = options.abortSignal; + if (abortSignal.aborted) { + throw abortSignal.reason; + } + + abortSignal.addEventListener('abort', () => { + abortController.abort(abortSignal.reason); + }); + } + + const upload = new Upload({ + client: this.client, + params: this.createPutObjectParams( + this.prefixer.prefixFilePath(path), + contents, + writeOptions, + ), + abortController, + ...this.options.uploadConfiguration, + }); + + await upload.done(); + } + + private createPutObjectParams( + key: string, + contents: Readable | '', + options: PutObjectOptions, + ): PutObjectCommandInput { + const params: PutObjectCommandInput = { + Bucket: this.options.bucket, + Key: key, + ...Object.assign({}, this.options.putObjectOptions, options), + }; + + if (contents !== '') { + params.Body = contents; + } + + return params; + } + + async deleteFile(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + const key = this.prefixer.prefixFilePath(path); + await this.client.send(new DeleteObjectCommand({ + Bucket: this.options.bucket, + Key: key, + }), { + abortSignal: options.abortSignal, + }); + } + + private visibilityToAcl(visibility: string): ObjectCannedACL { + if (visibility === Visibility.PUBLIC) { + return 'public-read'; + } else if (visibility === Visibility.PRIVATE) { + return 'private'; + } + + throw new Error(`Unrecognized visibility provided; ${visibility}`); + } + + async changeVisibility(path: string, visibility: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + await this.client.send(new PutObjectAclCommand({ + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + ACL: this.visibilityToAcl(visibility), + }), { + abortSignal: options.abortSignal, + }); + } + + async fileExists(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + try { + await this.client.send(new HeadObjectCommand({ + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + }), { + abortSignal: options.abortSignal, + }); + + return true; + } catch (e) { + if (e instanceof S3ServiceException && e.$metadata.httpStatusCode === 404) { + return false; + } + + throw e; + } + } + + async directoryExists(path: string, options: MiscellaneousOptions): Promise { + const listing = this.listObjects(path, { + deep: true, + includePrefixes: true, + includeSelf: true, + maxKeys: 1, + abortSignal: options.abortSignal, + }); + + for await (const _item of listing) { + return true; + } + + return false; + } + + async publicUrl(path: string, options: PublicUrlOptions): Promise { + maybeAbort(options.abortSignal); + return this.publicUrlGenerator.publicUrl(this.prefixer.prefixFilePath(path), { + bucket: this.options.bucket, + ...options, + ...this.options.publicUrlOptions, + }); + } + + async checksum(path: string, options: ChecksumOptions): Promise { + maybeAbort(options.abortSignal); + const algo = (options.algo || this.options.defaultChecksumAlgo || 'SHA256').toUpperCase(); + + if (!isSupportedAlgo(algo)) { + throw ChecksumIsNotAvailable.checksumNotSupported(algo); + } + + const responseKey = algo === 'ETAG' ? 'ETag' : `Checksum${algo}` as const; + + const response = await this.client.send(new HeadObjectCommand({ + Bucket: this.options.bucket, + Key: this.prefixer.prefixFilePath(path), + ...algo === 'ETAG' ? {} : {ChecksumMode: 'ENABLED'}, + }), { + abortSignal: options.abortSignal, + }); + + const checksum = response[responseKey]; + + if (checksum === undefined) { + throw new Error(`Unable to retrieve checksum with algo ${algo}`); + } + + return checksum.replace(/^"(.+)"$/, '$1'); + } + + private async lookupMimeTypeFromStream(path: string, options: MimeTypeOptions) { + const [mimetype, stream] = await resolveMimeType(path, Readable.from(await this.read(path, options))); + await closeReadable(stream); + + return mimetype; + } +} + +/** + * BC export + * + * @deprecated + */ +export class AwsS3FileStorage extends AwsS3StorageAdapter {} + +type ResolversForWriteOptions = { + [K in keyof WriteOptionsForS3]-?: (value: any) => value is WriteOptionsForS3[K] +} + +function isWriteOptionKey(key: string): key is string & keyof ResolversForWriteOptions { + return Object.hasOwn(writeOptionResolvers, key); +} + +export const writeOptionResolvers: ResolversForWriteOptions = { + ChecksumCRC64NVME: function (value: any): value is PutObjectOptions['ChecksumCRC64NVME'] { + return typeof value === 'string'; + }, + IfMatch: function (value: any): value is PutObjectOptions['IfMatch'] { + return typeof value === 'string'; + }, + WriteOffsetBytes: function (value: any): value is PutObjectOptions['WriteOffsetBytes'] { + return typeof value === 'string'; + }, + ChecksumSHA1: function (value: any): value is PutObjectOptions['ChecksumSHA1'] { + return typeof value === 'string'; + }, + ChecksumSHA256: function (value: any): value is PutObjectOptions['ChecksumSHA256'] { + return typeof value === 'string'; + }, + ChecksumCRC32: function (value: any): value is PutObjectOptions['ChecksumCRC32'] { + return typeof value === 'string'; + }, + ChecksumCRC32C: function (value: any): value is PutObjectOptions['ChecksumCRC32C'] { + return typeof value === 'string'; + }, + CacheControl: function (value: any): value is PutObjectOptions['CacheControl'] { + return typeof value === 'string'; + }, + ContentDisposition: function (value: any): value is PutObjectOptions['ContentDisposition'] { + return typeof value === 'string'; + }, + ContentEncoding: function (value: any): value is PutObjectOptions['ContentEncoding'] { + return typeof value === 'string'; + }, + ContentLanguage: function (value: any): value is PutObjectOptions['ContentLanguage'] { + return typeof value === 'string'; + }, + ContentMD5: function (value: any): value is PutObjectOptions['ContentMD5'] { + return typeof value === 'string'; + }, + ContentType: function (value: any): value is PutObjectOptions['ContentType'] { + return typeof value === 'string'; + }, + ChecksumAlgorithm: function (value: any): value is PutObjectOptions['ChecksumAlgorithm'] { + return typeof value === 'string'; + }, + Expires: function (value: any): value is PutObjectOptions['Expires'] { + return value instanceof Date; + }, + GrantFullControl: function (value: any): value is PutObjectOptions['GrantFullControl'] { + return typeof value === 'string'; + }, + GrantRead: function (value: any): value is PutObjectOptions['GrantRead'] { + return typeof value === 'string'; + }, + GrantReadACP: function (value: any): value is PutObjectOptions['GrantReadACP'] { + return typeof value === 'string'; + }, + GrantWriteACP: function (value: any): value is PutObjectOptions['GrantWriteACP'] { + return typeof value === 'string'; + }, + Metadata: function (value: any): value is PutObjectOptions['Metadata'] { + return typeof value === 'object'; + }, + ServerSideEncryption: function (value: any): value is PutObjectOptions['ServerSideEncryption'] { + return typeof value === 'string'; + }, + StorageClass: function (value: any): value is PutObjectOptions['StorageClass'] { + return typeof value === 'string'; + }, + WebsiteRedirectLocation: function (value: any): value is PutObjectOptions['WebsiteRedirectLocation'] { + return typeof value === 'string'; + }, + SSECustomerAlgorithm: function (value: any): value is PutObjectOptions['SSECustomerAlgorithm'] { + return typeof value === 'string'; + }, + SSECustomerKey: function (value: any): value is PutObjectOptions['SSECustomerKey'] { + return typeof value === 'string'; + }, + SSECustomerKeyMD5: function (value: any): value is PutObjectOptions['SSECustomerKeyMD5'] { + return typeof value === 'string'; + }, + SSEKMSKeyId: function (value: any): value is PutObjectOptions['SSEKMSKeyId'] { + return typeof value === 'string'; + }, + SSEKMSEncryptionContext: function (value: any): value is PutObjectOptions['SSEKMSEncryptionContext'] { + return typeof value === 'string'; + }, + BucketKeyEnabled: function (value: any): value is PutObjectOptions['BucketKeyEnabled'] { + return typeof value === 'string'; + }, + RequestPayer: function (value: any): value is PutObjectOptions['RequestPayer'] { + return typeof value === 'string'; + }, + Tagging: function (value: any): value is PutObjectOptions['Tagging'] { + return typeof value === 'string'; + }, + ObjectLockMode: function (value: any): value is PutObjectOptions['ObjectLockMode'] { + return typeof value === 'string'; + }, + ObjectLockRetainUntilDate: function (value: any): value is PutObjectOptions['ObjectLockRetainUntilDate'] { + return value instanceof Date; + }, + ObjectLockLegalHoldStatus: function (value: any): value is PutObjectOptions['ObjectLockLegalHoldStatus'] { + return typeof value === 'string'; + }, + ExpectedBucketOwner: function (value: any): value is PutObjectOptions['ExpectedBucketOwner'] { + return typeof value === 'string'; + }, + IfNoneMatch: function (value: any): value is WriteOptionsForS3['IfNoneMatch'] { + return typeof value === 'string'; + }, +}; diff --git a/packages/azure-storage-blob/package.json b/packages/azure-storage-blob/package.json index 69d005c..c4d7162 100644 --- a/packages/azure-storage-blob/package.json +++ b/packages/azure-storage-blob/package.json @@ -8,30 +8,24 @@ "@flystorage/stream-mime-type": "^1.0.0" }, "description": "", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, - "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" - }, "keywords": [ - "s3", - "file", + "azure", + "storage", + "blob", "storage", "flystorage", "filesystem" diff --git a/packages/azure-storage-blob/src/azure-storage-blob.ts b/packages/azure-storage-blob/src/azure-storage-blob.ts deleted file mode 100644 index 2caab99..0000000 --- a/packages/azure-storage-blob/src/azure-storage-blob.ts +++ /dev/null @@ -1,389 +0,0 @@ -import {Readable} from 'stream'; -import { - ChecksumIsNotAvailable, - ChecksumOptions, - CopyFileOptions, - FileContents, - FileWasNotFound, - ListOptions, - MimeTypeOptions, - MiscellaneousOptions, - MoveFileOptions, - normalizeExpiryToDate, - PathPrefixer, - PublicUrlOptions, - StatEntry, - StorageAdapter, - TemporaryUrlOptions, - UploadRequest, - UploadRequestHeaders, - UploadRequestOptions, - WriteOptions, -} from '@flystorage/file-storage'; -import { - BlobDownloadResponseParsed, - BlobGenerateSasUrlOptions, - BlobGetPropertiesResponse, - BlobProperties, - BlobSASPermissions, - ContainerClient, -} from '@azure/storage-blob'; -import {resolveMimeType} from '@flystorage/stream-mime-type'; -import {dirname} from 'node:path'; - - -export type AzureStorageBlobStorageAdapterOptions = { - prefix?: string, - uploadMaxConcurrency?: number, - ignoreVisibility?: boolean, - ignoredVisibilityResponse?: string, - deleteDirBatchSize?: number, - temporaryUrlOptions?: TemporaryUrlOptions, -} - -function maybeAbort(signal?: AbortSignal) { - if (signal?.aborted) { - throw signal.reason; - } -} - -export class AzureStorageBlobStorageAdapter implements StorageAdapter { - private readonly prefixer: PathPrefixer; - - constructor( - private readonly container: ContainerClient, - private readonly options: AzureStorageBlobStorageAdapterOptions = {}, - ) { - this.prefixer = new PathPrefixer(options.prefix || ''); - } - - async copyFile(from: string, to: string, options: CopyFileOptions): Promise { - const fromUrl = this.blockClient(from).url; - maybeAbort(options.abortSignal); - await this.blockClient(to).syncCopyFromURL(fromUrl, {abortSignal: options.abortSignal}); - } - async moveFile(from: string, to: string, options: MoveFileOptions): Promise { - await this.copyFile(from, to, options); - await this.deleteFile(from, options); - } - - async write(path: string, contents: Readable, options: WriteOptions): Promise { - let mimeType = options.mimeType; - let stream = contents; - - maybeAbort(options.abortSignal); - - if (mimeType === undefined) { - [mimeType, stream] = await this.resolveMimetype(path, contents, options); - } - - maybeAbort(options.abortSignal); - - const blob = this.blockClient(path); - await blob.uploadStream( - stream, - options.size, - this.options.uploadMaxConcurrency, - { - abortSignal: options.abortSignal, - blobHTTPHeaders: { - blobContentType: mimeType, - blobCacheControl: options.cacheControl - }, - }, - ); - } - - private blockClient(path: string) { - return this.container.getBlockBlobClient(this.prefixer.prefixFilePath(path)); - } - - async read(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - const blob = this.blockClient(path); - let response: BlobDownloadResponseParsed; - - try { - response = await blob.download(undefined, undefined, { - abortSignal: options.abortSignal, - }); - } catch (err) { - if ((err as any).statusCode === 404) { - throw FileWasNotFound.atLocation(path, { - context: {path, options}, - cause: err, - }) - } - - throw err; - } - - if (!response.readableStreamBody) { - throw new Error('No readable stream body in response.'); - } - - return response.readableStreamBody; - } - - async deleteFile(path: string, options: MiscellaneousOptions): Promise { - const blob = this.blockClient(path); - maybeAbort(options.abortSignal); - await blob.deleteIfExists({ - abortSignal: options.abortSignal, - }); - } - - async createDirectory(): Promise { - // no-op, directories do not exist. - } - - async stat(path: string, options: {abortSignal?: AbortSignal} = {}): Promise { - maybeAbort(options.abortSignal); - - const blob = this.blockClient(path); - const properties = await blob.getProperties({ - abortSignal: options.abortSignal, - }); - - return this.mapToStatEntry(path, properties); - } - - private mapToStatEntry(path: string, properties: BlobGetPropertiesResponse | BlobProperties): StatEntry { - return { - type: 'file', - isFile: true, - isDirectory: false, - path, - mimeType: properties.contentType, - size: properties.contentLength, - lastModifiedMs: properties.lastModified?.getTime(), - }; - } - - list(path: string, options: ListOptions): AsyncGenerator { - return options.deep - ? this.listDeep(path, options) - : this.listShallow(path, options); - - } - - async *listDeep(path: string, options: ListOptions): AsyncGenerator { - maybeAbort(options?.abortSignal); - const directories = new Set(); - const listing = this.container.listBlobsFlat({ - prefix: this.prefixer.prefixDirectoryPath(path), - abortSignal: options.abortSignal, - }); - const listedPath = path; - - for await (const item of listing) { - maybeAbort(options?.abortSignal); - const path = this.prefixer.stripFilePath(item.name); - let parentDir = dirname(path); - - while(!['.', '', listedPath].includes(parentDir)) { - if (directories.has(parentDir)) { - break; - } - - yield { - type: 'directory', - isFile: false, - isDirectory: true, - path: parentDir, - }; - - directories.add(parentDir); - parentDir = dirname(parentDir); - } - - yield this.mapToStatEntry(path, item.properties); - } - } - - async *listShallow(path: string, options: ListOptions): AsyncGenerator { - maybeAbort(options?.abortSignal); - - const listing = this.container.listBlobsByHierarchy('/', { - prefix: this.prefixer.prefixDirectoryPath(path), - abortSignal: options.abortSignal, - }); - - for await (const item of listing) { - maybeAbort(options?.abortSignal); - - if (item.kind === 'blob') { - yield this.mapToStatEntry( - this.prefixer.stripFilePath(item.name), - item.properties - ) - } else { - yield { - path: this.prefixer.stripDirectoryPath(item.name), - type: 'directory', - isFile: false, - isDirectory: true, - } - } - } - } - - async changeVisibility(path: string, visibility: string): Promise { - if (this.options.ignoreVisibility !== true) { - throw new Error('Not supported by this adapter'); - } - } - async visibility(path: string): Promise { - if (this.options.ignoreVisibility !== true) { - throw new Error('Not implemented'); - } - - // default to indicating it ss public because we cannot know if the default is private - return this.options.ignoredVisibilityResponse ?? 'public'; - } - async deleteDirectory(path: string, options: MiscellaneousOptions): Promise { - let deletes: Promise[] = []; - const batchSize = this.options.deleteDirBatchSize ?? 10; - - for await (const item of this.list(path, {deep: true})) { - if (item.isFile) { - deletes.push(this.deleteFile(item.path, options)); - } - - if (deletes.length >= batchSize) { - await Promise.all(deletes); - deletes = []; - } - - } - - await Promise.all(deletes); - } - async fileExists(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - return await this.blockClient(path).exists({ - abortSignal: options.abortSignal, - }) - } - async directoryExists(path: string, options: MiscellaneousOptions): Promise { - maybeAbort(options.abortSignal); - const listing = this.container.listBlobsFlat({ - prefix: this.prefixer.prefixDirectoryPath(path), - abortSignal: options.abortSignal, - }).byPage({ - maxPageSize: 1, - }); - - return (await listing.next()).value.segment.blobItems.length > 0; - } - async publicUrl(path: string, options?: PublicUrlOptions): Promise { - return this.blockClient(path).url; - } - async temporaryUrl(path: string, options: TemporaryUrlOptions): Promise { - return await this.blockClient(path).generateSasUrl({ - expiresOn: normalizeExpiryToDate(options.expiresAt), - permissions: BlobSASPermissions.parse('r'), - ...(this.options.temporaryUrlOptions ?? {}), - }); - } - - async prepareUpload(path: string, options: UploadRequestOptions): Promise { - const headers: UploadRequestHeaders = {}; - headers['x-ms-blob-type'] = options['x-ms-blob-type'] ?? 'BlockBlob'; - const config: BlobGenerateSasUrlOptions = { - expiresOn: normalizeExpiryToDate(options.expiresAt), - permissions: BlobSASPermissions.parse('w'), - ...(this.options.temporaryUrlOptions ?? {}), - }; - - - const contentType = options['Content-Type'] ?? options.contentType; - - if (typeof contentType === 'string') { - config.contentType = contentType; - headers['Content-Type'] = contentType; - } - - const url = await this.blockClient(path).generateSasUrl(config); - - return {method: 'PUT', provider: 'azure-storage-blob', url, headers}; - } - - async checksum(path: string, options: ChecksumOptions): Promise { - maybeAbort(options?.abortSignal); - const algo = options.algo ?? 'etag'; - - if (algo !== 'etag') { - throw ChecksumIsNotAvailable.checksumNotSupported(algo); - } - - const blob = this.blockClient(path); - const properties = await blob.getProperties({abortSignal: options.abortSignal}); - const etag = properties.etag; - - if (etag === undefined) { - throw new Error('Etag is not defined on blob properties.'); - } - - return etag; - } - - async mimeType(path: string, options: MimeTypeOptions): Promise { - const stat = await this.stat(path, options); - - if (stat.isDirectory) { - throw new Error('Path is not a file. No mimetype available.'); - } - - if (stat.mimeType === undefined) { - throw new Error('Mime-type not found for file.'); - } - - return stat.mimeType; - } - - async lastModified(path: string): Promise { - const stat = await this.stat(path); - - if (stat.isDirectory) { - throw new Error('Path is not a file. No last modified available.'); - } - - if (stat.lastModifiedMs === undefined) { - throw new Error('Last modified not found for file.'); - } - - return stat.lastModifiedMs; - } - - async fileSize(path: string): Promise { - const stat = await this.stat(path); - - if (stat.isDirectory) { - throw new Error('Path is not a file. No file size available.'); - } - - if (stat.size === undefined) { - throw new Error('File size not found for file.'); - } - - return stat.size; - } - - private async resolveMimetype(path: string, contents: Readable, options: WriteOptions): Promise<[string, Readable]> { - if (options.mimeType) { - return [options.mimeType, contents]; - } - - const [mimeType, stream] = await resolveMimeType(path, contents); - - return [mimeType ?? 'application/octet-stream', stream]; - } -} - -/** - * BC export - * - * @deprecated - */ -export class AzureStorageBlobFileStorage extends AzureStorageBlobStorageAdapter {} \ No newline at end of file diff --git a/packages/azure-storage-blob/src/azure-storage-blob.test.ts b/packages/azure-storage-blob/src/index.test.ts similarity index 99% rename from packages/azure-storage-blob/src/azure-storage-blob.test.ts rename to packages/azure-storage-blob/src/index.test.ts index 55d6b06..5e337a4 100644 --- a/packages/azure-storage-blob/src/azure-storage-blob.test.ts +++ b/packages/azure-storage-blob/src/index.test.ts @@ -1,5 +1,5 @@ import {BlobServiceClient} from "@azure/storage-blob"; -import {AzureStorageBlobStorageAdapter} from "./azure-storage-blob.js"; +import {AzureStorageBlobStorageAdapter} from "./index.js"; import {randomBytes} from "crypto"; import { FileStorage, diff --git a/packages/azure-storage-blob/src/index.ts b/packages/azure-storage-blob/src/index.ts index 5f15428..2caab99 100644 --- a/packages/azure-storage-blob/src/index.ts +++ b/packages/azure-storage-blob/src/index.ts @@ -1 +1,389 @@ -export * from './azure-storage-blob.js'; \ No newline at end of file +import {Readable} from 'stream'; +import { + ChecksumIsNotAvailable, + ChecksumOptions, + CopyFileOptions, + FileContents, + FileWasNotFound, + ListOptions, + MimeTypeOptions, + MiscellaneousOptions, + MoveFileOptions, + normalizeExpiryToDate, + PathPrefixer, + PublicUrlOptions, + StatEntry, + StorageAdapter, + TemporaryUrlOptions, + UploadRequest, + UploadRequestHeaders, + UploadRequestOptions, + WriteOptions, +} from '@flystorage/file-storage'; +import { + BlobDownloadResponseParsed, + BlobGenerateSasUrlOptions, + BlobGetPropertiesResponse, + BlobProperties, + BlobSASPermissions, + ContainerClient, +} from '@azure/storage-blob'; +import {resolveMimeType} from '@flystorage/stream-mime-type'; +import {dirname} from 'node:path'; + + +export type AzureStorageBlobStorageAdapterOptions = { + prefix?: string, + uploadMaxConcurrency?: number, + ignoreVisibility?: boolean, + ignoredVisibilityResponse?: string, + deleteDirBatchSize?: number, + temporaryUrlOptions?: TemporaryUrlOptions, +} + +function maybeAbort(signal?: AbortSignal) { + if (signal?.aborted) { + throw signal.reason; + } +} + +export class AzureStorageBlobStorageAdapter implements StorageAdapter { + private readonly prefixer: PathPrefixer; + + constructor( + private readonly container: ContainerClient, + private readonly options: AzureStorageBlobStorageAdapterOptions = {}, + ) { + this.prefixer = new PathPrefixer(options.prefix || ''); + } + + async copyFile(from: string, to: string, options: CopyFileOptions): Promise { + const fromUrl = this.blockClient(from).url; + maybeAbort(options.abortSignal); + await this.blockClient(to).syncCopyFromURL(fromUrl, {abortSignal: options.abortSignal}); + } + async moveFile(from: string, to: string, options: MoveFileOptions): Promise { + await this.copyFile(from, to, options); + await this.deleteFile(from, options); + } + + async write(path: string, contents: Readable, options: WriteOptions): Promise { + let mimeType = options.mimeType; + let stream = contents; + + maybeAbort(options.abortSignal); + + if (mimeType === undefined) { + [mimeType, stream] = await this.resolveMimetype(path, contents, options); + } + + maybeAbort(options.abortSignal); + + const blob = this.blockClient(path); + await blob.uploadStream( + stream, + options.size, + this.options.uploadMaxConcurrency, + { + abortSignal: options.abortSignal, + blobHTTPHeaders: { + blobContentType: mimeType, + blobCacheControl: options.cacheControl + }, + }, + ); + } + + private blockClient(path: string) { + return this.container.getBlockBlobClient(this.prefixer.prefixFilePath(path)); + } + + async read(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + const blob = this.blockClient(path); + let response: BlobDownloadResponseParsed; + + try { + response = await blob.download(undefined, undefined, { + abortSignal: options.abortSignal, + }); + } catch (err) { + if ((err as any).statusCode === 404) { + throw FileWasNotFound.atLocation(path, { + context: {path, options}, + cause: err, + }) + } + + throw err; + } + + if (!response.readableStreamBody) { + throw new Error('No readable stream body in response.'); + } + + return response.readableStreamBody; + } + + async deleteFile(path: string, options: MiscellaneousOptions): Promise { + const blob = this.blockClient(path); + maybeAbort(options.abortSignal); + await blob.deleteIfExists({ + abortSignal: options.abortSignal, + }); + } + + async createDirectory(): Promise { + // no-op, directories do not exist. + } + + async stat(path: string, options: {abortSignal?: AbortSignal} = {}): Promise { + maybeAbort(options.abortSignal); + + const blob = this.blockClient(path); + const properties = await blob.getProperties({ + abortSignal: options.abortSignal, + }); + + return this.mapToStatEntry(path, properties); + } + + private mapToStatEntry(path: string, properties: BlobGetPropertiesResponse | BlobProperties): StatEntry { + return { + type: 'file', + isFile: true, + isDirectory: false, + path, + mimeType: properties.contentType, + size: properties.contentLength, + lastModifiedMs: properties.lastModified?.getTime(), + }; + } + + list(path: string, options: ListOptions): AsyncGenerator { + return options.deep + ? this.listDeep(path, options) + : this.listShallow(path, options); + + } + + async *listDeep(path: string, options: ListOptions): AsyncGenerator { + maybeAbort(options?.abortSignal); + const directories = new Set(); + const listing = this.container.listBlobsFlat({ + prefix: this.prefixer.prefixDirectoryPath(path), + abortSignal: options.abortSignal, + }); + const listedPath = path; + + for await (const item of listing) { + maybeAbort(options?.abortSignal); + const path = this.prefixer.stripFilePath(item.name); + let parentDir = dirname(path); + + while(!['.', '', listedPath].includes(parentDir)) { + if (directories.has(parentDir)) { + break; + } + + yield { + type: 'directory', + isFile: false, + isDirectory: true, + path: parentDir, + }; + + directories.add(parentDir); + parentDir = dirname(parentDir); + } + + yield this.mapToStatEntry(path, item.properties); + } + } + + async *listShallow(path: string, options: ListOptions): AsyncGenerator { + maybeAbort(options?.abortSignal); + + const listing = this.container.listBlobsByHierarchy('/', { + prefix: this.prefixer.prefixDirectoryPath(path), + abortSignal: options.abortSignal, + }); + + for await (const item of listing) { + maybeAbort(options?.abortSignal); + + if (item.kind === 'blob') { + yield this.mapToStatEntry( + this.prefixer.stripFilePath(item.name), + item.properties + ) + } else { + yield { + path: this.prefixer.stripDirectoryPath(item.name), + type: 'directory', + isFile: false, + isDirectory: true, + } + } + } + } + + async changeVisibility(path: string, visibility: string): Promise { + if (this.options.ignoreVisibility !== true) { + throw new Error('Not supported by this adapter'); + } + } + async visibility(path: string): Promise { + if (this.options.ignoreVisibility !== true) { + throw new Error('Not implemented'); + } + + // default to indicating it ss public because we cannot know if the default is private + return this.options.ignoredVisibilityResponse ?? 'public'; + } + async deleteDirectory(path: string, options: MiscellaneousOptions): Promise { + let deletes: Promise[] = []; + const batchSize = this.options.deleteDirBatchSize ?? 10; + + for await (const item of this.list(path, {deep: true})) { + if (item.isFile) { + deletes.push(this.deleteFile(item.path, options)); + } + + if (deletes.length >= batchSize) { + await Promise.all(deletes); + deletes = []; + } + + } + + await Promise.all(deletes); + } + async fileExists(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + return await this.blockClient(path).exists({ + abortSignal: options.abortSignal, + }) + } + async directoryExists(path: string, options: MiscellaneousOptions): Promise { + maybeAbort(options.abortSignal); + const listing = this.container.listBlobsFlat({ + prefix: this.prefixer.prefixDirectoryPath(path), + abortSignal: options.abortSignal, + }).byPage({ + maxPageSize: 1, + }); + + return (await listing.next()).value.segment.blobItems.length > 0; + } + async publicUrl(path: string, options?: PublicUrlOptions): Promise { + return this.blockClient(path).url; + } + async temporaryUrl(path: string, options: TemporaryUrlOptions): Promise { + return await this.blockClient(path).generateSasUrl({ + expiresOn: normalizeExpiryToDate(options.expiresAt), + permissions: BlobSASPermissions.parse('r'), + ...(this.options.temporaryUrlOptions ?? {}), + }); + } + + async prepareUpload(path: string, options: UploadRequestOptions): Promise { + const headers: UploadRequestHeaders = {}; + headers['x-ms-blob-type'] = options['x-ms-blob-type'] ?? 'BlockBlob'; + const config: BlobGenerateSasUrlOptions = { + expiresOn: normalizeExpiryToDate(options.expiresAt), + permissions: BlobSASPermissions.parse('w'), + ...(this.options.temporaryUrlOptions ?? {}), + }; + + + const contentType = options['Content-Type'] ?? options.contentType; + + if (typeof contentType === 'string') { + config.contentType = contentType; + headers['Content-Type'] = contentType; + } + + const url = await this.blockClient(path).generateSasUrl(config); + + return {method: 'PUT', provider: 'azure-storage-blob', url, headers}; + } + + async checksum(path: string, options: ChecksumOptions): Promise { + maybeAbort(options?.abortSignal); + const algo = options.algo ?? 'etag'; + + if (algo !== 'etag') { + throw ChecksumIsNotAvailable.checksumNotSupported(algo); + } + + const blob = this.blockClient(path); + const properties = await blob.getProperties({abortSignal: options.abortSignal}); + const etag = properties.etag; + + if (etag === undefined) { + throw new Error('Etag is not defined on blob properties.'); + } + + return etag; + } + + async mimeType(path: string, options: MimeTypeOptions): Promise { + const stat = await this.stat(path, options); + + if (stat.isDirectory) { + throw new Error('Path is not a file. No mimetype available.'); + } + + if (stat.mimeType === undefined) { + throw new Error('Mime-type not found for file.'); + } + + return stat.mimeType; + } + + async lastModified(path: string): Promise { + const stat = await this.stat(path); + + if (stat.isDirectory) { + throw new Error('Path is not a file. No last modified available.'); + } + + if (stat.lastModifiedMs === undefined) { + throw new Error('Last modified not found for file.'); + } + + return stat.lastModifiedMs; + } + + async fileSize(path: string): Promise { + const stat = await this.stat(path); + + if (stat.isDirectory) { + throw new Error('Path is not a file. No file size available.'); + } + + if (stat.size === undefined) { + throw new Error('File size not found for file.'); + } + + return stat.size; + } + + private async resolveMimetype(path: string, contents: Readable, options: WriteOptions): Promise<[string, Readable]> { + if (options.mimeType) { + return [options.mimeType, contents]; + } + + const [mimeType, stream] = await resolveMimeType(path, contents); + + return [mimeType ?? 'application/octet-stream', stream]; + } +} + +/** + * BC export + * + * @deprecated + */ +export class AzureStorageBlobFileStorage extends AzureStorageBlobStorageAdapter {} \ No newline at end of file diff --git a/packages/chaos/package.json b/packages/chaos/package.json index 523589a..ab3b7fb 100644 --- a/packages/chaos/package.json +++ b/packages/chaos/package.json @@ -6,27 +6,20 @@ "@flystorage/file-storage": "^1.1.0" }, "description": "A storage adapter decorator with the ability to stage errors.", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, - "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" - }, "keywords": [ "testing", "chaos", diff --git a/packages/file-storage/changelog.md b/packages/file-storage/changelog.md index 54b822f..3317504 100644 --- a/packages/file-storage/changelog.md +++ b/packages/file-storage/changelog.md @@ -1,5 +1,11 @@ # `@flystorage/file-storage` +## 1.2.1 + +### Fixes + +- Prevent unprefixed root paths to become '/' for directory listings. + ## 1.2.0 ### Added diff --git a/packages/file-storage/package.json b/packages/file-storage/package.json index 078a26d..a71b4ac 100644 --- a/packages/file-storage/package.json +++ b/packages/file-storage/package.json @@ -3,27 +3,20 @@ "type": "module", "version": "1.2.1", "description": "File-storage abstraction: multiple filesystems, one API.", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, - "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" - }, "author": "Frank de Jonge (https://frankdejonge.nl)", "repository": { "type": "git", diff --git a/packages/google-cloud-storage/package.json b/packages/google-cloud-storage/package.json index a49d3fc..d3d706d 100644 --- a/packages/google-cloud-storage/package.json +++ b/packages/google-cloud-storage/package.json @@ -10,27 +10,20 @@ "mime-types": "^3.0.2" }, "description": "", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, - "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" - }, "keywords": [ "google", "file", diff --git a/packages/in-memory/package.json b/packages/in-memory/package.json index 3d74633..a05b32e 100644 --- a/packages/in-memory/package.json +++ b/packages/in-memory/package.json @@ -8,27 +8,20 @@ "mime-types": "^3.0.2" }, "description": "", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, - "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" - }, "keywords": [ "test double", "memory", diff --git a/packages/in-memory/src/in-memory-file-storage.ts b/packages/in-memory/src/in-memory-file-storage.ts deleted file mode 100644 index 4257fc0..0000000 --- a/packages/in-memory/src/in-memory-file-storage.ts +++ /dev/null @@ -1,271 +0,0 @@ -import { - ChecksumIsNotAvailable, - ChecksumOptions, - CopyFileOptions, - CreateDirectoryOptions, - FileContents, - MimeTypeOptions, - MoveFileOptions, - PublicUrlOptions, - StatEntry, - StorageAdapter, - TemporaryUrlOptions, - VisibilityOptions, - WriteOptions, - readableToBuffer, - readableToString, -} from '@flystorage/file-storage'; -import {Readable} from "node:stream"; -import {dirname, parse} from 'node:path' -import {lookup as mimeTimeForExt} from "mime-types"; - -type FileEntry = { - type: 'file', - path: string, - contents: Buffer, - lastModifiedMs: number, - visibility?: string, -} - -type DirectoryEntry = { - type: 'directory', - path: string, - visibility?: string, -} - -export type TimestampResolver = () => number; - -function cloneBuffer(input: Buffer): Buffer { - const output = Buffer.alloc(input.length); - input.copy(output); - - return output; -} - -export class InMemoryStorageAdapter implements StorageAdapter { - private entries: Map = new Map; - - constructor( - private readonly timestampResolver: TimestampResolver = () => Date.now(), - ) { - } - - deleteEverything(): void { - this.entries = new Map; - } - - async write(path: string, contents: Readable, options: WriteOptions): Promise { - this.ensureParentDirsExist(path, options); - - this.entries.set(path, { - type: 'file', - path, - contents: await readableToBuffer(contents), - lastModifiedMs: this.timestampResolver(), - visibility: options.visibility, - }) - } - - private ensureParentDirsExist(path: string, options: VisibilityOptions) { - let parentDir = dirname(path); - - while (!['.', ''].includes(parentDir) && !this.entries.has(parentDir)) { - this.entries.set(parentDir, { - path: parentDir, - type: 'directory', - visibility: options.directoryVisibility, - }); - - parentDir = dirname(parentDir); - } - } - - async read(path: string): Promise { - const file = this.entries.get(path); - - if (file?.type !== 'file') { - throw new Error(`Path "${path}" is not a file`); - } - - return Readable.from(cloneBuffer(file.contents)); - } - - async deleteFile(path: string): Promise { - this.entries.delete(path); - } - - async createDirectory(path: string, options: CreateDirectoryOptions): Promise { - path = path.replace(/\/+$/g, ''); - - this.entries.set(path, { - path, - type: 'directory', - visibility: options.directoryVisibility, - }); - } - async copyFile(from: string, to: string, options: CopyFileOptions): Promise { - const source = this.entries.get(from); - - if (source?.type !== 'file') { - throw new Error(`Source file ${from} does not exist`); - } - - this.ensureParentDirsExist(to, options); - this.entries.set(to, { - ...source, - path: to, - }); - } - async moveFile(from: string, to: string, options: MoveFileOptions): Promise { - await this.copyFile(from, to, options); - await this.deleteFile(from); - } - async stat(path: string): Promise { - const entry = this.entries.get(path); - - if (entry === undefined) { - throw new Error(`No entry found for path "${path}"`); - } - - return this.mapToStatEntry(entry); - } - private mapToStatEntry(entry: DirectoryEntry | FileEntry): StatEntry { - if (entry.type === 'directory') { - return { - ...entry, - isDirectory: true, - isFile: false, - }; - } - - return { - type: 'file', - path: entry.path, - visibility: entry.visibility, - isFile: true, - isDirectory: false, - lastModifiedMs: entry.lastModifiedMs, - } - } - async *list(path: string, options: { deep: boolean; }): AsyncGenerator { - const entries = this.entries.values(); - const prefix = path === '' || path === '/' - ? '' - : `${path.replace(/\/+$/g, '')}/`; - - for (const entry of entries) { - if (!entry.path.startsWith(prefix)) { - continue; - } - - if (options.deep !== true && entry.path.indexOf('/', prefix.length) !== -1) { - continue; - } - - yield this.mapToStatEntry(entry); - } - } - async changeVisibility(path: string, visibility: string): Promise { - const entry = this.entries.get(path); - - if (entry?.type !== 'file') { - throw new Error(`Path ${path} is not a file`); - } - - this.entries.set(path, { - ...entry, - visibility, - }); - } - async visibility(path: string): Promise { - const entry = this.entries.get(path); - - if (entry === undefined) { - throw new Error(`Path ${path} does not exist`); - } - - return entry.visibility ?? 'public'; - } - async deleteDirectory(path: string): Promise { - const entries = this.entries.values(); - const prefix = `${path.replace(/\/+$/g, '')}/`; - - for (const entry of entries) { - if (entry.path.startsWith(prefix) || entry.path === path) { - this.entries.delete(entry.path); - } - } - } - async fileExists(path: string): Promise { - return this.entries.get(path)?.type === 'file'; - } - async directoryExists(path: string): Promise { - return this.entries.get(path)?.type === 'directory'; - } - async publicUrl(path: string, options: PublicUrlOptions): Promise { - throw new Error("Method not implemented."); - } - async temporaryUrl(path: string, options: TemporaryUrlOptions): Promise { - throw new Error("Method not implemented."); - } - async checksum(path: string, options: ChecksumOptions): Promise { - if (this.entries.get(path)?.type !== 'file') { - // throw new Error(`File ${path} does not exists`); - } - - throw ChecksumIsNotAvailable.checksumNotSupported(options.algo ?? 'unknown', { - context: {path}, - }); - } - async mimeType(path: string, options: MimeTypeOptions): Promise { - const entry = this.entries.get(path); - - if (entry?.type !== 'file') { - throw new Error(`File ${path} does not exist`); - } - - return await resolveMimeType(path, Buffer.from(entry.contents)); - } - async lastModified(path: string): Promise { - const entry = this.entries.get(path); - - if (entry?.type !== 'file') { - throw new Error(`File ${path} does not exist`); - } - - return entry.lastModifiedMs; - } - - async fileSize(path: string): Promise { - const entry = this.entries.get(path); - - if (entry?.type !== 'file') { - throw new Error(`File ${path} does not exist`); - } - - return Buffer.byteLength(entry.contents); - } -} - -export async function resolveMimeType( - filename: string, - contents: Uint8Array, -): Promise { - const {fileTypeFromBuffer} = await import('file-type'); - const lookup = await fileTypeFromBuffer(contents); - - if (lookup) { - return lookup.mime; - } - - const {ext} = parse(filename); - - return mimeTimeForExt(ext) || 'application/octet-stream'; -} - -/** - * BC export - * - * @deprecated - */ -export class InMemoryFileStorage extends InMemoryStorageAdapter {} \ No newline at end of file diff --git a/packages/in-memory/src/in-memory-file-storage.test.ts b/packages/in-memory/src/index.test.ts similarity index 98% rename from packages/in-memory/src/in-memory-file-storage.test.ts rename to packages/in-memory/src/index.test.ts index ad2930b..edebffe 100644 --- a/packages/in-memory/src/in-memory-file-storage.test.ts +++ b/packages/in-memory/src/index.test.ts @@ -1,5 +1,5 @@ import {FileStorage, Visibility} from "@flystorage/file-storage"; -import {InMemoryStorageAdapter} from "./in-memory-file-storage.js"; +import {InMemoryStorageAdapter} from "./index.js"; describe('InMemoryStorageAdapter', () => { const adapter = new InMemoryStorageAdapter(); diff --git a/packages/in-memory/src/index.ts b/packages/in-memory/src/index.ts index febdc62..c1e8c30 100644 --- a/packages/in-memory/src/index.ts +++ b/packages/in-memory/src/index.ts @@ -1 +1,271 @@ -export * from './in-memory-file-storage.js'; \ No newline at end of file +import { + ChecksumIsNotAvailable, + ChecksumOptions, + CopyFileOptions, + CreateDirectoryOptions, + FileContents, + MimeTypeOptions, + MoveFileOptions, + PublicUrlOptions, + StatEntry, + StorageAdapter, + TemporaryUrlOptions, + VisibilityOptions, + WriteOptions, + readableToBuffer, + readableToString, +} from '@flystorage/file-storage'; +import {Readable} from "node:stream"; +import {dirname, parse} from 'node:path' +import {lookup as mimeTimeForExt} from "mime-types"; + +type FileEntry = { + type: 'file', + path: string, + contents: Buffer, + lastModifiedMs: number, + visibility?: string, +} + +type DirectoryEntry = { + type: 'directory', + path: string, + visibility?: string, +} + +export type TimestampResolver = () => number; + +function cloneBuffer(input: Buffer): Buffer { + const output = Buffer.alloc(input.length); + input.copy(output); + + return output; +} + +export class InMemoryStorageAdapter implements StorageAdapter { + private entries: Map = new Map; + + constructor( + private readonly timestampResolver: TimestampResolver = () => Date.now(), + ) { + } + + deleteEverything(): void { + this.entries = new Map; + } + + async write(path: string, contents: Readable, options: WriteOptions): Promise { + this.ensureParentDirsExist(path, options); + + this.entries.set(path, { + type: 'file', + path, + contents: await readableToBuffer(contents), + lastModifiedMs: this.timestampResolver(), + visibility: options.visibility, + }) + } + + private ensureParentDirsExist(path: string, options: VisibilityOptions) { + let parentDir = dirname(path); + + while (!['.', ''].includes(parentDir) && !this.entries.has(parentDir)) { + this.entries.set(parentDir, { + path: parentDir, + type: 'directory', + visibility: options.directoryVisibility, + }); + + parentDir = dirname(parentDir); + } + } + + async read(path: string): Promise { + const file = this.entries.get(path); + + if (file?.type !== 'file') { + throw new Error(`Path "${path}" is not a file`); + } + + return Readable.from(cloneBuffer(file.contents)); + } + + async deleteFile(path: string): Promise { + this.entries.delete(path); + } + + async createDirectory(path: string, options: CreateDirectoryOptions): Promise { + path = path.replace(/\/+$/g, ''); + + this.entries.set(path, { + path, + type: 'directory', + visibility: options.directoryVisibility, + }); + } + async copyFile(from: string, to: string, options: CopyFileOptions): Promise { + const source = this.entries.get(from); + + if (source?.type !== 'file') { + throw new Error(`Source file ${from} does not exist`); + } + + this.ensureParentDirsExist(to, options); + this.entries.set(to, { + ...source, + path: to, + }); + } + async moveFile(from: string, to: string, options: MoveFileOptions): Promise { + await this.copyFile(from, to, options); + await this.deleteFile(from); + } + async stat(path: string): Promise { + const entry = this.entries.get(path); + + if (entry === undefined) { + throw new Error(`No entry found for path "${path}"`); + } + + return this.mapToStatEntry(entry); + } + private mapToStatEntry(entry: DirectoryEntry | FileEntry): StatEntry { + if (entry.type === 'directory') { + return { + ...entry, + isDirectory: true, + isFile: false, + }; + } + + return { + type: 'file', + path: entry.path, + visibility: entry.visibility, + isFile: true, + isDirectory: false, + lastModifiedMs: entry.lastModifiedMs, + } + } + async *list(path: string, options: { deep: boolean; }): AsyncGenerator { + const entries = this.entries.values(); + const prefix = path === '' || path === '/' + ? '' + : `${path.replace(/\/+$/g, '')}/`; + + for (const entry of entries) { + if (!entry.path.startsWith(prefix)) { + continue; + } + + if (options.deep !== true && entry.path.indexOf('/', prefix.length) !== -1) { + continue; + } + + yield this.mapToStatEntry(entry); + } + } + async changeVisibility(path: string, visibility: string): Promise { + const entry = this.entries.get(path); + + if (entry?.type !== 'file') { + throw new Error(`Path ${path} is not a file`); + } + + this.entries.set(path, { + ...entry, + visibility, + }); + } + async visibility(path: string): Promise { + const entry = this.entries.get(path); + + if (entry === undefined) { + throw new Error(`Path ${path} does not exist`); + } + + return entry.visibility ?? 'public'; + } + async deleteDirectory(path: string): Promise { + const entries = this.entries.values(); + const prefix = `${path.replace(/\/+$/g, '')}/`; + + for (const entry of entries) { + if (entry.path.startsWith(prefix) || entry.path === path) { + this.entries.delete(entry.path); + } + } + } + async fileExists(path: string): Promise { + return this.entries.get(path)?.type === 'file'; + } + async directoryExists(path: string): Promise { + return this.entries.get(path)?.type === 'directory'; + } + async publicUrl(path: string, options: PublicUrlOptions): Promise { + throw new Error("Method not implemented."); + } + async temporaryUrl(path: string, options: TemporaryUrlOptions): Promise { + throw new Error("Method not implemented."); + } + async checksum(path: string, options: ChecksumOptions): Promise { + if (this.entries.get(path)?.type !== 'file') { + // throw new Error(`File ${path} does not exists`); + } + + throw ChecksumIsNotAvailable.checksumNotSupported(options.algo ?? 'unknown', { + context: {path}, + }); + } + async mimeType(path: string, options: MimeTypeOptions): Promise { + const entry = this.entries.get(path); + + if (entry?.type !== 'file') { + throw new Error(`File ${path} does not exist`); + } + + return await resolveMimeType(path, Buffer.from(entry.contents)); + } + async lastModified(path: string): Promise { + const entry = this.entries.get(path); + + if (entry?.type !== 'file') { + throw new Error(`File ${path} does not exist`); + } + + return entry.lastModifiedMs; + } + + async fileSize(path: string): Promise { + const entry = this.entries.get(path); + + if (entry?.type !== 'file') { + throw new Error(`File ${path} does not exist`); + } + + return Buffer.byteLength(entry.contents); + } +} + +export async function resolveMimeType( + filename: string, + contents: Uint8Array, +): Promise { + const {fileTypeFromBuffer} = await import('file-type'); + const lookup = await fileTypeFromBuffer(contents); + + if (lookup) { + return lookup.mime; + } + + const {ext} = parse(filename); + + return mimeTimeForExt(ext) || 'application/octet-stream'; +} + +/** + * BC export + * + * @deprecated + */ +export class Index extends InMemoryStorageAdapter {} \ No newline at end of file diff --git a/packages/local-fs/package.json b/packages/local-fs/package.json index 46bb4ca..d24468e 100644 --- a/packages/local-fs/package.json +++ b/packages/local-fs/package.json @@ -9,27 +9,22 @@ "mime-types": "^3.0.2" }, "description": "", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "patch": "gsed -i 's/dynamicallyImport(/import(/g' dist/esm/local-file-storage.js", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" + "patch": "gsed -i 's/dynamicallyImport(/import(/g' dist/local-file-storage.js" }, "keywords": [ "fs", diff --git a/packages/multer-storage/package.json b/packages/multer-storage/package.json index ffe4e6d..7f19b02 100644 --- a/packages/multer-storage/package.json +++ b/packages/multer-storage/package.json @@ -8,25 +8,25 @@ "multer": "^2.0.2" }, "description": "", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", + "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/package.cjson", "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", + "compile:types": "tsc --outDir ./dist/ --declaration --emitDeclarationOnly", "watch": "tsc --watch" }, "keywords": [ diff --git a/packages/stream-mime-type/package.json b/packages/stream-mime-type/package.json index 302b978..ae4ede4 100644 --- a/packages/stream-mime-type/package.json +++ b/packages/stream-mime-type/package.json @@ -8,27 +8,22 @@ "mime-types": "^3.0.2" }, "description": "Get the mime-type of a readable stream, non-destructive", - "main": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.ts", "exports": { ".": { "import": { - "types": "./dist/types/index.d.ts", - "default": "./dist/esm/index.js" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" }, "require": { - "types": "./dist/types/index.d.ts", - "default": "./dist/cjs/index.js" + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" } } }, "scripts": { - "compile": "rm -rf ./dist/ && concurrently npm:compile:* && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json", - "patch": "gsed -i 's/dynamicallyImport(/import(/g' dist/esm/stream-mime-type.js", - "compile:esm": "tsc --outDir ./dist/esm/ --declaration false", - "compile:cjs": "tsc --outDir ./dist/cjs/ --declaration false --module commonjs --moduleResolution node", - "compile:types": "tsc --outDir ./dist/types/ --declaration --emitDeclarationOnly", - "watch": "tsc --watch" + "patch": "gsed -i 's/dynamicallyImport(/import(/g' dist/index.js" }, "author": "Frank de Jonge (https://frankdejonge.nl)", "homepage": "https://flystorage.dev/tools/stream-mime-type/", diff --git a/packages/stream-mime-type/src/stream-mime-type.test.ts b/packages/stream-mime-type/src/index.test.ts similarity index 95% rename from packages/stream-mime-type/src/stream-mime-type.test.ts rename to packages/stream-mime-type/src/index.test.ts index 3199196..a17e986 100644 --- a/packages/stream-mime-type/src/stream-mime-type.test.ts +++ b/packages/stream-mime-type/src/index.test.ts @@ -2,7 +2,7 @@ import * as fs from 'node:fs'; import path from 'node:path'; import {Readable} from 'stream'; -import {resolveMimeType} from './stream-mime-type.js'; +import {resolveMimeType} from './index.js'; describe('resolveMimeType', () => { let stream: Readable; diff --git a/packages/stream-mime-type/src/index.ts b/packages/stream-mime-type/src/index.ts index 43084e7..1e15a3a 100644 --- a/packages/stream-mime-type/src/index.ts +++ b/packages/stream-mime-type/src/index.ts @@ -1 +1,80 @@ -export * from './stream-mime-type.js'; \ No newline at end of file +import {Readable} from 'node:stream'; +import {parse} from 'node:path'; +import {lookup as mimeTimeForExt} from 'mime-types'; +import {PassThrough} from 'node:stream'; +import {dynamicallyImport} from '@flystorage/dynamic-import'; + +function concatUint8Arrays(input: Uint8Array[]): Uint8Array { + const length = input.reduce((l, a) => l + a.byteLength, 0); + const output = new Uint8Array(length); + let position = 0; + input.forEach(i => { + output.set(i, position); + position += i.byteLength; + }); + + return output; +} + +export async function streamHead(stream: Readable, size: number): Promise<[Uint8Array, Readable]> { + return new Promise((resolve, reject) => { + const tunnel = new PassThrough(); + const outputStream = new PassThrough(); + let readBytes = 0; + let buffers: Uint8Array[] = []; + let resolved = false; + + tunnel.once('error', reject); + tunnel.on('data', (chunk: Uint8Array) => { + if (!resolved) { + readBytes += chunk.byteLength; + buffers.push(chunk); + + if (readBytes >= size) { + resolved = true; + const head = concatUint8Arrays(buffers); + buffers = []; + resolve([head, outputStream]); + } + } + }); + tunnel.once('end', () => { + if (!resolved) { + resolve([concatUint8Arrays(buffers), outputStream]); + } + }); + stream.pipe(tunnel).pipe(outputStream); + }); +} + +type FileTypePackage = typeof import('file-type'); +let fileTypeImport: Promise | undefined; +let fileTypes: FileTypePackage | undefined = undefined; + +export async function resolveMimeType( + filename: string, + stream: Readable, + fallback: string | undefined = undefined +): Promise<[string|undefined, Readable]> { + const [head, readable] = await streamHead(stream, 4100); + + if (fileTypeImport === undefined) { + fileTypeImport = dynamicallyImport('file-type'); + } + + if (fileTypes === undefined) { + fileTypes = await fileTypeImport; + } + + + const {fileTypeFromBuffer} = fileTypes; + const lookup = await fileTypeFromBuffer(head); + + if (lookup) { + return [lookup.mime, readable]; + } + + const {ext} = parse(filename); + + return [mimeTimeForExt(ext) || fallback, readable]; +} \ No newline at end of file diff --git a/packages/stream-mime-type/src/stream-mime-type.ts b/packages/stream-mime-type/src/stream-mime-type.ts deleted file mode 100644 index 1e15a3a..0000000 --- a/packages/stream-mime-type/src/stream-mime-type.ts +++ /dev/null @@ -1,80 +0,0 @@ -import {Readable} from 'node:stream'; -import {parse} from 'node:path'; -import {lookup as mimeTimeForExt} from 'mime-types'; -import {PassThrough} from 'node:stream'; -import {dynamicallyImport} from '@flystorage/dynamic-import'; - -function concatUint8Arrays(input: Uint8Array[]): Uint8Array { - const length = input.reduce((l, a) => l + a.byteLength, 0); - const output = new Uint8Array(length); - let position = 0; - input.forEach(i => { - output.set(i, position); - position += i.byteLength; - }); - - return output; -} - -export async function streamHead(stream: Readable, size: number): Promise<[Uint8Array, Readable]> { - return new Promise((resolve, reject) => { - const tunnel = new PassThrough(); - const outputStream = new PassThrough(); - let readBytes = 0; - let buffers: Uint8Array[] = []; - let resolved = false; - - tunnel.once('error', reject); - tunnel.on('data', (chunk: Uint8Array) => { - if (!resolved) { - readBytes += chunk.byteLength; - buffers.push(chunk); - - if (readBytes >= size) { - resolved = true; - const head = concatUint8Arrays(buffers); - buffers = []; - resolve([head, outputStream]); - } - } - }); - tunnel.once('end', () => { - if (!resolved) { - resolve([concatUint8Arrays(buffers), outputStream]); - } - }); - stream.pipe(tunnel).pipe(outputStream); - }); -} - -type FileTypePackage = typeof import('file-type'); -let fileTypeImport: Promise | undefined; -let fileTypes: FileTypePackage | undefined = undefined; - -export async function resolveMimeType( - filename: string, - stream: Readable, - fallback: string | undefined = undefined -): Promise<[string|undefined, Readable]> { - const [head, readable] = await streamHead(stream, 4100); - - if (fileTypeImport === undefined) { - fileTypeImport = dynamicallyImport('file-type'); - } - - if (fileTypes === undefined) { - fileTypes = await fileTypeImport; - } - - - const {fileTypeFromBuffer} = fileTypes; - const lookup = await fileTypeFromBuffer(head); - - if (lookup) { - return [lookup.mime, readable]; - } - - const {ext} = parse(filename); - - return [mimeTimeForExt(ext) || fallback, readable]; -} \ No newline at end of file diff --git a/packed/cjs/index.test.js b/packed/cjs/index.test.js index 3dc851d..ceef38f 100644 --- a/packed/cjs/index.test.js +++ b/packed/cjs/index.test.js @@ -14,5 +14,7 @@ describe('running inside jest', () => { const listing = await fs.list('jest').toArray(); expect(listing.length).toBe(1); + + expect(await fs.mimeType('jest/file.txt')).toEqual('text/plain'); }) }) \ No newline at end of file diff --git a/packed/cjs/package.json b/packed/cjs/package.json index 12dcb4b..17f514e 100644 --- a/packed/cjs/package.json +++ b/packed/cjs/package.json @@ -6,9 +6,12 @@ "description": "", "main": "index.js", "dependencies": { - "@flystorage/file-storage": "file:~/Sites/filestorage/packed/flystorage-file-storage-0.1.7.tgz", - "@flystorage/local-fs": "file:~/Sites/filestorage/packed/flystorage-local-fs-0.1.9.tgz", - "@flystorage/stream-mime-type": "file:~/Sites/filestorage/packed/flystorage-stream-mime-type-0.1.6.tgz" + "@flystorage/file-storage": "file:~/Sites/filestorage/packed/flystorage-file-storage-1.2.0.tgz", + "@flystorage/local-fs": "file:~/Sites/filestorage/packed/flystorage-local-fs-1.2.0.tgz", + "@flystorage/stream-mime-type": "file:~/Sites/filestorage/packed/flystorage-stream-mime-type-1.1.0.tgz" + }, + "scripts": { + "test": "jest" }, "keywords": [], "author": "", diff --git a/packed/esm/package.json b/packed/esm/package.json index 2b53d57..b4bbc1c 100644 --- a/packed/esm/package.json +++ b/packed/esm/package.json @@ -6,9 +6,9 @@ "description": "", "main": "index.js", "dependencies": { - "@flystorage/file-storage": "file:~/Sites/filestorage/packed/flystorage-file-storage-0.1.7.tgz", - "@flystorage/local-fs": "file:~/Sites/filestorage/packed/flystorage-local-fs-0.1.10.tgz", - "@flystorage/stream-mime-type": "file:~/Sites/filestorage/packed/flystorage-stream-mime-type-0.1.7.tgz" + "@flystorage/file-storage": "file:~/Sites/filestorage/packed/flystorage-file-storage-1.2.0.tgz", + "@flystorage/local-fs": "file:~/Sites/filestorage/packed/flystorage-local-fs-1.2.0.tgz", + "@flystorage/stream-mime-type": "file:~/Sites/filestorage/packed/flystorage-stream-mime-type-1.1.0.tgz" }, "keywords": [], "author": "", diff --git a/tsdown.config.ts b/tsdown.config.ts new file mode 100644 index 0000000..89281fd --- /dev/null +++ b/tsdown.config.ts @@ -0,0 +1,49 @@ +import {defineConfig} from 'tsdown'; +import {resolve} from 'path'; +import {readdir, readFile} from 'fs/promises'; + +const packageDirectories: string[] = Array.from( + (await readdir(resolve(import.meta.dirname, 'packages'), {withFileTypes: true})) + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name) + .filter(directory => !directory.endsWith('-tests') && directory !== 'dynamic-import'), +); + +const aliases: Record = {}; +const sources: Record = {}; + +await Promise.all(packageDirectories.map(async name => { + const packageFile = JSON.parse(await readFile(resolve(import.meta.dirname, 'packages', name, 'package.json'), 'utf8')); + const exportDeclarations = packageFile['exports'] ?? {}; + const sourceFiles: string[] = []; + + for (const key in exportDeclarations) { + const sourceFile = exportDeclarations[key]['import']['default'].replace('dist', 'src').replace('.js', '.ts'); + sourceFiles.push(sourceFile); + const destination = resolve(import.meta.dirname, 'packages', name, sourceFile); + + if (key === '.') { + aliases[`@flystorage/${name}`] = destination; + } else if (key.startsWith('./')) { + aliases[`@flystorage/${name}/${key.substring(2)}`] = destination; + } + } + + sources[name] = sourceFiles.map(file => `packages/${name}/${file}`); +})); + +export default [ + ...packageDirectories.map(dirname => { + return defineConfig({ + dts: true, + format: ['esm', 'cjs'], + external: [/^@flystorage\//], + alias: aliases, + skipNodeModulesBundle: true, + entry: sources[dirname] ?? [], + outDir: resolve(import.meta.dirname, `packages/${dirname}/dist`), + platform: 'node', + unbundle: true, + }); + }), +]; \ No newline at end of file