diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
index 99ab478..e8bbe9c 100644
--- a/.github/CODE_OF_CONDUCT.md
+++ b/.github/CODE_OF_CONDUCT.md
@@ -61,7 +61,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
-[INSERT CONTACT METHOD].
+willfarrell@proton.me.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 2767a9c..b6c9d79 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,10 +1,10 @@
# Contributing
-In the spirit of Open Source Software, everyone is very welcome to contribute to this repository. Feel free to [raise issues](https://github.com/willfarrell/csv-rex/issues) or to [submit Pull Requests](https://github.com/willfarrell/csv-rex/pulls).
+In the spirit of Open Source Software, everyone is very welcome to contribute to this repository. Feel free to [raise issues](https://github.com/willfarrell/datastream/issues) or to [submit Pull Requests](https://github.com/willfarrell/datastream/pulls).
Before contributing to the project, make sure to have a look at our [Code of Conduct](/.github/CODE_OF_CONDUCT.md).
## Licence
-Licensed under [MIT Licence](LICENSE). Copyright (c) 2022 [will Farrell](https://github.com/willfarrell), and the [csv-rex team](https://github.com/willfarrell/csv-rex/graphs/contributors).
+Licensed under [MIT Licence](LICENSE). Copyright (c) 2026 [will Farrell](https://github.com/willfarrell), and the [datastream team](https://github.com/willfarrell/datastream/graphs/contributors).
diff --git a/.github/package.json b/.github/package.json
index df08b5f..d329f2f 100644
--- a/.github/package.json
+++ b/.github/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/github-workflows",
- "version": "0.1.6",
+ "version": "0.2.0",
"private": true,
"engines": {
"node": ">=24.0"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3bb4574..eb400a0 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -16,7 +16,7 @@ permissions:
jobs:
build:
name: Build
- if: ${{ github.event.pull_request.merged }}
+ if: ${{ github.event.pull_request.merged && github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
permissions:
diff --git a/.gitignore b/.gitignore
index a34d27a..45fbb2c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,9 @@
*.cjs
*.cjs.map
+!*.config.cjs
*.mjs
*.mjs.map
+!*.config.mjs
coverage
# Logs
@@ -115,4 +117,4 @@ dist
.nova
# OS
-.DS_Store
\ No newline at end of file
+.DS_Store
diff --git a/bin/esbuild b/bin/esbuild
index 2be4668..139376e 100755
--- a/bin/esbuild
+++ b/bin/esbuild
@@ -10,13 +10,11 @@ for package in packages/*; do
module="${module#./}"
fi
if [ -f ${package}/${module}.js ]; then
- #node_modules/.bin/esbuild --platform=node --target=node18 --format=cjs ${package}/${module}.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.node.cjs
- node_modules/.bin/esbuild --platform=node --target=node18 --format=esm ${package}/${module}.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.node.mjs
+ node_modules/.bin/esbuild --platform=node --target=node24 --format=esm ${package}/${module}.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.node.mjs
node_modules/.bin/esbuild --platform=browser --format=esm ${package}/${module}.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.web.mjs
fi
if [ -f ${package}/${module}.node.js ]; then
- #node_modules/.bin/esbuild --platform=node --target=node18 --format=cjs ${package}/${module}.node.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.node.cjs
- node_modules/.bin/esbuild --platform=node --target=node18 --format=esm ${package}/${module}.node.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.node.mjs
+ node_modules/.bin/esbuild --platform=node --target=node24 --format=esm ${package}/${module}.node.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.node.mjs
fi
if [ -f ${package}/${module}.web.js ]; then
node_modules/.bin/esbuild --platform=browser --format=esm ${package}/${module}.web.js --sourcemap=external --allow-overwrite --outfile=${package}/${module}.web.mjs
diff --git a/biome.json b/biome.json
index 8cf08df..e24f7cc 100644
--- a/biome.json
+++ b/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/2.4.8/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.4.12/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
@@ -20,10 +20,10 @@
"noBannedTypes": "off"
},
"correctness": {
- "noUnusedFunctionParameters": "off"
+ "noUnusedFunctionParameters": "warn"
},
"suspicious": {
- "noExplicitAny": "off"
+ "noExplicitAny": "warn"
}
}
},
diff --git a/commitlint.config.cjs b/commitlint.config.cjs
new file mode 100644
index 0000000..26a88cb
--- /dev/null
+++ b/commitlint.config.cjs
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: ["@commitlint/config-conventional"],
+};
diff --git a/docs/packages/core.md b/docs/packages/core.md
index a6dd9f9..fbd2c18 100644
--- a/docs/packages/core.md
+++ b/docs/packages/core.md
@@ -23,6 +23,23 @@
- `chunkSize`
- `signal`
+## Null handling
+
+Node.js streams use `push(null)` to signal end-of-stream (EOF). To allow `null` values to flow through object-mode pipelines without terminating the stream, datastream wraps them with a sentinel Symbol (`Symbol.for("@datastream/null")`).
+
+This is handled automatically when using datastream's built-in functions (`createReadableStream`, `createTransformStream`, `createPassThroughStream`, `createWritableStream`, `streamToArray`). You only need to be aware of it when reading chunks directly from a stream, such as listening to `data` events or using `for await...of` on a mid-pipeline stream.
+
+```javascript
+// Handled automatically - null values round-trip correctly
+const output = await streamToArray(createReadableStream([1, null, 3]))
+// [1, null, 3]
+
+// Direct access - you may see the sentinel Symbol
+stream.on('data', (chunk) => {
+ // chunk may be Symbol.for("@datastream/null") instead of null
+})
+```
+
## Examples
```javascript
diff --git a/package-lock.json b/package-lock.json
index 39a6b2e..787609d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@datastream/monorepo",
- "version": "0.1.6",
+ "version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@datastream/monorepo",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"workspaces": [
"packages/*",
@@ -17,12 +17,12 @@
"@biomejs/biome": "^2.0.0",
"@commitlint/cli": "^20.0.0",
"@commitlint/config-conventional": "^20.0.0",
- "@types/node": "25.5.0",
- "esbuild": "^0.27.0",
+ "@types/node": "25.6.0",
+ "esbuild": "^0.28.0",
"fast-check": "^4.0.0",
"husky": "^9.0.0",
"tinybench": "^6.0.0",
- "tstyche": "^6.0.0"
+ "tstyche": "^7.0.0"
},
"engines": {
"node": ">=24"
@@ -30,7 +30,7 @@
},
".github": {
"name": "@datastream/github-workflows",
- "version": "0.1.6",
+ "version": "0.2.0",
"devDependencies": {
"license-check-and-add": "4.0.5",
"lockfile-lint": "5.0.0"
@@ -40,9 +40,9 @@
}
},
"node_modules/@apidevtools/json-schema-ref-parser": {
- "version": "15.3.1",
- "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.3.1.tgz",
- "integrity": "sha512-FIweGOR9zrNuskfDXn8dfsA4eJEe8LmmGsGSDikEZvgYm36SO36yMhasXSOX7/OTGZ3b7I9iPhOxB24D8xL5uQ==",
+ "version": "15.3.5",
+ "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.3.5.tgz",
+ "integrity": "sha512-orNOYXw3hYXxxisXMldjzjBzqqTLBPbwOtHg7ovBPvfBHDue1qM9YJENZ3W2BQuS+7z4ThogMbEzEsov57Itkg==",
"license": "MIT",
"dependencies": {
"js-yaml": "^4.1.1"
@@ -272,54 +272,163 @@
"node": ">=14.0.0"
}
},
+ "node_modules/@aws-sdk/client-cloudwatch-logs": {
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.1030.0.tgz",
+ "integrity": "sha512-8VVoVOy7bTERDwY1emGktBMB3f7eTDbjvb0RqRR1rtCdGGtelocdGJeazkZvWS3yQmErN5GK6Puvq+4Uq6BHqw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-crypto/sha256-browser": "5.2.0",
+ "@aws-crypto/sha256-js": "5.2.0",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/eventstream-serde-browser": "^4.2.13",
+ "@smithy/eventstream-serde-config-resolver": "^4.3.13",
+ "@smithy/eventstream-serde-node": "^4.2.13",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
+ "@smithy/util-base64": "^4.3.2",
+ "@smithy/util-body-length-browser": "^4.2.2",
+ "@smithy/util-body-length-node": "^4.2.3",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
+ "@smithy/util-utf8": "^4.2.2",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
"node_modules/@aws-sdk/client-dynamodb": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1012.0.tgz",
- "integrity": "sha512-9iy4ngJYXRtxEtHL8RFSV+hTr2Rx67qxRhh8wOE3tREokKUFMBwrvb0D0JIBcK76qqZvUanycSpNQhYm/AuWwA==",
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1030.0.tgz",
+ "integrity": "sha512-mJlCunrAcjOvRyjDiOSNNFEJWwGkfHChqNHZI36oZwnbWyVBkMa43Qhc54sWIhZVXzYONeQ+hviF6zLbFBTUAw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-crypto/sha256-browser": "5.2.0",
+ "@aws-crypto/sha256-js": "5.2.0",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/dynamodb-codec": "^3.972.28",
+ "@aws-sdk/middleware-endpoint-discovery": "^3.972.10",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
+ "@smithy/util-base64": "^4.3.2",
+ "@smithy/util-body-length-browser": "^4.2.2",
+ "@smithy/util-body-length-node": "^4.2.3",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
+ "@smithy/util-utf8": "^4.2.2",
+ "@smithy/util-waiter": "^4.2.15",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-kinesis": {
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-kinesis/-/client-kinesis-3.1030.0.tgz",
+ "integrity": "sha512-6uYjDKyorp5yEUpGNz5g23md3C8HQzDcxSWFn2rGxhbmoQifztk79RabbC1T4jd2HscC0vI+UqacekqrKJsr+w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/credential-provider-node": "^3.972.22",
- "@aws-sdk/dynamodb-codec": "^3.972.22",
- "@aws-sdk/middleware-endpoint-discovery": "^3.972.8",
- "@aws-sdk/middleware-host-header": "^3.972.8",
- "@aws-sdk/middleware-logger": "^3.972.8",
- "@aws-sdk/middleware-recursion-detection": "^3.972.8",
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/region-config-resolver": "^3.972.8",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@aws-sdk/util-user-agent-browser": "^3.972.8",
- "@aws-sdk/util-user-agent-node": "^3.973.8",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/core": "^3.23.12",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/hash-node": "^4.2.12",
- "@smithy/invalid-dependency": "^4.2.12",
- "@smithy/middleware-content-length": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-retry": "^4.4.43",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/eventstream-serde-browser": "^4.2.13",
+ "@smithy/eventstream-serde-config-resolver": "^4.3.13",
+ "@smithy/eventstream-serde-node": "^4.2.13",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
"@smithy/util-body-length-node": "^4.2.3",
- "@smithy/util-defaults-mode-browser": "^4.3.42",
- "@smithy/util-defaults-mode-node": "^4.2.45",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
"@smithy/util-utf8": "^4.2.2",
- "@smithy/util-waiter": "^4.2.13",
+ "@smithy/util-waiter": "^4.2.15",
"tslib": "^2.6.2"
},
"engines": {
@@ -327,55 +436,55 @@
}
},
"node_modules/@aws-sdk/client-lambda": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1012.0.tgz",
- "integrity": "sha512-ngJAVKHaM4zkzIrbnitVuSoPegBEdb8zHD5dmc452sRngoQXNpHIj6tEEZwdAuoVlP3WM9nAXn/monSY2l3pyg==",
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1030.0.tgz",
+ "integrity": "sha512-z02i8O8qpDVHQX5KMsB1cIn/RP0v2/dyLDIToRHZEbxy5SiiamSC3Gk+BxApILN2XQU+ZBhLlopaG8nrkyXTiQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/credential-provider-node": "^3.972.22",
- "@aws-sdk/middleware-host-header": "^3.972.8",
- "@aws-sdk/middleware-logger": "^3.972.8",
- "@aws-sdk/middleware-recursion-detection": "^3.972.8",
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/region-config-resolver": "^3.972.8",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@aws-sdk/util-user-agent-browser": "^3.972.8",
- "@aws-sdk/util-user-agent-node": "^3.973.8",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/core": "^3.23.12",
- "@smithy/eventstream-serde-browser": "^4.2.12",
- "@smithy/eventstream-serde-config-resolver": "^4.3.12",
- "@smithy/eventstream-serde-node": "^4.2.12",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/hash-node": "^4.2.12",
- "@smithy/invalid-dependency": "^4.2.12",
- "@smithy/middleware-content-length": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-retry": "^4.4.43",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/eventstream-serde-browser": "^4.2.13",
+ "@smithy/eventstream-serde-config-resolver": "^4.3.13",
+ "@smithy/eventstream-serde-node": "^4.2.13",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
"@smithy/util-body-length-node": "^4.2.3",
- "@smithy/util-defaults-mode-browser": "^4.3.42",
- "@smithy/util-defaults-mode-node": "^4.2.45",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
- "@smithy/util-stream": "^4.5.20",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
+ "@smithy/util-stream": "^4.5.22",
"@smithy/util-utf8": "^4.2.2",
- "@smithy/util-waiter": "^4.2.13",
+ "@smithy/util-waiter": "^4.2.15",
"tslib": "^2.6.2"
},
"engines": {
@@ -383,66 +492,66 @@
}
},
"node_modules/@aws-sdk/client-s3": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1012.0.tgz",
- "integrity": "sha512-YB44c/NVLwyLw2x8hYSIdMFRwFJyZRuaq1HCTS2RiUWmHucSGxohuKwQdQn/XWh+NILugB+RnXrBkSqTlR3ypw==",
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1030.0.tgz",
+ "integrity": "sha512-sgGb4ub0JXnHaXnok5td7A1KGwENFPwOrwgzvpkeWq9w16Sl7x2KhYtVl+Fdd/7LAvaEtm3HqrYtNmm2d0OXmQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha1-browser": "5.2.0",
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/credential-provider-node": "^3.972.22",
- "@aws-sdk/middleware-bucket-endpoint": "^3.972.8",
- "@aws-sdk/middleware-expect-continue": "^3.972.8",
- "@aws-sdk/middleware-flexible-checksums": "^3.974.1",
- "@aws-sdk/middleware-host-header": "^3.972.8",
- "@aws-sdk/middleware-location-constraint": "^3.972.8",
- "@aws-sdk/middleware-logger": "^3.972.8",
- "@aws-sdk/middleware-recursion-detection": "^3.972.8",
- "@aws-sdk/middleware-sdk-s3": "^3.972.21",
- "@aws-sdk/middleware-ssec": "^3.972.8",
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/region-config-resolver": "^3.972.8",
- "@aws-sdk/signature-v4-multi-region": "^3.996.9",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@aws-sdk/util-user-agent-browser": "^3.972.8",
- "@aws-sdk/util-user-agent-node": "^3.973.8",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/core": "^3.23.12",
- "@smithy/eventstream-serde-browser": "^4.2.12",
- "@smithy/eventstream-serde-config-resolver": "^4.3.12",
- "@smithy/eventstream-serde-node": "^4.2.12",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/hash-blob-browser": "^4.2.13",
- "@smithy/hash-node": "^4.2.12",
- "@smithy/hash-stream-node": "^4.2.12",
- "@smithy/invalid-dependency": "^4.2.12",
- "@smithy/md5-js": "^4.2.12",
- "@smithy/middleware-content-length": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-retry": "^4.4.43",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/middleware-bucket-endpoint": "^3.972.9",
+ "@aws-sdk/middleware-expect-continue": "^3.972.9",
+ "@aws-sdk/middleware-flexible-checksums": "^3.974.7",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-location-constraint": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-sdk-s3": "^3.972.28",
+ "@aws-sdk/middleware-ssec": "^3.972.9",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/signature-v4-multi-region": "^3.996.16",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/eventstream-serde-browser": "^4.2.13",
+ "@smithy/eventstream-serde-config-resolver": "^4.3.13",
+ "@smithy/eventstream-serde-node": "^4.2.13",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-blob-browser": "^4.2.14",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/hash-stream-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/md5-js": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
"@smithy/util-body-length-node": "^4.2.3",
- "@smithy/util-defaults-mode-browser": "^4.3.42",
- "@smithy/util-defaults-mode-node": "^4.2.45",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
- "@smithy/util-stream": "^4.5.20",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
+ "@smithy/util-stream": "^4.5.22",
"@smithy/util-utf8": "^4.2.2",
- "@smithy/util-waiter": "^4.2.13",
+ "@smithy/util-waiter": "^4.2.15",
"tslib": "^2.6.2"
},
"engines": {
@@ -450,49 +559,49 @@
}
},
"node_modules/@aws-sdk/client-sns": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.1012.0.tgz",
- "integrity": "sha512-vQkDcFVpsqQOR+Vk4XcKTozvmGRega2b/AhVTPO/5eMDMWgsGy/xClZ39kxIfFVwBPeVcDBjLw3whFS5jPy0OQ==",
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.1030.0.tgz",
+ "integrity": "sha512-mz9Q4U6I+gp6v7oeg7Ul0/45jG+9XAXQypy+XH6SpVNTlvsnE3TOkdPxUUDQOHcSHDFYHHS7yfjn1ExKRvNEEw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/credential-provider-node": "^3.972.22",
- "@aws-sdk/middleware-host-header": "^3.972.8",
- "@aws-sdk/middleware-logger": "^3.972.8",
- "@aws-sdk/middleware-recursion-detection": "^3.972.8",
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/region-config-resolver": "^3.972.8",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@aws-sdk/util-user-agent-browser": "^3.972.8",
- "@aws-sdk/util-user-agent-node": "^3.973.8",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/core": "^3.23.12",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/hash-node": "^4.2.12",
- "@smithy/invalid-dependency": "^4.2.12",
- "@smithy/middleware-content-length": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-retry": "^4.4.43",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
"@smithy/util-body-length-node": "^4.2.3",
- "@smithy/util-defaults-mode-browser": "^4.3.42",
- "@smithy/util-defaults-mode-node": "^4.2.45",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -501,51 +610,51 @@
}
},
"node_modules/@aws-sdk/client-sqs": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.1012.0.tgz",
- "integrity": "sha512-VBAX4BBvvhsPqEdR44YFTISHq08ttkxsEDOPb7CZoonrA0UJ+7dk+maz/hMC7Kqh2ZQlbolNxfaDTL3hBD9Wlg==",
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.1030.0.tgz",
+ "integrity": "sha512-v+m4uejMysJ+Ay9SKDqg8zzdw2WfOGwKIGeYEPR12Wn7j5vKRPXa5Yixnzi07qMGAgOiFj9iEjV2tcqkPqD4ww==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/credential-provider-node": "^3.972.22",
- "@aws-sdk/middleware-host-header": "^3.972.8",
- "@aws-sdk/middleware-logger": "^3.972.8",
- "@aws-sdk/middleware-recursion-detection": "^3.972.8",
- "@aws-sdk/middleware-sdk-sqs": "^3.972.16",
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/region-config-resolver": "^3.972.8",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@aws-sdk/util-user-agent-browser": "^3.972.8",
- "@aws-sdk/util-user-agent-node": "^3.973.8",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/core": "^3.23.12",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/hash-node": "^4.2.12",
- "@smithy/invalid-dependency": "^4.2.12",
- "@smithy/md5-js": "^4.2.12",
- "@smithy/middleware-content-length": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-retry": "^4.4.43",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-sdk-sqs": "^3.972.19",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/md5-js": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
"@smithy/util-body-length-node": "^4.2.3",
- "@smithy/util-defaults-mode-browser": "^4.3.42",
- "@smithy/util-defaults-mode-node": "^4.2.45",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -554,51 +663,51 @@
}
},
"node_modules/@aws-sdk/client-ssm": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1012.0.tgz",
- "integrity": "sha512-VMyo2xTGsqzdBicYcQmbxvLbmhuwptAGLq+Q769mTYXbAKYXixqLsUCR6pAt3f7hoIhl/47PnC0ddDYBXEaD9w==",
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1030.0.tgz",
+ "integrity": "sha512-FKu4tINBafrEp6FfoJDaM+KvTqwwK5gnVTrc0ZYbAQ5L7oMuCx02MEQvRI6VLaNhuIqXMKijKo2lodyLY+00WA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/credential-provider-node": "^3.972.22",
- "@aws-sdk/middleware-host-header": "^3.972.8",
- "@aws-sdk/middleware-logger": "^3.972.8",
- "@aws-sdk/middleware-recursion-detection": "^3.972.8",
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/region-config-resolver": "^3.972.8",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@aws-sdk/util-user-agent-browser": "^3.972.8",
- "@aws-sdk/util-user-agent-node": "^3.973.8",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/core": "^3.23.12",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/hash-node": "^4.2.12",
- "@smithy/invalid-dependency": "^4.2.12",
- "@smithy/middleware-content-length": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-retry": "^4.4.43",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-node": "^3.972.30",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
"@smithy/util-body-length-node": "^4.2.3",
- "@smithy/util-defaults-mode-browser": "^4.3.42",
- "@smithy/util-defaults-mode-node": "^4.2.45",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
"@smithy/util-utf8": "^4.2.2",
- "@smithy/util-waiter": "^4.2.13",
+ "@smithy/util-waiter": "^4.2.15",
"tslib": "^2.6.2"
},
"engines": {
@@ -606,23 +715,23 @@
}
},
"node_modules/@aws-sdk/core": {
- "version": "3.973.21",
- "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.21.tgz",
- "integrity": "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ==",
+ "version": "3.973.27",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.27.tgz",
+ "integrity": "sha512-CUZ5m8hwMCH6OYI4Li/WgMfIEx10Q2PLI9Y3XOUTPGZJ53aZ0007jCv+X/ywsaERyKPdw5MRZWk877roQksQ4A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/xml-builder": "^3.972.12",
- "@smithy/core": "^3.23.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/signature-v4": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/xml-builder": "^3.972.17",
+ "@smithy/core": "^3.23.14",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/signature-v4": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
"@smithy/util-base64": "^4.3.2",
- "@smithy/util-middleware": "^4.2.12",
+ "@smithy/util-middleware": "^4.2.13",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -631,13 +740,13 @@
}
},
"node_modules/@aws-sdk/crc64-nvme": {
- "version": "3.972.5",
- "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.5.tgz",
- "integrity": "sha512-2VbTstbjKdT+yKi8m7b3a9CiVac+pL/IY2PHJwsaGkkHmuuqkJZIErPck1h6P3T9ghQMLSdMPyW6Qp7Di5swFg==",
+ "version": "3.972.6",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.6.tgz",
+ "integrity": "sha512-NMbiqKdruhwwgI6nzBVe2jWMkXjaoQz2YOs3rFX+2F3gGyrJDkDPwMpV/RsTFeq2vAQ055wZNtOXFK4NYSkM8g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -645,16 +754,16 @@
}
},
"node_modules/@aws-sdk/credential-provider-env": {
- "version": "3.972.19",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.19.tgz",
- "integrity": "sha512-33NpkQtmnsjLr9QdZvL3w8bjy+WoBJ+jY8JwuzxIq38rDNi1kwpBWW7Yjh+8bMlksd+ZAWW0fH4S/6OeoAdU5A==",
+ "version": "3.972.25",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.25.tgz",
+ "integrity": "sha512-6QfI0wv4jpG5CrdO/AO0JfZ2ux+tKwJPrUwmvxXF50vI5KIypKVGNF6b4vlkYEnKumDTI1NX2zUBi8JoU5QU3A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -662,21 +771,21 @@
}
},
"node_modules/@aws-sdk/credential-provider-http": {
- "version": "3.972.21",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.21.tgz",
- "integrity": "sha512-xFke7yjbON4unNOG0TApQwz+o1LH5VhVLgWlUuiLRWNDyBfeHIFje2ck8qHybvJ8Fkm5m3SsN+pvHtVo6PGWlQ==",
+ "version": "3.972.27",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.27.tgz",
+ "integrity": "sha512-3V3Usj9Gs93h865DqN4M2NWJhC5kXU9BvZskfN3+69omuYlE3TZxOEcVQtBGLOloJB7BVfJKXVLqeNhOzHqSlQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/util-stream": "^4.5.20",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/util-stream": "^4.5.22",
"tslib": "^2.6.2"
},
"engines": {
@@ -684,25 +793,25 @@
}
},
"node_modules/@aws-sdk/credential-provider-ini": {
- "version": "3.972.21",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.21.tgz",
- "integrity": "sha512-fmJN7KhB7CoG65w9fC2LVOd2wZbR2d1yJIpZNe2J5CeDPu7nUHSmavuJAeGEoE3OL5UIBVPNhmK/fV/NQrs3Hw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/credential-provider-env": "^3.972.19",
- "@aws-sdk/credential-provider-http": "^3.972.21",
- "@aws-sdk/credential-provider-login": "^3.972.21",
- "@aws-sdk/credential-provider-process": "^3.972.19",
- "@aws-sdk/credential-provider-sso": "^3.972.21",
- "@aws-sdk/credential-provider-web-identity": "^3.972.21",
- "@aws-sdk/nested-clients": "^3.996.11",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/credential-provider-imds": "^4.2.12",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "version": "3.972.29",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.29.tgz",
+ "integrity": "sha512-SiBuAnXecCbT/OpAf3vqyI/AVE3mTaYr9ShXLybxZiPLBiPCCOIWSGAtYYGQWMRvobBTiqOewaB+wcgMMZI2Aw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/credential-provider-env": "^3.972.25",
+ "@aws-sdk/credential-provider-http": "^3.972.27",
+ "@aws-sdk/credential-provider-login": "^3.972.29",
+ "@aws-sdk/credential-provider-process": "^3.972.25",
+ "@aws-sdk/credential-provider-sso": "^3.972.29",
+ "@aws-sdk/credential-provider-web-identity": "^3.972.29",
+ "@aws-sdk/nested-clients": "^3.996.19",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/credential-provider-imds": "^4.2.13",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -710,19 +819,19 @@
}
},
"node_modules/@aws-sdk/credential-provider-login": {
- "version": "3.972.21",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.21.tgz",
- "integrity": "sha512-ENU+YCiuQocQjfIf9bPxZ+ZY0wIBkl3SMH22optBQwy8UFpSfonHynXzGT27xQxer4cYTNOpwDqbfo57BusbpQ==",
+ "version": "3.972.29",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.29.tgz",
+ "integrity": "sha512-OGOslTbOlxXexKMqhxCEbBQbUIfuhGxU5UXw3Fm56ypXHvrXH4aTt/xb5Y884LOoteP1QST1lVZzHfcTnWhiPQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/nested-clients": "^3.996.11",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/nested-clients": "^3.996.19",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -730,23 +839,23 @@
}
},
"node_modules/@aws-sdk/credential-provider-node": {
- "version": "3.972.22",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.22.tgz",
- "integrity": "sha512-VE6i8nkmrRyhKut7nnfCWRbdDf+CfyRr8ixSwdaPDguYlgvkAO2pHu9oK11XzbSuatB0io1ozI/vpYhelXn8Pg==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@aws-sdk/credential-provider-env": "^3.972.19",
- "@aws-sdk/credential-provider-http": "^3.972.21",
- "@aws-sdk/credential-provider-ini": "^3.972.21",
- "@aws-sdk/credential-provider-process": "^3.972.19",
- "@aws-sdk/credential-provider-sso": "^3.972.21",
- "@aws-sdk/credential-provider-web-identity": "^3.972.21",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/credential-provider-imds": "^4.2.12",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "version": "3.972.30",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.30.tgz",
+ "integrity": "sha512-FMnAnWxc8PG+ZrZ2OBKzY4luCUJhe9CG0B9YwYr4pzrYGLXBS2rl+UoUvjGbAwiptxRL6hyA3lFn03Bv1TLqTw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/credential-provider-env": "^3.972.25",
+ "@aws-sdk/credential-provider-http": "^3.972.27",
+ "@aws-sdk/credential-provider-ini": "^3.972.29",
+ "@aws-sdk/credential-provider-process": "^3.972.25",
+ "@aws-sdk/credential-provider-sso": "^3.972.29",
+ "@aws-sdk/credential-provider-web-identity": "^3.972.29",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/credential-provider-imds": "^4.2.13",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -754,17 +863,17 @@
}
},
"node_modules/@aws-sdk/credential-provider-process": {
- "version": "3.972.19",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.19.tgz",
- "integrity": "sha512-hjj5bFo4kf5/WzAMjDEFByVOMbq5gZiagIpJexf7Kp9nIDaGzhCphMsx03NCA8s9zUJzHlD1lXazd7MS+e03Lg==",
+ "version": "3.972.25",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.25.tgz",
+ "integrity": "sha512-HR7ynNRdNhNsdVCOCegy1HsfsRzozCOPtD3RzzT1JouuaHobWyRfJzCBue/3jP7gECHt+kQyZUvwg/cYLWurNQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -772,19 +881,19 @@
}
},
"node_modules/@aws-sdk/credential-provider-sso": {
- "version": "3.972.21",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.21.tgz",
- "integrity": "sha512-9jWRCuMZpZKlqCZ46bvievqdfswsyB2yPAr9rOiN+FxaGgf8jrR5iYDqJgscvk1jrbAxiK4cIjHv3XjIAWAhzQ==",
+ "version": "3.972.29",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.29.tgz",
+ "integrity": "sha512-HWv4SEq3jZDYPlwryZVef97+U8CxxRos5mK8sgGO1dQaFZpV5giZLzqGE5hkDmh2csYcBO2uf5XHjPTpZcJlig==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/nested-clients": "^3.996.11",
- "@aws-sdk/token-providers": "3.1012.0",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/nested-clients": "^3.996.19",
+ "@aws-sdk/token-providers": "3.1026.0",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -792,18 +901,18 @@
}
},
"node_modules/@aws-sdk/credential-provider-web-identity": {
- "version": "3.972.21",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.21.tgz",
- "integrity": "sha512-ShWQO/cQVZ+j3zUDK7Kj+m7grPzQCVA2iaZdJ+hJTGvVH5lR32Ip/rgZZ+zBdH6D6wczP9Upa4NMXoqJdGpK1g==",
+ "version": "3.972.29",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.29.tgz",
+ "integrity": "sha512-PdMBza1WEKEUPFEmMGCfnU2RYCz9MskU2e8JxjyUOsMKku7j9YaDKvbDi2dzC0ihFoM6ods2SbhfAAro+Gwlew==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/nested-clients": "^3.996.11",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/nested-clients": "^3.996.19",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -811,16 +920,16 @@
}
},
"node_modules/@aws-sdk/dynamodb-codec": {
- "version": "3.972.22",
- "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.972.22.tgz",
- "integrity": "sha512-q+hLEZbn3fMQJjy5YLYL74Yzaw1WnlAdjOJ0vw8RK2eBAmwkgBtQJt72S0lZEeMFOGDmnOy4wFavlifgpUdRKQ==",
+ "version": "3.972.28",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.972.28.tgz",
+ "integrity": "sha512-wx5jKLKPVJRsr/dwK9Xp26+SDb95xHlZU9Bgm2AglnMxQ0DlRlq3PyKlGi9y0OCuWZ7hLNcQJ7uDSN+PgsiuGg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@smithy/core": "^3.23.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/core": "^3.973.27",
+ "@smithy/core": "^3.23.14",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
"@smithy/util-base64": "^4.3.2",
"tslib": "^2.6.2"
},
@@ -829,9 +938,9 @@
}
},
"node_modules/@aws-sdk/endpoint-cache": {
- "version": "3.972.4",
- "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.4.tgz",
- "integrity": "sha512-GdASDnWanLnHxKK0hqV97xz23QmfA/C8yGe0PiuEmWiHSe+x+x+mFEj4sXqx9IbfyPncWz8f4EhNwBSG9cgYCg==",
+ "version": "3.972.5",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.5.tgz",
+ "integrity": "sha512-itVdge0NozgtgmtbZ25FVwWU3vGlE7x7feE/aOEJNkQfEpbkrF8Rj1QmnK+2blFfYE1xWt/iU+6/jUp/pv1+MA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -843,15 +952,16 @@
}
},
"node_modules/@aws-sdk/lib-storage": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1012.0.tgz",
- "integrity": "sha512-aqfwgwxOrBDMd7SBDnaduDljAhrL9corXZrekkrxEaPLte/0OxDYRSDQCRb6JYFycEgqOY06Hi1sjzkrORTssw==",
+ "version": "3.1030.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1030.0.tgz",
+ "integrity": "sha512-1Hn+m1sioy3OMvF/I1uDz9QjpqcE3QSsHvz0Y0UXyMthNCpvAEvN4qO9RWBDGfVqddY1Flsp0rfvjwYP4KVr+w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/abort-controller": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/smithy-client": "^4.12.6",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
"buffer": "5.6.0",
"events": "3.3.0",
"stream-browserify": "3.0.0",
@@ -861,21 +971,21 @@
"node": ">=20.0.0"
},
"peerDependencies": {
- "@aws-sdk/client-s3": "^3.1012.0"
+ "@aws-sdk/client-s3": "^3.1030.0"
}
},
"node_modules/@aws-sdk/middleware-bucket-endpoint": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.8.tgz",
- "integrity": "sha512-WR525Rr2QJSETa9a050isktyWi/4yIGcmY3BQ1kpHqb0LqUglQHCS8R27dTJxxWNZvQ0RVGtEZjTCbZJpyF3Aw==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.9.tgz",
+ "integrity": "sha512-COToYKgquDyligbcAep7ygs48RK+mwe/IYprq4+TSrVFzNOYmzWvHf6werpnKV5VYpRiwdn+Wa5ZXkPqLVwcTg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
+ "@aws-sdk/types": "^3.973.7",
"@aws-sdk/util-arn-parser": "^3.972.3",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"@smithy/util-config-provider": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -884,17 +994,17 @@
}
},
"node_modules/@aws-sdk/middleware-endpoint-discovery": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.8.tgz",
- "integrity": "sha512-S0oXx1QbSpMDBMJn4P0hOxW8ieGAdRT+G9NbL+ESWkkoCGf9D++fKYD2fyBGtIy88OrP7wgECpXgGLAcGpIj0A==",
+ "version": "3.972.10",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.10.tgz",
+ "integrity": "sha512-b3hf8dPxWonxFKgxBijMehVblgbY0gPprTvyuHYMxnOPfiCIY467kZltPoeOCQYLr9v0v0HuL9fIGtT6utd15w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/endpoint-cache": "^3.972.4",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/endpoint-cache": "^3.972.5",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -902,15 +1012,15 @@
}
},
"node_modules/@aws-sdk/middleware-expect-continue": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.8.tgz",
- "integrity": "sha512-5DTBTiotEES1e2jOHAq//zyzCjeMB78lEHd35u15qnrid4Nxm7diqIf9fQQ3Ov0ChH1V3Vvt13thOnrACmfGVQ==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.9.tgz",
+ "integrity": "sha512-V/FNCjFxnh4VGu+HdSiW4Yg5GELihA1MIDSAdsEPvuayXBVmr0Jaa6jdLAZLH38KYXl/vVjri9DQJWnTAujHEA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -918,24 +1028,24 @@
}
},
"node_modules/@aws-sdk/middleware-flexible-checksums": {
- "version": "3.974.1",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.1.tgz",
- "integrity": "sha512-1MQ8czTjW8b8SpM+ZoQ0k5yD4rd19G9ALPlGgbFdRS7bwlm9ArxXWu2M22mUgSjsGJwzDkpV8e9tjUnre6adAw==",
+ "version": "3.974.7",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.7.tgz",
+ "integrity": "sha512-uU4/ch2CLHB8Phu1oTKnnQ4e8Ujqi49zEnQYBhWYT53zfFvtJCdGsaOoypBr8Fm/pmCBssRmGoIQ4sixgdLP9w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/crc32": "5.2.0",
"@aws-crypto/crc32c": "5.2.0",
"@aws-crypto/util": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/crc64-nvme": "^3.972.5",
- "@aws-sdk/types": "^3.973.6",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/crc64-nvme": "^3.972.6",
+ "@aws-sdk/types": "^3.973.7",
"@smithy/is-array-buffer": "^4.2.2",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-stream": "^4.5.20",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-stream": "^4.5.22",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -944,15 +1054,15 @@
}
},
"node_modules/@aws-sdk/middleware-host-header": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.8.tgz",
- "integrity": "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.9.tgz",
+ "integrity": "sha512-je5vRdNw4SkuTnmRbFZLdye4sQ0faLt8kwka5wnnSU30q1mHO4X+idGEJOOE+Tn1ME7Oryn05xxkDvIb3UaLaQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -960,14 +1070,14 @@
}
},
"node_modules/@aws-sdk/middleware-location-constraint": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.8.tgz",
- "integrity": "sha512-KaUoFuoFPziIa98DSQsTPeke1gvGXlc5ZGMhy+b+nLxZ4A7jmJgLzjEF95l8aOQN2T/qlPP3MrAyELm8ExXucw==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.9.tgz",
+ "integrity": "sha512-TyfOi2XNdOZpNKeTJwRUsVAGa+14nkyMb2VVGG+eDgcWG/ed6+NUo72N3hT6QJioxym80NSinErD+LBRF0Ir1w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -975,14 +1085,14 @@
}
},
"node_modules/@aws-sdk/middleware-logger": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.8.tgz",
- "integrity": "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.9.tgz",
+ "integrity": "sha512-HsVgDrruhqI28RkaXALm8grJ7Agc1wF6Et0xh6pom8NdO2VdO/SD9U/tPwUjewwK/pVoka+EShBxyCvgsPCtog==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -990,16 +1100,16 @@
}
},
"node_modules/@aws-sdk/middleware-recursion-detection": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.8.tgz",
- "integrity": "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA==",
+ "version": "3.972.10",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.10.tgz",
+ "integrity": "sha512-RVQQbq5orQ/GHUnXvqEOj2HHPBJm+mM+ySwZKS5UaLBwra5ugRtiH09PLUoOZRl7a1YzaOzXSuGbn9iD5j60WQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
+ "@aws-sdk/types": "^3.973.7",
"@aws/lambda-invoke-store": "^0.2.2",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1007,24 +1117,24 @@
}
},
"node_modules/@aws-sdk/middleware-sdk-s3": {
- "version": "3.972.21",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.21.tgz",
- "integrity": "sha512-SXkHy8OET88y4NaSui3gMfoTpg4jHvcbAVXYJuP74vsgsJKCv/vzWM+0hVJ1W+EBOghd+qFIud80ZiuPt2RXRw==",
+ "version": "3.972.28",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.28.tgz",
+ "integrity": "sha512-qJHcJQH9UNPUrnPlRtCozKjtqAaypQ5IgQxTNoPsVYIQeuwNIA8Rwt3NvGij1vCDYDfCmZaPLpnJEHlZXeFqmg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/types": "^3.973.6",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/types": "^3.973.7",
"@aws-sdk/util-arn-parser": "^3.972.3",
- "@smithy/core": "^3.23.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/signature-v4": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
+ "@smithy/core": "^3.23.14",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/signature-v4": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
"@smithy/util-config-provider": "^4.2.2",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-stream": "^4.5.20",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-stream": "^4.5.22",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -1033,15 +1143,15 @@
}
},
"node_modules/@aws-sdk/middleware-sdk-sqs": {
- "version": "3.972.16",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.972.16.tgz",
- "integrity": "sha512-RU6LLNYF7vfsSAvVXZ5Sx+zvPQ3lwW8GULDvKYtLevvKwRtPKakz8HehG6vNZ6pW8XY2U0vilF26jFhnSBzQfA==",
+ "version": "3.972.19",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.972.19.tgz",
+ "integrity": "sha512-S7AWsrOTcs52AdS4uWPtP6n7tloOscfeNfJWK4wvNPJBI01lrfHb6g+tYRckwDzruhhdaPpn/CARZ+YPw6oMGw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
"@smithy/util-hex-encoding": "^4.2.2",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
@@ -1051,14 +1161,14 @@
}
},
"node_modules/@aws-sdk/middleware-ssec": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.8.tgz",
- "integrity": "sha512-wqlK0yO/TxEC2UsY9wIlqeeutF6jjLe0f96Pbm40XscTo57nImUk9lBcw0dPgsm0sppFtAkSlDrfpK+pC30Wqw==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.9.tgz",
+ "integrity": "sha512-wSA2BR7L0CyBNDJeSrleIIzC+DzL93YNTdfU0KPGLiocK6YsRv1nPAzPF+BFSdcs0Qa5ku5Kcf4KvQcWwKGenQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1066,19 +1176,19 @@
}
},
"node_modules/@aws-sdk/middleware-user-agent": {
- "version": "3.972.22",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.22.tgz",
- "integrity": "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ==",
+ "version": "3.972.29",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.29.tgz",
+ "integrity": "sha512-f/sIRzuTfEjg6NsbMYvye2VsmnQoNgntntleQyx5uGacUYzszbfIlO3GcI6G6daWUmTm0IDZc11qMHWwF0o0mQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@smithy/core": "^3.23.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
- "@smithy/util-retry": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@smithy/core": "^3.23.14",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
+ "@smithy/util-retry": "^4.3.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1086,48 +1196,48 @@
}
},
"node_modules/@aws-sdk/nested-clients": {
- "version": "3.996.11",
- "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.11.tgz",
- "integrity": "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ==",
+ "version": "3.996.19",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.19.tgz",
+ "integrity": "sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/middleware-host-header": "^3.972.8",
- "@aws-sdk/middleware-logger": "^3.972.8",
- "@aws-sdk/middleware-recursion-detection": "^3.972.8",
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/region-config-resolver": "^3.972.8",
- "@aws-sdk/types": "^3.973.6",
- "@aws-sdk/util-endpoints": "^3.996.5",
- "@aws-sdk/util-user-agent-browser": "^3.972.8",
- "@aws-sdk/util-user-agent-node": "^3.973.8",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/core": "^3.23.12",
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/hash-node": "^4.2.12",
- "@smithy/invalid-dependency": "^4.2.12",
- "@smithy/middleware-content-length": "^4.2.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-retry": "^4.4.43",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/middleware-host-header": "^3.972.9",
+ "@aws-sdk/middleware-logger": "^3.972.9",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.10",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/region-config-resolver": "^3.972.11",
+ "@aws-sdk/types": "^3.973.7",
+ "@aws-sdk/util-endpoints": "^3.996.6",
+ "@aws-sdk/util-user-agent-browser": "^3.972.9",
+ "@aws-sdk/util-user-agent-node": "^3.973.15",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/core": "^3.23.14",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/hash-node": "^4.2.13",
+ "@smithy/invalid-dependency": "^4.2.13",
+ "@smithy/middleware-content-length": "^4.2.13",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-retry": "^4.5.0",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
"@smithy/util-body-length-node": "^4.2.3",
- "@smithy/util-defaults-mode-browser": "^4.3.42",
- "@smithy/util-defaults-mode-node": "^4.2.45",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
+ "@smithy/util-defaults-mode-browser": "^4.3.45",
+ "@smithy/util-defaults-mode-node": "^4.2.49",
+ "@smithy/util-endpoints": "^3.3.4",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.0",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -1136,16 +1246,16 @@
}
},
"node_modules/@aws-sdk/region-config-resolver": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.8.tgz",
- "integrity": "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw==",
+ "version": "3.972.11",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.11.tgz",
+ "integrity": "sha512-6Q8B1dcx6BBqUTY1Mc/eROKA0FImEEY5VPSd6AGPEUf0ErjExz4snVqa9kNJSoVDV1rKaNf3qrWojgcKW+SdDg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/config-resolver": "^4.4.14",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1153,17 +1263,17 @@
}
},
"node_modules/@aws-sdk/signature-v4-multi-region": {
- "version": "3.996.9",
- "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.9.tgz",
- "integrity": "sha512-2aAUwudVQ3uNkCfkBLQwNVD2jkfb299NSeDueXsT2NcNdFrWtHRkiQzX3wk47UFYbm87BkdxrsAJcQO7PdQOhA==",
+ "version": "3.996.16",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.16.tgz",
+ "integrity": "sha512-EMdXYB4r/k5RWq86fugjRhid5JA+Z6MpS7n4sij4u5/C+STrkvuf9aFu41rJA9MjUzxCLzv8U2XL8cH2GSRYpQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/middleware-sdk-s3": "^3.972.21",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/signature-v4": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/middleware-sdk-s3": "^3.972.28",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/signature-v4": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1171,18 +1281,18 @@
}
},
"node_modules/@aws-sdk/token-providers": {
- "version": "3.1012.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1012.0.tgz",
- "integrity": "sha512-vzKwy020zjuiF4WTJzejx5nYcXJnRhHpb6i3lyZHIwfFwXG1yX4bzBVNMWYWF+bz1i2Pp2VhJbPyzpqj4VuJXQ==",
+ "version": "3.1026.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1026.0.tgz",
+ "integrity": "sha512-Ieq/HiRrbEtrYP387Nes0XlR7H1pJiJOZKv+QyQzMYpvTiDs0VKy2ZB3E2Zf+aFovWmeE7lRE4lXyF7dYM6GgA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "^3.973.21",
- "@aws-sdk/nested-clients": "^3.996.11",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/core": "^3.973.27",
+ "@aws-sdk/nested-clients": "^3.996.19",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1190,13 +1300,13 @@
}
},
"node_modules/@aws-sdk/types": {
- "version": "3.973.6",
- "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.6.tgz",
- "integrity": "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==",
+ "version": "3.973.7",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.7.tgz",
+ "integrity": "sha512-reXRwoJ6CfChoqAsBszUYajAF8Z2LRE+CRcKocvFSMpIiLOtYU3aJ9trmn6VVPAzbbY5LXF+FfmUslbXk1SYFg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1217,16 +1327,16 @@
}
},
"node_modules/@aws-sdk/util-endpoints": {
- "version": "3.996.5",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.5.tgz",
- "integrity": "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==",
+ "version": "3.996.6",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.6.tgz",
+ "integrity": "sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
- "@smithy/util-endpoints": "^3.3.3",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
+ "@smithy/util-endpoints": "^3.3.4",
"tslib": "^2.6.2"
},
"engines": {
@@ -1247,29 +1357,29 @@
}
},
"node_modules/@aws-sdk/util-user-agent-browser": {
- "version": "3.972.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.8.tgz",
- "integrity": "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.9.tgz",
+ "integrity": "sha512-sn/LMzTbGjYqCCF24390WxPd6hkpoSptiUn5DzVp4cD71yqw+yGEGm1YCxyEoPXyc8qciM8UzLJcZBFslxo5Uw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "^3.973.6",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/types": "^4.14.0",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/util-user-agent-node": {
- "version": "3.973.8",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.8.tgz",
- "integrity": "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ==",
+ "version": "3.973.15",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.15.tgz",
+ "integrity": "sha512-fYn3s9PtKdgQkczGZCFMgkNEe8aq1JCVbnRqjqN9RSVW43xn2RV9xdcZ3z01a48Jpkuh/xCmBKJxdLOo4Ozg7w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/middleware-user-agent": "^3.972.22",
- "@aws-sdk/types": "^3.973.6",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/types": "^4.13.1",
+ "@aws-sdk/middleware-user-agent": "^3.972.29",
+ "@aws-sdk/types": "^3.973.7",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/types": "^4.14.0",
"@smithy/util-config-provider": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -1286,14 +1396,14 @@
}
},
"node_modules/@aws-sdk/xml-builder": {
- "version": "3.972.12",
- "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.12.tgz",
- "integrity": "sha512-xjyucfn+F+kMf25c+LIUnvX3oyLSlj9T0Vncs5WMQI6G36JdnSwC8g0qf8RajfmSClXr660EpTz7FFKluZ4BqQ==",
+ "version": "3.972.17",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.17.tgz",
+ "integrity": "sha512-Ra7hjqAZf1OXRRMueB13qex7mFJRDK/pgCvdSFemXBT8KCGnQDPoKzHY1SjN+TjJVmnpSF14W5tJ1vDamFu+Gg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
- "fast-xml-parser": "5.5.6",
+ "@smithy/types": "^4.14.0",
+ "fast-xml-parser": "5.5.8",
"tslib": "^2.6.2"
},
"engines": {
@@ -1346,9 +1456,9 @@
}
},
"node_modules/@biomejs/biome": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.8.tgz",
- "integrity": "sha512-ponn0oKOky1oRXBV+rlSaUlixUxf1aZvWC19Z41zBfUOUesthrQqL3OtiAlSB1EjFjyWpn98Q64DHelhA6jNlA==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.12.tgz",
+ "integrity": "sha512-Rro7adQl3NLq/zJCIL98eElXKI8eEiBtoeu5TbXF/U3qbjuSc7Jb5rjUbeHHcquDWeSf3HnGP7XI5qGrlRk/pA==",
"dev": true,
"license": "MIT OR Apache-2.0",
"bin": {
@@ -1362,20 +1472,20 @@
"url": "https://opencollective.com/biome"
},
"optionalDependencies": {
- "@biomejs/cli-darwin-arm64": "2.4.8",
- "@biomejs/cli-darwin-x64": "2.4.8",
- "@biomejs/cli-linux-arm64": "2.4.8",
- "@biomejs/cli-linux-arm64-musl": "2.4.8",
- "@biomejs/cli-linux-x64": "2.4.8",
- "@biomejs/cli-linux-x64-musl": "2.4.8",
- "@biomejs/cli-win32-arm64": "2.4.8",
- "@biomejs/cli-win32-x64": "2.4.8"
+ "@biomejs/cli-darwin-arm64": "2.4.12",
+ "@biomejs/cli-darwin-x64": "2.4.12",
+ "@biomejs/cli-linux-arm64": "2.4.12",
+ "@biomejs/cli-linux-arm64-musl": "2.4.12",
+ "@biomejs/cli-linux-x64": "2.4.12",
+ "@biomejs/cli-linux-x64-musl": "2.4.12",
+ "@biomejs/cli-win32-arm64": "2.4.12",
+ "@biomejs/cli-win32-x64": "2.4.12"
}
},
"node_modules/@biomejs/cli-darwin-arm64": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.8.tgz",
- "integrity": "sha512-ARx0tECE8I7S2C2yjnWYLNbBdDoPdq3oyNLhMglmuctThwUsuzFWRKrHmIGwIRWKz0Mat9DuzLEDp52hGnrxGQ==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.12.tgz",
+ "integrity": "sha512-BnMU4Pc3ciEVteVpZ0BK33MLr7X57F5w1dwDLDn+/iy/yTrA4Q/N2yftidFtsA4vrDh0FMXDpacNV/Tl3fbmng==",
"cpu": [
"arm64"
],
@@ -1390,9 +1500,9 @@
}
},
"node_modules/@biomejs/cli-darwin-x64": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.8.tgz",
- "integrity": "sha512-Jg9/PsB9vDCJlANE8uhG7qDhb5w0Ix69D7XIIc8IfZPUoiPrbLm33k2Ig3NOJ/7nb3UbesFz3D1aDKm9DvzjhQ==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.12.tgz",
+ "integrity": "sha512-x9uJ0bI1rJsWICp3VH8w/5PnAVD3A7SqzDpbrfoUQX1QyWrK5jSU4fRLo/wSgGeplCivbxBRKmt5Xq4/nWvq8A==",
"cpu": [
"x64"
],
@@ -1407,13 +1517,16 @@
}
},
"node_modules/@biomejs/cli-linux-arm64": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.8.tgz",
- "integrity": "sha512-5CdrsJct76XG2hpKFwXnEtlT1p+4g4yV+XvvwBpzKsTNLO9c6iLlAxwcae2BJ7ekPGWjNGw9j09T5KGPKKxQig==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.12.tgz",
+ "integrity": "sha512-tOwuCuZZtKi1jVzbk/5nXmIsziOB6yqN8c9r9QM0EJYPU6DpQWf11uBOSCfFKKM4H3d9ZoarvlgMfbcuD051Pw==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
@@ -1424,13 +1537,16 @@
}
},
"node_modules/@biomejs/cli-linux-arm64-musl": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.8.tgz",
- "integrity": "sha512-Zo9OhBQDJ3IBGPlqHiTISloo5H0+FBIpemqIJdW/0edJ+gEcLR+MZeZozcUyz3o1nXkVA7++DdRKQT0599j9jA==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.12.tgz",
+ "integrity": "sha512-FhfpkAAlKL6kwvcVap0Hgp4AhZmtd3YImg0kK1jd7C/aSoh4SfsB2f++yG1rU0lr8Y5MCFJrcSkmssiL9Xnnig==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
@@ -1441,13 +1557,16 @@
}
},
"node_modules/@biomejs/cli-linux-x64": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.8.tgz",
- "integrity": "sha512-PdKXspVEaMCQLjtZCn6vfSck/li4KX9KGwSDbZdgIqlrizJ2MnMcE3TvHa2tVfXNmbjMikzcfJpuPWH695yJrw==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.12.tgz",
+ "integrity": "sha512-8pFeAnLU9QdW9jCIslB/v82bI0lhBmz2ZAKc8pVMFPO0t0wAHsoEkrUQUbMkIorTRIjbqyNZHA3lEXavsPWYSw==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
@@ -1458,13 +1577,16 @@
}
},
"node_modules/@biomejs/cli-linux-x64-musl": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.8.tgz",
- "integrity": "sha512-Gi8quv8MEuDdKaPFtS2XjEnMqODPsRg6POT6KhoP+VrkNb+T2ywunVB+TvOU0LX1jAZzfBr+3V1mIbBhzAMKvw==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.12.tgz",
+ "integrity": "sha512-dwTIgZrGutzhkQCuvHynCkyW6hJxUuyZqKKO0YNfaS2GUoRO+tOvxXZqZB6SkWAOdfZTzwaw8IEdUnIkHKHoew==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
@@ -1475,9 +1597,9 @@
}
},
"node_modules/@biomejs/cli-win32-arm64": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.8.tgz",
- "integrity": "sha512-LoFatS0tnHv6KkCVpIy3qZCih+MxUMvdYiPWLHRri7mhi2vyOOs8OrbZBcLTUEWCS+ktO72nZMy4F96oMhkOHQ==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.12.tgz",
+ "integrity": "sha512-B0DLnx0vA9ya/3v7XyCaP+/lCpnbWbMOfUFFve+xb5OxyYvdHaS55YsSddr228Y+JAFk58agCuZTsqNiw2a6ig==",
"cpu": [
"arm64"
],
@@ -1492,9 +1614,9 @@
}
},
"node_modules/@biomejs/cli-win32-x64": {
- "version": "2.4.8",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.8.tgz",
- "integrity": "sha512-vAn7iXDoUbqFXqVocuq1sMYAd33p8+mmurqJkWl6CtIhobd/O6moe4rY5AJvzbunn/qZCdiDVcveqtkFh1e7Hg==",
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.12.tgz",
+ "integrity": "sha512-yMckRzTyZ83hkk8iDFWswqSdU8tvZxspJKnYNh7JZr/zhZNOlzH13k4ecboU6MurKExCe2HUkH75pGI/O2JwGA==",
"cpu": [
"x64"
],
@@ -1519,9 +1641,9 @@
}
},
"node_modules/@cloudflare/unenv-preset": {
- "version": "2.15.0",
- "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.15.0.tgz",
- "integrity": "sha512-EGYmJaGZKWl+X8tXxcnx4v2bOZSjQeNI5dWFeXivgX9+YCT69AkzHHwlNbVpqtEUTbew8eQurpyOpeN8fg00nw==",
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.0.tgz",
+ "integrity": "sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg==",
"dev": true,
"license": "MIT OR Apache-2.0",
"peerDependencies": {
@@ -1535,9 +1657,9 @@
}
},
"node_modules/@cloudflare/workerd-darwin-64": {
- "version": "1.20260317.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260317.1.tgz",
- "integrity": "sha512-8hjh3sPMwY8M/zedq3/sXoA2Q4BedlGufn3KOOleIG+5a4ReQKLlUah140D7J6zlKmYZAFMJ4tWC7hCuI/s79g==",
+ "version": "1.20260415.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260415.1.tgz",
+ "integrity": "sha512-dsxaKsQm3LnPGNPEdsRv09QN3Y4DqCw7kX5j6noKqbAtro2jTr95sVlYM1jUxZ5FkOl1f7SXgaKKB9t5H5Nkbg==",
"cpu": [
"x64"
],
@@ -1552,9 +1674,9 @@
}
},
"node_modules/@cloudflare/workerd-darwin-arm64": {
- "version": "1.20260317.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260317.1.tgz",
- "integrity": "sha512-M/MnNyvO5HMgoIdr3QHjdCj2T1ki9gt0vIUnxYxBu9ISXS/jgtMl6chUVPJ7zHYBn9MyYr8ByeN6frjYxj0MGg==",
+ "version": "1.20260415.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260415.1.tgz",
+ "integrity": "sha512-+JgSgVA49KyKteHRA1SnonE4Zn5Ei5zdAp5FQMxFmXI8qulZw4Hl7safXxRyK4i9sTO8gl7TFOKO5Q64VPvSDQ==",
"cpu": [
"arm64"
],
@@ -1569,9 +1691,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-64": {
- "version": "1.20260317.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260317.1.tgz",
- "integrity": "sha512-1ltuEjkRcS3fsVF7CxsKlWiRmzq2ZqMfqDN0qUOgbUwkpXsLVJsXmoblaLf5OP00ELlcgF0QsN0p2xPEua4Uug==",
+ "version": "1.20260415.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260415.1.tgz",
+ "integrity": "sha512-tU+9pwsqCy8afOVlGtiWrWQc/fedQK4SRm4KPIAt+zOiQWDxWASm6YGBUJis5c648WN80yz47qnmdDi8DQNOcA==",
"cpu": [
"x64"
],
@@ -1586,9 +1708,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-arm64": {
- "version": "1.20260317.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260317.1.tgz",
- "integrity": "sha512-3QrNnPF1xlaNwkHpasvRvAMidOvQs2NhXQmALJrEfpIJ/IDL2la8g499yXp3eqhG3hVMCB07XVY149GTs42Xtw==",
+ "version": "1.20260415.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260415.1.tgz",
+ "integrity": "sha512-bR9uITnV19r5NQ14xnypi2xHXu2iQvfYV8cVgx0JouFUmWwTEEAwFVojDdssGq93VHX9hr/pi2IRUZeegbYBog==",
"cpu": [
"arm64"
],
@@ -1603,9 +1725,9 @@
}
},
"node_modules/@cloudflare/workerd-windows-64": {
- "version": "1.20260317.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260317.1.tgz",
- "integrity": "sha512-MfZTz+7LfuIpMGTa3RLXHX8Z/pnycZLItn94WRdHr8LPVet+C5/1Nzei399w/jr3+kzT4pDKk26JF/tlI5elpQ==",
+ "version": "1.20260415.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260415.1.tgz",
+ "integrity": "sha512-4NuMLlerI0Ijua3Ir8HXQ+qyNvCUDEG5gDco5Om+sAiK6rnWiz+aGoSlbB8W16yW9QAgzCstbmXLiVknUBflfQ==",
"cpu": [
"x64"
],
@@ -1620,9 +1742,9 @@
}
},
"node_modules/@cloudflare/workers-types": {
- "version": "4.20260317.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260317.1.tgz",
- "integrity": "sha512-+G4eVwyCpm8Au1ex8vQBCuA9wnwqetz4tPNRoB/53qvktERWBRMQnrtvC1k584yRE3emMThtuY0gWshvSJ++PQ==",
+ "version": "4.20260416.2",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260416.2.tgz",
+ "integrity": "sha512-f7VGuKsHckH5n9KATTPJQ6AGdc2q58eM2waGzzDoCKw+PBtw9j2TWdRz8tLkviv7XcjkcuKy181vQFffXJicrA==",
"dev": true,
"license": "MIT OR Apache-2.0"
},
@@ -1883,9 +2005,9 @@
}
},
"node_modules/@conventional-changelog/git-client": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.6.0.tgz",
- "integrity": "sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==",
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz",
+ "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1898,7 +2020,7 @@
},
"peerDependencies": {
"conventional-commits-filter": "^5.0.0",
- "conventional-commits-parser": "^6.3.0"
+ "conventional-commits-parser": "^6.4.0"
},
"peerDependenciesMeta": {
"conventional-commits-filter": {
@@ -1961,6 +2083,10 @@
"resolved": "packages/digest",
"link": true
},
+ "node_modules/@datastream/encrypt": {
+ "resolved": "packages/encrypt",
+ "link": true
+ },
"node_modules/@datastream/fetch": {
"resolved": "packages/fetch",
"link": true
@@ -1981,6 +2107,10 @@
"resolved": "packages/ipfs",
"link": true
},
+ "node_modules/@datastream/json": {
+ "resolved": "packages/json",
+ "link": true
+ },
"node_modules/@datastream/object": {
"resolved": "packages/object",
"link": true
@@ -1993,10 +2123,33 @@
"resolved": "packages/validate",
"link": true
},
+ "node_modules/@emnapi/core": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
+ "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@emnapi/runtime": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz",
- "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==",
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
+ "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -2005,9 +2158,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz",
- "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
+ "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
"cpu": [
"ppc64"
],
@@ -2021,9 +2174,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz",
- "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
+ "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
"cpu": [
"arm"
],
@@ -2037,9 +2190,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz",
- "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
+ "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
"cpu": [
"arm64"
],
@@ -2053,9 +2206,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz",
- "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
+ "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
"cpu": [
"x64"
],
@@ -2069,9 +2222,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz",
- "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
+ "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
"cpu": [
"arm64"
],
@@ -2085,9 +2238,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz",
- "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
+ "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
"cpu": [
"x64"
],
@@ -2101,9 +2254,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz",
- "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
"cpu": [
"arm64"
],
@@ -2117,9 +2270,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz",
- "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
+ "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
"cpu": [
"x64"
],
@@ -2133,9 +2286,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz",
- "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
+ "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
"cpu": [
"arm"
],
@@ -2149,9 +2302,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz",
- "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
+ "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
"cpu": [
"arm64"
],
@@ -2165,9 +2318,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz",
- "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
+ "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
"cpu": [
"ia32"
],
@@ -2181,9 +2334,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz",
- "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
+ "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
"cpu": [
"loong64"
],
@@ -2197,9 +2350,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz",
- "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
+ "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
"cpu": [
"mips64el"
],
@@ -2213,9 +2366,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz",
- "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
+ "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
"cpu": [
"ppc64"
],
@@ -2229,9 +2382,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz",
- "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
+ "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
"cpu": [
"riscv64"
],
@@ -2245,9 +2398,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz",
- "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
+ "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
"cpu": [
"s390x"
],
@@ -2261,9 +2414,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz",
- "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
+ "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
"cpu": [
"x64"
],
@@ -2277,9 +2430,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz",
- "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
"cpu": [
"arm64"
],
@@ -2293,9 +2446,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz",
- "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
"cpu": [
"x64"
],
@@ -2309,9 +2462,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz",
- "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
"cpu": [
"arm64"
],
@@ -2325,9 +2478,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz",
- "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
"cpu": [
"x64"
],
@@ -2341,9 +2494,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz",
- "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
+ "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
"cpu": [
"arm64"
],
@@ -2357,9 +2510,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz",
- "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
+ "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
"cpu": [
"x64"
],
@@ -2373,9 +2526,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz",
- "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
+ "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
"cpu": [
"arm64"
],
@@ -2389,9 +2542,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz",
- "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
+ "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
"cpu": [
"ia32"
],
@@ -2405,9 +2558,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz",
- "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
+ "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
"cpu": [
"x64"
],
@@ -2528,6 +2681,9 @@
"arm"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2545,6 +2701,9 @@
"arm64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2562,6 +2721,9 @@
"ppc64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2579,6 +2741,9 @@
"riscv64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2596,6 +2761,9 @@
"s390x"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2613,6 +2781,9 @@
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2630,6 +2801,9 @@
"arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2647,6 +2821,9 @@
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2664,6 +2841,9 @@
"arm"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2687,6 +2867,9 @@
"arm64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2710,6 +2893,9 @@
"ppc64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2733,6 +2919,9 @@
"riscv64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2756,6 +2945,9 @@
"s390x"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2779,6 +2971,9 @@
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2802,6 +2997,9 @@
"arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2825,6 +3023,9 @@
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3061,6 +3262,38 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+ "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@tybys/wasm-util": "^0.10.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ },
+ "peerDependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1"
+ }
+ },
+ "node_modules/@nodable/entities": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-1.1.0.tgz",
+ "integrity": "sha512-bidpxmTBP0pOsxULw6XlxzQpTgrAGLDHGBK/JuWhPDL6ZV0GZ/PmN9CA9do6e+A9lYI6qx6ikJUtJYRxup141g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodable"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -3105,6 +3338,16 @@
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
"license": "MIT"
},
+ "node_modules/@oxc-project/types": {
+ "version": "0.124.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz",
+ "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ }
+ },
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -3170,24 +3413,10 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
- "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-android-arm64": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
- "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
+ "node_modules/@rolldown/binding-android-arm64": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz",
+ "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==",
"cpu": [
"arm64"
],
@@ -3196,12 +3425,15 @@
"optional": true,
"os": [
"android"
- ]
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
- "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
+ "node_modules/@rolldown/binding-darwin-arm64": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz",
+ "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==",
"cpu": [
"arm64"
],
@@ -3210,12 +3442,15 @@
"optional": true,
"os": [
"darwin"
- ]
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
- "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
+ "node_modules/@rolldown/binding-darwin-x64": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz",
+ "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==",
"cpu": [
"x64"
],
@@ -3224,26 +3459,15 @@
"optional": true,
"os": [
"darwin"
- ]
- },
- "node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
- "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
- "cpu": [
- "arm64"
],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
- "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
+ "node_modules/@rolldown/binding-freebsd-x64": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz",
+ "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==",
"cpu": [
"x64"
],
@@ -3252,26 +3476,15 @@
"optional": true,
"os": [
"freebsd"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
- "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
- "cpu": [
- "arm"
],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
- "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
+ "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz",
+ "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==",
"cpu": [
"arm"
],
@@ -3280,180 +3493,135 @@
"optional": true,
"os": [
"linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
- "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
- "cpu": [
- "arm64"
],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
- "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
+ "node_modules/@rolldown/binding-linux-arm64-gnu": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz",
+ "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-loong64-gnu": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
- "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
- "cpu": [
- "loong64"
+ "libc": [
+ "glibc"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-loong64-musl": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
- "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
- "cpu": [
- "loong64"
],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-linux-ppc64-gnu": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
- "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
+ "node_modules/@rolldown/binding-linux-arm64-musl": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz",
+ "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==",
"cpu": [
- "ppc64"
+ "arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-linux-ppc64-musl": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
- "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
+ "node_modules/@rolldown/binding-linux-ppc64-gnu": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz",
+ "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==",
"cpu": [
"ppc64"
],
"dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
- "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
- "cpu": [
- "riscv64"
+ "libc": [
+ "glibc"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
- "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
- "cpu": [
- "riscv64"
],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
- "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
+ "node_modules/@rolldown/binding-linux-s390x-gnu": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz",
+ "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==",
"cpu": [
"s390x"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
- "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
+ "node_modules/@rolldown/binding-linux-x64-gnu": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz",
+ "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "MIT",
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
- "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
+ "node_modules/@rolldown/binding-linux-x64-musl": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz",
+ "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "MIT",
"optional": true,
"os": [
"linux"
- ]
- },
- "node_modules/@rollup/rollup-openbsd-x64": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
- "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
- "cpu": [
- "x64"
],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ]
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-openharmony-arm64": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
- "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
+ "node_modules/@rolldown/binding-openharmony-arm64": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz",
+ "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==",
"cpu": [
"arm64"
],
@@ -3462,40 +3630,51 @@
"optional": true,
"os": [
"openharmony"
- ]
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
- "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
+ "node_modules/@rolldown/binding-wasm32-wasi": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz",
+ "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==",
"cpu": [
- "arm64"
+ "wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
- "os": [
- "win32"
- ]
+ "dependencies": {
+ "@emnapi/core": "1.9.2",
+ "@emnapi/runtime": "1.9.2",
+ "@napi-rs/wasm-runtime": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
},
- "node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
- "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
+ "node_modules/@rolldown/binding-win32-arm64-msvc": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz",
+ "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==",
"cpu": [
- "ia32"
+ "arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
- ]
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
- "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
+ "node_modules/@rolldown/binding-win32-x64-msvc": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz",
+ "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==",
"cpu": [
"x64"
],
@@ -3504,21 +3683,17 @@
"optional": true,
"os": [
"win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
- "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
- "cpu": [
- "x64"
],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz",
+ "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==",
"dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
+ "license": "MIT"
},
"node_modules/@silverbucket/ajv-formats-draft2019": {
"version": "1.6.5",
@@ -3570,9 +3745,9 @@
}
},
"node_modules/@simplewebauthn/browser": {
- "version": "13.2.2",
- "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.2.2.tgz",
- "integrity": "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==",
+ "version": "13.3.0",
+ "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.3.0.tgz",
+ "integrity": "sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==",
"license": "MIT"
},
"node_modules/@sindresorhus/is": {
@@ -3629,20 +3804,6 @@
"node": ">=4"
}
},
- "node_modules/@smithy/abort-controller": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.12.tgz",
- "integrity": "sha512-xolrFw6b+2iYGl6EcOL7IJY71vvyZ0DJ3mcKtpykqPe2uscwtzDZJa1uVQXyP7w9Dd+kGwYnPbMsJrGISKiY/Q==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@smithy/types": "^4.13.1",
- "tslib": "^2.6.2"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
"node_modules/@smithy/chunked-blob-reader": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.2.tgz",
@@ -3671,17 +3832,17 @@
}
},
"node_modules/@smithy/config-resolver": {
- "version": "4.4.11",
- "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.11.tgz",
- "integrity": "sha512-YxFiiG4YDAtX7WMN7RuhHZLeTmRRAOyCbr+zB8e3AQzHPnUhS8zXjB1+cniPVQI3xbWsQPM0X2aaIkO/ME0ymw==",
+ "version": "4.4.15",
+ "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.15.tgz",
+ "integrity": "sha512-BJdMBY5YO9iHh+lPLYdHv6LbX+J8IcPCYMl1IJdBt2KDWNHwONHrPVHk3ttYBqJd9wxv84wlbN0f7GlQzcQtNQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/types": "^4.14.0",
"@smithy/util-config-provider": "^4.2.2",
- "@smithy/util-endpoints": "^3.3.3",
- "@smithy/util-middleware": "^4.2.12",
+ "@smithy/util-endpoints": "^3.4.0",
+ "@smithy/util-middleware": "^4.2.13",
"tslib": "^2.6.2"
},
"engines": {
@@ -3689,19 +3850,19 @@
}
},
"node_modules/@smithy/core": {
- "version": "3.23.12",
- "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.12.tgz",
- "integrity": "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w==",
+ "version": "3.23.14",
+ "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.14.tgz",
+ "integrity": "sha512-vJ0IhpZxZAkFYOegMKSrxw7ujhhT2pass/1UEcZ4kfl5srTAqtPU5I7MdYQoreVas3204ykCiNhY1o7Xlz6Yyg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-body-length-browser": "^4.2.2",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-stream": "^4.5.20",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-stream": "^4.5.22",
"@smithy/util-utf8": "^4.2.2",
"@smithy/uuid": "^1.1.2",
"tslib": "^2.6.2"
@@ -3711,16 +3872,16 @@
}
},
"node_modules/@smithy/credential-provider-imds": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.12.tgz",
- "integrity": "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.13.tgz",
+ "integrity": "sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
"tslib": "^2.6.2"
},
"engines": {
@@ -3728,14 +3889,14 @@
}
},
"node_modules/@smithy/eventstream-codec": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.12.tgz",
- "integrity": "sha512-FE3bZdEl62ojmy8x4FHqxq2+BuOHlcxiH5vaZ6aqHJr3AIZzwF5jfx8dEiU/X0a8RboyNDjmXjlbr8AdEyLgiA==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.13.tgz",
+ "integrity": "sha512-vYahwBAtRaAcFbOmE9aLr12z7RiHYDSLcnogSdxfm7kKfsNa3wH+NU5r7vTeB5rKvLsWyPjVX8iH94brP7umiQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/crc32": "5.2.0",
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"@smithy/util-hex-encoding": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -3744,14 +3905,14 @@
}
},
"node_modules/@smithy/eventstream-serde-browser": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.12.tgz",
- "integrity": "sha512-XUSuMxlTxV5pp4VpqZf6Sa3vT/Q75FVkLSpSSE3KkWBvAQWeuWt1msTv8fJfgA4/jcJhrbrbMzN1AC/hvPmm5A==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.13.tgz",
+ "integrity": "sha512-wwybfcOX0tLqCcBP378TIU9IqrDuZq/tDV48LlZNydMpCnqnYr+hWBAYbRE+rFFf/p7IkDJySM3bgiMKP2ihPg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/eventstream-serde-universal": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/eventstream-serde-universal": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3759,13 +3920,13 @@
}
},
"node_modules/@smithy/eventstream-serde-config-resolver": {
- "version": "4.3.12",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.12.tgz",
- "integrity": "sha512-7epsAZ3QvfHkngz6RXQYseyZYHlmWXSTPOfPmXkiS+zA6TBNo1awUaMFL9vxyXlGdoELmCZyZe1nQE+imbmV+Q==",
+ "version": "4.3.13",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.13.tgz",
+ "integrity": "sha512-ied1lO559PtAsMJzg2TKRlctLnEi1PfkNeMMpdwXDImk1zV9uvS/Oxoy/vcy9uv1GKZAjDAB5xT6ziE9fzm5wA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3773,14 +3934,14 @@
}
},
"node_modules/@smithy/eventstream-serde-node": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.12.tgz",
- "integrity": "sha512-D1pFuExo31854eAvg89KMn9Oab/wEeJR6Buy32B49A9Ogdtx5fwZPqBHUlDzaCDpycTFk2+fSQgX689Qsk7UGA==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.13.tgz",
+ "integrity": "sha512-hFyK+ORJrxAN3RYoaD6+gsGDQjeix8HOEkosoajvXYZ4VeqonM3G4jd9IIRm/sWGXUKmudkY9KdYjzosUqdM8A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/eventstream-serde-universal": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/eventstream-serde-universal": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3788,14 +3949,14 @@
}
},
"node_modules/@smithy/eventstream-serde-universal": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.12.tgz",
- "integrity": "sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.13.tgz",
+ "integrity": "sha512-kRrq4EKLGeOxhC2CBEhRNcu1KSzNJzYY7RK3S7CxMPgB5dRrv55WqQOtRwQxQLC04xqORFLUgnDlc6xrNUULaA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/eventstream-codec": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/eventstream-codec": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3803,15 +3964,15 @@
}
},
"node_modules/@smithy/fetch-http-handler": {
- "version": "5.3.15",
- "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.15.tgz",
- "integrity": "sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A==",
+ "version": "5.3.16",
+ "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.16.tgz",
+ "integrity": "sha512-nYDRUIvNd4mFmuXraRWt6w5UsZTNqtj4hXJA/iiOD4tuseIdLP9Lq38teH/SZTcIFCa2f+27o7hYpIsWktJKEQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/querystring-builder": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/querystring-builder": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"@smithy/util-base64": "^4.3.2",
"tslib": "^2.6.2"
},
@@ -3820,15 +3981,15 @@
}
},
"node_modules/@smithy/hash-blob-browser": {
- "version": "4.2.13",
- "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.13.tgz",
- "integrity": "sha512-YrF4zWKh+ghLuquldj6e/RzE3xZYL8wIPfkt0MqCRphVICjyyjH8OwKD7LLlKpVEbk4FLizFfC1+gwK6XQdR3g==",
+ "version": "4.2.14",
+ "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.14.tgz",
+ "integrity": "sha512-rtQ5es8r/5v4rav7q5QTsfx9CtCyzrz/g7ZZZBH2xtMmd6G/KQrLOWfSHTvFOUPlVy59RQvxeBYJaLRoybMEyA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@smithy/chunked-blob-reader": "^5.2.2",
"@smithy/chunked-blob-reader-native": "^4.2.3",
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3836,13 +3997,13 @@
}
},
"node_modules/@smithy/hash-node": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.12.tgz",
- "integrity": "sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.13.tgz",
+ "integrity": "sha512-4/oy9h0jjmY80a2gOIo75iLl8TOPhmtx4E2Hz+PfMjvx/vLtGY4TMU/35WRyH2JHPfT5CVB38u4JRow7gnmzJA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"@smithy/util-buffer-from": "^4.2.2",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
@@ -3852,13 +4013,13 @@
}
},
"node_modules/@smithy/hash-stream-node": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.12.tgz",
- "integrity": "sha512-O3YbmGExeafuM/kP7Y8r6+1y0hIh3/zn6GROx0uNlB54K9oihAL75Qtc+jFfLNliTi6pxOAYZrRKD9A7iA6UFw==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.13.tgz",
+ "integrity": "sha512-WdQ7HwUjINXETeh6dqUeob1UHIYx8kAn9PSp1HhM2WWegiZBYVy2WXIs1lB07SZLan/udys9SBnQGt9MQbDpdg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -3867,13 +4028,13 @@
}
},
"node_modules/@smithy/invalid-dependency": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.12.tgz",
- "integrity": "sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.13.tgz",
+ "integrity": "sha512-jvC0RB/8BLj2SMIkY0Npl425IdnxZJxInpZJbu563zIRnVjpDMXevU3VMCRSabaLB0kf/eFIOusdGstrLJ8IDg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3894,13 +4055,13 @@
}
},
"node_modules/@smithy/md5-js": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.12.tgz",
- "integrity": "sha512-W/oIpHCpWU2+iAkfZYyGWE+qkpuf3vEXHLxQQDx9FPNZTTdnul0dZ2d/gUFrtQ5je1G2kp4cjG0/24YueG2LbQ==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.13.tgz",
+ "integrity": "sha512-cNm7I9NXolFxtS20ojROddOEpSAeI1Obq6pd1Kj5HtHws3s9Fkk8DdHDfQSs5KuxCewZuVK6UqrJnfJmiMzDuQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -3909,14 +4070,14 @@
}
},
"node_modules/@smithy/middleware-content-length": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.12.tgz",
- "integrity": "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.13.tgz",
+ "integrity": "sha512-IPMLm/LE4AZwu6qiE8Rr8vJsWhs9AtOdySRXrOM7xnvclp77Tyh7hMs/FRrMf26kgIe67vFJXXOSmVxS7oKeig==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3924,19 +4085,19 @@
}
},
"node_modules/@smithy/middleware-endpoint": {
- "version": "4.4.26",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.26.tgz",
- "integrity": "sha512-8Qfikvd2GVKSm8S6IbjfwFlRY9VlMrj0Dp4vTwAuhqbX7NhJKE5DQc2bnfJIcY0B+2YKMDBWfvexbSZeejDgeg==",
+ "version": "4.4.29",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.29.tgz",
+ "integrity": "sha512-R9Q/58U+qBiSARGWbAbFLczECg/RmysRksX6Q8BaQEpt75I7LI6WGDZnjuC9GXSGKljEbA7N118LhGaMbfrTXw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.23.12",
- "@smithy/middleware-serde": "^4.2.15",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
- "@smithy/url-parser": "^4.2.12",
- "@smithy/util-middleware": "^4.2.12",
+ "@smithy/core": "^3.23.14",
+ "@smithy/middleware-serde": "^4.2.17",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
+ "@smithy/url-parser": "^4.2.13",
+ "@smithy/util-middleware": "^4.2.13",
"tslib": "^2.6.2"
},
"engines": {
@@ -3944,19 +4105,20 @@
}
},
"node_modules/@smithy/middleware-retry": {
- "version": "4.4.43",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.43.tgz",
- "integrity": "sha512-ZwsifBdyuNHrFGmbc7bAfP2b54+kt9J2rhFd18ilQGAB+GDiP4SrawqyExbB7v455QVR7Psyhb2kjULvBPIhvA==",
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.5.1.tgz",
+ "integrity": "sha512-/zY+Gp7Qj2D2hVm3irkCyONER7E9MiX3cUUm/k2ZmhkzZkrPgwVS4aJ5NriZUEN/M0D1hhjrgjUmX04HhRwdWA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/service-error-classification": "^4.2.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
- "@smithy/util-middleware": "^4.2.12",
- "@smithy/util-retry": "^4.2.12",
+ "@smithy/core": "^3.23.14",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/service-error-classification": "^4.2.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
+ "@smithy/util-middleware": "^4.2.13",
+ "@smithy/util-retry": "^4.3.1",
"@smithy/uuid": "^1.1.2",
"tslib": "^2.6.2"
},
@@ -3965,15 +4127,15 @@
}
},
"node_modules/@smithy/middleware-serde": {
- "version": "4.2.15",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.15.tgz",
- "integrity": "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg==",
+ "version": "4.2.17",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.17.tgz",
+ "integrity": "sha512-0T2mcaM6v9W1xku86Dk0bEW7aEseG6KenFkPK98XNw0ZhOqOiD1MrMsdnQw9QsL3/Oa85T53iSMlm0SZdSuIEQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.23.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/core": "^3.23.14",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3981,13 +4143,13 @@
}
},
"node_modules/@smithy/middleware-stack": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.12.tgz",
- "integrity": "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.13.tgz",
+ "integrity": "sha512-g72jN/sGDLyTanrCLH9fhg3oysO3f7tQa6eWWsMyn2BiYNCgjF24n4/I9wff/5XidFvjj9ilipAoQrurTUrLvw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -3995,15 +4157,15 @@
}
},
"node_modules/@smithy/node-config-provider": {
- "version": "4.3.12",
- "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.12.tgz",
- "integrity": "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw==",
+ "version": "4.3.13",
+ "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.13.tgz",
+ "integrity": "sha512-iGxQ04DsKXLckbgnX4ipElrOTk+IHgTyu0q0WssZfYhDm9CQWHmu6cOeI5wmWRxpXbBDhIIfXMWz5tPEtcVqbw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/property-provider": "^4.2.12",
- "@smithy/shared-ini-file-loader": "^4.4.7",
- "@smithy/types": "^4.13.1",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/shared-ini-file-loader": "^4.4.8",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4011,16 +4173,15 @@
}
},
"node_modules/@smithy/node-http-handler": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.0.tgz",
- "integrity": "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A==",
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.2.tgz",
+ "integrity": "sha512-/oD7u8M0oj2ZTFw7GkuuHWpIxtWdLlnyNkbrWcyVYhd5RJNDuczdkb0wfnQICyNFrVPlr8YHOhamjNy3zidhmA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/abort-controller": "^4.2.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/querystring-builder": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/querystring-builder": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4028,13 +4189,13 @@
}
},
"node_modules/@smithy/property-provider": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.12.tgz",
- "integrity": "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.13.tgz",
+ "integrity": "sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4042,13 +4203,13 @@
}
},
"node_modules/@smithy/protocol-http": {
- "version": "5.3.12",
- "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.12.tgz",
- "integrity": "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw==",
+ "version": "5.3.13",
+ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.13.tgz",
+ "integrity": "sha512-+HsmuJUF4u8POo6s8/a2Yb/AQ5t/YgLovCuHF9oxbocqv+SZ6gd8lC2duBFiCA/vFHoHQhoq7QjqJqZC6xOxxg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4056,13 +4217,13 @@
}
},
"node_modules/@smithy/querystring-builder": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.12.tgz",
- "integrity": "sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.13.tgz",
+ "integrity": "sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"@smithy/util-uri-escape": "^4.2.2",
"tslib": "^2.6.2"
},
@@ -4071,13 +4232,13 @@
}
},
"node_modules/@smithy/querystring-parser": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.12.tgz",
- "integrity": "sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.13.tgz",
+ "integrity": "sha512-hqW3Q4P+CDzUyQ87GrboGMeD7XYNMOF+CuTwu936UQRB/zeYn3jys8C3w+wMkDfY7CyyyVwZQ5cNFoG0x1pYmA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4085,26 +4246,26 @@
}
},
"node_modules/@smithy/service-error-classification": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.12.tgz",
- "integrity": "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.13.tgz",
+ "integrity": "sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1"
+ "@smithy/types": "^4.14.0"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/shared-ini-file-loader": {
- "version": "4.4.7",
- "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.7.tgz",
- "integrity": "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw==",
+ "version": "4.4.8",
+ "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.8.tgz",
+ "integrity": "sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4112,17 +4273,17 @@
}
},
"node_modules/@smithy/signature-v4": {
- "version": "5.3.12",
- "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.12.tgz",
- "integrity": "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw==",
+ "version": "5.3.13",
+ "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.13.tgz",
+ "integrity": "sha512-YpYSyM0vMDwKbHD/JA7bVOF6kToVRpa+FM5ateEVRpsTNu564g1muBlkTubXhSKKYXInhpADF46FPyrZcTLpXg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@smithy/is-array-buffer": "^4.2.2",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
"@smithy/util-hex-encoding": "^4.2.2",
- "@smithy/util-middleware": "^4.2.12",
+ "@smithy/util-middleware": "^4.2.13",
"@smithy/util-uri-escape": "^4.2.2",
"@smithy/util-utf8": "^4.2.2",
"tslib": "^2.6.2"
@@ -4132,18 +4293,18 @@
}
},
"node_modules/@smithy/smithy-client": {
- "version": "4.12.6",
- "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.6.tgz",
- "integrity": "sha512-aib3f0jiMsJ6+cvDnXipBsGDL7ztknYSVqJs1FdN9P+u9tr/VzOR7iygSh6EUOdaBeMCMSh3N0VdyYsG4o91DQ==",
+ "version": "4.12.9",
+ "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.9.tgz",
+ "integrity": "sha512-ovaLEcTU5olSeHcRXcxV6viaKtpkHZumn6Ps0yn7dRf2rRSfy794vpjOtrWDO0d1auDSvAqxO+lyhERSXQ03EQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.23.12",
- "@smithy/middleware-endpoint": "^4.4.26",
- "@smithy/middleware-stack": "^4.2.12",
- "@smithy/protocol-http": "^5.3.12",
- "@smithy/types": "^4.13.1",
- "@smithy/util-stream": "^4.5.20",
+ "@smithy/core": "^3.23.14",
+ "@smithy/middleware-endpoint": "^4.4.29",
+ "@smithy/middleware-stack": "^4.2.13",
+ "@smithy/protocol-http": "^5.3.13",
+ "@smithy/types": "^4.14.0",
+ "@smithy/util-stream": "^4.5.22",
"tslib": "^2.6.2"
},
"engines": {
@@ -4151,9 +4312,9 @@
}
},
"node_modules/@smithy/types": {
- "version": "4.13.1",
- "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz",
- "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==",
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.0.tgz",
+ "integrity": "sha512-OWgntFLW88kx2qvf/c/67Vno1yuXm/f9M7QFAtVkkO29IJXGBIg0ycEaBTH0kvCtwmvZxRujrgP5a86RvsXJAQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -4164,14 +4325,14 @@
}
},
"node_modules/@smithy/url-parser": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.12.tgz",
- "integrity": "sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.13.tgz",
+ "integrity": "sha512-2G03yoboIRZlZze2+PT4GZEjgwQsJjUgn6iTsvxA02bVceHR6vp4Cuk7TUnPFWKF+ffNUk3kj4COwkENS2K3vw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/querystring-parser": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/querystring-parser": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4247,15 +4408,15 @@
}
},
"node_modules/@smithy/util-defaults-mode-browser": {
- "version": "4.3.42",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.42.tgz",
- "integrity": "sha512-0vjwmcvkWAUtikXnWIUOyV6IFHTEeQUYh3JUZcDgcszF+hD/StAsQ3rCZNZEPHgI9kVNcbnyc8P2CBHnwgmcwg==",
+ "version": "4.3.45",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.45.tgz",
+ "integrity": "sha512-ag9sWc6/nWZAuK3Wm9KlFJUnRkXLrXn33RFjIAmCTFThqLHY+7wCst10BGq56FxslsDrjhSie46c8OULS+BiIw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/property-provider": "^4.2.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4263,18 +4424,18 @@
}
},
"node_modules/@smithy/util-defaults-mode-node": {
- "version": "4.2.45",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.45.tgz",
- "integrity": "sha512-q5dOqqfTgUcLe38TAGiFn9srToKj2YCHJ34QGOLzM+xYLLA+qRZv7N+33kl1MERVusue36ZHnlNaNEvY/PzSrw==",
+ "version": "4.2.50",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.50.tgz",
+ "integrity": "sha512-xpjncL5XozFA3No7WypTsPU1du0fFS8flIyO+Wh2nhCy7bpEapvU7BR55Bg+wrfw+1cRA+8G8UsTjaxgzrMzXg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/config-resolver": "^4.4.11",
- "@smithy/credential-provider-imds": "^4.2.12",
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/property-provider": "^4.2.12",
- "@smithy/smithy-client": "^4.12.6",
- "@smithy/types": "^4.13.1",
+ "@smithy/config-resolver": "^4.4.15",
+ "@smithy/credential-provider-imds": "^4.2.13",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/property-provider": "^4.2.13",
+ "@smithy/smithy-client": "^4.12.9",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4282,14 +4443,14 @@
}
},
"node_modules/@smithy/util-endpoints": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.3.tgz",
- "integrity": "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig==",
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.4.0.tgz",
+ "integrity": "sha512-QQHGPKkw6NPcU6TJ1rNEEa201srPtZiX4k61xL163vvs9sTqW/XKz+UEuJ00uvPqoN+5Rs4Ka1UJ7+Mp03IXJw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/node-config-provider": "^4.3.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4310,13 +4471,13 @@
}
},
"node_modules/@smithy/util-middleware": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.12.tgz",
- "integrity": "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ==",
+ "version": "4.2.13",
+ "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.13.tgz",
+ "integrity": "sha512-GTooyrlmRTqvUen4eK7/K1p6kryF7bnDfq6XsAbIsf2mo51B/utaH+XThY6dKgNCWzMAaH/+OLmqaBuLhLWRow==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4324,14 +4485,14 @@
}
},
"node_modules/@smithy/util-retry": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.12.tgz",
- "integrity": "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.3.1.tgz",
+ "integrity": "sha512-FwmicpgWOkP5kZUjN3y+3JIom8NLGqSAJBeoIgK0rIToI817TEBHCrd0A2qGeKQlgDeP+Jzn4i0H/NLAXGy9uQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/service-error-classification": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/service-error-classification": "^4.2.13",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4339,15 +4500,15 @@
}
},
"node_modules/@smithy/util-stream": {
- "version": "4.5.20",
- "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.20.tgz",
- "integrity": "sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw==",
+ "version": "4.5.22",
+ "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.22.tgz",
+ "integrity": "sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/fetch-http-handler": "^5.3.15",
- "@smithy/node-http-handler": "^4.5.0",
- "@smithy/types": "^4.13.1",
+ "@smithy/fetch-http-handler": "^5.3.16",
+ "@smithy/node-http-handler": "^4.5.2",
+ "@smithy/types": "^4.14.0",
"@smithy/util-base64": "^4.3.2",
"@smithy/util-buffer-from": "^4.2.2",
"@smithy/util-hex-encoding": "^4.2.2",
@@ -4386,14 +4547,13 @@
}
},
"node_modules/@smithy/util-waiter": {
- "version": "4.2.13",
- "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.13.tgz",
- "integrity": "sha512-2zdZ9DTHngRtcYxJK1GUDxruNr53kv5W2Lupe0LMU+Imr6ohQg8M2T14MNkj1Y0wS3FFwpgpGQyvuaMF7CiTmQ==",
+ "version": "4.2.15",
+ "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.15.tgz",
+ "integrity": "sha512-oUt9o7n8hBv3BL56sLSneL0XeigZSuem0Hr78JaoK33D9oKieyCvVP8eTSe3j7g2mm/S1DvzxKieG7JEWNJUNg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@smithy/abort-controller": "^4.2.12",
- "@smithy/types": "^4.13.1",
+ "@smithy/types": "^4.14.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -4452,9 +4612,9 @@
}
},
"node_modules/@sveltejs/kit": {
- "version": "2.55.0",
- "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.55.0.tgz",
- "integrity": "sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA==",
+ "version": "2.57.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.57.1.tgz",
+ "integrity": "sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4481,7 +4641,7 @@
"@opentelemetry/api": "^1.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0",
"svelte": "^4.0.0 || ^5.0.0-next.0",
- "typescript": "^5.3.3",
+ "typescript": "^5.3.3 || ^6.0.0",
"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0"
},
"peerDependenciesMeta": {
@@ -4494,42 +4654,34 @@
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
- "version": "6.2.4",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz",
- "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-7.0.0.tgz",
+ "integrity": "sha512-ILXmxC7HAsnkK2eslgPetrqqW1BKSL7LktsFgqzNj83MaivMGZzluWq32m25j2mDOjmSKX7GGWahePhuEs7P/g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0",
"deepmerge": "^4.3.1",
"magic-string": "^0.30.21",
"obug": "^2.1.0",
- "vitefu": "^1.1.1"
+ "vitefu": "^1.1.2"
},
"engines": {
"node": "^20.19 || ^22.12 || >=24"
},
"peerDependencies": {
- "svelte": "^5.0.0",
- "vite": "^6.3.0 || ^7.0.0"
+ "svelte": "^5.46.4",
+ "vite": "^8.0.0-beta.7 || ^8.0.0"
}
},
- "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz",
- "integrity": "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==",
+ "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": {
- "obug": "^2.1.0"
- },
- "engines": {
- "node": "^20.19 || ^22.12 || >=24"
- },
- "peerDependencies": {
- "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0",
- "svelte": "^5.0.0",
- "vite": "^6.3.0 || ^7.0.0"
+ "tslib": "^2.4.0"
}
},
"node_modules/@types/cookie": {
@@ -4589,13 +4741,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "25.5.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz",
- "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
+ "version": "25.6.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
+ "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~7.18.0"
+ "undici-types": "~7.19.0"
}
},
"node_modules/@types/sinon": {
@@ -4627,19 +4779,6 @@
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
"license": "MIT"
},
- "node_modules/@typescript-eslint/types": {
- "version": "8.57.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz",
- "integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==",
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
"node_modules/@ungap/custom-elements": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@ungap/custom-elements/-/custom-elements-1.3.0.tgz",
@@ -4647,14 +4786,14 @@
"license": "ISC"
},
"node_modules/@willfarrell-ds/cli": {
- "version": "0.0.0-alpha.4",
- "resolved": "https://registry.npmjs.org/@willfarrell-ds/cli/-/cli-0.0.0-alpha.4.tgz",
- "integrity": "sha512-HipRSG/nDEu+LsJYpaOcyRebC5HTLXZtagZJZTT6Ex4jhgphANT2EKC46xhQsPWpan5mV0oRYgThRMcV+0gUsw==",
+ "version": "0.0.0-alpha.6",
+ "resolved": "https://registry.npmjs.org/@willfarrell-ds/cli/-/cli-0.0.0-alpha.6.tgz",
+ "integrity": "sha512-CIEnRyopUAil0yPrAYqg8jEnSwc1dzIe5LQbi0/ghuWukSHrwcrWGoqBwTfuBOddg3087kIHj3YXHyJncOG1qw==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "3.1.3",
- "commander": "10.0.1",
+ "commander": "14.0.3",
"mathjs": "15.1.1"
},
"bin": {
@@ -4685,12 +4824,12 @@
}
},
"node_modules/@willfarrell-ds/svelte": {
- "version": "0.0.0-alpha.4",
- "resolved": "https://registry.npmjs.org/@willfarrell-ds/svelte/-/svelte-0.0.0-alpha.4.tgz",
- "integrity": "sha512-qp+xJpEPwa3vXaCYJbtRnfadoeTm0kx2Rm+4ajDM07++e69hMx3qd1/JK8McWgFDoKOK8IhGpNlVjXvl1r0/4g==",
+ "version": "0.0.0-alpha.6",
+ "resolved": "https://registry.npmjs.org/@willfarrell-ds/svelte/-/svelte-0.0.0-alpha.6.tgz",
+ "integrity": "sha512-6xnvXlOWj6h/kWIx6RG0J28XmmwMTIVp6zxqeZlmifymS8l28G8qsg2tCHyaN+09gw7hTvLoQ2P4wCF2FMr9HA==",
"license": "MIT",
"dependencies": {
- "@willfarrell-ds/vanilla": "0.0.0-alpha.4",
+ "@willfarrell-ds/vanilla": "0.0.0-alpha.6",
"pretty": "2.0.0",
"prismjs": "1.30.0",
"tinykeys": "3.0.0"
@@ -4700,12 +4839,12 @@
}
},
"node_modules/@willfarrell-ds/vanilla": {
- "version": "0.0.0-alpha.4",
- "resolved": "https://registry.npmjs.org/@willfarrell-ds/vanilla/-/vanilla-0.0.0-alpha.4.tgz",
- "integrity": "sha512-G2rOFUccvSlBBwhIYXFhMg9i2wLE4ey+om8kgFSkVo+qOm0coVZimtG/ML19EN+mI2xWeU2/wOOawVm+7RyeEw==",
+ "version": "0.0.0-alpha.6",
+ "resolved": "https://registry.npmjs.org/@willfarrell-ds/vanilla/-/vanilla-0.0.0-alpha.6.tgz",
+ "integrity": "sha512-a7fWbPJZkDcMQ/OK1pLMSAk6DIBBVN52VaJrXu/lUur4VUrX3Sa0W3UVPAQgWaJ5gkFYfxBjTw3rVkm2PwWLGQ==",
"license": "MIT",
"dependencies": {
- "@simplewebauthn/browser": "13.2.2",
+ "@simplewebauthn/browser": "13.3.0",
"@ungap/custom-elements": "1.3.0",
"accessible-autocomplete": "3.0.1"
}
@@ -4800,15 +4939,15 @@
}
},
"node_modules/ajv-cmd": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/ajv-cmd/-/ajv-cmd-0.10.0.tgz",
- "integrity": "sha512-PFmUQRk+M2QRhx0pWsounn5Vy+ECDz2GX2cMpHqmWqpRF6TGZNfnVGGqib+J5iX6/M4U0/IEBm8w2zZCuMenJw==",
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/ajv-cmd/-/ajv-cmd-0.11.0.tgz",
+ "integrity": "sha512-aQBWyTwiuQuxAUZcXwfUSkQMS8iZ8sMpK/mVC6NM8O1nlB3zsLWeInGxIkR9tMA2bWcuBbovqN56c+D2gCY7+A==",
"license": "MIT",
"workspaces": [
".github"
],
"dependencies": {
- "@apidevtools/json-schema-ref-parser": "15.3.1",
+ "@apidevtools/json-schema-ref-parser": "15.3.5",
"@silverbucket/ajv-formats-draft2019": "1.6.5",
"ajv": "8.18.0",
"ajv-errors": "3.0.0",
@@ -4817,8 +4956,9 @@
"ajv-i18n": "4.2.0",
"ajv-keywords": "5.1.0",
"commander": "14.0.3",
- "esbuild": "^0.27.0",
- "sast-json-schema": "^0.0.0-alpha.3"
+ "esbuild": "^0.28.0",
+ "redos-detector": "6.1.4",
+ "sast-json-schema": "^0.1.0"
},
"bin": {
"ajv": "cli.js"
@@ -4831,15 +4971,6 @@
"url": "https://github.com/sponsors/willfarrell"
}
},
- "node_modules/ajv-cmd/node_modules/commander": {
- "version": "14.0.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
- "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
- "license": "MIT",
- "engines": {
- "node": ">=20"
- }
- },
"node_modules/ajv-errors": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz",
@@ -4889,15 +5020,6 @@
"url": "https://github.com/sponsors/willfarrell"
}
},
- "node_modules/ajv-ftl-i18n/node_modules/commander": {
- "version": "14.0.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
- "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
- "license": "MIT",
- "engines": {
- "node": ">=20"
- }
- },
"node_modules/ajv-i18n": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/ajv-i18n/-/ajv-i18n-4.2.0.tgz",
@@ -4975,13 +5097,6 @@
"node": ">=8"
}
},
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/aws-sdk-client-mock": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/aws-sdk-client-mock/-/aws-sdk-client-mock-4.1.0.tgz",
@@ -4994,18 +5109,6 @@
"tslib": "^2.1.0"
}
},
- "node_modules/axios": {
- "version": "1.13.6",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
- "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "follow-redirects": "^1.15.11",
- "form-data": "^4.0.5",
- "proxy-from-env": "^1.1.0"
- }
- },
"node_modules/axobject-query": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
@@ -5068,9 +5171,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
- "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5104,20 +5207,6 @@
"ieee754": "^1.1.4"
}
},
- "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",
- "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -5194,6 +5283,16 @@
"url": "https://github.com/sponsors/fb55"
}
},
+ "node_modules/cheerio/node_modules/undici": {
+ "version": "7.25.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz",
+ "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@@ -5236,26 +5335,13 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/commander": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
- "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
+ "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
"license": "MIT",
"engines": {
- "node": ">=14"
+ "node": ">=20"
}
},
"node_modules/compare-func": {
@@ -5314,9 +5400,9 @@
"license": "ISC"
},
"node_modules/conventional-changelog-angular": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.0.tgz",
- "integrity": "sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==",
+ "version": "8.3.1",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.1.tgz",
+ "integrity": "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -5327,9 +5413,9 @@
}
},
"node_modules/conventional-changelog-conventionalcommits": {
- "version": "9.3.0",
- "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.0.tgz",
- "integrity": "sha512-kYFx6gAyjSIMwNtASkI3ZE99U1fuVDJr0yTYgVy+I2QG46zNZfl2her+0+eoviG82c5WQvW1jMt1eOQTeJLodA==",
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.1.tgz",
+ "integrity": "sha512-dTYtpIacRpcZgrvBYvBfArMmK2xvIpv2TaxM0/ZI5CBtNUzvF2x0t15HsbRABWprS6UPmvj+PzHVjSx4qAVKyw==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -5340,9 +5426,9 @@
}
},
"node_modules/conventional-commits-parser": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.3.0.tgz",
- "integrity": "sha512-RfOq/Cqy9xV9bOA8N+ZH6DlrDR+5S3Mi0B5kACEjESpE+AviIpAptx9a9cFpWCCvgRtWT+0BbUw+e1BZfts9jg==",
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz",
+ "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5394,13 +5480,13 @@
}
},
"node_modules/cosmiconfig-typescript-loader": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz",
- "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==",
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz",
+ "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "jiti": "^2.6.1"
+ "jiti": "2.6.1"
},
"engines": {
"node": ">=v18"
@@ -5554,16 +5640,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -5575,9 +5651,9 @@
}
},
"node_modules/devalue": {
- "version": "5.6.4",
- "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz",
- "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.7.1.tgz",
+ "integrity": "sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==",
"license": "MIT"
},
"node_modules/diff": {
@@ -5681,21 +5757,6 @@
"node": ">=8"
}
},
- "node_modules/dunder-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
- "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -5727,14 +5788,23 @@
"license": "MIT"
},
"node_modules/editorconfig/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
+ "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
+ "node_modules/editorconfig/node_modules/commander": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/editorconfig/node_modules/minimatch": {
"version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
@@ -5826,59 +5896,10 @@
"url": "https://github.com/sponsors/antfu"
}
},
- "node_modules/es-define-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-object-atoms": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
- "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-set-tostringtag": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
- "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/esbuild": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
- "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
+ "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
@@ -5888,32 +5909,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.27.4",
- "@esbuild/android-arm": "0.27.4",
- "@esbuild/android-arm64": "0.27.4",
- "@esbuild/android-x64": "0.27.4",
- "@esbuild/darwin-arm64": "0.27.4",
- "@esbuild/darwin-x64": "0.27.4",
- "@esbuild/freebsd-arm64": "0.27.4",
- "@esbuild/freebsd-x64": "0.27.4",
- "@esbuild/linux-arm": "0.27.4",
- "@esbuild/linux-arm64": "0.27.4",
- "@esbuild/linux-ia32": "0.27.4",
- "@esbuild/linux-loong64": "0.27.4",
- "@esbuild/linux-mips64el": "0.27.4",
- "@esbuild/linux-ppc64": "0.27.4",
- "@esbuild/linux-riscv64": "0.27.4",
- "@esbuild/linux-s390x": "0.27.4",
- "@esbuild/linux-x64": "0.27.4",
- "@esbuild/netbsd-arm64": "0.27.4",
- "@esbuild/netbsd-x64": "0.27.4",
- "@esbuild/openbsd-arm64": "0.27.4",
- "@esbuild/openbsd-x64": "0.27.4",
- "@esbuild/openharmony-arm64": "0.27.4",
- "@esbuild/sunos-x64": "0.27.4",
- "@esbuild/win32-arm64": "0.27.4",
- "@esbuild/win32-ia32": "0.27.4",
- "@esbuild/win32-x64": "0.27.4"
+ "@esbuild/aix-ppc64": "0.28.0",
+ "@esbuild/android-arm": "0.28.0",
+ "@esbuild/android-arm64": "0.28.0",
+ "@esbuild/android-x64": "0.28.0",
+ "@esbuild/darwin-arm64": "0.28.0",
+ "@esbuild/darwin-x64": "0.28.0",
+ "@esbuild/freebsd-arm64": "0.28.0",
+ "@esbuild/freebsd-x64": "0.28.0",
+ "@esbuild/linux-arm": "0.28.0",
+ "@esbuild/linux-arm64": "0.28.0",
+ "@esbuild/linux-ia32": "0.28.0",
+ "@esbuild/linux-loong64": "0.28.0",
+ "@esbuild/linux-mips64el": "0.28.0",
+ "@esbuild/linux-ppc64": "0.28.0",
+ "@esbuild/linux-riscv64": "0.28.0",
+ "@esbuild/linux-s390x": "0.28.0",
+ "@esbuild/linux-x64": "0.28.0",
+ "@esbuild/netbsd-arm64": "0.28.0",
+ "@esbuild/netbsd-x64": "0.28.0",
+ "@esbuild/openbsd-arm64": "0.28.0",
+ "@esbuild/openbsd-x64": "0.28.0",
+ "@esbuild/openharmony-arm64": "0.28.0",
+ "@esbuild/sunos-x64": "0.28.0",
+ "@esbuild/win32-arm64": "0.28.0",
+ "@esbuild/win32-ia32": "0.28.0",
+ "@esbuild/win32-x64": "0.28.0"
}
},
"node_modules/escalade": {
@@ -5954,13 +5975,20 @@
}
},
"node_modules/esrap": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz",
- "integrity": "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==",
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.5.tgz",
+ "integrity": "sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig==",
"license": "MIT",
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.4.15",
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ },
+ "peerDependencies": {
"@typescript-eslint/types": "^8.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@typescript-eslint/types": {
+ "optional": true
+ }
}
},
"node_modules/events": {
@@ -6064,9 +6092,9 @@
}
},
"node_modules/fast-xml-parser": {
- "version": "5.5.6",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.6.tgz",
- "integrity": "sha512-3+fdZyBRVg29n4rXP0joHthhcHdPUHaIC16cuyyd1iLsuaO6Vea36MPrxgAzbZna8lhvZeRL8Bc9GP56/J9xEw==",
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.6.0.tgz",
+ "integrity": "sha512-5G+uaEBbOm9M4dgMOV3K/rBzfUNGqGqoUTaYJM3hBwM8t71w07gxLQZoTsjkY8FtfjabqgQHEkeIySBDYeBmJw==",
"dev": true,
"funding": [
{
@@ -6076,9 +6104,10 @@
],
"license": "MIT",
"dependencies": {
+ "@nodable/entities": "^1.1.0",
"fast-xml-builder": "^1.1.4",
- "path-expression-matcher": "^1.1.3",
- "strnum": "^2.1.2"
+ "path-expression-matcher": "^1.5.0",
+ "strnum": "^2.2.3"
},
"bin": {
"fxparser": "src/cli/cli.js"
@@ -6144,36 +6173,6 @@
"url": "https://github.com/sponsors/willfarrell"
}
},
- "node_modules/fluent-transpiler/node_modules/commander": {
- "version": "14.0.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
- "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
- "license": "MIT",
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/follow-redirects": {
- "version": "1.15.11",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
- "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
@@ -6190,23 +6189,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/form-data": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
- "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "es-set-tostringtag": "^2.1.0",
- "hasown": "^2.0.2",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/fraction.js": {
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
@@ -6258,16 +6240,6 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -6278,45 +6250,6 @@
"node": "6.* || 8.* || >= 10.*"
}
},
- "node_modules/get-intrinsic": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
- "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "function-bind": "^1.1.2",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
- "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/git-raw-commits": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-5.0.1.tgz",
@@ -6415,19 +6348,6 @@
"node": ">=8"
}
},
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -6445,54 +6365,12 @@
"node": ">=8"
}
},
- "node_modules/has-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-symbols": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/hash-wasm": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz",
"integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==",
"license": "MIT"
},
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/hast-util-to-string": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz",
@@ -6846,9 +6724,9 @@
"license": "MIT"
},
"node_modules/js-beautify/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
+ "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -6918,6 +6796,18 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -7081,59 +6971,332 @@
"ansi-regex": "^4.1.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=6"
+ }
+ },
+ "node_modules/license-check-and-add/node_modules/wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/license-check-and-add/node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/license-check-and-add/node_modules/yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ }
+ },
+ "node_modules/license-check-and-add/node_modules/yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/license-check-and-add/node_modules/wrap-ansi": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
- "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^3.2.0",
- "string-width": "^3.0.0",
- "strip-ansi": "^5.0.0"
- },
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=6"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/license-check-and-add/node_modules/y18n": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
- "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "license": "ISC"
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
},
- "node_modules/license-check-and-add/node_modules/yargs": {
- "version": "13.3.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
- "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "license": "MIT",
- "dependencies": {
- "cliui": "^5.0.0",
- "find-up": "^3.0.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^3.0.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^13.1.2"
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/license-check-and-add/node_modules/yargs-parser": {
- "version": "13.1.2",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
- "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "license": "ISC",
- "dependencies": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
"node_modules/lines-and-columns": {
@@ -7255,20 +7418,10 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
- "node_modules/math-intrinsics": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
- "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/mathjs": {
- "version": "15.1.1",
- "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.1.1.tgz",
- "integrity": "sha512-rM668DTtpSzMVoh/cKAllyQVEbBApM5g//IMGD8vD7YlrIz9ITRr3SrdhjaDxcBNTdyETWwPebj2unZyHD7ZdA==",
+ "version": "15.2.0",
+ "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.2.0.tgz",
+ "integrity": "sha512-UAQzSVob9rNLdGpqcFMYmSu9dkuLYy7Lr2hBEQS5SHQdknA9VppJz3cy2KkpMzTODunad6V6cNv+5kOLsePLow==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -7371,40 +7524,17 @@
"node": ">=8.6"
}
},
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/miniflare": {
- "version": "4.20260317.0",
- "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260317.0.tgz",
- "integrity": "sha512-xuwk5Kjv+shi5iUBAdCrRl9IaWSGnTU8WuTQzsUS2GlSDIMCJuu8DiF/d9ExjMXYiQG5ml+k9SVKnMj8cRkq0w==",
+ "version": "4.20260415.0",
+ "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260415.0.tgz",
+ "integrity": "sha512-JoExRWN4YBI2luA5BoSMFEgi8rQWXUGzo3mtE+58VXCLV3jj/Xnk5Yeqs/IXWz8Es5GJIaq6BtsixDvAxXSIng==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "0.8.1",
"sharp": "^0.34.5",
- "undici": "7.24.4",
- "workerd": "1.20260317.1",
+ "undici": "7.24.8",
+ "workerd": "1.20260415.1",
"ws": "8.18.0",
"youch": "4.1.0-beta.10"
},
@@ -7415,14 +7545,24 @@
"node": ">=18.0.0"
}
},
+ "node_modules/miniflare/node_modules/undici": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz",
+ "integrity": "sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
"node_modules/minimatch": {
- "version": "10.2.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
- "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
- "brace-expansion": "^5.0.2"
+ "brace-expansion": "^5.0.5"
},
"engines": {
"node": "18 || 20 || >=22"
@@ -7531,9 +7671,9 @@
"license": "MIT"
},
"node_modules/nise": {
- "version": "6.1.4",
- "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.4.tgz",
- "integrity": "sha512-vSA4IpRHRWZkmotu61SvF45Jirq4CTLT3KKOWJPsPMtxtOBOlxcAlXfv/OrWxkzAJiCBrvdfWvGQjHT7r7+Qqg==",
+ "version": "6.1.5",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.5.tgz",
+ "integrity": "sha512-SnRDPDBjxZZoU2n0+gzzLtSvo1OZo7j6jnbXsoh3AFxEGhaFU7ZF0TmefuKERq79wxR2U+MPn7ArW+Tl+clC3A==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -7544,9 +7684,9 @@
}
},
"node_modules/nise/node_modules/@sinonjs/fake-timers": {
- "version": "15.1.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz",
- "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==",
+ "version": "15.3.2",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.2.tgz",
+ "integrity": "sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -7781,9 +7921,9 @@
}
},
"node_modules/path-expression-matcher": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.1.3.tgz",
- "integrity": "sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz",
+ "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==",
"dev": true,
"funding": [
{
@@ -7832,9 +7972,9 @@
}
},
"node_modules/path-to-regexp": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
- "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
+ "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
"dev": true,
"license": "MIT",
"funding": {
@@ -7867,9 +8007,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -7880,9 +8020,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.8",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
- "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
+ "version": "8.5.10",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
+ "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
"dev": true,
"funding": [
{
@@ -7944,17 +8084,10 @@
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
"license": "ISC"
},
- "node_modules/proxy-from-env": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/pure-rand": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.2.0.tgz",
- "integrity": "sha512-KHnUjm68KSO/hqpWlVwagMDPrIjnDNY9r0DbKN79xEa5RU2MLUe0lICBGpWDF8cwmhUiN8r9A8DLGPVcFB62/A==",
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz",
+ "integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==",
"dev": true,
"funding": [
{
@@ -8023,6 +8156,21 @@
"node": ">= 6"
}
},
+ "node_modules/redos-detector": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/redos-detector/-/redos-detector-6.1.4.tgz",
+ "integrity": "sha512-lPlka1rEH6kK42gtgokvvxMmpAvyc28DcRjQbGxeP5RJsJWgAduBOdGedVCDPdSyCr4ay/JDxq3nGYsJZyt8tA==",
+ "license": "MIT",
+ "dependencies": {
+ "regjsparser": "0.13.0"
+ },
+ "bin": {
+ "redos-detector": "bin.js"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"node_modules/regexparam": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz",
@@ -8033,6 +8181,18 @@
"node": ">=8"
}
},
+ "node_modules/regjsparser": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz",
+ "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "jsesc": "~3.1.0"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -8089,49 +8249,38 @@
"node": ">=0.10.0"
}
},
- "node_modules/rollup": {
- "version": "4.59.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
- "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
+ "node_modules/rolldown": {
+ "version": "1.0.0-rc.15",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz",
+ "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/estree": "1.0.8"
+ "@oxc-project/types": "=0.124.0",
+ "@rolldown/pluginutils": "1.0.0-rc.15"
},
"bin": {
- "rollup": "dist/bin/rollup"
+ "rolldown": "bin/cli.mjs"
},
"engines": {
- "node": ">=18.0.0",
- "npm": ">=8.0.0"
+ "node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.59.0",
- "@rollup/rollup-android-arm64": "4.59.0",
- "@rollup/rollup-darwin-arm64": "4.59.0",
- "@rollup/rollup-darwin-x64": "4.59.0",
- "@rollup/rollup-freebsd-arm64": "4.59.0",
- "@rollup/rollup-freebsd-x64": "4.59.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.59.0",
- "@rollup/rollup-linux-arm64-gnu": "4.59.0",
- "@rollup/rollup-linux-arm64-musl": "4.59.0",
- "@rollup/rollup-linux-loong64-gnu": "4.59.0",
- "@rollup/rollup-linux-loong64-musl": "4.59.0",
- "@rollup/rollup-linux-ppc64-gnu": "4.59.0",
- "@rollup/rollup-linux-ppc64-musl": "4.59.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.59.0",
- "@rollup/rollup-linux-riscv64-musl": "4.59.0",
- "@rollup/rollup-linux-s390x-gnu": "4.59.0",
- "@rollup/rollup-linux-x64-gnu": "4.59.0",
- "@rollup/rollup-linux-x64-musl": "4.59.0",
- "@rollup/rollup-openbsd-x64": "4.59.0",
- "@rollup/rollup-openharmony-arm64": "4.59.0",
- "@rollup/rollup-win32-arm64-msvc": "4.59.0",
- "@rollup/rollup-win32-ia32-msvc": "4.59.0",
- "@rollup/rollup-win32-x64-gnu": "4.59.0",
- "@rollup/rollup-win32-x64-msvc": "4.59.0",
- "fsevents": "~2.3.2"
+ "@rolldown/binding-android-arm64": "1.0.0-rc.15",
+ "@rolldown/binding-darwin-arm64": "1.0.0-rc.15",
+ "@rolldown/binding-darwin-x64": "1.0.0-rc.15",
+ "@rolldown/binding-freebsd-x64": "1.0.0-rc.15",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15",
+ "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15",
+ "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15",
+ "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15",
+ "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15",
+ "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15",
+ "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15",
+ "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15",
+ "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15",
+ "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15",
+ "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15"
}
},
"node_modules/run-parallel": {
@@ -8186,10 +8335,16 @@
"license": "MIT"
},
"node_modules/sast-json-schema": {
- "version": "0.0.0-alpha.4",
- "resolved": "https://registry.npmjs.org/sast-json-schema/-/sast-json-schema-0.0.0-alpha.4.tgz",
- "integrity": "sha512-t+heIMb51EpOmTpnRfakPNF1SIJdRunU2NPWJeozSOltpL/D+hznoaQYlZW/lVfNf9kmB1GZsZz1frpePJGskA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/sast-json-schema/-/sast-json-schema-0.1.0.tgz",
+ "integrity": "sha512-aVtzdQ3jYop1if6YcSeVzCC8VD+iXqg00IUBuXEGWelSVKmcc4iJMN/CfKlakzXzeNmXfX1dwXpNigGDvaufpg==",
"license": "MIT",
+ "workspaces": [
+ ".github"
+ ],
+ "engines": {
+ "node": ">=24"
+ },
"funding": {
"type": "github",
"url": "https://github.com/sponsors/willfarrell"
@@ -8232,9 +8387,9 @@
"license": "ISC"
},
"node_modules/set-cookie-parser": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz",
- "integrity": "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz",
+ "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==",
"dev": true,
"license": "MIT"
},
@@ -8465,9 +8620,9 @@
}
},
"node_modules/strnum": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz",
- "integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz",
+ "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==",
"dev": true,
"funding": [
{
@@ -8491,9 +8646,9 @@
}
},
"node_modules/svelte": {
- "version": "5.54.0",
- "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.54.0.tgz",
- "integrity": "sha512-TTDxwYnHkova6Wsyj1PGt9TByuWqvMoeY1bQiuAf2DM/JeDSMw7FjRKzk8K/5mJ99vGOKhbCqTDpyAKwjp4igg==",
+ "version": "5.55.4",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.55.4.tgz",
+ "integrity": "sha512-q8DFohk6vUswSng95IZb9nzWJnbINZsK7OiM1snAa3qCjJBL0ZQpvMyAaVXjUukdM75J/m8UE8xwqat8Ors/zQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.4",
@@ -8507,7 +8662,7 @@
"clsx": "^2.1.1",
"devalue": "^5.6.4",
"esm-env": "^1.2.1",
- "esrap": "^2.2.2",
+ "esrap": "^2.2.4",
"is-reference": "^3.0.3",
"locate-character": "^3.0.0",
"magic-string": "^0.30.11",
@@ -8571,9 +8726,9 @@
}
},
"node_modules/tinyexec": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz",
- "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz",
+ "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -8581,14 +8736,14 @@
}
},
"node_modules/tinyglobby": {
- "version": "0.2.15",
- "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
- "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
- "picomatch": "^4.0.3"
+ "picomatch": "^4.0.4"
},
"engines": {
"node": ">=12.0.0"
@@ -8616,9 +8771,9 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -8672,9 +8827,9 @@
"license": "0BSD"
},
"node_modules/tstyche": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/tstyche/-/tstyche-6.2.0.tgz",
- "integrity": "sha512-WBiB6fGGsmQCFFRGwYaKq528pCLJ0CUUdrIdUm2rnVJ1Ineskbrv9uQADWsD3uHndEV/Hesdx1Gj8PdkBahxlQ==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/tstyche/-/tstyche-7.0.0.tgz",
+ "integrity": "sha512-dWuDvU8b0mfgMMZfYz8qPo3My/UVgcG05Q8PBr3NbCWv+lHD7RqrOn9EBIZM59MmubP1/txVard0D/7ScFXddg==",
"dev": true,
"license": "MIT",
"bin": {
@@ -8716,9 +8871,9 @@
}
},
"node_modules/typescript": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz",
+ "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
@@ -8731,19 +8886,19 @@
}
},
"node_modules/undici": {
- "version": "7.24.4",
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz",
- "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-8.1.0.tgz",
+ "integrity": "sha512-E9MkTS4xXLnRPYqxH2e6Hr2/49e7WFDKczKcCaFH4VaZs2iNvHMqeIkyUAD9vM8kujy9TjVrRlQ5KkdEJxB2pw==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=20.18.1"
+ "node": ">=22.19.0"
}
},
"node_modules/undici-types": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
- "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
+ "version": "7.19.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
+ "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
"dev": true,
"license": "MIT"
},
@@ -8893,17 +9048,16 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz",
- "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
+ "version": "8.0.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz",
+ "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "esbuild": "^0.27.0",
- "fdir": "^6.5.0",
- "picomatch": "^4.0.3",
- "postcss": "^8.5.6",
- "rollup": "^4.43.0",
+ "lightningcss": "^1.32.0",
+ "picomatch": "^4.0.4",
+ "postcss": "^8.5.8",
+ "rolldown": "1.0.0-rc.15",
"tinyglobby": "^0.2.15"
},
"bin": {
@@ -8920,9 +9074,10 @@
},
"peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0",
+ "@vitejs/devtools": "^0.1.0",
+ "esbuild": "^0.27.0 || ^0.28.0",
"jiti": ">=1.21.0",
"less": "^4.0.0",
- "lightningcss": "^1.21.0",
"sass": "^1.70.0",
"sass-embedded": "^1.70.0",
"stylus": ">=0.54.8",
@@ -8935,13 +9090,16 @@
"@types/node": {
"optional": true
},
- "jiti": {
+ "@vitejs/devtools": {
"optional": true
},
- "less": {
+ "esbuild": {
+ "optional": true
+ },
+ "jiti": {
"optional": true
},
- "lightningcss": {
+ "less": {
"optional": true
},
"sass": {
@@ -8978,23 +9136,36 @@
}
},
"node_modules/vite-plugin-mkcert": {
- "version": "1.17.10",
- "resolved": "https://registry.npmjs.org/vite-plugin-mkcert/-/vite-plugin-mkcert-1.17.10.tgz",
- "integrity": "sha512-703hecAoGZYgNrkY76OIbo0M9j0tfGIIM6n7c0sYvhaczQMPwD0nFi+bS44d8kwdbCtV7885FYBWnTzhsaC7QQ==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-mkcert/-/vite-plugin-mkcert-2.0.0.tgz",
+ "integrity": "sha512-+5roXeOT91WRO3NKFRcDZKEHhze/1uahSSKOIq3vz2w19mJojBcyOo0JyLRHbME31Ym5qPRNJ8CwKO0mu4RJ2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "axios": "^1.13.5",
"debug": "^4.4.3",
- "picocolors": "^1.1.1"
+ "supports-color": "^10.2.2",
+ "undici": "^8.0.2"
},
"engines": {
- "node": ">=v16.7.0"
+ "node": ">=22.19.0"
},
"peerDependencies": {
"vite": ">=3"
}
},
+ "node_modules/vite-plugin-mkcert/node_modules/supports-color": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
+ "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
"node_modules/vite-plugin-sitemap": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/vite-plugin-sitemap/-/vite-plugin-sitemap-0.8.2.tgz",
@@ -9012,28 +9183,10 @@
"node-fetch": "^2.6.1"
}
},
- "node_modules/vite/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
"node_modules/vite/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9044,9 +9197,9 @@
}
},
"node_modules/vitefu": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz",
- "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz",
+ "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==",
"dev": true,
"license": "MIT",
"workspaces": [
@@ -9055,7 +9208,7 @@
"tests/projects/workspace/packages/*"
],
"peerDependencies": {
- "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0"
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"vite": {
@@ -9141,9 +9294,9 @@
"license": "ISC"
},
"node_modules/workerd": {
- "version": "1.20260317.1",
- "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260317.1.tgz",
- "integrity": "sha512-ZuEq1OdrJBS+NV+L5HMYPCzVn49a2O60slQiiLpG44jqtlOo+S167fWC76kEXteXLLLydeuRrluRel7WdOUa4g==",
+ "version": "1.20260415.1",
+ "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260415.1.tgz",
+ "integrity": "sha512-phyPjRnx+mQDfkhN9ENPioL1L0SdhYs4S0YmJK/xF9Oga+ykNfdSy1MHnsOj8yqnOV96zcVQMx32dJ0r3pq0jQ==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
@@ -9154,11 +9307,11 @@
"node": ">=16"
},
"optionalDependencies": {
- "@cloudflare/workerd-darwin-64": "1.20260317.1",
- "@cloudflare/workerd-darwin-arm64": "1.20260317.1",
- "@cloudflare/workerd-linux-64": "1.20260317.1",
- "@cloudflare/workerd-linux-arm64": "1.20260317.1",
- "@cloudflare/workerd-windows-64": "1.20260317.1"
+ "@cloudflare/workerd-darwin-64": "1.20260415.1",
+ "@cloudflare/workerd-darwin-arm64": "1.20260415.1",
+ "@cloudflare/workerd-linux-64": "1.20260415.1",
+ "@cloudflare/workerd-linux-arm64": "1.20260415.1",
+ "@cloudflare/workerd-windows-64": "1.20260415.1"
}
},
"node_modules/worktop": {
@@ -9176,33 +9329,33 @@
}
},
"node_modules/wrangler": {
- "version": "4.75.0",
- "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.75.0.tgz",
- "integrity": "sha512-Efk1tcnm4eduBYpH1sSjMYydXMnIFPns/qABI3+fsbDrUk5GksNYX8nYGVP4sFygvGPO7kJc36YJKB5ooA7JAg==",
+ "version": "4.83.0",
+ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.83.0.tgz",
+ "integrity": "sha512-gw5g3LCiuAqVWxaoKY6+quE0HzAUEFb/FV3oAlNkE1ttd4XP3FiV91XDkkzUCcdqxS4WjhQvPhIDBNdhEi8P0A==",
"dev": true,
"license": "MIT OR Apache-2.0",
"dependencies": {
"@cloudflare/kv-asset-handler": "0.4.2",
- "@cloudflare/unenv-preset": "2.15.0",
+ "@cloudflare/unenv-preset": "2.16.0",
"blake3-wasm": "2.1.5",
"esbuild": "0.27.3",
- "miniflare": "4.20260317.0",
+ "miniflare": "4.20260415.0",
"path-to-regexp": "6.3.0",
"unenv": "2.0.0-rc.24",
- "workerd": "1.20260317.1"
+ "workerd": "1.20260415.1"
},
"bin": {
"wrangler": "bin/wrangler.js",
"wrangler2": "bin/wrangler.js"
},
"engines": {
- "node": ">=20.0.0"
+ "node": ">=20.3.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
- "@cloudflare/workers-types": "^4.20260317.1"
+ "@cloudflare/workers-types": "^4.20260415.1"
},
"peerDependenciesMeta": {
"@cloudflare/workers-types": {
@@ -9852,13 +10005,15 @@
},
"packages/aws": {
"name": "@datastream/aws",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"devDependencies": {
+ "@aws-sdk/client-cloudwatch-logs": "^3.0.0",
"@aws-sdk/client-dynamodb": "^3.0.0",
+ "@aws-sdk/client-kinesis": "^3.0.0",
"@aws-sdk/client-lambda": "^3.0.0",
"@aws-sdk/client-s3": "^3.0.0",
"@aws-sdk/client-sns": "^3.0.0",
@@ -9871,7 +10026,9 @@
"node": ">=24"
},
"peerDependencies": {
+ "@aws-sdk/client-cloudwatch-logs": "^3.0.0",
"@aws-sdk/client-dynamodb": "^3.0.0",
+ "@aws-sdk/client-kinesis": "^3.0.0",
"@aws-sdk/client-lambda": "^3.0.0",
"@aws-sdk/client-s3": "^3.0.0",
"@aws-sdk/client-sns": "^3.0.0",
@@ -9880,9 +10037,15 @@
"@aws-sdk/lib-storage": "^3.0.0"
},
"peerDependenciesMeta": {
+ "@aws-sdk/client-cloudwatch-logs": {
+ "optional": true
+ },
"@aws-sdk/client-dynamodb": {
"optional": true
},
+ "@aws-sdk/client-kinesis": {
+ "optional": true
+ },
"@aws-sdk/client-lambda": {
"optional": true
},
@@ -9905,10 +10068,10 @@
},
"packages/base64": {
"name": "@datastream/base64",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -9916,10 +10079,10 @@
},
"packages/charset": {
"name": "@datastream/charset",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6",
+ "@datastream/core": "0.2.0",
"charset-detector": "0.0.2",
"iconv-lite": "0.7.2"
},
@@ -9929,18 +10092,18 @@
},
"packages/compress": {
"name": "@datastream/compress",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"engines": {
"node": ">=24"
},
"peerDependencies": {
- "brotli-wasm": "3.0.1",
- "protobufjs": "8.0.0",
- "zstd-codec": "0.1.5"
+ "brotli-wasm": "^3.0.0",
+ "protobufjs": "^8.0.0",
+ "zstd-codec": "^0.1.0"
},
"peerDependenciesMeta": {
"brotli-wasm": {
@@ -9956,10 +10119,10 @@
},
"packages/core": {
"name": "@datastream/core",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"devDependencies": {
- "@datastream/object": "0.1.6"
+ "@datastream/object": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -9967,11 +10130,11 @@
},
"packages/csv": {
"name": "@datastream/csv",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6",
- "@datastream/object": "0.1.6"
+ "@datastream/core": "0.2.0",
+ "@datastream/object": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -9979,22 +10142,41 @@
},
"packages/digest": {
"name": "@datastream/digest",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6",
+ "@datastream/core": "0.2.0",
"hash-wasm": "4.12.0"
},
"engines": {
"node": ">=24"
}
},
+ "packages/encrypt": {
+ "name": "@datastream/encrypt",
+ "version": "0.2.0",
+ "license": "MIT",
+ "dependencies": {
+ "@datastream/core": "0.2.0"
+ },
+ "engines": {
+ "node": ">=24"
+ },
+ "peerDependencies": {
+ "libsodium-wrappers": ">=0.7.0"
+ },
+ "peerDependenciesMeta": {
+ "libsodium-wrappers": {
+ "optional": true
+ }
+ }
+ },
"packages/fetch": {
"name": "@datastream/fetch",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -10002,10 +10184,10 @@
},
"packages/file": {
"name": "@datastream/file",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -10013,10 +10195,10 @@
},
"packages/indexeddb": {
"name": "@datastream/indexeddb",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6",
+ "@datastream/core": "0.2.0",
"idb": "8.0.3"
},
"engines": {
@@ -10025,10 +10207,21 @@
},
"packages/ipfs": {
"name": "@datastream/ipfs",
+ "version": "0.2.0",
+ "license": "MIT",
+ "dependencies": {
+ "@datastream/core": "0.2.0"
+ },
+ "engines": {
+ "node": ">=24"
+ }
+ },
+ "packages/json": {
+ "name": "@datastream/json",
"version": "0.1.6",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -10036,10 +10229,10 @@
},
"packages/object": {
"name": "@datastream/object",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -10047,10 +10240,10 @@
},
"packages/string": {
"name": "@datastream/string",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"engines": {
"node": ">=24"
@@ -10058,22 +10251,22 @@
},
"packages/validate": {
"name": "@datastream/validate",
- "version": "0.1.6",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
- "@datastream/core": "0.1.6",
- "ajv-cmd": "0.10.0"
+ "@datastream/core": "0.2.0",
+ "ajv-cmd": "0.11.0"
},
"engines": {
"node": ">=24"
}
},
"websites/datastream.js.org": {
- "version": "0.1.6",
+ "version": "0.2.0",
"dependencies": {
"@plausible-analytics/tracker": "0.4.4",
- "@willfarrell-ds/svelte": "0.0.0-alpha.4",
- "@willfarrell-ds/vanilla": "0.0.0-alpha.4",
+ "@willfarrell-ds/svelte": "0.0.0-alpha.6",
+ "@willfarrell-ds/vanilla": "0.0.0-alpha.6",
"hast-util-to-string": "3.0.1",
"mdast-util-to-string": "4.0.0",
"uuid": "13.0.0"
@@ -10081,15 +10274,15 @@
"devDependencies": {
"@sveltejs/adapter-cloudflare": "^7.0.0",
"@sveltejs/kit": "^2.0.0",
- "@sveltejs/vite-plugin-svelte": "^6.0.0",
- "@willfarrell-ds/cli": "0.0.0-alpha.4",
- "esbuild": "^0.27.0",
+ "@sveltejs/vite-plugin-svelte": "^7.0.0",
+ "@willfarrell-ds/cli": "0.0.0-alpha.6",
+ "esbuild": "^0.28.0",
"mdsvex": "^0.12.0",
"svelte": "^5.0.0",
"svgo": "^4.0.0",
- "vite": "^7.3.2",
+ "vite": "^8.0.0",
"vite-plugin-llms": "^1.0.0",
- "vite-plugin-mkcert": "^1.0.0",
+ "vite-plugin-mkcert": "^2.0.0",
"vite-plugin-sitemap": "^0.8.0",
"vite-plugin-sri": "^0.0.2",
"wrangler": "^4.0.0"
diff --git a/package.json b/package.json
index f5da322..3f49425 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/monorepo",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "Streams made easy.",
"private": true,
"type": "module",
@@ -72,20 +72,23 @@
"@biomejs/biome": "^2.0.0",
"@commitlint/cli": "^20.0.0",
"@commitlint/config-conventional": "^20.0.0",
- "@types/node": "25.5.0",
- "esbuild": "^0.27.0",
+ "@types/node": "25.6.0",
+ "esbuild": "^0.28.0",
"fast-check": "^4.0.0",
"husky": "^9.0.0",
"tinybench": "^6.0.0",
- "tstyche": "^6.0.0"
+ "tstyche": "^7.0.0"
},
"overrides": {
"@sveltejs/kit": {
"cookie": "^0.7.2"
},
- "fast-xml-parser": ">=5.5.6",
+ "@willfarrell-ds/cli": {
+ "mathjs": ">=15.2.0"
+ },
+ "fast-xml-parser": ">=5.5.12",
"license-check-and-add": {
- "minimatch": "^10.2.4"
+ "minimatch": "^10.2.5"
}
},
"workspaces": [
diff --git a/packages/aws/README.md b/packages/aws/README.md
index 91e79d4..ff53c99 100644
--- a/packages/aws/README.md
+++ b/packages/aws/README.md
@@ -1,7 +1,7 @@
<datastream> `aws`

-
AWS service streams for S3, SQS, SNS, Lambda, and DynamoDB.
+
AWS service streams for CloudWatch Logs, DynamoDB, Kinesis, Lambda, S3, SNS, and SQS.
diff --git a/packages/aws/cloudwatch-logs.d.ts b/packages/aws/cloudwatch-logs.d.ts
new file mode 100644
index 0000000..3933bd6
--- /dev/null
+++ b/packages/aws/cloudwatch-logs.d.ts
@@ -0,0 +1,36 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import type { StreamOptions } from "@datastream/core";
+
+export function awsCloudWatchLogsSetClient(cwlClient: unknown): void;
+
+export function awsCloudWatchLogsGetLogEventsStream(
+ options: {
+ client?: unknown;
+ logGroupName?: string;
+ logGroupIdentifier?: string;
+ logStreamName?: string;
+ startTime?: number;
+ endTime?: number;
+ startFromHead?: boolean;
+ pollingActive?: boolean;
+ pollingDelay?: number;
+ [key: string]: unknown;
+ },
+ streamOptions?: StreamOptions,
+): Promise;
+
+export function awsCloudWatchLogsFilterLogEventsStream(
+ options: {
+ client?: unknown;
+ logGroupName?: string;
+ logGroupIdentifier?: string;
+ filterPattern?: string;
+ startTime?: number;
+ endTime?: number;
+ logStreamNames?: string[];
+ logStreamNamePrefix?: string;
+ [key: string]: unknown;
+ },
+ streamOptions?: StreamOptions,
+): Promise;
diff --git a/packages/aws/cloudwatch-logs.js b/packages/aws/cloudwatch-logs.js
new file mode 100644
index 0000000..9f3a803
--- /dev/null
+++ b/packages/aws/cloudwatch-logs.js
@@ -0,0 +1,72 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import {
+ CloudWatchLogsClient,
+ FilterLogEventsCommand,
+ GetLogEventsCommand,
+} from "@aws-sdk/client-cloudwatch-logs";
+import { awsClientDefaults } from "./client.js";
+
+let client = new CloudWatchLogsClient(awsClientDefaults);
+export const awsCloudWatchLogsSetClient = (cwlClient) => {
+ client = cwlClient;
+};
+
+export const awsCloudWatchLogsGetLogEventsStream = async (
+ options,
+ _streamOptions = {},
+) => {
+ const { pollingActive, pollingDelay = 1000, ...cwlOptions } = options;
+ cwlOptions.startFromHead ??= true;
+ async function* command(options) {
+ let previousToken;
+ let expectMore = true;
+ while (expectMore) {
+ const response = await client.send(new GetLogEventsCommand(options));
+ const events = response.events ?? [];
+ for (const item of events) {
+ yield item;
+ }
+ const tokenUnchanged =
+ response.nextForwardToken === previousToken ||
+ response.nextForwardToken === options.nextToken;
+ previousToken = response.nextForwardToken;
+ options.nextToken = response.nextForwardToken;
+
+ if (tokenUnchanged) {
+ if (pollingActive) {
+ if (pollingDelay > 0) {
+ await new Promise((resolve) => setTimeout(resolve, pollingDelay));
+ }
+ } else {
+ expectMore = false;
+ }
+ }
+ }
+ }
+ return command(cwlOptions);
+};
+
+export const awsCloudWatchLogsFilterLogEventsStream = async (
+ options,
+ _streamOptions = {},
+) => {
+ async function* command(options) {
+ let expectMore = true;
+ while (expectMore) {
+ const response = await client.send(new FilterLogEventsCommand(options));
+ for (const item of response.events ?? []) {
+ yield item;
+ }
+ options.nextToken = response.nextToken;
+ expectMore = !!response.nextToken;
+ }
+ }
+ return command(options);
+};
+
+export default {
+ setClient: awsCloudWatchLogsSetClient,
+ getLogEventsStream: awsCloudWatchLogsGetLogEventsStream,
+ filterLogEventsStream: awsCloudWatchLogsFilterLogEventsStream,
+};
diff --git a/packages/aws/cloudwatch-logs.test.js b/packages/aws/cloudwatch-logs.test.js
new file mode 100644
index 0000000..92208fe
--- /dev/null
+++ b/packages/aws/cloudwatch-logs.test.js
@@ -0,0 +1,203 @@
+import { deepStrictEqual } from "node:assert";
+import test from "node:test";
+import {
+ CloudWatchLogsClient,
+ FilterLogEventsCommand,
+ GetLogEventsCommand,
+} from "@aws-sdk/client-cloudwatch-logs";
+import {
+ awsCloudWatchLogsFilterLogEventsStream,
+ awsCloudWatchLogsGetLogEventsStream,
+ awsCloudWatchLogsSetClient,
+} from "@datastream/aws/cloudwatch-logs";
+
+import { streamToArray } from "@datastream/core";
+import { mockClient } from "aws-sdk-client-mock";
+
+let variant = "unknown";
+for (const execArgv of process.execArgv) {
+ const flag = "--conditions=";
+ if (execArgv.includes(flag)) {
+ variant = execArgv.replace(flag, "");
+ }
+}
+
+// --- GetLogEventsStream ---
+
+test(`${variant}: awsCloudWatchLogsGetLogEventsStream should get events`, async (_t) => {
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client
+ .on(GetLogEventsCommand)
+ .resolvesOnce({
+ events: [{ message: "log1" }],
+ nextForwardToken: "token2",
+ })
+ .resolvesOnce({
+ events: [],
+ nextForwardToken: "token2",
+ });
+
+ const options = { logGroupName: "/test/group", logStreamName: "stream1" };
+ const stream = await awsCloudWatchLogsGetLogEventsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ message: "log1" }]);
+});
+
+test(`${variant}: awsCloudWatchLogsGetLogEventsStream should handle empty events (undefined)`, async (_t) => {
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client.on(GetLogEventsCommand).resolves({
+ nextForwardToken: "token1",
+ });
+
+ const options = { logGroupName: "/test/group", logStreamName: "stream1" };
+ const stream = await awsCloudWatchLogsGetLogEventsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, []);
+});
+
+test(`${variant}: awsCloudWatchLogsGetLogEventsStream should stop when nextForwardToken repeats`, async (_t) => {
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client
+ .on(GetLogEventsCommand)
+ .resolvesOnce({
+ events: [{ message: "log1" }],
+ nextForwardToken: "token2",
+ })
+ .resolvesOnce({
+ events: [{ message: "log2" }],
+ nextForwardToken: "token3",
+ })
+ .resolvesOnce({
+ events: [],
+ nextForwardToken: "token3",
+ });
+
+ const options = { logGroupName: "/test/group", logStreamName: "stream1" };
+ const stream = await awsCloudWatchLogsGetLogEventsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ message: "log1" }, { message: "log2" }]);
+});
+
+test(`${variant}: awsCloudWatchLogsGetLogEventsStream should keep polling with pollingActive option`, async (_t) => {
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client
+ .on(GetLogEventsCommand)
+ .resolvesOnce({ events: [{ message: "log1" }], nextForwardToken: "token2" })
+ .resolvesOnce({ events: [], nextForwardToken: "token2" })
+ .resolvesOnce({ events: [{ message: "log2" }], nextForwardToken: "token3" })
+ .resolves({ events: [], nextForwardToken: "token3" });
+
+ const options = {
+ logGroupName: "/test/group",
+ logStreamName: "stream1",
+ pollingActive: true,
+ pollingDelay: 0,
+ };
+ const stream = await awsCloudWatchLogsGetLogEventsStream(options);
+
+ const output = [];
+ for await (const item of stream) {
+ output.push(item);
+ if (output.length >= 2) break;
+ }
+
+ deepStrictEqual(output, [{ message: "log1" }, { message: "log2" }]);
+});
+
+test(`${variant}: awsCloudWatchLogsGetLogEventsStream should delay polling when pollingActive and no events`, async (t) => {
+ t.mock.timers.enable({ apis: ["setTimeout"] });
+
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client
+ .on(GetLogEventsCommand)
+ .resolvesOnce({ events: [], nextForwardToken: "token1" })
+ .resolvesOnce({ events: [{ message: "log1" }], nextForwardToken: "token2" })
+ .resolves({ events: [], nextForwardToken: "token2" });
+
+ const options = {
+ logGroupName: "/test/group",
+ logStreamName: "stream1",
+ pollingActive: true,
+ pollingDelay: 1000,
+ };
+ const stream = await awsCloudWatchLogsGetLogEventsStream(options);
+
+ const output = [];
+ const consuming = (async () => {
+ for await (const item of stream) {
+ output.push(item);
+ if (output.length >= 1) break;
+ }
+ })();
+
+ await new Promise((resolve) => setImmediate(resolve));
+ t.mock.timers.tick(1000);
+
+ await consuming;
+
+ deepStrictEqual(output, [{ message: "log1" }]);
+});
+
+// --- FilterLogEventsStream ---
+
+test(`${variant}: awsCloudWatchLogsFilterLogEventsStream should get events`, async (_t) => {
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client
+ .on(FilterLogEventsCommand)
+ .resolvesOnce({
+ events: [{ message: "log1" }],
+ nextToken: "token2",
+ })
+ .resolvesOnce({
+ events: [{ message: "log2" }],
+ });
+
+ const options = { logGroupName: "/test/group" };
+ const stream = await awsCloudWatchLogsFilterLogEventsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ message: "log1" }, { message: "log2" }]);
+});
+
+test(`${variant}: awsCloudWatchLogsFilterLogEventsStream should stop when no nextToken`, async (_t) => {
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client.on(FilterLogEventsCommand).resolves({
+ events: [{ message: "log1" }],
+ });
+
+ const options = { logGroupName: "/test/group" };
+ const stream = await awsCloudWatchLogsFilterLogEventsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ message: "log1" }]);
+});
+
+test(`${variant}: awsCloudWatchLogsFilterLogEventsStream should handle empty events (undefined)`, async (_t) => {
+ const client = mockClient(CloudWatchLogsClient);
+ awsCloudWatchLogsSetClient(client);
+
+ client.on(FilterLogEventsCommand).resolves({});
+
+ const options = { logGroupName: "/test/group" };
+ const stream = await awsCloudWatchLogsFilterLogEventsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, []);
+});
diff --git a/packages/aws/dynamodb.d.ts b/packages/aws/dynamodb.d.ts
index 9eff50f..43ed3c8 100644
--- a/packages/aws/dynamodb.d.ts
+++ b/packages/aws/dynamodb.d.ts
@@ -25,6 +25,16 @@ export function awsDynamoDBScanStream(
streamOptions?: StreamOptions,
): Promise;
+export function awsDynamoDBExecuteStatementStream(
+ options: {
+ client?: unknown;
+ Statement?: string;
+ NextToken?: string;
+ [key: string]: unknown;
+ },
+ streamOptions?: StreamOptions,
+): Promise;
+
export function awsDynamoDBGetItemStream(
options: {
client?: unknown;
diff --git a/packages/aws/dynamodb.js b/packages/aws/dynamodb.js
index 7902db4..edf1972 100644
--- a/packages/aws/dynamodb.js
+++ b/packages/aws/dynamodb.js
@@ -4,6 +4,7 @@ import {
BatchGetItemCommand,
BatchWriteItemCommand,
DynamoDBClient,
+ ExecuteStatementCommand,
QueryCommand,
ScanCommand,
} from "@aws-sdk/client-dynamodb";
@@ -18,11 +19,13 @@ awsDynamoDBSetClient(client);
// options = {TableName, ...}
-export const awsDynamoDBQueryStream = async (options, _streamOptions = {}) => {
+export const awsDynamoDBQueryStream = async (options, streamOptions = {}) => {
async function* command(options) {
let expectMore = true;
while (expectMore) {
- const response = await client.send(new QueryCommand(options));
+ const response = await client.send(new QueryCommand(options), {
+ abortSignal: streamOptions.signal,
+ });
for (const item of response.Items) {
yield item;
}
@@ -33,11 +36,13 @@ export const awsDynamoDBQueryStream = async (options, _streamOptions = {}) => {
return command(options);
};
-export const awsDynamoDBScanStream = async (options, _streamOptions = {}) => {
+export const awsDynamoDBScanStream = async (options, streamOptions = {}) => {
async function* command(options) {
let expectMore = true;
while (expectMore) {
- const response = await client.send(new ScanCommand(options));
+ const response = await client.send(new ScanCommand(options), {
+ abortSignal: streamOptions.signal,
+ });
for (const item of response.Items) {
yield item;
}
@@ -48,27 +53,44 @@ export const awsDynamoDBScanStream = async (options, _streamOptions = {}) => {
return command(options);
};
-// TODO awsDynamoDBExecuteStatementStream
-
-export const awsDynamoDBGetItemStream = async (
+export const awsDynamoDBExecuteStatementStream = async (
options,
- _streamOptions = {},
+ streamOptions = {},
) => {
+ async function* command(options) {
+ let expectMore = true;
+ while (expectMore) {
+ const response = await client.send(new ExecuteStatementCommand(options), {
+ abortSignal: streamOptions.signal,
+ });
+ for (const item of response.Items ?? []) {
+ yield item;
+ }
+ options.NextToken = response.NextToken;
+ expectMore = !!response.NextToken;
+ }
+ }
+ return command(options);
+};
+
+export const awsDynamoDBGetItemStream = async (options, streamOptions = {}) => {
if (options.Keys?.length > 100) {
throw new Error(
`awsDynamoDBGetItemStream Keys.length (${options.Keys.length}) exceeds BatchGetItem limit of 100`,
);
}
- options.retryCount ??= 0;
- options.retryMaxCount ??= 10;
async function* command(options) {
+ let keys = options.Keys;
+ let retryCount = options.retryCount ?? 0;
+ const retryMaxCount = options.retryMaxCount ?? 10;
while (true) {
const response = await client.send(
new BatchGetItemCommand({
RequestItems: {
- [options.TableName]: { Keys: options.Keys },
+ [options.TableName]: { Keys: keys },
},
}),
+ { abortSignal: streamOptions.signal },
);
for (const item of response.Responses[options.TableName]) {
yield item;
@@ -79,7 +101,7 @@ export const awsDynamoDBGetItemStream = async (
break;
}
- if (options.retryCount >= options.retryMaxCount) {
+ if (retryCount >= retryMaxCount) {
throw new Error("awsDynamoDBBatchGetItem has UnprocessedKeys", {
cause: {
...options,
@@ -88,9 +110,9 @@ export const awsDynamoDBGetItemStream = async (
});
}
- await timeout(3 ** options.retryCount++); // 3^10 == 59sec
-
- options.Keys = UnprocessedKeys;
+ await timeout(3 ** retryCount); // 3^10 == 59sec
+ retryCount++;
+ keys = UnprocessedKeys;
}
}
return command(options);
@@ -136,18 +158,23 @@ export const awsDynamoDBDeleteItemStream = (options, streamOptions = {}) => {
return createWritableStream(write, final, streamOptions);
};
-const dynamodbBatchWrite = async (options, batch, streamOptions) => {
- options.retryCount ??= 0;
- options.retryMaxCount ??= 10;
+const dynamodbBatchWrite = async (
+ options,
+ batch,
+ streamOptions,
+ retryCount = 0,
+) => {
+ const retryMaxCount = options.retryMaxCount ?? 10;
const { UnprocessedItems } = await client.send(
new BatchWriteItemCommand({
RequestItems: {
[options.TableName]: batch,
},
}),
+ { abortSignal: streamOptions?.signal },
);
if (UnprocessedItems?.[options.TableName]?.length) {
- if (options.retryCount >= options.retryMaxCount) {
+ if (retryCount >= retryMaxCount) {
throw new Error("awsDynamoDBBatchWriteItem has UnprocessedItems", {
cause: {
...options,
@@ -156,20 +183,21 @@ const dynamodbBatchWrite = async (options, batch, streamOptions) => {
});
}
- await timeout(3 ** options.retryCount++); // 3^10 == 59sec
+ await timeout(3 ** retryCount); // 3^10 == 59sec
return dynamodbBatchWrite(
options,
UnprocessedItems[options.TableName],
streamOptions,
+ retryCount + 1,
);
}
- options.retryCount = 0; // reset for next batch
};
export default {
setClient: awsDynamoDBSetClient,
queryStream: awsDynamoDBQueryStream,
scanStream: awsDynamoDBScanStream,
+ executeStatementStream: awsDynamoDBExecuteStatementStream,
getItemStream: awsDynamoDBGetItemStream,
putItemStream: awsDynamoDBPutItemStream,
deleteItemStream: awsDynamoDBDeleteItemStream,
diff --git a/packages/aws/dynamodb.test.js b/packages/aws/dynamodb.test.js
index 8830b46..13cb7dd 100644
--- a/packages/aws/dynamodb.test.js
+++ b/packages/aws/dynamodb.test.js
@@ -4,11 +4,13 @@ import {
BatchGetItemCommand,
BatchWriteItemCommand,
DynamoDBClient,
+ ExecuteStatementCommand,
QueryCommand,
ScanCommand,
} from "@aws-sdk/client-dynamodb";
-import {
+import dynamodbDefault, {
awsDynamoDBDeleteItemStream,
+ awsDynamoDBExecuteStatementStream,
awsDynamoDBGetItemStream,
awsDynamoDBPutItemStream,
awsDynamoDBQueryStream,
@@ -210,6 +212,57 @@ test(`${variant}: awsDynamoDBScanStream should return items`, async (_t) => {
]);
});
+test(`${variant}: awsDynamoDBExecuteStatementStream should return items`, async (_t) => {
+ const client = mockClient(DynamoDBClient);
+ awsDynamoDBSetClient(client);
+ client
+ .on(ExecuteStatementCommand, {
+ Statement: 'SELECT * FROM "TableName"',
+ })
+ .resolves({
+ Items: [
+ { key: "a", value: 1 },
+ { key: "b", value: 2 },
+ ],
+ NextToken: "token1",
+ })
+ .on(ExecuteStatementCommand, {
+ Statement: 'SELECT * FROM "TableName"',
+ NextToken: "token1",
+ })
+ .resolves({
+ Items: [{ key: "c", value: 3 }],
+ });
+
+ const options = {
+ Statement: 'SELECT * FROM "TableName"',
+ };
+ const stream = await awsDynamoDBExecuteStatementStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [
+ { key: "a", value: 1 },
+ { key: "b", value: 2 },
+ { key: "c", value: 3 },
+ ]);
+});
+
+test(`${variant}: awsDynamoDBExecuteStatementStream should handle empty result`, async (_t) => {
+ const client = mockClient(DynamoDBClient);
+ awsDynamoDBSetClient(client);
+ client.on(ExecuteStatementCommand).resolves({
+ Items: [],
+ });
+
+ const options = {
+ Statement: "SELECT * FROM \"TableName\" WHERE key = 'missing'",
+ };
+ const stream = await awsDynamoDBExecuteStatementStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, []);
+});
+
test(`${variant}: awsDynamoDBPutItemStream should store items`, async (_t) => {
const client = mockClient(DynamoDBClient);
awsDynamoDBSetClient(client);
@@ -522,3 +575,32 @@ test(`${variant}: awsDynamoDBDeleteItemStream should throw error`, async (_t) =>
message: "awsDynamoDBBatchWriteItem has UnprocessedItems",
});
});
+
+test(`${variant}: awsDynamoDBPutItemStream should pass abort signal to batch write`, async (_t) => {
+ const client = mockClient(DynamoDBClient);
+ awsDynamoDBSetClient(client);
+ client.on(BatchWriteItemCommand).resolves({ UnprocessedItems: {} });
+
+ const controller = new AbortController();
+ const input = [{ key: "a", value: 1 }];
+ const stream = [
+ createReadableStream(input),
+ awsDynamoDBPutItemStream({ TableName: "T" }, { signal: controller.signal }),
+ ];
+ await pipeline(stream);
+
+ const calls = client.commandCalls(BatchWriteItemCommand);
+ deepStrictEqual(calls[0].args[1]?.abortSignal, controller.signal);
+});
+
+test(`${variant}: default export should include all stream functions`, (_t) => {
+ deepStrictEqual(Object.keys(dynamodbDefault).sort(), [
+ "deleteItemStream",
+ "executeStatementStream",
+ "getItemStream",
+ "putItemStream",
+ "queryStream",
+ "scanStream",
+ "setClient",
+ ]);
+});
diff --git a/packages/aws/index.d.ts b/packages/aws/index.d.ts
index b1ddaf2..04bb467 100644
--- a/packages/aws/index.d.ts
+++ b/packages/aws/index.d.ts
@@ -1,5 +1,15 @@
// Copyright 2026 will Farrell, and datastream contributors.
// SPDX-License-Identifier: MIT
+export {
+ awsCloudWatchLogsGetLogEventsStream,
+ awsCloudWatchLogsFilterLogEventsStream,
+ awsCloudWatchLogsSetClient,
+} from "@datastream/aws/cloudwatch-logs";
+export {
+ awsKinesisGetRecordsStream,
+ awsKinesisPutRecordsStream,
+ awsKinesisSetClient,
+} from "@datastream/aws/kinesis";
export {
awsS3GetObjectStream,
awsS3PutObjectStream,
@@ -9,6 +19,7 @@ export {
export {
awsDynamoDBQueryStream,
awsDynamoDBScanStream,
+ awsDynamoDBExecuteStatementStream,
awsDynamoDBGetItemStream,
awsDynamoDBPutItemStream,
awsDynamoDBDeleteItemStream,
diff --git a/packages/aws/index.fuzz.js b/packages/aws/index.fuzz.js
new file mode 100644
index 0000000..222f5e8
--- /dev/null
+++ b/packages/aws/index.fuzz.js
@@ -0,0 +1,234 @@
+import test from "node:test";
+import {
+ BatchWriteItemCommand,
+ DynamoDBClient,
+ QueryCommand,
+} from "@aws-sdk/client-dynamodb";
+import { PublishBatchCommand, SNSClient } from "@aws-sdk/client-sns";
+import { SendMessageBatchCommand, SQSClient } from "@aws-sdk/client-sqs";
+import {
+ awsDynamoDBDeleteItemStream,
+ awsDynamoDBPutItemStream,
+ awsDynamoDBQueryStream,
+ awsDynamoDBSetClient,
+} from "@datastream/aws/dynamodb";
+import {
+ awsSNSPublishMessageStream,
+ awsSNSSetClient,
+} from "@datastream/aws/sns";
+import { awsSQSSendMessageStream, awsSQSSetClient } from "@datastream/aws/sqs";
+import {
+ createReadableStream,
+ pipeline,
+ streamToArray,
+} from "@datastream/core";
+import { mockClient } from "aws-sdk-client-mock";
+import fc from "fast-check";
+
+const catchError = (input, e) => {
+ const expectedErrors = [];
+ if (expectedErrors.includes(e.message)) {
+ return;
+ }
+ console.error(input, e);
+ throw e;
+};
+
+// *** awsDynamoDBPutItemStream w/ varying batch sizes *** //
+test("fuzz awsDynamoDBPutItemStream w/ random item count", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(
+ fc.record({
+ key: fc.string({ minLength: 1, maxLength: 10 }),
+ value: fc.anything().filter((v) => v !== null),
+ }),
+ { minLength: 0, maxLength: 100 },
+ ),
+ async (input) => {
+ const ddbMock = mockClient(DynamoDBClient);
+ awsDynamoDBSetClient(ddbMock);
+ ddbMock.on(BatchWriteItemCommand).resolves({ UnprocessedItems: {} });
+
+ try {
+ const streams = [
+ createReadableStream(input),
+ awsDynamoDBPutItemStream({ TableName: "FuzzTable" }),
+ ];
+ await pipeline(streams);
+ } catch (e) {
+ catchError(input, e);
+ } finally {
+ ddbMock.restore();
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** awsDynamoDBDeleteItemStream w/ varying batch sizes *** //
+test("fuzz awsDynamoDBDeleteItemStream w/ random item count", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(
+ fc.record({
+ key: fc.string({ minLength: 1, maxLength: 10 }),
+ }),
+ { minLength: 0, maxLength: 100 },
+ ),
+ async (input) => {
+ const ddbMock = mockClient(DynamoDBClient);
+ awsDynamoDBSetClient(ddbMock);
+ ddbMock.on(BatchWriteItemCommand).resolves({ UnprocessedItems: {} });
+
+ try {
+ const streams = [
+ createReadableStream(input),
+ awsDynamoDBDeleteItemStream({ TableName: "FuzzTable" }),
+ ];
+ await pipeline(streams);
+ } catch (e) {
+ catchError(input, e);
+ } finally {
+ ddbMock.restore();
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** awsDynamoDBQueryStream w/ varying page sizes *** //
+test("fuzz awsDynamoDBQueryStream w/ random page sizes", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(
+ fc.array(
+ fc.record({
+ key: fc.string({ minLength: 1, maxLength: 10 }),
+ }),
+ { minLength: 1, maxLength: 20 },
+ ),
+ { minLength: 1, maxLength: 5 },
+ ),
+ async (pages) => {
+ const ddbMock = mockClient(DynamoDBClient);
+ awsDynamoDBSetClient(ddbMock);
+
+ let callIdx = 0;
+ ddbMock.on(QueryCommand).callsFake(() => {
+ const items = pages[callIdx] ?? [];
+ callIdx++;
+ return {
+ Items: items,
+ LastEvaluatedKey:
+ callIdx < pages.length ? { key: "next" } : undefined,
+ };
+ });
+
+ try {
+ const stream = await awsDynamoDBQueryStream({
+ TableName: "FuzzTable",
+ });
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(pages, e);
+ } finally {
+ ddbMock.restore();
+ }
+ },
+ ),
+ {
+ numRuns: 500,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** awsSNSPublishMessageStream w/ varying batch sizes *** //
+test("fuzz awsSNSPublishMessageStream w/ random message count", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(
+ fc.record({
+ Id: fc.string({ minLength: 1, maxLength: 10 }),
+ Message: fc.string(),
+ }),
+ { minLength: 0, maxLength: 50 },
+ ),
+ async (input) => {
+ const snsMock = mockClient(SNSClient);
+ awsSNSSetClient(snsMock);
+ snsMock.on(PublishBatchCommand).resolves({});
+
+ try {
+ const streams = [
+ createReadableStream(input),
+ awsSNSPublishMessageStream({
+ TopicArn: "arn:aws:sns:us-east-1:000000000000:fuzz",
+ }),
+ ];
+ await pipeline(streams);
+ } catch (e) {
+ catchError(input, e);
+ } finally {
+ snsMock.restore();
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** awsSQSSendMessageStream w/ varying batch sizes *** //
+test("fuzz awsSQSSendMessageStream w/ random message count", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(
+ fc.record({
+ Id: fc.string({ minLength: 1, maxLength: 10 }),
+ MessageBody: fc.string(),
+ }),
+ { minLength: 0, maxLength: 50 },
+ ),
+ async (input) => {
+ const sqsMock = mockClient(SQSClient);
+ awsSQSSetClient(sqsMock);
+ sqsMock.on(SendMessageBatchCommand).resolves({});
+
+ try {
+ const streams = [
+ createReadableStream(input),
+ awsSQSSendMessageStream({
+ QueueUrl: "https://sqs.us-east-1.amazonaws.com/000000000000/fuzz",
+ }),
+ ];
+ await pipeline(streams);
+ } catch (e) {
+ catchError(input, e);
+ } finally {
+ sqsMock.restore();
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
diff --git a/packages/aws/index.js b/packages/aws/index.js
index 4fa9f61..339bf2c 100644
--- a/packages/aws/index.js
+++ b/packages/aws/index.js
@@ -1,6 +1,8 @@
// Copyright 2026 will Farrell, and datastream contributors.
// SPDX-License-Identifier: MIT
+export * from "@datastream/aws/cloudwatch-logs";
export * from "@datastream/aws/dynamodb";
+export * from "@datastream/aws/kinesis";
export * from "@datastream/aws/lambda";
export * from "@datastream/aws/s3";
export * from "@datastream/aws/sns";
diff --git a/packages/aws/index.tst.ts b/packages/aws/index.tst.ts
index c74858a..c70c7f2 100644
--- a/packages/aws/index.tst.ts
+++ b/packages/aws/index.tst.ts
@@ -1,10 +1,17 @@
import {
+ awsCloudWatchLogsFilterLogEventsStream,
+ awsCloudWatchLogsGetLogEventsStream,
+ awsCloudWatchLogsSetClient,
awsDynamoDBDeleteItemStream,
+ awsDynamoDBExecuteStatementStream,
awsDynamoDBGetItemStream,
awsDynamoDBPutItemStream,
awsDynamoDBQueryStream,
awsDynamoDBScanStream,
awsDynamoDBSetClient,
+ awsKinesisGetRecordsStream,
+ awsKinesisPutRecordsStream,
+ awsKinesisSetClient,
awsLambdaReadableStream,
awsLambdaResponseStream,
awsLambdaSetClient,
@@ -21,6 +28,47 @@ import {
} from "@datastream/aws";
import { describe, expect, test } from "tstyche";
+describe("CloudWatch Logs", () => {
+ test("awsCloudWatchLogsSetClient accepts client", () => {
+ expect(awsCloudWatchLogsSetClient({})).type.toBe();
+ });
+
+ test("awsCloudWatchLogsGetLogEventsStream returns promise", () => {
+ expect(
+ awsCloudWatchLogsGetLogEventsStream({
+ logGroupName: "/test/group",
+ logStreamName: "stream1",
+ }),
+ ).type.toBeAssignableTo>();
+ });
+
+ test("awsCloudWatchLogsFilterLogEventsStream returns promise", () => {
+ expect(
+ awsCloudWatchLogsFilterLogEventsStream({
+ logGroupName: "/test/group",
+ }),
+ ).type.toBeAssignableTo>();
+ });
+});
+
+describe("Kinesis", () => {
+ test("awsKinesisSetClient accepts client", () => {
+ expect(awsKinesisSetClient({})).type.toBe();
+ });
+
+ test("awsKinesisGetRecordsStream returns promise", () => {
+ expect(
+ awsKinesisGetRecordsStream({ ShardIterator: "iter1" }),
+ ).type.toBeAssignableTo>();
+ });
+
+ test("awsKinesisPutRecordsStream returns stream", () => {
+ expect(
+ awsKinesisPutRecordsStream({ StreamName: "test-stream" }),
+ ).type.not.toBeAssignableTo();
+ });
+});
+
describe("S3", () => {
test("awsS3SetClient accepts client", () => {
expect(awsS3SetClient({})).type.toBe();
@@ -66,6 +114,14 @@ describe("DynamoDB", () => {
>();
});
+ test("awsDynamoDBExecuteStatementStream returns promise", () => {
+ expect(
+ awsDynamoDBExecuteStatementStream({
+ Statement: 'SELECT * FROM "TableName"',
+ }),
+ ).type.toBeAssignableTo>();
+ });
+
test("awsDynamoDBGetItemStream returns promise", () => {
expect(
awsDynamoDBGetItemStream({ TableName: "t", Keys: [{}] }),
diff --git a/packages/aws/kinesis.d.ts b/packages/aws/kinesis.d.ts
new file mode 100644
index 0000000..be8e906
--- /dev/null
+++ b/packages/aws/kinesis.d.ts
@@ -0,0 +1,26 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import type { StreamOptions } from "@datastream/core";
+
+export function awsKinesisSetClient(kinesisClient: unknown): void;
+
+export function awsKinesisGetRecordsStream(
+ options: {
+ client?: unknown;
+ ShardIterator?: string;
+ pollingActive?: boolean;
+ pollingDelay?: number;
+ [key: string]: unknown;
+ },
+ streamOptions?: StreamOptions,
+): Promise;
+
+export function awsKinesisPutRecordsStream(
+ options: {
+ client?: unknown;
+ StreamName?: string;
+ StreamARN?: string;
+ [key: string]: unknown;
+ },
+ streamOptions?: StreamOptions,
+): unknown;
diff --git a/packages/aws/kinesis.js b/packages/aws/kinesis.js
new file mode 100644
index 0000000..f07cc66
--- /dev/null
+++ b/packages/aws/kinesis.js
@@ -0,0 +1,60 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import {
+ GetRecordsCommand,
+ KinesisClient,
+ PutRecordsCommand,
+} from "@aws-sdk/client-kinesis";
+import { createWritableStream } from "@datastream/core";
+import { awsClientDefaults } from "./client.js";
+
+let client = new KinesisClient(awsClientDefaults);
+export const awsKinesisSetClient = (kinesisClient) => {
+ client = kinesisClient;
+};
+
+export const awsKinesisGetRecordsStream = async (
+ options,
+ _streamOptions = {},
+) => {
+ const { pollingActive, pollingDelay = 1000, ...kinesisOptions } = options;
+ async function* command(options) {
+ let expectMore = true;
+ while (expectMore) {
+ const response = await client.send(new GetRecordsCommand(options));
+ const records = response.Records ?? [];
+ for (const item of records) {
+ yield item;
+ }
+ options.ShardIterator = response.NextShardIterator;
+ expectMore = pollingActive || records.length > 0;
+ if (pollingActive && records.length === 0 && pollingDelay > 0) {
+ await new Promise((resolve) => setTimeout(resolve, pollingDelay));
+ }
+ }
+ }
+ return command(kinesisOptions);
+};
+
+export const awsKinesisPutRecordsStream = (options, streamOptions = {}) => {
+ let batch = [];
+ const send = () => {
+ options.Records = batch;
+ batch = [];
+ return client.send(new PutRecordsCommand(options));
+ };
+ const write = async (chunk) => {
+ if (batch.length === 500) {
+ await send();
+ }
+ batch.push(chunk);
+ };
+ const final = () => (batch.length ? send() : undefined);
+ return createWritableStream(write, final, streamOptions);
+};
+
+export default {
+ setClient: awsKinesisSetClient,
+ getRecordsStream: awsKinesisGetRecordsStream,
+ putRecordsStream: awsKinesisPutRecordsStream,
+};
diff --git a/packages/aws/kinesis.test.js b/packages/aws/kinesis.test.js
new file mode 100644
index 0000000..1df3801
--- /dev/null
+++ b/packages/aws/kinesis.test.js
@@ -0,0 +1,190 @@
+import { deepStrictEqual } from "node:assert";
+import test from "node:test";
+import {
+ GetRecordsCommand,
+ KinesisClient,
+ PutRecordsCommand,
+} from "@aws-sdk/client-kinesis";
+import {
+ awsKinesisGetRecordsStream,
+ awsKinesisPutRecordsStream,
+ awsKinesisSetClient,
+} from "@datastream/aws/kinesis";
+
+import {
+ createReadableStream,
+ pipeline,
+ streamToArray,
+} from "@datastream/core";
+import { mockClient } from "aws-sdk-client-mock";
+
+let variant = "unknown";
+for (const execArgv of process.execArgv) {
+ const flag = "--conditions=";
+ if (execArgv.includes(flag)) {
+ variant = execArgv.replace(flag, "");
+ }
+}
+
+test(`${variant}: awsKinesisGetRecordsStream should get chunk`, async (_t) => {
+ const client = mockClient(KinesisClient);
+ awsKinesisSetClient(client);
+
+ client
+ .on(GetRecordsCommand)
+ .resolvesOnce({
+ Records: [{ Data: "a" }],
+ NextShardIterator: "iter2",
+ })
+ .resolvesOnce({
+ Records: [],
+ NextShardIterator: "iter3",
+ });
+
+ const options = { ShardIterator: "iter1" };
+ const stream = await awsKinesisGetRecordsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ Data: "a" }]);
+});
+
+test(`${variant}: awsKinesisGetRecordsStream should handle empty Records (undefined)`, async (_t) => {
+ const client = mockClient(KinesisClient);
+ awsKinesisSetClient(client);
+
+ client.on(GetRecordsCommand).resolves({ NextShardIterator: "iter2" });
+
+ const options = { ShardIterator: "iter1" };
+ const stream = await awsKinesisGetRecordsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, []);
+});
+
+test(`${variant}: awsKinesisGetRecordsStream should track NextShardIterator across calls`, async (_t) => {
+ const client = mockClient(KinesisClient);
+ awsKinesisSetClient(client);
+
+ client
+ .on(GetRecordsCommand)
+ .resolvesOnce({
+ Records: [{ Data: "a" }],
+ NextShardIterator: "iter2",
+ })
+ .resolvesOnce({
+ Records: [{ Data: "b" }],
+ NextShardIterator: "iter3",
+ })
+ .resolvesOnce({
+ Records: [],
+ NextShardIterator: "iter4",
+ });
+
+ const options = { ShardIterator: "iter1" };
+ const stream = await awsKinesisGetRecordsStream(options);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ Data: "a" }, { Data: "b" }]);
+});
+
+test(`${variant}: awsKinesisGetRecordsStream should keep polling with pollingActive option`, async (_t) => {
+ const client = mockClient(KinesisClient);
+ awsKinesisSetClient(client);
+
+ client
+ .on(GetRecordsCommand)
+ .resolvesOnce({ Records: [{ Data: "a" }], NextShardIterator: "iter2" })
+ .resolvesOnce({ Records: [], NextShardIterator: "iter3" })
+ .resolvesOnce({ Records: [{ Data: "b" }], NextShardIterator: "iter4" })
+ .resolves({ Records: [], NextShardIterator: "iter5" });
+
+ const options = {
+ ShardIterator: "iter1",
+ pollingActive: true,
+ pollingDelay: 0,
+ };
+ const stream = await awsKinesisGetRecordsStream(options);
+
+ const output = [];
+ for await (const item of stream) {
+ output.push(item);
+ if (output.length >= 2) break;
+ }
+
+ deepStrictEqual(output, [{ Data: "a" }, { Data: "b" }]);
+});
+
+test(`${variant}: awsKinesisGetRecordsStream should delay polling when pollingActive and no records`, async (t) => {
+ t.mock.timers.enable({ apis: ["setTimeout"] });
+
+ const client = mockClient(KinesisClient);
+ awsKinesisSetClient(client);
+
+ client
+ .on(GetRecordsCommand)
+ .resolvesOnce({ Records: [], NextShardIterator: "iter2" })
+ .resolvesOnce({ Records: [{ Data: "a" }], NextShardIterator: "iter3" })
+ .resolves({ Records: [], NextShardIterator: "iter4" });
+
+ const options = {
+ ShardIterator: "iter1",
+ pollingActive: true,
+ pollingDelay: 1000,
+ };
+ const stream = await awsKinesisGetRecordsStream(options);
+
+ const output = [];
+ const consuming = (async () => {
+ for await (const item of stream) {
+ output.push(item);
+ if (output.length >= 1) break;
+ }
+ })();
+
+ await new Promise((resolve) => setImmediate(resolve));
+ t.mock.timers.tick(1000);
+
+ await consuming;
+
+ deepStrictEqual(output, [{ Data: "a" }]);
+});
+
+test(`${variant}: awsKinesisPutRecordsStream should put chunk`, async (_t) => {
+ const client = mockClient(KinesisClient);
+ awsKinesisSetClient(client);
+
+ const input = "abcdefghijk"
+ .split("")
+ .map((id) => ({ Data: id, PartitionKey: id }));
+ const options = {
+ StreamName: "test-stream",
+ };
+
+ client.on(PutRecordsCommand).resolves({});
+
+ const stream = [
+ createReadableStream(input),
+ awsKinesisPutRecordsStream(options),
+ ];
+ const result = await pipeline(stream);
+
+ deepStrictEqual(result, {});
+});
+
+test(`${variant}: awsKinesisPutRecordsStream should handle empty input`, async (_t) => {
+ const client = mockClient(KinesisClient);
+ awsKinesisSetClient(client);
+
+ const input = [];
+ const options = {
+ StreamName: "test-stream",
+ };
+
+ const stream = [
+ createReadableStream(input),
+ awsKinesisPutRecordsStream(options),
+ ];
+ const result = await pipeline(stream);
+
+ deepStrictEqual(result, {});
+});
diff --git a/packages/aws/lambda.js b/packages/aws/lambda.js
index 6699f80..45bc198 100644
--- a/packages/aws/lambda.js
+++ b/packages/aws/lambda.js
@@ -13,17 +13,21 @@ export const awsLambdaSetClient = (lambdaClient) => {
};
export const awsLambdaReadableStream = (lambdaOptions, streamOptions = {}) => {
- return createReadableStream(awsLambdaGenerator(lambdaOptions), streamOptions);
+ return createReadableStream(
+ awsLambdaGenerator(lambdaOptions, streamOptions),
+ streamOptions,
+ );
};
export const awsLambdaResponseStream = awsLambdaReadableStream;
-async function* awsLambdaGenerator(lambdaOptions, _streamOptions = {}) {
+async function* awsLambdaGenerator(lambdaOptions, streamOptions = {}) {
if (!Array.isArray(lambdaOptions)) {
lambdaOptions = [lambdaOptions];
}
for (const options of lambdaOptions) {
const response = await defaultClient.send(
new InvokeWithResponseStreamCommand(options),
+ { abortSignal: streamOptions.signal },
);
for await (const chunk of response.EventStream) {
if (chunk?.PayloadChunk?.Payload) {
diff --git a/packages/aws/lambda.test.js b/packages/aws/lambda.test.js
index 560b4fb..5323cbe 100644
--- a/packages/aws/lambda.test.js
+++ b/packages/aws/lambda.test.js
@@ -13,9 +13,12 @@ if (variant === "node") {
const { InvokeWithResponseStreamCommand, LambdaClient } = await import(
"@aws-sdk/client-lambda"
);
- const { awsLambdaReadableStream, awsLambdaSetClient } = await import(
- "@datastream/aws/lambda"
- );
+ const lambdaModule = await import("@datastream/aws/lambda");
+ const {
+ default: lambdaDefault,
+ awsLambdaReadableStream,
+ awsLambdaSetClient,
+ } = lambdaModule;
const { createReadableStream, pipeline } = await import("@datastream/core");
const { mockClient } = await import("aws-sdk-client-mock");
@@ -120,4 +123,35 @@ if (variant === "node") {
deepStrictEqual(result, "abc");
});
+
+ test(`${variant}: awsLambdaReadableStream should pass abort signal to client.send`, async (_t) => {
+ const client = mockClient(LambdaClient);
+ awsLambdaSetClient(client);
+
+ const encoder = new TextEncoder();
+ client.on(InvokeWithResponseStreamCommand).resolves({
+ EventStream: createReadableStream([
+ { PayloadChunk: { Payload: encoder.encode("ok") } },
+ ]),
+ });
+
+ const controller = new AbortController();
+ for await (const _chunk of await awsLambdaReadableStream(
+ { FunctionName: "f" },
+ { signal: controller.signal },
+ )) {
+ // consume
+ }
+
+ const calls = client.commandCalls(InvokeWithResponseStreamCommand);
+ deepStrictEqual(calls[0].args[1]?.abortSignal, controller.signal);
+ });
+
+ test(`${variant}: default export should include all stream functions`, (_t) => {
+ deepStrictEqual(Object.keys(lambdaDefault).sort(), [
+ "readableStream",
+ "responseStream",
+ "setClient",
+ ]);
+ });
}
diff --git a/packages/aws/package.json b/packages/aws/package.json
index 1234ea7..ceffe8b 100644
--- a/packages/aws/package.json
+++ b/packages/aws/package.json
@@ -1,7 +1,7 @@
{
"name": "@datastream/aws",
- "version": "0.1.6",
- "description": "AWS service streaming integrations for S3, DynamoDB, Lambda, SNS, and SQS",
+ "version": "0.2.0",
+ "description": "AWS service streaming integrations for CloudWatch Logs, DynamoDB, Kinesis, Lambda, S3, SNS, and SQS",
"type": "module",
"engines": {
"node": ">=24"
@@ -73,6 +73,30 @@
"default": "./sns.web.mjs"
}
},
+ "./cloudwatch-logs": {
+ "node": {
+ "import": {
+ "types": "./cloudwatch-logs.d.ts",
+ "default": "./cloudwatch-logs.node.mjs"
+ }
+ },
+ "import": {
+ "types": "./cloudwatch-logs.d.ts",
+ "default": "./cloudwatch-logs.web.mjs"
+ }
+ },
+ "./kinesis": {
+ "node": {
+ "import": {
+ "types": "./kinesis.d.ts",
+ "default": "./kinesis.node.mjs"
+ }
+ },
+ "import": {
+ "types": "./kinesis.d.ts",
+ "default": "./kinesis.web.mjs"
+ }
+ },
"./sqs": {
"node": {
"import": {
@@ -100,7 +124,9 @@
"license": "MIT",
"keywords": [
"AWS",
+ "CloudWatch",
"DynamoDB",
+ "Kinesis",
"Lambda",
"S3",
"SNS",
@@ -122,10 +148,12 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"peerDependencies": {
+ "@aws-sdk/client-cloudwatch-logs": "^3.0.0",
"@aws-sdk/client-dynamodb": "^3.0.0",
+ "@aws-sdk/client-kinesis": "^3.0.0",
"@aws-sdk/client-lambda": "^3.0.0",
"@aws-sdk/client-s3": "^3.0.0",
"@aws-sdk/client-sns": "^3.0.0",
@@ -134,9 +162,15 @@
"@aws-sdk/lib-storage": "^3.0.0"
},
"peerDependenciesMeta": {
+ "@aws-sdk/client-cloudwatch-logs": {
+ "optional": true
+ },
"@aws-sdk/client-dynamodb": {
"optional": true
},
+ "@aws-sdk/client-kinesis": {
+ "optional": true
+ },
"@aws-sdk/client-lambda": {
"optional": true
},
@@ -157,7 +191,9 @@
}
},
"devDependencies": {
+ "@aws-sdk/client-cloudwatch-logs": "^3.0.0",
"@aws-sdk/client-dynamodb": "^3.0.0",
+ "@aws-sdk/client-kinesis": "^3.0.0",
"@aws-sdk/client-lambda": "^3.0.0",
"@aws-sdk/client-s3": "^3.0.0",
"@aws-sdk/client-sns": "^3.0.0",
diff --git a/packages/aws/s3.js b/packages/aws/s3.js
index 73e2596..b74472d 100644
--- a/packages/aws/s3.js
+++ b/packages/aws/s3.js
@@ -19,6 +19,7 @@ export const awsS3GetObjectStream = async (options, streamOptions = {}) => {
const { client, ...params } = options;
const { Body } = await (client ?? defaultClient).send(
new GetObjectCommand(params),
+ { abortSignal: streamOptions.signal },
);
if (!Body) {
throw new Error("S3.GetObject not found", { cause: params });
@@ -56,7 +57,7 @@ export const awsS3ChecksumStream = (
streamOptions = {},
) => {
ChecksumAlgorithm ??= "SHA256";
- partSize ??= 17_179_870;
+ partSize ??= 17_179_870; // ~16MB, just under S3 multipart minimum
const algorithm = _algorithms[ChecksumAlgorithm];
if (!algorithm)
throw new Error(`Unsupported ChecksumAlgorithm: ${ChecksumAlgorithm}`);
diff --git a/packages/aws/s3.test.js b/packages/aws/s3.test.js
index 31e7af1..353a173 100644
--- a/packages/aws/s3.test.js
+++ b/packages/aws/s3.test.js
@@ -343,6 +343,22 @@ test(`${variant}: awsS3ChecksumStream should cache result on second call`, async
deepStrictEqual(result1, result2);
});
+test(`${variant}: awsS3GetObjectStream should pass abort signal to client.send`, async (_t) => {
+ const client = mockClient(S3Client);
+ client.on(GetObjectCommand).resolves({
+ Body: createReadableStream("data"),
+ });
+
+ const controller = new AbortController();
+ await awsS3GetObjectStream(
+ { Bucket: "b", Key: "k", client },
+ { signal: controller.signal },
+ );
+
+ const calls = client.commandCalls(GetObjectCommand);
+ deepStrictEqual(calls[0].args[1]?.abortSignal, controller.signal);
+});
+
test(`${variant}: default export should include all stream functions`, (_t) => {
deepStrictEqual(Object.keys(s3Default).sort(), [
"checksumStream",
diff --git a/packages/aws/sns.test.js b/packages/aws/sns.test.js
index bafaaeb..c845380 100644
--- a/packages/aws/sns.test.js
+++ b/packages/aws/sns.test.js
@@ -1,7 +1,7 @@
import { deepStrictEqual } from "node:assert";
import test from "node:test";
import { PublishBatchCommand, SNSClient } from "@aws-sdk/client-sns";
-import {
+import snsDefault, {
awsSNSPublishMessageStream,
awsSNSSetClient,
} from "@datastream/aws/sns";
@@ -62,3 +62,10 @@ test(`${variant}: awsSNSPublishMessageStream should handle empty input`, async (
deepStrictEqual(result, {});
});
+
+test(`${variant}: default export should include all stream functions`, (_t) => {
+ deepStrictEqual(Object.keys(snsDefault).sort(), [
+ "publishMessageStream",
+ "setClient",
+ ]);
+});
diff --git a/packages/aws/sqs.d.ts b/packages/aws/sqs.d.ts
index 79dbedd..1f47400 100644
--- a/packages/aws/sqs.d.ts
+++ b/packages/aws/sqs.d.ts
@@ -8,6 +8,8 @@ export function awsSQSReceiveMessageStream(
options: {
client?: unknown;
QueueUrl?: string;
+ pollingActive?: boolean;
+ pollingDelay?: number;
[key: string]: unknown;
},
streamOptions?: StreamOptions,
diff --git a/packages/aws/sqs.js b/packages/aws/sqs.js
index deb8bcb..2b623ea 100644
--- a/packages/aws/sqs.js
+++ b/packages/aws/sqs.js
@@ -16,21 +16,26 @@ export const awsSQSSetClient = (sqsClient) => {
export const awsSQSReceiveMessageStream = async (
options,
- _streamOptions = {},
+ streamOptions = {},
) => {
- // TODO needs option to keep polling or not
+ const { pollingActive, pollingDelay = 1000, ...sqsOptions } = options;
async function* command(options) {
let expectMore = true;
while (expectMore) {
- const response = await client.send(new ReceiveMessageCommand(options));
+ const response = await client.send(new ReceiveMessageCommand(options), {
+ abortSignal: streamOptions.signal,
+ });
const messages = response.Messages ?? [];
for (const item of messages) {
yield item;
}
- expectMore = messages.length;
+ expectMore = pollingActive || messages.length > 0;
+ if (pollingActive && messages.length === 0 && pollingDelay > 0) {
+ await new Promise((resolve) => setTimeout(resolve, pollingDelay));
+ }
}
}
- return command(options);
+ return command(sqsOptions);
};
export const awsSQSDeleteMessageStream = (options, streamOptions = {}) => {
diff --git a/packages/aws/sqs.test.js b/packages/aws/sqs.test.js
index 175f7ce..de05ba7 100644
--- a/packages/aws/sqs.test.js
+++ b/packages/aws/sqs.test.js
@@ -6,7 +6,7 @@ import {
SendMessageBatchCommand,
SQSClient,
} from "@aws-sdk/client-sqs";
-import {
+import sqsDefault, {
awsSQSDeleteMessageStream,
awsSQSReceiveMessageStream,
awsSQSSendMessageStream,
@@ -61,6 +61,85 @@ test(`${variant}: awsSQSReceiveMessageStream should handle empty queue (Messages
deepStrictEqual(output, []);
});
+test(`${variant}: awsSQSReceiveMessageStream should keep polling with pollingActive option`, async (_t) => {
+ const client = mockClient(SQSClient);
+ awsSQSSetClient(client);
+
+ client
+ .on(ReceiveMessageCommand)
+ .resolvesOnce({ Messages: [{ id: "a" }] })
+ .resolvesOnce({ Messages: [] })
+ .resolvesOnce({ Messages: [{ id: "b" }] })
+ .resolves({ Messages: [] });
+
+ const options = { pollingActive: true, pollingDelay: 0 };
+ const stream = await awsSQSReceiveMessageStream(options);
+
+ // Collect first 2 items manually since pollingActive means infinite generator
+ const output = [];
+ for await (const item of stream) {
+ output.push(item);
+ if (output.length >= 2) break;
+ }
+
+ deepStrictEqual(output, [{ id: "a" }, { id: "b" }]);
+});
+
+test(`${variant}: awsSQSReceiveMessageStream should delay polling when pollingActive and queue is empty`, async (t) => {
+ t.mock.timers.enable({ apis: ["setTimeout"] });
+
+ const client = mockClient(SQSClient);
+ awsSQSSetClient(client);
+
+ client
+ .on(ReceiveMessageCommand)
+ .resolvesOnce({ Messages: [] })
+ .resolvesOnce({ Messages: [{ id: "a" }] })
+ .resolves({ Messages: [] });
+
+ const options = { pollingActive: true, pollingDelay: 1000 };
+ const stream = await awsSQSReceiveMessageStream(options);
+
+ const output = [];
+ const consuming = (async () => {
+ for await (const item of stream) {
+ output.push(item);
+ if (output.length >= 1) break;
+ }
+ })();
+
+ // Allow microtasks to settle so generator reaches setTimeout
+ await new Promise((resolve) => setImmediate(resolve));
+ // Advance mock timer past pollingDelay
+ t.mock.timers.tick(1000);
+
+ await consuming;
+
+ deepStrictEqual(output, [{ id: "a" }]);
+});
+
+test(`${variant}: awsSQSReceiveMessageStream should not delay polling when messages are returned`, async (_t) => {
+ const client = mockClient(SQSClient);
+ awsSQSSetClient(client);
+
+ client
+ .on(ReceiveMessageCommand)
+ .resolvesOnce({ Messages: [{ id: "a" }] })
+ .resolvesOnce({ Messages: [{ id: "b" }] })
+ .resolves({ Messages: [] });
+
+ const options = { pollingActive: true, pollingDelay: 1000 };
+ const stream = await awsSQSReceiveMessageStream(options);
+
+ const output = [];
+ for await (const item of stream) {
+ output.push(item);
+ if (output.length >= 2) break;
+ }
+
+ deepStrictEqual(output, [{ id: "a" }, { id: "b" }]);
+});
+
test(`${variant}: awsSQSDeleteMessageStream should delete chunk`, async (_t) => {
const client = mockClient(SQSClient);
awsSQSSetClient(client);
@@ -152,3 +231,12 @@ test(`${variant}: awsSQSSendMessageStream should handle empty input`, async (_t)
deepStrictEqual(result, {});
});
+
+test(`${variant}: default export should include all stream functions`, (_t) => {
+ deepStrictEqual(Object.keys(sqsDefault).sort(), [
+ "deleteMessageStream",
+ "receiveMessageStream",
+ "sendMessageStream",
+ "setClient",
+ ]);
+});
diff --git a/packages/base64/package.json b/packages/base64/package.json
index 9c716f8..b767fe0 100644
--- a/packages/base64/package.json
+++ b/packages/base64/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/base64",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "Base64 encoding and decoding transform streams",
"type": "module",
"engines": {
@@ -60,6 +60,6 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
}
}
diff --git a/packages/charset/detect.js b/packages/charset/detect.js
index 1ec4572..92793f0 100644
--- a/packages/charset/detect.js
+++ b/packages/charset/detect.js
@@ -3,37 +3,38 @@
import { createPassThroughStream } from "@datastream/core";
import detect from "charset-detector";
-const charsets = {
- "UTF-8": 0,
- "UTF-16BE": 0,
- "UTF-16LE": 0,
- "UTF-32BE": 0,
- "UTF-32LE": 0,
- Shift_JIS: 0,
- "ISO-2022-JP": 0,
- "ISO-2022-CN": 0,
- "ISO-2022-KR": 0,
- GB18030: 0,
- "EUC-JP": 0,
- "EUC-KR": 0,
- Big5: 0,
- "ISO-8859-1": 0,
- "ISO-8859-2": 0,
- "ISO-8859-5": 0,
- "ISO-8859-6": 0,
- "ISO-8859-7": 0,
- "ISO-8859-8-I": 0,
- "ISO-8859-8": 0,
- "windows-1251": 0,
- "windows-1256": 0,
- "windows-1252": 0,
- "windows-1254": 0,
- "windows-1250": 0,
- "KOIR8-R": 0,
- "ISO-8859-9": 0,
-};
+const charsetKeys = [
+ "UTF-8",
+ "UTF-16BE",
+ "UTF-16LE",
+ "UTF-32BE",
+ "UTF-32LE",
+ "Shift_JIS",
+ "ISO-2022-JP",
+ "ISO-2022-CN",
+ "ISO-2022-KR",
+ "GB18030",
+ "EUC-JP",
+ "EUC-KR",
+ "Big5",
+ "ISO-8859-1",
+ "ISO-8859-2",
+ "ISO-8859-5",
+ "ISO-8859-6",
+ "ISO-8859-7",
+ "ISO-8859-8-I",
+ "ISO-8859-8",
+ "windows-1251",
+ "windows-1256",
+ "windows-1252",
+ "windows-1254",
+ "windows-1250",
+ "KOIR8-R",
+ "ISO-8859-9",
+];
export const charsetDetectStream = ({ resultKey } = {}, streamOptions = {}) => {
+ const charsets = Object.fromEntries(charsetKeys.map((k) => [k, 0]));
const passThrough = (chunk) => {
const matches = detect(chunk);
if (matches.length) {
diff --git a/packages/charset/index.fuzz.js b/packages/charset/index.fuzz.js
new file mode 100644
index 0000000..76a4cef
--- /dev/null
+++ b/packages/charset/index.fuzz.js
@@ -0,0 +1,190 @@
+import test from "node:test";
+import {
+ charsetDecodeStream,
+ charsetDetectStream,
+ charsetEncodeStream,
+} from "@datastream/charset";
+import {
+ createReadableStream,
+ pipejoin,
+ pipeline,
+ streamToArray,
+ streamToString,
+} from "@datastream/core";
+import fc from "fast-check";
+
+const catchError = (input, e) => {
+ const expectedErrors = [];
+ if (expectedErrors.includes(e.message)) {
+ return;
+ }
+ console.error(input, e);
+ throw e;
+};
+
+const supportedCharsets = [
+ "UTF-8",
+ "UTF-16LE",
+ "UTF-16BE",
+ "ISO-8859-1",
+ "ISO-8859-2",
+ "ISO-8859-8-I",
+ "windows-1251",
+ "windows-1252",
+ "windows-1256",
+ "Shift_JIS",
+ "EUC-JP",
+ "EUC-KR",
+ "Big5",
+ "GB18030",
+];
+
+// *** charsetDetectStream *** //
+test("fuzz charsetDetectStream w/ random buffers", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(fc.uint8Array({ minLength: 1, maxLength: 256 }), {
+ minLength: 1,
+ }),
+ async (input) => {
+ try {
+ const buffers = input.map((arr) => Buffer.from(arr));
+ const streams = [
+ createReadableStream(buffers),
+ charsetDetectStream(),
+ ];
+ await pipeline(streams);
+ streams[1].result();
+ } catch (e) {
+ catchError(input, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** charsetEncodeStream *** //
+test("fuzz charsetEncodeStream w/ string input and charset", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(fc.string(), { minLength: 1 }),
+ fc.constantFrom(...supportedCharsets),
+ async (input, charset) => {
+ try {
+ const streams = [
+ createReadableStream(input),
+ charsetEncodeStream({ charset }),
+ ];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError({ input, charset }, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** charsetDecodeStream *** //
+test("fuzz charsetDecodeStream w/ buffer input and charset", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(fc.uint8Array({ minLength: 1, maxLength: 256 }), {
+ minLength: 1,
+ }),
+ fc.constantFrom(...supportedCharsets),
+ async (input, charset) => {
+ try {
+ const buffers = input.map((arr) => Buffer.from(arr));
+ const streams = [
+ createReadableStream(buffers),
+ charsetDecodeStream({ charset }),
+ ];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError({ input, charset }, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** roundtrip encode -> decode *** //
+test("fuzz charset roundtrip encode -> decode w/ UTF-8", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.string({ minLength: 1, maxLength: 500 }),
+ async (input) => {
+ try {
+ const encodeStreams = [
+ createReadableStream(input),
+ charsetEncodeStream({ charset: "UTF-8" }),
+ ];
+ const encoded = await streamToArray(pipejoin(encodeStreams));
+
+ const decodeStreams = [
+ createReadableStream(encoded),
+ charsetDecodeStream({ charset: "UTF-8" }),
+ ];
+ const decoded = await streamToString(pipejoin(decodeStreams));
+
+ if (decoded !== input) {
+ throw new Error(
+ `Roundtrip failed: input=${JSON.stringify(input)}, decoded=${JSON.stringify(decoded)}`,
+ );
+ }
+ } catch (e) {
+ catchError(input, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** charsetEncodeStream w/ unsupported charset fallback *** //
+test("fuzz charsetEncodeStream w/ random charset string", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(fc.string(), { minLength: 1 }),
+ fc.string({ minLength: 1, maxLength: 20 }),
+ async (input, charset) => {
+ try {
+ const streams = [
+ createReadableStream(input),
+ charsetEncodeStream({ charset }),
+ ];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError({ input, charset }, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
diff --git a/packages/charset/index.test.js b/packages/charset/index.test.js
index bf6efc8..da29d78 100644
--- a/packages/charset/index.test.js
+++ b/packages/charset/index.test.js
@@ -311,3 +311,24 @@ test(`${variant}: charsetDecodeStream should handle empty chunks`, async (_t) =>
deepStrictEqual(output, "test");
});
+
+// *** charsetDetectStream concurrent isolation regression *** //
+test(`${variant}: charsetDetectStream instances should not share state`, async (_t) => {
+ const input1 = [Buffer.from("Hello World")];
+ const input2 = [Buffer.from("Bonjour le monde")];
+
+ const streams1 = [createReadableStream(input1), charsetDetectStream()];
+ const streams2 = [createReadableStream(input2), charsetDetectStream()];
+
+ await Promise.all([pipeline(streams1), pipeline(streams2)]);
+
+ const result1 = streams1[1].result();
+ const result2 = streams2[1].result();
+
+ // Each stream should have independent results
+ strictEqual(result1.key, "charset");
+ strictEqual(result2.key, "charset");
+ // Confidence should reflect only the data from each respective stream
+ strictEqual(typeof result1.value.confidence, "number");
+ strictEqual(typeof result2.value.confidence, "number");
+});
diff --git a/packages/charset/package.json b/packages/charset/package.json
index 18816b2..d8449e5 100644
--- a/packages/charset/package.json
+++ b/packages/charset/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/charset",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "Character encoding detection, decoding, and conversion streams",
"type": "module",
"engines": {
@@ -108,7 +108,7 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6",
+ "@datastream/core": "0.2.0",
"charset-detector": "0.0.2",
"iconv-lite": "0.7.2"
}
diff --git a/packages/compress/brotli.node.js b/packages/compress/brotli.node.js
index a884938..094db80 100644
--- a/packages/compress/brotli.node.js
+++ b/packages/compress/brotli.node.js
@@ -16,8 +16,31 @@ export const brotliCompressStream = ({ quality } = {}, streamOptions = {}) => {
},
});
};
-export const brotliDecompressStream = (params, streamOptions = {}) => {
- return createBrotliDecompress({ ...streamOptions, params });
+export const brotliDecompressStream = (options = {}, streamOptions = {}) => {
+ const { maxOutputSize, ...params } = options;
+ const zlibOptions = Object.keys(params).length
+ ? { ...streamOptions, params }
+ : streamOptions;
+ const stream = createBrotliDecompress(zlibOptions);
+ if (maxOutputSize != null) {
+ let outputSize = 0;
+ const originalPush = stream.push.bind(stream);
+ stream.push = (chunk) => {
+ if (chunk !== null) {
+ outputSize += chunk.length;
+ if (outputSize > maxOutputSize) {
+ stream.destroy(
+ new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ ),
+ );
+ return false;
+ }
+ }
+ return originalPush(chunk);
+ };
+ }
+ return stream;
};
export default {
diff --git a/packages/compress/brotli.web.js b/packages/compress/brotli.web.js
index 47f5aa6..16f17c5 100644
--- a/packages/compress/brotli.web.js
+++ b/packages/compress/brotli.web.js
@@ -25,14 +25,34 @@ export const brotliCompressStream = (options = {}, streamOptions = {}) => {
};
return createTransformStream(transform, flush, streamOptions);
};
-export const brotliDecompressStream = (_options = {}, streamOptions = {}) => {
+export const brotliDecompressStream = (options = {}, streamOptions = {}) => {
+ const { maxOutputSize } = options;
const engine = new DecompressStream();
+ let outputSize = 0;
const transform = (chunk, enqueue) => {
- enqueue(engine.decompress(chunk));
+ const result = engine.decompress(chunk);
+ if (maxOutputSize != null) {
+ outputSize += result.byteLength;
+ if (outputSize > maxOutputSize) {
+ throw new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ );
+ }
+ }
+ enqueue(result);
};
const flush = (enqueue) => {
if (engine.result() === BrotliStreamResult.NeedsMoreInput) {
- enqueue(engine.decompress(undefined, 100));
+ const result = engine.decompress(undefined, 100);
+ if (maxOutputSize != null) {
+ outputSize += result.byteLength;
+ if (outputSize > maxOutputSize) {
+ throw new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ );
+ }
+ }
+ enqueue(result);
}
};
return createTransformStream(transform, flush, streamOptions);
diff --git a/packages/compress/deflate.node.js b/packages/compress/deflate.node.js
index 5cd8dcd..810cb12 100644
--- a/packages/compress/deflate.node.js
+++ b/packages/compress/deflate.node.js
@@ -2,14 +2,33 @@
// SPDX-License-Identifier: MIT
import { createDeflate, createInflate } from "node:zlib";
-// TODO benchmark against `fflate`
// quality -1 - 9
export const deflateCompressStream = (options = {}, _streamOptions = {}) => {
const { quality, ...rest } = options;
return createDeflate({ ...rest, level: rest.level ?? quality });
};
-export const deflateDecompressStream = (_options = {}, streamOptions = {}) => {
- return createInflate(streamOptions);
+export const deflateDecompressStream = (options = {}, streamOptions = {}) => {
+ const { maxOutputSize } = options;
+ const stream = createInflate(streamOptions);
+ if (maxOutputSize != null) {
+ let outputSize = 0;
+ const originalPush = stream.push.bind(stream);
+ stream.push = (chunk) => {
+ if (chunk !== null) {
+ outputSize += chunk.length;
+ if (outputSize > maxOutputSize) {
+ stream.destroy(
+ new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ ),
+ );
+ return false;
+ }
+ }
+ return originalPush(chunk);
+ };
+ }
+ return stream;
};
export default {
diff --git a/packages/compress/deflate.web.js b/packages/compress/deflate.web.js
index 4ba9107..d770280 100644
--- a/packages/compress/deflate.web.js
+++ b/packages/compress/deflate.web.js
@@ -9,8 +9,31 @@
export const deflateCompressStream = (_options = {}, _streamOptions = {}) => {
return new CompressionStream("deflate");
};
-export const deflateDecompressStream = (_options = {}, _streamOptions = {}) => {
- return new DecompressionStream("deflate");
+export const deflateDecompressStream = (options = {}, _streamOptions = {}) => {
+ const { maxOutputSize } = options;
+ const decompressor = new DecompressionStream("deflate");
+ if (maxOutputSize != null) {
+ let outputSize = 0;
+ const limiter = new TransformStream({
+ transform(chunk, controller) {
+ outputSize += chunk.byteLength;
+ if (outputSize > maxOutputSize) {
+ controller.error(
+ new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ ),
+ );
+ return;
+ }
+ controller.enqueue(chunk);
+ },
+ });
+ return {
+ readable: decompressor.readable.pipeThrough(limiter),
+ writable: decompressor.writable,
+ };
+ }
+ return decompressor;
};
export default {
diff --git a/packages/compress/gzip.node.js b/packages/compress/gzip.node.js
index 4c3bae3..566e57a 100644
--- a/packages/compress/gzip.node.js
+++ b/packages/compress/gzip.node.js
@@ -6,8 +6,28 @@ import { createGunzip, createGzip } from "node:zlib";
export const gzipCompressStream = ({ quality } = {}, streamOptions = {}) => {
return createGzip({ ...streamOptions, level: quality });
};
-export const gzipDecompressStream = (_options = {}, streamOptions = {}) => {
- return createGunzip(streamOptions);
+export const gzipDecompressStream = (options = {}, streamOptions = {}) => {
+ const { maxOutputSize } = options;
+ const stream = createGunzip(streamOptions);
+ if (maxOutputSize != null) {
+ let outputSize = 0;
+ const originalPush = stream.push.bind(stream);
+ stream.push = (chunk) => {
+ if (chunk !== null) {
+ outputSize += chunk.length;
+ if (outputSize > maxOutputSize) {
+ stream.destroy(
+ new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ ),
+ );
+ return false;
+ }
+ }
+ return originalPush(chunk);
+ };
+ }
+ return stream;
};
export default {
diff --git a/packages/compress/gzip.web.js b/packages/compress/gzip.web.js
index 54e9937..736d3b4 100644
--- a/packages/compress/gzip.web.js
+++ b/packages/compress/gzip.web.js
@@ -9,8 +9,31 @@
export const gzipCompressStream = (_options = {}, _streamOptions = {}) => {
return new CompressionStream("gzip");
};
-export const gzipDecompressStream = (_options = {}, _streamOptions = {}) => {
- return new DecompressionStream("gzip");
+export const gzipDecompressStream = (options = {}, _streamOptions = {}) => {
+ const { maxOutputSize } = options;
+ const decompressor = new DecompressionStream("gzip");
+ if (maxOutputSize != null) {
+ let outputSize = 0;
+ const limiter = new TransformStream({
+ transform(chunk, controller) {
+ outputSize += chunk.byteLength;
+ if (outputSize > maxOutputSize) {
+ controller.error(
+ new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ ),
+ );
+ return;
+ }
+ controller.enqueue(chunk);
+ },
+ });
+ return {
+ readable: decompressor.readable.pipeThrough(limiter),
+ writable: decompressor.writable,
+ };
+ }
+ return decompressor;
};
export default {
diff --git a/packages/compress/index.test.js b/packages/compress/index.test.js
index f3878f9..466c5c5 100644
--- a/packages/compress/index.test.js
+++ b/packages/compress/index.test.js
@@ -1,4 +1,4 @@
-import { strictEqual } from "node:assert";
+import { ok, strictEqual } from "node:assert";
import test from "node:test";
import {
brotliCompressSync,
@@ -22,6 +22,7 @@ import {
import {
createReadableStream,
pipejoin,
+ pipeline,
streamToBuffer,
streamToString,
} from "@datastream/core";
@@ -102,3 +103,55 @@ test(`${variant}: deflateDecompressStream should decompress`, async (_t) => {
const output = await streamToString(pipejoin(streams));
strictEqual(output, compressibleBody);
});
+
+// *** decompression bomb protection *** //
+if (variant === "node") {
+ test(`${variant}: gzipDecompressStream should enforce maxOutputSize`, async (_t) => {
+ const input = gzipSync(compressibleBody);
+ const streams = [
+ createReadableStream(input),
+ gzipDecompressStream({ maxOutputSize: 100 }),
+ ];
+ try {
+ await pipeline(streams);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxOutputSize"));
+ }
+ });
+
+ test(`${variant}: deflateDecompressStream should enforce maxOutputSize`, async (_t) => {
+ const input = deflateSync(compressibleBody);
+ const streams = [
+ createReadableStream(input),
+ deflateDecompressStream({ maxOutputSize: 100 }),
+ ];
+ try {
+ await pipeline(streams);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxOutputSize"));
+ }
+ });
+
+ test(`${variant}: brotliDecompressStream should enforce maxOutputSize`, async (_t) => {
+ const input = brotliCompressSync(compressibleBody);
+ const streams = [
+ createReadableStream(input),
+ brotliDecompressStream({ maxOutputSize: 100 }),
+ ];
+ try {
+ await pipeline(streams);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxOutputSize"));
+ }
+ });
+
+ test(`${variant}: gzipDecompressStream should work without maxOutputSize`, async (_t) => {
+ const input = gzipSync(compressibleBody);
+ const streams = [createReadableStream(input), gzipDecompressStream()];
+ const output = await streamToString(pipejoin(streams));
+ strictEqual(output, compressibleBody);
+ });
+}
diff --git a/packages/compress/index.tst.ts b/packages/compress/index.tst.ts
index 8c36e8d..eebe39d 100644
--- a/packages/compress/index.tst.ts
+++ b/packages/compress/index.tst.ts
@@ -57,13 +57,17 @@ describe("zstd", () => {
describe("protobuf", () => {
test("protobufSerializeStream accepts Type", () => {
expect(
- protobufSerializeStream({ Type: {} as any }),
+ protobufSerializeStream({
+ Type: {} as import("@datastream/compress/protobuf").ProtobufType,
+ }),
).type.not.toBeAssignableTo();
});
test("protobufDeserializeStream accepts Type", () => {
expect(
- protobufDeserializeStream({ Type: {} as any }),
+ protobufDeserializeStream({
+ Type: {} as import("@datastream/compress/protobuf").ProtobufType,
+ }),
).type.not.toBeAssignableTo();
});
});
diff --git a/packages/compress/package.json b/packages/compress/package.json
index 3f92c04..50e2693 100644
--- a/packages/compress/package.json
+++ b/packages/compress/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/compress",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "Compression and decompression streams for gzip, deflate, brotli, and zstd",
"type": "module",
"engines": {
@@ -140,12 +140,12 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
},
"peerDependencies": {
- "brotli-wasm": "3.0.1",
- "protobufjs": "8.0.0",
- "zstd-codec": "0.1.5"
+ "brotli-wasm": "^3.0.0",
+ "protobufjs": "^8.0.0",
+ "zstd-codec": "^0.1.0"
},
"peerDependenciesMeta": {
"brotli-wasm": {
diff --git a/packages/compress/protobuf.node.js b/packages/compress/protobuf.node.js
index f5cd826..eb743ef 100644
--- a/packages/compress/protobuf.node.js
+++ b/packages/compress/protobuf.node.js
@@ -10,11 +10,22 @@ export const protobufSerializeStream = ({ Type } = {}, streamOptions = {}) => {
};
export const protobufDeserializeStream = (
- { Type } = {},
+ { Type, maxOutputSize } = {},
streamOptions = {},
) => {
+ let outputSize = 0;
const transform = (chunk, enqueue) => {
- enqueue(Type.decode(chunk));
+ const decoded = Type.decode(chunk);
+ if (maxOutputSize != null) {
+ const encoded = JSON.stringify(decoded);
+ outputSize += encoded?.length ?? 0;
+ if (outputSize > maxOutputSize) {
+ throw new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ );
+ }
+ }
+ enqueue(decoded);
};
return createTransformStream(transform, streamOptions);
};
diff --git a/packages/compress/protobuf.web.js b/packages/compress/protobuf.web.js
index f5cd826..eb743ef 100644
--- a/packages/compress/protobuf.web.js
+++ b/packages/compress/protobuf.web.js
@@ -10,11 +10,22 @@ export const protobufSerializeStream = ({ Type } = {}, streamOptions = {}) => {
};
export const protobufDeserializeStream = (
- { Type } = {},
+ { Type, maxOutputSize } = {},
streamOptions = {},
) => {
+ let outputSize = 0;
const transform = (chunk, enqueue) => {
- enqueue(Type.decode(chunk));
+ const decoded = Type.decode(chunk);
+ if (maxOutputSize != null) {
+ const encoded = JSON.stringify(decoded);
+ outputSize += encoded?.length ?? 0;
+ if (outputSize > maxOutputSize) {
+ throw new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ );
+ }
+ }
+ enqueue(decoded);
};
return createTransformStream(transform, streamOptions);
};
diff --git a/packages/compress/zstd.node.js b/packages/compress/zstd.node.js
index e2814e3..1899c16 100644
--- a/packages/compress/zstd.node.js
+++ b/packages/compress/zstd.node.js
@@ -13,7 +13,27 @@ export const zstdCompressStream = (options = {}, _streamOptions = {}) => {
});
};
export const zstdDecompressStream = (options = {}, _streamOptions = {}) => {
- return createZstdDecompress(options);
+ const { maxOutputSize, ...rest } = options;
+ const stream = createZstdDecompress(rest);
+ if (maxOutputSize != null) {
+ let outputSize = 0;
+ const originalPush = stream.push.bind(stream);
+ stream.push = (chunk) => {
+ if (chunk !== null) {
+ outputSize += chunk.length;
+ if (outputSize > maxOutputSize) {
+ stream.destroy(
+ new Error(
+ `Decompression output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ ),
+ );
+ return false;
+ }
+ }
+ return originalPush(chunk);
+ };
+ }
+ return stream;
};
export default {
diff --git a/packages/core/index.d.ts b/packages/core/index.d.ts
index 01e0852..62f189a 100644
--- a/packages/core/index.d.ts
+++ b/packages/core/index.d.ts
@@ -1,5 +1,7 @@
// Copyright 2026 will Farrell, and datastream contributors.
// SPDX-License-Identifier: MIT
+import type { Readable, Transform, Writable } from "node:stream";
+
// Core types used across all packages
export interface StreamOptions {
highWaterMark?: number;
@@ -13,28 +15,63 @@ export interface StreamResult {
value: T;
}
-export interface ResultStream<_S, T = unknown> {
+export interface ResultStream {
result: () => StreamResult | Promise>;
}
+export type DatastreamReadable = (ReadableStream | Readable) & {
+ push?: (chunk: T | null) => void;
+};
+export type DatastreamTransform =
+ | TransformStream
+ | Transform;
+export type DatastreamWritable = (WritableStream | Writable) &
+ Partial;
+export type DatastreamPassThrough = (
+ | TransformStream
+ | Transform
+) &
+ Partial;
+export type DatastreamStream =
+ | DatastreamReadable
+ | DatastreamTransform
+ | DatastreamWritable
+ | DatastreamPassThrough;
+
// Pipeline & utilities
export function pipeline(
- streams: unknown[],
+ streams: DatastreamStream[],
streamOptions?: StreamOptions,
): Promise>;
export function pipejoin(
- streams: unknown[],
+ streams: DatastreamStream[],
onError?: (error: Error) => void,
-): unknown;
-export function result(streams: unknown[]): Promise>;
+): DatastreamStream;
+export function result(
+ streams: DatastreamStream[],
+): Promise>;
// Stream converters
-export function streamToArray(stream: unknown): Promise;
+export interface StreamCollectorOptions {
+ maxBufferSize?: number;
+}
+
+export function streamToArray(
+ stream: DatastreamReadable,
+ options?: StreamCollectorOptions,
+): Promise;
export function streamToObject>(
- stream: unknown,
+ stream: DatastreamReadable,
+ options?: StreamCollectorOptions,
): Promise;
-export function streamToString(stream: unknown): Promise;
-export function streamToBuffer(stream: unknown): Promise;
+export function streamToString(
+ stream: DatastreamReadable,
+ options?: StreamCollectorOptions,
+): Promise;
+export function streamToBuffer(
+ stream: DatastreamReadable,
+ options?: StreamCollectorOptions,
+): Promise;
// Type guards
export function isReadable(stream: unknown): stream is ReadableStream;
@@ -47,21 +84,21 @@ export function makeOptions(options?: StreamOptions): Record;
export function createReadableStream(
input?: string | T[] | Iterable | AsyncIterable,
streamOptions?: StreamOptions,
-): unknown;
+): DatastreamReadable;
export function createReadableStreamFromString(
input: string,
streamOptions?: StreamOptions,
-): unknown;
+): DatastreamReadable;
export function createReadableStreamFromArrayBuffer(
input: ArrayBuffer | ArrayBufferLike,
streamOptions?: StreamOptions,
-): unknown;
+): DatastreamReadable;
export function createPassThroughStream(
passThrough?: ((chunk: T) => void | Promise) | null,
flush?: (() => void | Promise) | StreamOptions,
streamOptions?: StreamOptions,
-): unknown & ResultStream;
+): DatastreamPassThrough & ResultStream;
export function createTransformStream(
transform?:
@@ -74,13 +111,13 @@ export function createTransformStream(
| ((enqueue: (chunk: O, encoding?: string) => void) => void | Promise)
| StreamOptions,
streamOptions?: StreamOptions,
-): unknown;
+): DatastreamTransform;
export function createWritableStream(
write?: ((chunk: T) => void | Promise) | null,
close?: (() => void | Promise) | StreamOptions,
streamOptions?: StreamOptions,
-): unknown;
+): DatastreamWritable;
// Backpressure (Node.js only)
export function backpressureGauge(streams: Record): Record<
diff --git a/packages/core/index.node.js b/packages/core/index.node.js
index c5435ac..7d57e25 100644
--- a/packages/core/index.node.js
+++ b/packages/core/index.node.js
@@ -2,7 +2,12 @@
// SPDX-License-Identifier: MIT
import { Readable, Transform, Writable } from "node:stream";
import { pipeline as pipelinePromise } from "node:stream/promises";
-import { setTimeout } from "node:timers/promises";
+
+// Node.js streams interpret push(null) as EOF.
+// Use a sentinel so null values flow through object-mode streams.
+const NULL_SENTINEL = Symbol.for("@datastream/null");
+const toSafe = (v) => (v === null ? NULL_SENTINEL : v);
+const fromSafe = (v) => (v === NULL_SENTINEL ? null : v);
export const pipeline = async (streams, streamOptions = {}) => {
for (let idx = 0, l = streams.length; idx < l; idx++) {
@@ -78,12 +83,24 @@ export const backpressureGauge = (streams) => {
return metrics;
};
-export const streamToArray = (stream) => {
+export const streamToArray = (stream, { maxBufferSize } = {}) => {
if (typeof stream.on === "function") {
return new Promise((resolve, reject) => {
const value = [];
+ let size = 0;
stream.on("data", (chunk) => {
- value.push(chunk);
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 1;
+ if (size > maxBufferSize) {
+ stream.destroy(
+ new Error(
+ `streamToArray buffer exceeds maxBufferSize (${maxBufferSize})`,
+ ),
+ );
+ return;
+ }
+ }
+ value.push(fromSafe(chunk));
});
stream.on("end", () => {
resolve(value);
@@ -93,63 +110,127 @@ export const streamToArray = (stream) => {
}
return (async () => {
const value = [];
+ let size = 0;
for await (const chunk of stream) {
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 1;
+ if (size > maxBufferSize) {
+ throw new Error(
+ `streamToArray buffer exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ }
value.push(chunk);
}
return value;
})();
};
-export const streamToObject = (stream) => {
+export const streamToObject = (stream, { maxBufferSize } = {}) => {
if (typeof stream.on === "function") {
return new Promise((resolve, reject) => {
- const value = {};
+ const value = Object.create(null);
+ let size = 0;
stream.on("data", (chunk) => {
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 1;
+ if (size > maxBufferSize) {
+ stream.destroy(
+ new Error(
+ `streamToObject buffer exceeds maxBufferSize (${maxBufferSize})`,
+ ),
+ );
+ return;
+ }
+ }
Object.assign(value, chunk);
});
stream.on("end", () => {
- resolve(value);
+ resolve({ ...value });
});
stream.on("error", reject);
});
}
return (async () => {
- const value = {};
+ const value = Object.create(null);
+ let size = 0;
for await (const chunk of stream) {
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 1;
+ if (size > maxBufferSize) {
+ throw new Error(
+ `streamToObject buffer exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ }
Object.assign(value, chunk);
}
- return value;
+ return { ...value };
})();
};
-export const streamToString = (stream) => {
+export const streamToString = (stream, { maxBufferSize } = {}) => {
if (typeof stream.on === "function") {
return new Promise((resolve, reject) => {
- let value = "";
+ const chunks = [];
+ let size = 0;
stream.on("data", (chunk) => {
- value += chunk;
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 0;
+ if (size > maxBufferSize) {
+ stream.destroy(
+ new Error(
+ `streamToString buffer exceeds maxBufferSize (${maxBufferSize})`,
+ ),
+ );
+ return;
+ }
+ }
+ chunks.push(chunk);
});
stream.on("end", () => {
- resolve(value);
+ resolve(chunks.join(""));
});
stream.on("error", reject);
});
}
return (async () => {
- let value = "";
+ const chunks = [];
+ let size = 0;
for await (const chunk of stream) {
- value += chunk;
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 0;
+ if (size > maxBufferSize) {
+ throw new Error(
+ `streamToString buffer exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ }
+ chunks.push(chunk);
}
- return value;
+ return chunks.join("");
})();
};
-export const streamToBuffer = (stream) => {
+export const streamToBuffer = (stream, { maxBufferSize } = {}) => {
if (typeof stream.on === "function") {
return new Promise((resolve, reject) => {
const value = [];
+ let size = 0;
stream.on("data", (chunk) => {
- value.push(Buffer.from(chunk));
+ const buf = Buffer.from(chunk);
+ if (maxBufferSize != null) {
+ size += buf.length;
+ if (size > maxBufferSize) {
+ stream.destroy(
+ new Error(
+ `streamToBuffer buffer exceeds maxBufferSize (${maxBufferSize})`,
+ ),
+ );
+ return;
+ }
+ }
+ value.push(buf);
});
stream.on("end", () => {
resolve(Buffer.concat(value));
@@ -159,8 +240,18 @@ export const streamToBuffer = (stream) => {
}
return (async () => {
const value = [];
+ let size = 0;
for await (const chunk of stream) {
- value.push(Buffer.from(chunk));
+ const buf = Buffer.from(chunk);
+ if (maxBufferSize != null) {
+ size += buf.length;
+ if (size > maxBufferSize) {
+ throw new Error(
+ `streamToBuffer buffer exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ }
+ value.push(buf);
}
return Buffer.concat(value);
})();
@@ -195,7 +286,27 @@ export const makeOptions = ({
};
};
-export const createReadableStream = (input = "", streamOptions = {}) => {
+export const createReadableStream = (input, streamOptions = {}) => {
+ if (input === undefined) {
+ const maxQueueSize = streamOptions.highWaterMark ?? 1024;
+ let queueSize = 0;
+ const stream = new Readable({
+ objectMode: streamOptions.objectMode ?? true,
+ highWaterMark: streamOptions.highWaterMark,
+ read() {},
+ });
+ const nativePush = Readable.prototype.push.bind(stream);
+ stream.push = (chunk) => {
+ if (chunk !== null && queueSize >= maxQueueSize) {
+ throw new Error(
+ `createReadableStream queue size (${queueSize}) exceeds limit (${maxQueueSize})`,
+ );
+ }
+ if (chunk !== null) queueSize++;
+ return nativePush(chunk);
+ };
+ return stream;
+ }
// string doesn't chunk, and is slow
if (typeof input === "string") {
return createReadableStreamFromString(input, streamOptions);
@@ -203,12 +314,15 @@ export const createReadableStream = (input = "", streamOptions = {}) => {
if (typeof input === "object" && input.byteLength) {
return createReadableStreamFromArrayBuffer(input, streamOptions);
}
+ if (Array.isArray(input)) {
+ return Readable.from(input.map(toSafe), streamOptions);
+ }
return Readable.from(input, streamOptions);
};
export const createReadableStreamFromString = (input, streamOptions = {}) => {
function* iterator(input) {
- const size = streamOptions?.chunkSize ?? 16 * 1024;
+ const size = streamOptions?.chunkSize ?? 16_384; // 16KB
let position = 0;
const length = input.length;
while (position < length) {
@@ -224,7 +338,7 @@ export const createReadableStreamFromArrayBuffer = (
streamOptions = {},
) => {
function* iterator(input) {
- const size = streamOptions?.chunkSize ?? 16 * 1024;
+ const size = streamOptions?.chunkSize ?? 16_384; // 16KB
const bytes = new Uint8Array(input);
let position = 0;
const length = bytes.byteLength;
@@ -247,7 +361,7 @@ export const createPassThroughStream = (passThrough, flush, streamOptions) => {
...makeOptions(streamOptions),
transform(chunk, _encoding, callback) {
try {
- const result = passThrough(chunk);
+ const result = passThrough(fromSafe(chunk));
if (result != null && typeof result.then === "function") {
result.then(() => {
this.push(chunk);
@@ -290,7 +404,7 @@ export const createTransformStream = (transform, flush, streamOptions) => {
...makeOptions(streamOptions),
transform(chunk, _encoding, callback) {
try {
- const result = transform(chunk, enqueue);
+ const result = transform(fromSafe(chunk), enqueue);
if (result != null && typeof result.then === "function") {
result.then(() => callback(), callback);
} else {
@@ -318,7 +432,7 @@ export const createTransformStream = (transform, flush, streamOptions) => {
},
});
const enqueue = (chunk, encoding) => {
- stream.push(chunk, encoding);
+ stream.push(toSafe(chunk), encoding);
};
return stream;
};
@@ -333,7 +447,7 @@ export const createWritableStream = (write, final, streamOptions) => {
...makeOptions(streamOptions),
write(chunk, _encoding, callback) {
try {
- const result = write(chunk);
+ const result = write(fromSafe(chunk));
if (result != null && typeof result.then === "function") {
result.then(() => callback(), callback);
} else {
@@ -363,5 +477,21 @@ export const createWritableStream = (write, final, streamOptions) => {
};
export const timeout = (ms, { signal } = {}) => {
- return setTimeout(ms, { signal });
+ if (signal?.aborted) {
+ return Promise.reject(
+ new Error("Aborted", { cause: { code: "AbortError" } }),
+ );
+ }
+ return new Promise((resolve, reject) => {
+ const abortHandler = () => {
+ clearTimeout(timerId);
+ signal.removeEventListener("abort", abortHandler);
+ reject(new Error("Aborted", { cause: { code: "AbortError" } }));
+ };
+ if (signal) signal.addEventListener("abort", abortHandler);
+ const timerId = setTimeout(() => {
+ if (signal) signal.removeEventListener("abort", abortHandler);
+ resolve();
+ }, ms);
+ });
};
diff --git a/packages/core/index.test.js b/packages/core/index.test.js
index 42cc202..7cff41a 100644
--- a/packages/core/index.test.js
+++ b/packages/core/index.test.js
@@ -734,4 +734,85 @@ if (variant === "node") {
// signal: undefined
// })
// })
+
+ // *** timeout abort cleanup regression *** //
+ test(`${variant}: timeout should clear timer when aborted`, async (_t) => {
+ const controller = new AbortController();
+ const promise = timeout(60_000, { signal: controller.signal });
+ controller.abort();
+ try {
+ await promise;
+ throw new Error("Should have thrown");
+ } catch (e) {
+ strictEqual(e.message, "Aborted");
+ deepStrictEqual(e.cause, { code: "AbortError" });
+ }
+ });
+
+ test(`${variant}: timeout should reject immediately if signal already aborted`, async (_t) => {
+ const controller = new AbortController();
+ controller.abort();
+ try {
+ await timeout(60_000, { signal: controller.signal });
+ throw new Error("Should have thrown");
+ } catch (e) {
+ strictEqual(e.message, "Aborted");
+ }
+ });
+
+ // *** maxBufferSize *** //
+ test(`${variant}: streamToArray should throw when exceeding maxBufferSize`, async (_t) => {
+ const stream = createReadableStream(["aaa", "bbb", "ccc"]);
+ try {
+ await streamToArray(stream, { maxBufferSize: 6 });
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxBufferSize"));
+ }
+ });
+
+ test(`${variant}: streamToArray should not throw when within maxBufferSize`, async (_t) => {
+ const stream = createReadableStream(["aaa", "bbb"]);
+ const result = await streamToArray(stream, { maxBufferSize: 6 });
+ deepStrictEqual(result, ["aaa", "bbb"]);
+ });
+
+ test(`${variant}: streamToString should throw when exceeding maxBufferSize`, async (_t) => {
+ const stream = createReadableStream(["aaa", "bbb", "ccc"]);
+ try {
+ await streamToString(stream, { maxBufferSize: 6 });
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxBufferSize"));
+ }
+ });
+
+ test(`${variant}: streamToObject should throw when exceeding maxBufferSize`, async (_t) => {
+ const stream = createReadableStream([
+ { a: 1 },
+ { b: 2 },
+ { c: 3 },
+ { d: 4 },
+ ]);
+ try {
+ await streamToObject(stream, { maxBufferSize: 2 });
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxBufferSize"));
+ }
+ });
+
+ // *** createReadableStream queue limit regression *** //
+ test(`${variant}: createReadableStream should throw when queue exceeds limit`, async (_t) => {
+ const stream = createReadableStream(undefined, { highWaterMark: 3 });
+ stream.push("a");
+ stream.push("b");
+ stream.push("c");
+ try {
+ stream.push("d");
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("exceeds limit"));
+ }
+ });
}
diff --git a/packages/core/index.tst.ts b/packages/core/index.tst.ts
index d478abc..2c013bf 100644
--- a/packages/core/index.tst.ts
+++ b/packages/core/index.tst.ts
@@ -1,4 +1,12 @@
-import type { StreamOptions, StreamResult } from "@datastream/core";
+///
+///
+import type {
+ DatastreamReadable,
+ DatastreamTransform,
+ DatastreamWritable,
+ StreamOptions,
+ StreamResult,
+} from "@datastream/core";
import {
createReadableStream,
createTransformStream,
@@ -55,29 +63,38 @@ describe("result", () => {
describe("streamToArray", () => {
test("returns Promise of array", () => {
- expect(streamToArray({})).type.toBe>();
+ const stream = createReadableStream([1]);
+ expect(streamToArray(stream)).type.toBeAssignableTo>();
});
test("accepts generic type", () => {
- expect(streamToArray({})).type.toBe>();
+ const stream = createReadableStream(["a"]);
+ expect(streamToArray(stream)).type.toBeAssignableTo<
+ Promise
+ >();
});
});
describe("streamToObject", () => {
test("returns Promise of object", () => {
- expect(streamToObject({})).type.toBe>>();
+ const stream = createReadableStream();
+ expect(streamToObject(stream)).type.toBeAssignableTo<
+ Promise>
+ >();
});
});
describe("streamToString", () => {
test("returns Promise of string", () => {
- expect(streamToString({})).type.toBe>();
+ const stream = createReadableStream();
+ expect(streamToString(stream)).type.toBeAssignableTo>();
});
});
describe("streamToBuffer", () => {
test("returns Promise of Buffer", () => {
- expect(streamToBuffer({})).type.toBe>();
+ const stream = createReadableStream();
+ expect(streamToBuffer(stream)).type.toBeAssignableTo>();
});
});
@@ -111,15 +128,21 @@ describe("makeOptions", () => {
describe("createReadableStream", () => {
test("accepts string input", () => {
- expect(createReadableStream("hello")).type.not.toBeAssignableTo();
+ expect(createReadableStream("hello")).type.toBeAssignableTo<
+ DatastreamReadable
+ >();
});
test("accepts array input", () => {
- expect(createReadableStream([1, 2, 3])).type.not.toBeAssignableTo();
+ expect(createReadableStream([1, 2, 3])).type.toBeAssignableTo<
+ DatastreamReadable
+ >();
});
test("accepts no input", () => {
- expect(createReadableStream()).type.not.toBeAssignableTo();
+ expect(createReadableStream()).type.toBeAssignableTo<
+ DatastreamReadable
+ >();
});
});
@@ -129,19 +152,21 @@ describe("createTransformStream", () => {
createTransformStream((chunk: string, enqueue: (c: string) => void) => {
enqueue(chunk);
}),
- ).type.not.toBeAssignableTo();
+ ).type.toBeAssignableTo>();
});
});
describe("createWritableStream", () => {
test("accepts write function", () => {
- expect(
- createWritableStream((chunk: unknown) => {}),
- ).type.not.toBeAssignableTo();
+ expect(createWritableStream((_chunk: unknown) => {})).type.toBeAssignableTo<
+ DatastreamWritable
+ >();
});
test("accepts no arguments", () => {
- expect(createWritableStream()).type.not.toBeAssignableTo();
+ expect(createWritableStream()).type.toBeAssignableTo<
+ DatastreamWritable
+ >();
});
});
diff --git a/packages/core/index.web.js b/packages/core/index.web.js
index 8490b57..b7650ef 100644
--- a/packages/core/index.web.js
+++ b/packages/core/index.web.js
@@ -39,28 +39,55 @@ export const result = async (streams) => {
return output;
};
-export const streamToArray = async (stream) => {
+export const streamToArray = async (stream, { maxBufferSize } = {}) => {
const value = [];
+ let size = 0;
for await (const chunk of stream) {
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 1;
+ if (size > maxBufferSize) {
+ throw new Error(
+ `streamToArray buffer exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ }
value.push(chunk);
}
return value;
};
-export const streamToObject = async (stream) => {
- const value = {};
+export const streamToObject = async (stream, { maxBufferSize } = {}) => {
+ const value = Object.create(null);
+ let size = 0;
for await (const chunk of stream) {
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 1;
+ if (size > maxBufferSize) {
+ throw new Error(
+ `streamToObject buffer exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ }
Object.assign(value, chunk);
}
- return value;
+ return { ...value };
};
-export const streamToString = async (stream) => {
- let value = "";
+export const streamToString = async (stream, { maxBufferSize } = {}) => {
+ const chunks = [];
+ let size = 0;
for await (const chunk of stream) {
- value += chunk;
+ if (maxBufferSize != null) {
+ size += chunk?.length ?? chunk?.byteLength ?? 0;
+ if (size > maxBufferSize) {
+ throw new Error(
+ `streamToString buffer exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ }
+ chunks.push(chunk);
}
- return value;
+ return chunks.join("");
};
export const isReadable = (stream) => {
@@ -92,7 +119,9 @@ export const makeOptions = ({
};
export const createReadableStream = (input, streamOptions = {}) => {
+ const maxQueueSize = streamOptions.highWaterMark ?? 1024;
const queued = [];
+ const { readableStrategy } = makeOptions(streamOptions);
const stream = new ReadableStream(
{
async start(controller) {
@@ -101,7 +130,7 @@ export const createReadableStream = (input, streamOptions = {}) => {
controller.enqueue(chunk);
}
if (typeof input === "string") {
- const chunkSize = streamOptions?.chunkSize ?? 16 * 1024;
+ const chunkSize = streamOptions?.chunkSize ?? 16_384; // 16KB
let position = 0;
const length = input.length;
while (position < length) {
@@ -111,9 +140,18 @@ export const createReadableStream = (input, streamOptions = {}) => {
}
controller.close();
} else if (Array.isArray(input)) {
- // TODO update to for(;;) loop, faster
- for (const chunk of input) {
- controller.enqueue(chunk);
+ for (let i = 0, l = input.length; i < l; i++) {
+ controller.enqueue(input[i]);
+ }
+ controller.close();
+ } else if (typeof input === "object" && input.byteLength) {
+ const bytes = new Uint8Array(input.buffer ?? input);
+ const chunkSize = streamOptions?.chunkSize ?? 16_384; // 16KB
+ let position = 0;
+ const length = bytes.byteLength;
+ while (position < length) {
+ controller.enqueue(bytes.subarray(position, position + chunkSize));
+ position += chunkSize;
}
controller.close();
} else if (["function", "object"].includes(typeof input)) {
@@ -134,9 +172,16 @@ export const createReadableStream = (input, streamOptions = {}) => {
}
},
},
- makeOptions(streamOptions),
+ readableStrategy,
);
- stream.push = (chunk) => queued.push(chunk);
+ stream.push = (chunk) => {
+ if (queued.length >= maxQueueSize) {
+ throw new Error(
+ `createReadableStream queue size (${queued.length}) exceeds limit (${maxQueueSize})`,
+ );
+ }
+ queued.push(chunk);
+ };
return stream;
};
@@ -146,9 +191,19 @@ export const createPassThroughStream = (passThrough, flush, streamOptions) => {
streamOptions = flush;
flush = undefined;
}
+ const { signal } = streamOptions ?? {};
+ const { writableStrategy, readableStrategy } = makeOptions(streamOptions);
return new TransformStream(
{
- start() {},
+ start(controller) {
+ if (signal) {
+ signal.addEventListener("abort", () => {
+ controller.error(
+ signal.reason ?? new DOMException("Aborted", "AbortError"),
+ );
+ });
+ }
+ },
async transform(chunk, controller) {
await passThrough(chunk);
controller.enqueue(chunk);
@@ -160,7 +215,8 @@ export const createPassThroughStream = (passThrough, flush, streamOptions) => {
controller.terminate();
},
},
- makeOptions(streamOptions),
+ writableStrategy,
+ readableStrategy,
);
};
@@ -170,9 +226,19 @@ export const createTransformStream = (transform, flush, streamOptions) => {
streamOptions = flush;
flush = undefined;
}
+ const { signal } = streamOptions ?? {};
+ const { writableStrategy, readableStrategy } = makeOptions(streamOptions);
return new TransformStream(
{
- start() {},
+ start(controller) {
+ if (signal) {
+ signal.addEventListener("abort", () => {
+ controller.error(
+ signal.reason ?? new DOMException("Aborted", "AbortError"),
+ );
+ });
+ }
+ },
async transform(chunk, controller) {
const enqueue = (chunk) => {
controller.enqueue(chunk);
@@ -189,7 +255,8 @@ export const createTransformStream = (transform, flush, streamOptions) => {
controller.terminate();
},
},
- makeOptions(streamOptions),
+ writableStrategy,
+ readableStrategy,
);
};
@@ -199,8 +266,19 @@ export const createWritableStream = (write, close, streamOptions) => {
streamOptions = close;
close = undefined;
}
+ const { signal } = streamOptions ?? {};
+ const { writableStrategy } = makeOptions(streamOptions);
return new WritableStream(
{
+ start(controller) {
+ if (signal) {
+ signal.addEventListener("abort", () => {
+ controller.error(
+ signal.reason ?? new DOMException("Aborted", "AbortError"),
+ );
+ });
+ }
+ },
async write(chunk) {
await write(chunk);
},
@@ -210,23 +288,26 @@ export const createWritableStream = (write, close, streamOptions) => {
}
},
},
- makeOptions(streamOptions),
+ writableStrategy,
);
};
export const timeout = (ms, { signal } = {}) => {
if (signal?.aborted) {
- return Promise.reject(new Error("Aborted", "AbortError"));
+ return Promise.reject(
+ new Error("Aborted", { cause: { code: "AbortError" } }),
+ );
}
return new Promise((resolve, reject) => {
const abortHandler = () => {
- clearTimeout(timeout);
- reject(new Error("Aborted", "AbortError"));
+ clearTimeout(timerId);
+ signal.removeEventListener("abort", abortHandler);
+ reject(new Error("Aborted", { cause: { code: "AbortError" } }));
};
if (signal) signal.addEventListener("abort", abortHandler);
- setTimeout(() => {
- resolve();
+ const timerId = setTimeout(() => {
if (signal) signal.removeEventListener("abort", abortHandler);
+ resolve();
}, ms);
});
};
diff --git a/packages/core/package.json b/packages/core/package.json
index fc29d70..f9761c8 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/core",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "Stream creation utilities and pipeline functions for Web Streams API and Node.js streams",
"type": "module",
"engines": {
@@ -61,6 +61,6 @@
"homepage": "https://datastream.js.org",
"dependencies": {},
"devDependencies": {
- "@datastream/object": "0.1.6"
+ "@datastream/object": "0.2.0"
}
}
diff --git a/packages/csv/index.d.ts b/packages/csv/index.d.ts
index 8ed6c52..1576c3d 100644
--- a/packages/csv/index.d.ts
+++ b/packages/csv/index.d.ts
@@ -12,6 +12,7 @@ export interface CsvDelimiters {
export interface CsvParserOptions extends CsvDelimiters {
numCols?: number;
idx?: number;
+ fieldMaxSize?: number;
delimiterCharCode?: number;
delimiterCharLength?: number;
delimiterCharSingle?: boolean;
@@ -81,6 +82,7 @@ export function csvUnquotedParser(
export function csvParseStream(
options?: {
chunkSize?: number;
+ fieldMaxSize?: number;
resultKey?: string;
parser?: (
text: string,
diff --git a/packages/csv/index.js b/packages/csv/index.js
index 7fc82fd..310808d 100644
--- a/packages/csv/index.js
+++ b/packages/csv/index.js
@@ -36,7 +36,10 @@ const stripBOM = (str) => {
const resolveLazy = (value) => (typeof value === "function" ? value() : value);
export const csvDetectDelimitersStream = (options = {}, streamOptions = {}) => {
- const { chunkSize = 1024, resultKey } = options;
+ const {
+ chunkSize = 1024, // 1KB
+ resultKey,
+ } = options;
const value = {
delimiterChar: undefined,
@@ -99,7 +102,7 @@ export const csvDetectDelimitersStream = (options = {}, streamOptions = {}) => {
export const csvDetectHeaderStream = (options = {}, streamOptions = {}) => {
let {
- chunkSize = 1024,
+ chunkSize = 1024, // 1KB
parser,
delimiterChar,
newlineChar,
@@ -209,6 +212,7 @@ const csvParseInline = (text, ctx, isFlushing, enqueue) => {
const escapeCharCode = ctx.escapeCharCode;
const escapeIsQuote = ctx.escapeIsQuote;
const escapedQuote = ctx.escapedQuote;
+ const fieldMaxSize = ctx.fieldMaxSize;
const len = text.length;
let numCols = ctx.numCols;
@@ -275,6 +279,11 @@ const csvParseInline = (text, ctx, isFlushing, enqueue) => {
.substring(contentStart, closeQ)
.replaceAll(escapedQuote, quoteChar)
: text.substring(contentStart, closeQ);
+ if (field.length > fieldMaxSize) {
+ throw new Error(
+ `CSV field size (${field.length}) exceeds fieldMaxSize (${fieldMaxSize} bytes)`,
+ );
+ }
pos = closeQ + 1;
// Post-quote dispatch: delimiter, newline, or end-of-input
@@ -362,6 +371,11 @@ const csvParseInline = (text, ctx, isFlushing, enqueue) => {
.substring(contentStart, closeQ)
.replaceAll(escapedQuote, quoteChar)
: text.substring(contentStart, closeQ);
+ if (field.length > fieldMaxSize) {
+ throw new Error(
+ `CSV field size (${field.length}) exceeds fieldMaxSize (${fieldMaxSize} bytes)`,
+ );
+ }
pos = closeQ + 1;
// Post-quote dispatch: delimiter, newline, or end-of-input
@@ -553,12 +567,6 @@ const csvParseInline = (text, ctx, isFlushing, enqueue) => {
ctx.errors = errors;
};
-// Stable enqueue callback — avoids V8 "wrong call target" deopt from per-call closures
-let _quotedParserRows = [];
-const _quotedParserEnqueue = (row) => {
- _quotedParserRows.push(row);
-};
-
export const csvQuotedParser = (text, options = {}, isFlushing = false) => {
const delimiterChar = options.delimiterChar ?? defaultDelimiterChar;
const newlineChar = options.newlineChar ?? defaultNewlineChar;
@@ -588,10 +596,8 @@ export const csvQuotedParser = (text, options = {}, isFlushing = false) => {
tail: "",
errors: null,
};
- _quotedParserRows = [];
- csvParseInline(text, ctx, isFlushing, _quotedParserEnqueue);
- const rows = _quotedParserRows;
- _quotedParserRows = [];
+ const rows = [];
+ csvParseInline(text, ctx, isFlushing, (row) => rows.push(row));
return {
rows,
tail: ctx.tail,
@@ -637,7 +643,14 @@ export const csvUnquotedParser = (text, options = {}, isFlushing = false) => {
// --- Streaming wrapper ---
const csvSteamifyParser = (options = {}) => {
- let { parser, delimiterChar, newlineChar, quoteChar, escapeChar } = options;
+ let {
+ parser,
+ delimiterChar,
+ newlineChar,
+ quoteChar,
+ escapeChar,
+ fieldMaxSize,
+ } = options;
const useCustomParser = parser != null;
parser ??= csvQuotedParser;
@@ -667,6 +680,7 @@ const csvSteamifyParser = (options = {}) => {
ctx.escapeCharCode = escapeChar.charCodeAt(0);
ctx.escapeIsQuote = escapeChar === quoteChar;
ctx.escapedQuote = escapeChar + quoteChar;
+ ctx.fieldMaxSize = fieldMaxSize ?? 16_777_216;
resolved = true;
};
@@ -675,6 +689,11 @@ const csvSteamifyParser = (options = {}) => {
const str = typeof chunk === "string" ? chunk : chunk.toString();
const text = buffer.length > 0 ? buffer + str : str;
buffer = "";
+ if (text.length > ctx.fieldMaxSize * 2) {
+ throw new Error(
+ `CSV buffer size (${text.length}) exceeds safety limit, likely unterminated quoted field`,
+ );
+ }
if (useCustomParser) {
const result = parser(text, ctx, false);
@@ -721,7 +740,13 @@ const csvSteamifyParser = (options = {}) => {
// --- Stream exports ---
export const csvParseStream = (options = {}, streamOptions = {}) => {
- const { chunkSize = 2 * 1024 * 1024, resultKey, ...parserOptions } = options;
+ const {
+ chunkSize = 2_097_152, // 2MB
+ fieldMaxSize = 16_777_216, // 16MB
+ resultKey,
+ ...parserOptions
+ } = options;
+ parserOptions.fieldMaxSize = fieldMaxSize;
streamOptions.highWaterMark ??= 16384;
const streamParse = csvSteamifyParser(parserOptions);
diff --git a/packages/csv/package.json b/packages/csv/package.json
index 056bd49..b90e749 100644
--- a/packages/csv/package.json
+++ b/packages/csv/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/csv",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "CSV parsing and formatting transform streams",
"type": "module",
"engines": {
@@ -63,7 +63,7 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6",
- "@datastream/object": "0.1.6"
+ "@datastream/core": "0.2.0",
+ "@datastream/object": "0.2.0"
}
}
diff --git a/packages/digest/index.d.ts b/packages/digest/index.d.ts
index 0cd9270..2afcfc7 100644
--- a/packages/digest/index.d.ts
+++ b/packages/digest/index.d.ts
@@ -10,16 +10,16 @@ export type DigestAlgorithm =
| "SHA3-384"
| "SHA3-512";
+type DigestStreamResult = unknown & {
+ result: () => StreamResult;
+};
+
export function digestStream(
options: {
algorithm: DigestAlgorithm;
resultKey?: string;
},
streamOptions?: StreamOptions,
-): Promise<
- unknown & {
- result: () => StreamResult;
- }
->;
+): DigestStreamResult | Promise;
export default digestStream;
diff --git a/packages/digest/index.tst.ts b/packages/digest/index.tst.ts
index add60b9..102119e 100644
--- a/packages/digest/index.tst.ts
+++ b/packages/digest/index.tst.ts
@@ -18,14 +18,14 @@ describe("DigestAlgorithm", () => {
});
describe("digestStream", () => {
- test("returns a promise", () => {
+ test("returns a stream or promise of stream", () => {
const result = digestStream({ algorithm: "SHA2-256" });
- expect(result).type.toBeAssignableTo>();
+ expect(result).type.not.toBeAssignableTo();
});
test("accepts resultKey", () => {
expect(
digestStream({ algorithm: "SHA3-512", resultKey: "hash" }),
- ).type.toBeAssignableTo>();
+ ).type.not.toBeAssignableTo();
});
});
diff --git a/packages/digest/package.json b/packages/digest/package.json
index 8b3b57f..f64b3d4 100644
--- a/packages/digest/package.json
+++ b/packages/digest/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/digest",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "Cryptographic hash digest pass-through streams",
"type": "module",
"engines": {
@@ -60,7 +60,7 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6",
+ "@datastream/core": "0.2.0",
"hash-wasm": "4.12.0"
}
}
diff --git a/packages/encrypt/README.md b/packages/encrypt/README.md
new file mode 100644
index 0000000..8c126da
--- /dev/null
+++ b/packages/encrypt/README.md
@@ -0,0 +1,52 @@
+
+
+
+## Install
+
+To install datastream you can use NPM:
+
+```bash
+npm install --save @datastream/encrypt
+```
+
+
+## Documentation and examples
+
+For documentation and examples, refer to the main [datastream monorepo on GitHub](https://github.com/willfarrell/datastream) or [datastream official website](https://datastream.js.org).
+
+
+## Contributing
+
+Everyone is very welcome to contribute to this repository. Feel free to [raise issues](https://github.com/willfarrell/datastream/issues) or to [submit Pull Requests](https://github.com/willfarrell/datastream/pulls).
+
+
+## License
+
+Licensed under [MIT License](LICENSE). Copyright (c) 2026 [will Farrell](https://github.com/willfarrell), and [datastream contributors](https://github.com/willfarrell/datastream/graphs/contributors).
diff --git a/packages/encrypt/index.d.ts b/packages/encrypt/index.d.ts
new file mode 100644
index 0000000..e3edcbc
--- /dev/null
+++ b/packages/encrypt/index.d.ts
@@ -0,0 +1,49 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import type { StreamOptions, StreamResult } from "@datastream/core";
+
+export type EncryptAlgorithm =
+ | "AES-256-GCM"
+ | "AES-256-CTR"
+ | "CHACHA20-POLY1305";
+
+type EncryptStreamResult = unknown & {
+ result: () => StreamResult<{
+ algorithm: EncryptAlgorithm;
+ iv: Uint8Array;
+ authTag?: Uint8Array;
+ }>;
+};
+
+export function encryptStream(
+ options: {
+ algorithm?: EncryptAlgorithm;
+ key: Uint8Array | Buffer;
+ iv?: Uint8Array | Buffer;
+ aad?: Uint8Array | Buffer;
+ maxInputSize?: number;
+ },
+ streamOptions?: StreamOptions,
+): EncryptStreamResult | Promise;
+
+export function decryptStream(
+ options: {
+ algorithm?: EncryptAlgorithm;
+ key: Uint8Array | Buffer;
+ iv: Uint8Array | Buffer;
+ authTag?: Uint8Array | Buffer;
+ aad?: Uint8Array | Buffer;
+ maxOutputSize?: number;
+ },
+ streamOptions?: StreamOptions,
+): unknown | Promise;
+
+export function generateEncryptionKey(options?: {
+ bits?: 128 | 256;
+}): Uint8Array;
+
+export default {
+ encryptStream,
+ decryptStream,
+ generateEncryptionKey,
+};
diff --git a/packages/encrypt/index.fuzz.js b/packages/encrypt/index.fuzz.js
new file mode 100644
index 0000000..8170e65
--- /dev/null
+++ b/packages/encrypt/index.fuzz.js
@@ -0,0 +1,183 @@
+import { randomBytes } from "node:crypto";
+import test from "node:test";
+import { createReadableStream } from "@datastream/core";
+import { decryptStream, encryptStream } from "@datastream/encrypt";
+import fc from "fast-check";
+
+const catchError = (input, e) => {
+ const expectedErrors = [
+ "Unsupported state or unable to authenticate data",
+ "Unsupported algorithm",
+ ];
+ if (expectedErrors.includes(e.message)) {
+ return;
+ }
+ console.error(input, e);
+ throw e;
+};
+
+const key = randomBytes(32);
+
+// *** encryptStream roundtrip with random data *** //
+test("fuzz encryptStream AES-256-GCM roundtrip", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.uint8Array({ minLength: 0, maxLength: 10_000 }),
+ async (input) => {
+ try {
+ const enc = encryptStream({ key });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(input).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ const dec = decryptStream({ key, iv, authTag });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks);
+ if (!Buffer.from(input).equals(decrypted)) {
+ throw new Error("Roundtrip mismatch");
+ }
+ } catch (e) {
+ catchError(input, e);
+ }
+ },
+ ),
+ {
+ numRuns: 100,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+test("fuzz encryptStream AES-256-CTR roundtrip", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.uint8Array({ minLength: 0, maxLength: 10_000 }),
+ async (input) => {
+ try {
+ const enc = encryptStream({
+ key,
+ algorithm: "AES-256-CTR",
+ });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(input).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv } = enc.result().value;
+
+ const dec = decryptStream({
+ key,
+ iv,
+ algorithm: "AES-256-CTR",
+ });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks);
+ if (!Buffer.from(input).equals(decrypted)) {
+ throw new Error("Roundtrip mismatch");
+ }
+ } catch (e) {
+ catchError(input, e);
+ }
+ },
+ ),
+ {
+ numRuns: 100,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+test("fuzz encryptStream CHACHA20-POLY1305 roundtrip", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.uint8Array({ minLength: 0, maxLength: 10_000 }),
+ async (input) => {
+ try {
+ const enc = encryptStream({
+ key,
+ algorithm: "CHACHA20-POLY1305",
+ });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(input).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ const dec = decryptStream({
+ key,
+ iv,
+ authTag,
+ algorithm: "CHACHA20-POLY1305",
+ });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks);
+ if (!Buffer.from(input).equals(decrypted)) {
+ throw new Error("Roundtrip mismatch");
+ }
+ } catch (e) {
+ catchError(input, e);
+ }
+ },
+ ),
+ {
+ numRuns: 100,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+test("fuzz decryptStream with wrong key should fail", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.uint8Array({ minLength: 1, maxLength: 1_000 }),
+ async (input) => {
+ const enc = encryptStream({ key });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(input).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ const wrongKey = randomBytes(32);
+ const dec = decryptStream({ key: wrongKey, iv, authTag });
+ try {
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ for await (const _chunk of decStream) {
+ // should fail
+ }
+ throw new Error("Expected decryption to fail");
+ } catch (e) {
+ if (e.message === "Expected decryption to fail") {
+ throw e;
+ }
+ // Expected: authentication failure
+ }
+ },
+ ),
+ {
+ numRuns: 50,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
diff --git a/packages/encrypt/index.node.js b/packages/encrypt/index.node.js
new file mode 100644
index 0000000..141509f
--- /dev/null
+++ b/packages/encrypt/index.node.js
@@ -0,0 +1,135 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
+
+const algorithmMap = {
+ "AES-256-GCM": { cipher: "aes-256-gcm", ivSize: 12 },
+ "AES-256-CTR": { cipher: "aes-256-ctr", ivSize: 16 },
+ "CHACHA20-POLY1305": { cipher: "chacha20-poly1305", ivSize: 12 },
+};
+
+const authAlgorithms = ["AES-256-GCM", "CHACHA20-POLY1305"];
+
+const validateKey = (key) => {
+ if (!key || key.length !== 32) {
+ throw new Error(
+ `Encryption key must be 32 bytes (256 bits), got ${key?.length ?? 0}`,
+ );
+ }
+};
+
+const validateIv = (iv, expectedSize, algorithm) => {
+ if (!iv || iv.length !== expectedSize) {
+ throw new Error(
+ `IV for ${algorithm} must be ${expectedSize} bytes, got ${iv?.length ?? 0}`,
+ );
+ }
+};
+
+const validateAuthTag = (authTag, algorithm) => {
+ if (!authTag || authTag.length !== 16) {
+ throw new Error(
+ `authTag for ${algorithm} must be 16 bytes, got ${authTag?.length ?? 0}`,
+ );
+ }
+};
+
+const validateAad = (aad) => {
+ if (aad != null && !Buffer.isBuffer(aad) && !(aad instanceof Uint8Array)) {
+ throw new Error("aad must be a Buffer or Uint8Array");
+ }
+};
+
+export const encryptStream = (
+ { algorithm = "AES-256-GCM", key, iv, aad } = {},
+ streamOptions = {},
+) => {
+ const config = algorithmMap[algorithm];
+ if (!config) {
+ throw new Error(`Unsupported algorithm: ${algorithm}`);
+ }
+ const { cipher: cipherName, ivSize } = config;
+ validateKey(key);
+ iv ??= randomBytes(ivSize);
+ validateIv(iv, ivSize, algorithm);
+ validateAad(aad);
+ const authTagLength = authAlgorithms.includes(algorithm) ? 16 : undefined;
+ const stream = createCipheriv(cipherName, key, iv, {
+ ...streamOptions,
+ authTagLength,
+ });
+ if (aad && authAlgorithms.includes(algorithm)) {
+ stream.setAAD(aad);
+ }
+ stream.result = () => ({
+ key: "encrypt",
+ value: {
+ algorithm,
+ iv,
+ ...(authAlgorithms.includes(algorithm)
+ ? { authTag: stream.getAuthTag() }
+ : {}),
+ },
+ });
+ return stream;
+};
+
+export const decryptStream = (
+ { algorithm = "AES-256-GCM", key, iv, authTag, aad, maxOutputSize } = {},
+ streamOptions = {},
+) => {
+ const config = algorithmMap[algorithm];
+ if (!config) {
+ throw new Error(`Unsupported algorithm: ${algorithm}`);
+ }
+ const { cipher: cipherName, ivSize } = config;
+ validateKey(key);
+ validateIv(iv, ivSize, algorithm);
+ validateAad(aad);
+ const authTagLength = authAlgorithms.includes(algorithm) ? 16 : undefined;
+ if (authAlgorithms.includes(algorithm)) {
+ validateAuthTag(authTag, algorithm);
+ }
+ const stream = createDecipheriv(cipherName, key, iv, {
+ ...streamOptions,
+ authTagLength,
+ });
+ if (authTag) {
+ stream.setAuthTag(authTag);
+ }
+ if (aad && authAlgorithms.includes(algorithm)) {
+ stream.setAAD(aad);
+ }
+ if (maxOutputSize != null) {
+ let outputSize = 0;
+ const originalPush = stream.push.bind(stream);
+ stream.push = (chunk) => {
+ if (chunk !== null) {
+ outputSize += chunk.length;
+ if (outputSize > maxOutputSize) {
+ stream.destroy(
+ new Error(
+ `Decryption output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ ),
+ );
+ return false;
+ }
+ }
+ return originalPush(chunk);
+ };
+ }
+ return stream;
+};
+
+export const generateEncryptionKey = ({ bits = 256 } = {}) => {
+ if (![128, 256].includes(bits)) {
+ throw new Error(`Unsupported key size: ${bits}. Must be 128 or 256.`);
+ }
+ return randomBytes(bits / 8);
+};
+
+export default {
+ encryptStream,
+ decryptStream,
+ generateEncryptionKey,
+};
diff --git a/packages/encrypt/index.perf.js b/packages/encrypt/index.perf.js
new file mode 100644
index 0000000..f7abbea
--- /dev/null
+++ b/packages/encrypt/index.perf.js
@@ -0,0 +1,101 @@
+import { randomBytes } from "node:crypto";
+import test from "node:test";
+import { createReadableStream, pipeline } from "@datastream/core";
+import { decryptStream, encryptStream } from "@datastream/encrypt";
+import { Bench } from "tinybench";
+
+// -- Data generators --
+
+const time = Number(process.env.BENCH_TIME ?? 5_000);
+
+const smallBuffer = randomBytes(1_024); // 1KB
+const bigBuffer = randomBytes(1_024 * 1_024); // 1MB
+const key = randomBytes(32);
+
+// -- Tests --
+
+test("perf: encryptStream AES-256-GCM", async () => {
+ const bench = new Bench({ name: "encryptStream AES-256-GCM", time });
+
+ bench.add("1KB", async () => {
+ const enc = encryptStream({ key });
+ const streams = [createReadableStream(smallBuffer), enc];
+ await pipeline(streams);
+ });
+
+ bench.add("1MB", async () => {
+ const enc = encryptStream({ key });
+ const streams = [createReadableStream(bigBuffer), enc];
+ await pipeline(streams);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: encryptStream AES-256-CTR", async () => {
+ const bench = new Bench({ name: "encryptStream AES-256-CTR", time });
+
+ bench.add("1KB", async () => {
+ const enc = encryptStream({ key, algorithm: "AES-256-CTR" });
+ const streams = [createReadableStream(smallBuffer), enc];
+ await pipeline(streams);
+ });
+
+ bench.add("1MB", async () => {
+ const enc = encryptStream({ key, algorithm: "AES-256-CTR" });
+ const streams = [createReadableStream(bigBuffer), enc];
+ await pipeline(streams);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: encryptStream CHACHA20-POLY1305", async () => {
+ const bench = new Bench({ name: "encryptStream CHACHA20-POLY1305", time });
+
+ bench.add("1KB", async () => {
+ const enc = encryptStream({ key, algorithm: "CHACHA20-POLY1305" });
+ const streams = [createReadableStream(smallBuffer), enc];
+ await pipeline(streams);
+ });
+
+ bench.add("1MB", async () => {
+ const enc = encryptStream({ key, algorithm: "CHACHA20-POLY1305" });
+ const streams = [createReadableStream(bigBuffer), enc];
+ await pipeline(streams);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: encrypt→decrypt roundtrip comparison", async () => {
+ const bench = new Bench({ name: "roundtrip comparison 1MB", time });
+
+ for (const algorithm of ["AES-256-GCM", "AES-256-CTR", "CHACHA20-POLY1305"]) {
+ bench.add(algorithm, async () => {
+ const enc = encryptStream({ key, algorithm });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(bigBuffer).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ const dec = decryptStream({ key, iv, authTag, algorithm });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ for await (const _chunk of decStream) {
+ // consume
+ }
+ });
+ }
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
diff --git a/packages/encrypt/index.test.js b/packages/encrypt/index.test.js
new file mode 100644
index 0000000..9271546
--- /dev/null
+++ b/packages/encrypt/index.test.js
@@ -0,0 +1,283 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import { deepStrictEqual, strictEqual, throws } from "node:assert";
+import { randomBytes } from "node:crypto";
+import test from "node:test";
+
+import { createReadableStream, pipeline } from "@datastream/core";
+
+import encryptDefault, {
+ decryptStream,
+ encryptStream,
+ generateEncryptionKey,
+} from "@datastream/encrypt";
+
+let variant = "unknown";
+for (const execArgv of process.execArgv) {
+ const flag = "--conditions=";
+ if (execArgv.includes("--conditions=")) {
+ variant = execArgv.replace(flag, "");
+ }
+}
+
+const key = randomBytes(32);
+
+// *** generateEncryptionKey *** //
+test(`${variant}: generateEncryptionKey should generate 32-byte key by default`, (_t) => {
+ const k = generateEncryptionKey();
+ strictEqual(k.byteLength, 32);
+});
+
+test(`${variant}: generateEncryptionKey should generate 16-byte key for 128 bits`, (_t) => {
+ const k = generateEncryptionKey({ bits: 128 });
+ strictEqual(k.byteLength, 16);
+});
+
+// *** AES-256-GCM (default) *** //
+test(`${variant}: encryptStream should encrypt and decrypt with AES-256-GCM`, async (_t) => {
+ const input = "hello, world!";
+ const enc = encryptStream({ key });
+ const streams = [createReadableStream(input), enc];
+ await pipeline(streams);
+
+ const { key: resultKey, value } = enc.result();
+ strictEqual(resultKey, "encrypt");
+ strictEqual(value.algorithm, "AES-256-GCM");
+ strictEqual(value.iv.byteLength, 12);
+ strictEqual(value.authTag.byteLength, 16);
+});
+
+test(`${variant}: encryptStream roundtrip with AES-256-GCM`, async (_t) => {
+ const input = "secret data to encrypt";
+
+ // Encrypt
+ const enc = encryptStream({ key });
+ const encStreams = [createReadableStream(input), enc];
+ const encryptedChunks = [];
+ const encStream = encStreams[0].pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ // Decrypt
+ const dec = decryptStream({ key, iv, authTag });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks).toString("utf8");
+ strictEqual(decrypted, input);
+});
+
+test(`${variant}: encryptStream should use custom IV`, async (_t) => {
+ const iv = randomBytes(12);
+ const enc = encryptStream({ key, iv });
+ const streams = [createReadableStream("test"), enc];
+ await pipeline(streams);
+
+ const { value } = enc.result();
+ deepStrictEqual(value.iv, iv);
+});
+
+test(`${variant}: encryptStream should support AAD`, async (_t) => {
+ const aad = Buffer.from("metadata");
+
+ // Encrypt with AAD
+ const enc = encryptStream({ key, aad });
+ const encStreams = [createReadableStream("aad test"), enc];
+ const encryptedChunks = [];
+ const encStream = encStreams[0].pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ // Decrypt with matching AAD
+ const dec = decryptStream({ key, iv, authTag, aad });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks).toString("utf8");
+ strictEqual(decrypted, "aad test");
+});
+
+test(`${variant}: encryptStream should collect result via pipeline`, async (_t) => {
+ const enc = encryptStream({ key });
+ const streams = [createReadableStream("pipeline test"), enc];
+ const result = await pipeline(streams);
+
+ strictEqual(typeof result.encrypt, "object");
+ strictEqual(result.encrypt.algorithm, "AES-256-GCM");
+});
+
+// *** AES-256-CTR *** //
+test(`${variant}: encryptStream roundtrip with AES-256-CTR`, async (_t) => {
+ const input = "ctr mode test data";
+
+ const enc = encryptStream({ key, algorithm: "AES-256-CTR" });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(input).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv } = enc.result().value;
+ strictEqual(iv.byteLength, 16);
+ strictEqual(enc.result().value.authTag, undefined);
+
+ const dec = decryptStream({ key, iv, algorithm: "AES-256-CTR" });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks).toString("utf8");
+ strictEqual(decrypted, input);
+});
+
+// *** CHACHA20-POLY1305 *** //
+test(`${variant}: encryptStream roundtrip with CHACHA20-POLY1305`, async (_t) => {
+ const input = "chacha20 test data";
+
+ const enc = encryptStream({ key, algorithm: "CHACHA20-POLY1305" });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(input).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+ strictEqual(iv.byteLength, 12);
+ strictEqual(authTag.byteLength, 16);
+
+ const dec = decryptStream({
+ key,
+ iv,
+ authTag,
+ algorithm: "CHACHA20-POLY1305",
+ });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks).toString("utf8");
+ strictEqual(decrypted, input);
+});
+
+// *** Error cases *** //
+test(`${variant}: encryptStream should throw for unsupported algorithm`, (_t) => {
+ throws(
+ () => encryptStream({ key, algorithm: "INVALID" }),
+ /Unsupported algorithm/,
+ );
+});
+
+test(`${variant}: decryptStream should throw for unsupported algorithm`, (_t) => {
+ throws(
+ () => decryptStream({ key, iv: randomBytes(12), algorithm: "INVALID" }),
+ /Unsupported algorithm/,
+ );
+});
+
+test(`${variant}: decryptStream should fail with wrong key`, async (_t) => {
+ const enc = encryptStream({ key });
+ const encryptedChunks = [];
+ const encStream = createReadableStream("wrong key test").pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ const wrongKey = randomBytes(32);
+ const dec = decryptStream({ key: wrongKey, iv, authTag });
+ try {
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ for await (const _chunk of decStream) {
+ // should fail
+ }
+ throw new Error("Expected decryption to fail");
+ } catch (e) {
+ strictEqual(e.message !== "Expected decryption to fail", true);
+ }
+});
+
+test(`${variant}: decryptStream maxOutputSize should limit output`, async (_t) => {
+ const input = "a".repeat(1000);
+ const enc = encryptStream({ key, algorithm: "AES-256-CTR" });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(input).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv } = enc.result().value;
+
+ const dec = decryptStream({
+ key,
+ iv,
+ algorithm: "AES-256-CTR",
+ maxOutputSize: 100,
+ });
+ try {
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ for await (const _chunk of decStream) {
+ // should fail
+ }
+ throw new Error("Expected maxOutputSize error");
+ } catch (e) {
+ strictEqual(e.message.includes("maxOutputSize"), true);
+ }
+});
+
+// *** Chunked input *** //
+test(`${variant}: encryptStream should handle chunked input`, async (_t) => {
+ const chunks = ["hello, ", "world", "!"];
+
+ const enc = encryptStream({ key });
+ const encryptedChunks = [];
+ const encStream = createReadableStream(chunks).pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ const dec = decryptStream({ key, iv, authTag });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks).toString("utf8");
+ strictEqual(decrypted, "hello, world!");
+});
+
+// *** Empty input *** //
+test(`${variant}: encryptStream should handle empty input`, async (_t) => {
+ const enc = encryptStream({ key });
+ const encryptedChunks = [];
+ const encStream = createReadableStream("").pipe(enc);
+ for await (const chunk of encStream) {
+ encryptedChunks.push(chunk);
+ }
+ const { iv, authTag } = enc.result().value;
+
+ const dec = decryptStream({ key, iv, authTag });
+ const decStream = createReadableStream(encryptedChunks).pipe(dec);
+ const decryptedChunks = [];
+ for await (const chunk of decStream) {
+ decryptedChunks.push(chunk);
+ }
+ const decrypted = Buffer.concat(decryptedChunks).toString("utf8");
+ strictEqual(decrypted, "");
+});
+
+// *** default export *** //
+test(`${variant}: default export should include all functions`, (_t) => {
+ deepStrictEqual(Object.keys(encryptDefault).sort(), [
+ "decryptStream",
+ "encryptStream",
+ "generateEncryptionKey",
+ ]);
+});
diff --git a/packages/encrypt/index.web.js b/packages/encrypt/index.web.js
new file mode 100644
index 0000000..9a05f15
--- /dev/null
+++ b/packages/encrypt/index.web.js
@@ -0,0 +1,384 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+/* global crypto */
+import { createTransformStream } from "@datastream/core";
+
+const DEFAULT_MAX_INPUT_SIZE = 64 * 1024 * 1024; // 64MB
+
+const expectedIvSize = {
+ "AES-256-GCM": 12,
+ "AES-256-CTR": 16,
+ "CHACHA20-POLY1305": 12,
+};
+
+const validateKey = (key) => {
+ if (!key || key.byteLength !== 32) {
+ throw new Error(
+ `Encryption key must be 32 bytes (256 bits), got ${key?.byteLength ?? 0}`,
+ );
+ }
+};
+
+const validateIv = (iv, algorithm) => {
+ const expected = expectedIvSize[algorithm];
+ if (!iv || iv.byteLength !== expected) {
+ throw new Error(
+ `IV for ${algorithm} must be ${expected} bytes, got ${iv?.byteLength ?? 0}`,
+ );
+ }
+};
+
+const validateAuthTag = (authTag, algorithm) => {
+ if (!authTag || authTag.byteLength !== 16) {
+ throw new Error(
+ `authTag for ${algorithm} must be 16 bytes, got ${authTag?.byteLength ?? 0}`,
+ );
+ }
+};
+
+const validateAad = (aad) => {
+ if (
+ aad != null &&
+ !(aad instanceof Uint8Array) &&
+ !(aad instanceof ArrayBuffer)
+ ) {
+ throw new Error("aad must be a Uint8Array or ArrayBuffer");
+ }
+};
+
+const concatBuffers = (chunks) => {
+ let totalLength = 0;
+ const buffers = chunks.map((chunk) => {
+ const buf =
+ chunk instanceof Uint8Array ? chunk : new TextEncoder().encode(chunk);
+ totalLength += buf.byteLength;
+ return buf;
+ });
+ const result = new Uint8Array(totalLength);
+ let offset = 0;
+ for (const buf of buffers) {
+ result.set(buf, offset);
+ offset += buf.byteLength;
+ }
+ return result;
+};
+
+// Max safe counter: 2^64 blocks = 2^68 bytes (256 EB).
+// Beyond this, keystream reuse breaks confidentiality.
+const MAX_CTR_BLOCKS = 2 ** 64;
+
+const incrementCounter = (iv, blockOffset) => {
+ if (blockOffset >= MAX_CTR_BLOCKS) {
+ throw new Error(
+ "AES-CTR counter overflow: data exceeds safe limit. Use a new key/IV pair.",
+ );
+ }
+ const counter = new Uint8Array(iv);
+ let carry = blockOffset;
+ for (let i = counter.length - 1; i >= 0 && carry > 0; i--) {
+ const sum = counter[i] + (carry & 0xff);
+ counter[i] = sum & 0xff;
+ carry = (carry >> 8) + (sum >> 8);
+ }
+ return counter;
+};
+
+// AES-GCM: buffer all chunks, encrypt on flush
+const aesGcmEncrypt = async ({ key, iv, aad, maxInputSize }, streamOptions) => {
+ validateKey(key);
+ iv ??= crypto.getRandomValues(new Uint8Array(12));
+ validateIv(iv, "AES-256-GCM");
+ validateAad(aad);
+ maxInputSize ??= DEFAULT_MAX_INPUT_SIZE;
+ const chunks = [];
+ let inputSize = 0;
+ let authTag;
+ const transform = (chunk) => {
+ const buf =
+ chunk instanceof Uint8Array ? chunk : new TextEncoder().encode(chunk);
+ inputSize += buf.byteLength;
+ if (inputSize > maxInputSize) {
+ throw new Error(
+ `Encryption input exceeds maxInputSize (${maxInputSize} bytes). Use AES-256-CTR for large data.`,
+ );
+ }
+ chunks.push(buf);
+ };
+ const flush = async (enqueue) => {
+ const data = concatBuffers(chunks);
+ const cryptoKey = await crypto.subtle.importKey(
+ "raw",
+ key,
+ "AES-GCM",
+ false,
+ ["encrypt"],
+ );
+ const encrypted = await crypto.subtle.encrypt(
+ { name: "AES-GCM", iv, ...(aad ? { additionalData: aad } : {}) },
+ cryptoKey,
+ data,
+ );
+ const result = new Uint8Array(encrypted);
+ // Web Crypto appends 16-byte auth tag to ciphertext
+ authTag = result.slice(-16);
+ enqueue(result.slice(0, -16));
+ };
+ const stream = createTransformStream(transform, flush, streamOptions);
+ stream.result = () => ({
+ key: "encrypt",
+ value: { algorithm: "AES-256-GCM", iv, authTag },
+ });
+ return stream;
+};
+
+const aesGcmDecrypt = async (
+ { key, iv, authTag, aad, maxOutputSize },
+ streamOptions,
+) => {
+ validateKey(key);
+ validateIv(iv, "AES-256-GCM");
+ validateAuthTag(authTag, "AES-256-GCM");
+ validateAad(aad);
+ const chunks = [];
+ const transform = (chunk) => {
+ const buf =
+ chunk instanceof Uint8Array ? chunk : new TextEncoder().encode(chunk);
+ chunks.push(buf);
+ };
+ const flush = async (enqueue) => {
+ const ciphertext = concatBuffers(chunks);
+ // Re-append auth tag for Web Crypto
+ const combined = new Uint8Array(ciphertext.byteLength + authTag.byteLength);
+ combined.set(ciphertext);
+ combined.set(authTag, ciphertext.byteLength);
+ const cryptoKey = await crypto.subtle.importKey(
+ "raw",
+ key,
+ "AES-GCM",
+ false,
+ ["decrypt"],
+ );
+ const decrypted = await crypto.subtle.decrypt(
+ { name: "AES-GCM", iv, ...(aad ? { additionalData: aad } : {}) },
+ cryptoKey,
+ combined,
+ );
+ const result = new Uint8Array(decrypted);
+ if (maxOutputSize != null && result.byteLength > maxOutputSize) {
+ throw new Error(
+ `Decryption output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ );
+ }
+ enqueue(result);
+ };
+ return createTransformStream(transform, flush, streamOptions);
+};
+
+// AES-CTR: true streaming (counter mode is chunk-friendly)
+const aesCtrEncrypt = async ({ key, iv }, streamOptions) => {
+ validateKey(key);
+ iv ??= crypto.getRandomValues(new Uint8Array(16));
+ validateIv(iv, "AES-256-CTR");
+ const cryptoKey = await crypto.subtle.importKey(
+ "raw",
+ key,
+ "AES-CTR",
+ false,
+ ["encrypt"],
+ );
+ let blockOffset = 0;
+ const transform = async (chunk, enqueue) => {
+ const buf =
+ chunk instanceof Uint8Array ? chunk : new TextEncoder().encode(chunk);
+ const counter = incrementCounter(iv, blockOffset);
+ const encrypted = await crypto.subtle.encrypt(
+ { name: "AES-CTR", counter, length: 64 },
+ cryptoKey,
+ buf,
+ );
+ blockOffset += Math.ceil(buf.byteLength / 16);
+ enqueue(new Uint8Array(encrypted));
+ };
+ const stream = createTransformStream(transform, streamOptions);
+ stream.result = () => ({
+ key: "encrypt",
+ value: { algorithm: "AES-256-CTR", iv },
+ });
+ return stream;
+};
+
+const aesCtrDecrypt = async ({ key, iv, maxOutputSize }, streamOptions) => {
+ validateKey(key);
+ validateIv(iv, "AES-256-CTR");
+ const cryptoKey = await crypto.subtle.importKey(
+ "raw",
+ key,
+ "AES-CTR",
+ false,
+ ["decrypt"],
+ );
+ let blockOffset = 0;
+ let outputSize = 0;
+ const transform = async (chunk, enqueue) => {
+ const buf =
+ chunk instanceof Uint8Array ? chunk : new TextEncoder().encode(chunk);
+ const counter = incrementCounter(iv, blockOffset);
+ const decrypted = await crypto.subtle.decrypt(
+ { name: "AES-CTR", counter, length: 64 },
+ cryptoKey,
+ buf,
+ );
+ blockOffset += Math.ceil(buf.byteLength / 16);
+ const result = new Uint8Array(decrypted);
+ if (maxOutputSize != null) {
+ outputSize += result.byteLength;
+ if (outputSize > maxOutputSize) {
+ throw new Error(
+ `Decryption output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ );
+ }
+ }
+ enqueue(result);
+ };
+ return createTransformStream(transform, streamOptions);
+};
+
+// ChaCha20-Poly1305: requires optional peer dep
+const chacha20Encrypt = async ({ key, iv, aad }, streamOptions) => {
+ validateKey(key);
+ validateAad(aad);
+ let sodium;
+ try {
+ sodium = await import("libsodium-wrappers");
+ await sodium.ready;
+ } catch {
+ throw new Error(
+ "CHACHA20-POLY1305 requires libsodium-wrappers. Install it: npm install libsodium-wrappers",
+ );
+ }
+ iv ??= sodium.randombytes_buf(12);
+ validateIv(iv, "CHACHA20-POLY1305");
+ const chunks = [];
+ let authTag;
+ const transform = (chunk) => {
+ const buf =
+ chunk instanceof Uint8Array ? chunk : new TextEncoder().encode(chunk);
+ chunks.push(buf);
+ };
+ const flush = (enqueue) => {
+ const data = concatBuffers(chunks);
+ const encrypted = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(
+ data,
+ aad ?? null,
+ null,
+ iv,
+ key,
+ );
+ // Last 16 bytes are the auth tag
+ authTag = encrypted.slice(-16);
+ enqueue(encrypted.slice(0, -16));
+ };
+ const stream = createTransformStream(transform, flush, streamOptions);
+ stream.result = () => ({
+ key: "encrypt",
+ value: { algorithm: "CHACHA20-POLY1305", iv, authTag },
+ });
+ return stream;
+};
+
+const chacha20Decrypt = async (
+ { key, iv, authTag, aad, maxOutputSize },
+ streamOptions,
+) => {
+ validateKey(key);
+ validateAuthTag(authTag, "CHACHA20-POLY1305");
+ validateAad(aad);
+ let sodium;
+ try {
+ sodium = await import("libsodium-wrappers");
+ await sodium.ready;
+ } catch {
+ throw new Error(
+ "CHACHA20-POLY1305 requires libsodium-wrappers. Install it: npm install libsodium-wrappers",
+ );
+ }
+ validateIv(iv, "CHACHA20-POLY1305");
+ const chunks = [];
+ const transform = (chunk) => {
+ const buf =
+ chunk instanceof Uint8Array ? chunk : new TextEncoder().encode(chunk);
+ chunks.push(buf);
+ };
+ const flush = (enqueue) => {
+ const ciphertext = concatBuffers(chunks);
+ // Re-append auth tag
+ const combined = new Uint8Array(ciphertext.byteLength + authTag.byteLength);
+ combined.set(ciphertext);
+ combined.set(authTag, ciphertext.byteLength);
+ const decrypted = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(
+ null,
+ combined,
+ aad ?? null,
+ iv,
+ key,
+ );
+ if (maxOutputSize != null && decrypted.byteLength > maxOutputSize) {
+ throw new Error(
+ `Decryption output exceeds maxOutputSize (${maxOutputSize} bytes)`,
+ );
+ }
+ enqueue(decrypted);
+ };
+ return createTransformStream(transform, flush, streamOptions);
+};
+
+export const encryptStream = async (
+ { algorithm = "AES-256-GCM", key, iv, aad, maxInputSize } = {},
+ streamOptions = {},
+) => {
+ if (algorithm === "AES-256-GCM") {
+ return aesGcmEncrypt({ key, iv, aad, maxInputSize }, streamOptions);
+ }
+ if (algorithm === "AES-256-CTR") {
+ return aesCtrEncrypt({ key, iv }, streamOptions);
+ }
+ if (algorithm === "CHACHA20-POLY1305") {
+ return chacha20Encrypt({ key, iv, aad }, streamOptions);
+ }
+ throw new Error(`Unsupported algorithm: ${algorithm}`);
+};
+
+export const decryptStream = async (
+ { algorithm = "AES-256-GCM", key, iv, authTag, aad, maxOutputSize } = {},
+ streamOptions = {},
+) => {
+ if (algorithm === "AES-256-GCM") {
+ return aesGcmDecrypt(
+ { key, iv, authTag, aad, maxOutputSize },
+ streamOptions,
+ );
+ }
+ if (algorithm === "AES-256-CTR") {
+ return aesCtrDecrypt({ key, iv, maxOutputSize }, streamOptions);
+ }
+ if (algorithm === "CHACHA20-POLY1305") {
+ return chacha20Decrypt(
+ { key, iv, authTag, aad, maxOutputSize },
+ streamOptions,
+ );
+ }
+ throw new Error(`Unsupported algorithm: ${algorithm}`);
+};
+
+export const generateEncryptionKey = ({ bits = 256 } = {}) => {
+ if (![128, 256].includes(bits)) {
+ throw new Error(`Unsupported key size: ${bits}. Must be 128 or 256.`);
+ }
+ return crypto.getRandomValues(new Uint8Array(bits / 8));
+};
+
+export default {
+ encryptStream,
+ decryptStream,
+ generateEncryptionKey,
+};
diff --git a/packages/encrypt/package.json b/packages/encrypt/package.json
new file mode 100644
index 0000000..639a93d
--- /dev/null
+++ b/packages/encrypt/package.json
@@ -0,0 +1,73 @@
+{
+ "name": "@datastream/encrypt",
+ "version": "0.2.0",
+ "description": "Symmetric encryption/decryption streams",
+ "type": "module",
+ "engines": {
+ "node": ">=24"
+ },
+ "engineStrict": true,
+ "publishConfig": {
+ "access": "public"
+ },
+ "main": "./index.node.mjs",
+ "module": "./index.web.mjs",
+ "exports": {
+ ".": {
+ "node": {
+ "import": {
+ "types": "./index.d.ts",
+ "default": "./index.node.mjs"
+ }
+ },
+ "import": {
+ "types": "./index.d.ts",
+ "default": "./index.web.mjs"
+ }
+ },
+ "./webstream": {
+ "types": "./index.d.ts",
+ "default": "./index.web.mjs"
+ }
+ },
+ "types": "index.d.ts",
+ "files": [
+ "*.mjs",
+ "*.map",
+ "*.d.ts"
+ ],
+ "scripts": {
+ "test": "npm run test:unit",
+ "test:unit": "node --test",
+ "test:benchmark": "node __benchmarks__/index.js"
+ },
+ "license": "MIT",
+ "keywords": [
+ "Web Stream API",
+ "Node Stream API"
+ ],
+ "author": {
+ "name": "datastream contributors",
+ "url": "https://github.com/willfarrell/datastream/graphs/contributors"
+ },
+ "repository": {
+ "type": "git",
+ "url": "github:willfarrell/datastream",
+ "directory": "packages/encrypt"
+ },
+ "bugs": {
+ "url": "https://github.com/willfarrell/datastream/issues"
+ },
+ "homepage": "https://datastream.js.org",
+ "dependencies": {
+ "@datastream/core": "0.2.0"
+ },
+ "peerDependencies": {
+ "libsodium-wrappers": ">=0.7.0"
+ },
+ "peerDependenciesMeta": {
+ "libsodium-wrappers": {
+ "optional": true
+ }
+ }
+}
diff --git a/packages/fetch/index.fuzz.js b/packages/fetch/index.fuzz.js
new file mode 100644
index 0000000..14dae45
--- /dev/null
+++ b/packages/fetch/index.fuzz.js
@@ -0,0 +1,171 @@
+/* global Headers, Response */
+
+import test from "node:test";
+import { streamToArray } from "@datastream/core";
+import { fetchResponseStream, fetchSetDefaults } from "@datastream/fetch";
+import fc from "fast-check";
+
+const catchError = (input, e) => {
+ const expectedErrors = ["fetch 404 GET", "fetch 500 GET"];
+ if (expectedErrors.some((msg) => e.message?.includes(msg))) {
+ return;
+ }
+ console.error(input, e);
+ throw e;
+};
+
+// Mock fetch for fuzz testing
+const originalFetch = global.fetch;
+global.fetch = (_url, _request) => {
+ // Return JSON array response for any URL
+ return Promise.resolve(
+ new Response(
+ JSON.stringify({
+ data: [{ id: 1 }, { id: 2 }],
+ items: [{ key: "a" }],
+ nested: { deep: { values: [{ n: 1 }] } },
+ }),
+ {
+ status: 200,
+ statusText: "OK",
+ headers: new Headers({
+ "Content-Type": "application/json; charset=UTF-8",
+ }),
+ },
+ ),
+ );
+};
+
+// *** fetchResponseStream w/ various dataPath *** //
+test("fuzz fetchResponseStream w/ dataPath variations", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.constantFrom("", "data", "items", "nested.deep.values"),
+ async (dataPath) => {
+ try {
+ fetchSetDefaults({
+ rateLimit: 0,
+ headers: { Accept: "application/json" },
+ });
+ const config = {
+ url: "https://example.org/fuzz",
+ dataPath,
+ };
+ const stream = fetchResponseStream(config);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError({ dataPath }, e);
+ }
+ },
+ ),
+ {
+ numRuns: 100,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** fetchResponseStream w/ query string params *** //
+test("fuzz fetchResponseStream w/ random qs params", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.object({ maxDepth: 0, maxKeys: 5, values: [fc.string()] }),
+ async (qs) => {
+ try {
+ fetchSetDefaults({
+ rateLimit: 0,
+ headers: { Accept: "application/json" },
+ });
+ const config = {
+ url: "https://example.org/fuzz",
+ dataPath: "data",
+ qs,
+ };
+ const stream = fetchResponseStream(config);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError({ qs }, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** fetchResponseStream w/ multiple configs *** //
+test("fuzz fetchResponseStream w/ array of configs", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(
+ fc.record({
+ dataPath: fc.constantFrom("", "data", "items"),
+ }),
+ { minLength: 1, maxLength: 5 },
+ ),
+ async (configs) => {
+ try {
+ fetchSetDefaults({
+ rateLimit: 0,
+ headers: { Accept: "application/json" },
+ });
+ const fetchConfigs = configs.map((c) => ({
+ url: "https://example.org/fuzz",
+ ...c,
+ }));
+ const stream = fetchResponseStream(fetchConfigs);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(configs, e);
+ }
+ },
+ ),
+ {
+ numRuns: 100,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** fetchResponseStream w/ dataPath as array *** //
+test("fuzz fetchResponseStream w/ dataPath as array", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(fc.constantFrom("nested", "deep", "values", "data", "items"), {
+ minLength: 0,
+ maxLength: 3,
+ }),
+ async (dataPath) => {
+ try {
+ fetchSetDefaults({
+ rateLimit: 0,
+ headers: { Accept: "application/json" },
+ });
+ const config = {
+ url: "https://example.org/fuzz",
+ dataPath,
+ };
+ const stream = fetchResponseStream(config);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError({ dataPath }, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// Restore original fetch
+test.after(() => {
+ global.fetch = originalFetch;
+});
diff --git a/packages/fetch/index.js b/packages/fetch/index.js
index 61cb87a..9d9491c 100644
--- a/packages/fetch/index.js
+++ b/packages/fetch/index.js
@@ -7,7 +7,22 @@ import {
timeout,
} from "@datastream/core";
-const defaults = {
+const validatePaginationUrl = (nextUrl, origin) => {
+ if (!nextUrl) return;
+ let url;
+ try {
+ url = new URL(nextUrl);
+ } catch {
+ throw new Error(`Invalid pagination URL: ${nextUrl}`);
+ }
+ if (url.origin !== origin) {
+ throw new Error(
+ `Pagination URL origin (${url.origin}) does not match initial URL origin (${origin})`,
+ );
+ }
+};
+
+let defaults = {
// custom
rateLimit: 0.01, // 100 per sec
dataPath: undefined, // for json response, where the data is to return form body root
@@ -34,7 +49,7 @@ const mergeOptions = (options = {}) => {
};
export const fetchSetDefaults = (options) => {
- Object.assign(defaults, mergeOptions(options));
+ defaults = mergeOptions(options);
};
// Note: requires EncodeStream to ensure it's Uint8Array
@@ -83,6 +98,7 @@ async function* fetchGenerator(fetchOptions, streamOptions) {
"%20",
);
}
+ options.__origin = new URL(options.url).origin;
const response = await fetchUnknown(options, streamOptions);
for await (const chunk of response) {
yield chunk;
@@ -117,6 +133,7 @@ async function* fetchJson(options, streamOptions) {
url = parseLinkFromHeader(response.headers);
url ??= parseNextPath(body, nextPath);
url ??= paginateUsingQuery(options);
+ validatePaginationUrl(url, options.__origin);
options.url = url;
const data = pickPath(body, dataPath);
if (Array.isArray(data)) {
@@ -194,8 +211,30 @@ export const fetchRateLimit = async (options, streamOptions = {}) => {
if (!response.ok) {
// 429 Too Many Requests
if (response.status === 429) {
+ options.retryCount = (options.retryCount ?? 0) + 1;
+ const retryMaxCount = options.retryMaxCount ?? 10;
+ if (options.retryCount >= retryMaxCount) {
+ await response.body?.cancel();
+ throw new Error(
+ `fetch ${response.status} ${options.method} ${options.url} max retries (${retryMaxCount}) exceeded`,
+ {
+ cause: {
+ status: response.status,
+ url: options.url,
+ method: options.method,
+ },
+ },
+ );
+ }
+ await response.body?.cancel();
+ const retryAfter = response.headers.get("Retry-After");
+ const backoffMs = retryAfter
+ ? Number.parseInt(retryAfter, 10) * 1000 || 1000
+ : Math.min(1000 * 2 ** (options.retryCount - 1), 30_000);
+ await timeout(backoffMs, streamOptions);
return fetchRateLimit(options, streamOptions);
}
+ await response.body?.cancel();
throw new Error(
`fetch ${response.status} ${options.method} ${options.url}`,
{
diff --git a/packages/fetch/index.test.js b/packages/fetch/index.test.js
index c100f0b..5c20385 100644
--- a/packages/fetch/index.test.js
+++ b/packages/fetch/index.test.js
@@ -1,6 +1,6 @@
/* global Headers, Response */
-import { deepStrictEqual, strictEqual } from "node:assert";
+import { deepStrictEqual, ok, strictEqual } from "node:assert";
import test from "node:test";
import {
createPassThroughStream,
@@ -470,6 +470,181 @@ test(`${variant}: fetchResponseStream should handle dataPath as array`, async (_
deepStrictEqual(output, [{ id: 1 }]);
});
+// *** fetchRateLimit 429 max retry regression *** //
+test(`${variant}: fetchRateLimit should throw after max retries on persistent 429`, async (_t) => {
+ const originalFetch = global.fetch;
+ let callCount = 0;
+ global.fetch = () => {
+ callCount++;
+ return Promise.resolve(
+ new Response("rate limited", {
+ status: 429,
+ statusText: "Too Many Requests",
+ }),
+ );
+ };
+
+ fetchSetDefaults({ rateLimit: 0 });
+ const config = [
+ {
+ url: "https://example.org/always-429",
+ rateLimit: 0,
+ retryMaxCount: 2,
+ },
+ ];
+ try {
+ const stream = fetchResponseStream(config);
+ await streamToArray(stream);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("max retries"));
+ ok(callCount >= 2, `Expected at least 2 calls, got ${callCount}`);
+ } finally {
+ global.fetch = originalFetch;
+ }
+});
+
+// *** SSRF protection: same-origin pagination *** //
+test(`${variant}: fetchResponseStream should reject Link header with cross-origin URL`, async (_t) => {
+ const originalFetch = global.fetch;
+ global.fetch = async (url) => {
+ if (url === "https://example.org/ssrf-link") {
+ return new Response(JSON.stringify({ data: [{ id: 1 }] }), {
+ status: 200,
+ headers: new Headers({
+ "Content-Type": "application/json",
+ Link: '; rel="next"',
+ }),
+ });
+ }
+ return originalFetch(url);
+ };
+ fetchSetDefaults({ dataPath: "data" });
+ try {
+ const stream = fetchResponseStream({
+ url: "https://example.org/ssrf-link",
+ });
+ await streamToArray(stream);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("does not match initial URL origin"));
+ } finally {
+ global.fetch = originalFetch;
+ }
+});
+
+test(`${variant}: fetchResponseStream should reject nextPath with cross-origin URL`, async (_t) => {
+ const originalFetch = global.fetch;
+ global.fetch = async (url) => {
+ if (url === "https://example.org/ssrf-next") {
+ return new Response(
+ JSON.stringify({
+ data: [{ id: 1 }],
+ next: "http://127.0.0.1:8080/internal",
+ }),
+ {
+ status: 200,
+ headers: new Headers({
+ "Content-Type": "application/json",
+ }),
+ },
+ );
+ }
+ return originalFetch(url);
+ };
+ fetchSetDefaults({});
+ try {
+ const stream = fetchResponseStream({
+ url: "https://example.org/ssrf-next",
+ dataPath: "data",
+ nextPath: "next",
+ });
+ await streamToArray(stream);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("does not match initial URL origin"));
+ } finally {
+ global.fetch = originalFetch;
+ }
+});
+
+test(`${variant}: fetchResponseStream should reject nextPath with different protocol`, async (_t) => {
+ const originalFetch = global.fetch;
+ global.fetch = async (url) => {
+ if (url === "https://example.org/ssrf-proto") {
+ return new Response(
+ JSON.stringify({
+ data: [{ id: 1 }],
+ next: "file:///etc/passwd",
+ }),
+ {
+ status: 200,
+ headers: new Headers({
+ "Content-Type": "application/json",
+ }),
+ },
+ );
+ }
+ return originalFetch(url);
+ };
+ fetchSetDefaults({});
+ try {
+ const stream = fetchResponseStream({
+ url: "https://example.org/ssrf-proto",
+ dataPath: "data",
+ nextPath: "next",
+ });
+ await streamToArray(stream);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("does not match initial URL origin"));
+ } finally {
+ global.fetch = originalFetch;
+ }
+});
+
+test(`${variant}: fetchResponseStream should reject Link header with different port`, async (_t) => {
+ const originalFetch = global.fetch;
+ global.fetch = async (url) => {
+ if (url === "https://example.org/ssrf-port") {
+ return new Response(JSON.stringify({ data: [{ id: 1 }] }), {
+ status: 200,
+ headers: new Headers({
+ "Content-Type": "application/json",
+ Link: '; rel="next"',
+ }),
+ });
+ }
+ return originalFetch(url);
+ };
+ fetchSetDefaults({ dataPath: "data" });
+ try {
+ const stream = fetchResponseStream({
+ url: "https://example.org/ssrf-port",
+ });
+ await streamToArray(stream);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("does not match initial URL origin"));
+ } finally {
+ global.fetch = originalFetch;
+ }
+});
+
+test(`${variant}: fetchResponseStream should allow same-origin pagination`, async (_t) => {
+ // Existing Link header tests (json-obj/2 → json-obj/3) already verify this,
+ // but adding an explicit test for clarity.
+ fetchSetDefaults({ dataPath: "", headers: { Accept: "application/json" } });
+ const config = [{ url: "https://example.org/json-obj/2" }];
+ const stream = fetchResponseStream(config);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [
+ { key: "item", value: 2 },
+ { key: "item", value: 3 },
+ ]);
+});
+
// *** default export *** //
test(`${variant}: default export should include all stream functions`, (_t) => {
deepStrictEqual(Object.keys(fetchDefault).sort(), [
diff --git a/packages/fetch/package.json b/packages/fetch/package.json
index 8184ff3..246453f 100644
--- a/packages/fetch/package.json
+++ b/packages/fetch/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/fetch",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "HTTP fetch-based readable and writable streams with pagination and rate limiting",
"type": "module",
"engines": {
@@ -60,6 +60,6 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
}
}
diff --git a/packages/file/index.d.ts b/packages/file/index.d.ts
index 8ec7af9..351804f 100644
--- a/packages/file/index.d.ts
+++ b/packages/file/index.d.ts
@@ -21,3 +21,9 @@ export function fileWriteStream(
},
streamOptions?: StreamOptions,
): Promise;
+
+declare const _default: {
+ readStream: typeof fileReadStream;
+ writeStream: typeof fileWriteStream;
+};
+export default _default;
diff --git a/packages/file/index.fuzz.js b/packages/file/index.fuzz.js
index ae84ff1..69cc346 100644
--- a/packages/file/index.fuzz.js
+++ b/packages/file/index.fuzz.js
@@ -1,9 +1,14 @@
+import { strictEqual } from "node:assert";
import test from "node:test";
import { fileReadStream, fileWriteStream } from "@datastream/file";
import fc from "fast-check";
const catchError = (input, e) => {
- const expectedErrors = ["Invalid extension"];
+ const expectedErrors = [
+ "Invalid extension",
+ "Path traversal detected",
+ "Symbolic links are not allowed",
+ ];
if (expectedErrors.includes(e.message)) {
return;
}
@@ -83,3 +88,43 @@ test("fuzz fileReadStream w/ types", async () => {
},
);
});
+
+// *** path traversal protection regression *** //
+test("fileReadStream should reject path traversal when basePath is set", () => {
+ try {
+ fileReadStream({
+ path: "/etc/passwd",
+ basePath: "/tmp/safe",
+ types: [],
+ });
+ throw new Error("Should have thrown");
+ } catch (e) {
+ strictEqual(e.message, "Path traversal detected");
+ }
+});
+
+test("fileReadStream should reject relative path traversal when basePath is set", () => {
+ try {
+ fileReadStream({
+ path: "/tmp/safe/../../etc/passwd",
+ basePath: "/tmp/safe",
+ types: [],
+ });
+ throw new Error("Should have thrown");
+ } catch (e) {
+ strictEqual(e.message, "Path traversal detected");
+ }
+});
+
+test("fileWriteStream should reject path traversal when basePath is set", () => {
+ try {
+ fileWriteStream({
+ path: "/etc/shadow",
+ basePath: "/tmp/safe",
+ types: [],
+ });
+ throw new Error("Should have thrown");
+ } catch (e) {
+ strictEqual(e.message, "Path traversal detected");
+ }
+});
diff --git a/packages/file/index.node.js b/packages/file/index.node.js
index 90e4162..de23729 100644
--- a/packages/file/index.node.js
+++ b/packages/file/index.node.js
@@ -1,19 +1,70 @@
// Copyright 2026 will Farrell, and datastream contributors.
// SPDX-License-Identifier: MIT
-import { createReadStream, createWriteStream } from "node:fs";
-import { extname } from "node:path";
+import {
+ constants,
+ createReadStream,
+ createWriteStream,
+ lstatSync,
+ openSync,
+} from "node:fs";
+import { extname, resolve } from "node:path";
import { makeOptions } from "@datastream/core";
-export const fileReadStream = ({ path, types }, streamOptions = {}) => {
+export const fileReadStream = (
+ { path, basePath, types },
+ streamOptions = {},
+) => {
+ enforcePath(path, basePath);
enforceType(path, types);
+ if (basePath != null) {
+ // Open with O_NOFOLLOW to prevent TOCTOU symlink race
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
+ return createReadStream(null, { ...makeOptions(streamOptions), fd });
+ }
return createReadStream(path, makeOptions(streamOptions));
};
-export const fileWriteStream = ({ path, types }, streamOptions = {}) => {
+export const fileWriteStream = (
+ { path, basePath, types },
+ streamOptions = {},
+) => {
+ enforcePath(path, basePath);
enforceType(path, types);
+ if (basePath != null) {
+ const fd = openSync(
+ path,
+ constants.O_WRONLY |
+ constants.O_CREAT |
+ constants.O_TRUNC |
+ constants.O_NOFOLLOW,
+ );
+ return createWriteStream(null, { ...makeOptions(streamOptions), fd });
+ }
return createWriteStream(path, makeOptions(streamOptions));
};
+const enforcePath = (path, basePath) => {
+ if (basePath != null) {
+ const resolvedPath = resolve(path);
+ const resolvedBase = resolve(basePath);
+ if (!resolvedPath.startsWith(resolvedBase)) {
+ throw new Error("Path traversal detected");
+ }
+ try {
+ const stat = lstatSync(resolvedPath);
+ if (stat.isSymbolicLink()) {
+ throw new Error("Symbolic links are not allowed");
+ }
+ } catch (e) {
+ if (e.message === "Symbolic links are not allowed") throw e;
+ // File may not exist yet (for writes), that's ok
+ if (e.code !== "ENOENT") {
+ throw new Error("Path not found", { cause: e });
+ }
+ }
+ }
+};
+
const enforceType = (path, types = []) => {
const pathExt = extname(path);
for (const type of types) {
diff --git a/packages/file/index.test.js b/packages/file/index.test.js
new file mode 100644
index 0000000..b500cad
--- /dev/null
+++ b/packages/file/index.test.js
@@ -0,0 +1,114 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import { deepStrictEqual, strictEqual, throws } from "node:assert";
+import { mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import test from "node:test";
+import { streamToString } from "@datastream/core";
+import fileDefault, { fileReadStream, fileWriteStream } from "@datastream/file";
+
+let variant = "unknown";
+for (const execArgv of process.execArgv) {
+ const flag = "--conditions=";
+ if (execArgv.includes("--conditions=")) {
+ variant = execArgv.replace(flag, "");
+ }
+}
+
+const testDir = mkdtempSync(join(tmpdir(), "datastream-file-test-"));
+const testFile = join(testDir, "test.csv");
+const testContent = "a,b,c\n1,2,3\n";
+
+test.before(() => {
+ writeFileSync(testFile, testContent);
+});
+
+test.after(() => {
+ rmSync(testDir, { recursive: true, force: true });
+});
+
+const csvTypes = [{ accept: { "text/csv": [".csv"] } }];
+const jsonTypes = [{ accept: { "application/json": [".json"] } }];
+
+// *** fileReadStream *** //
+test(`${variant}: fileReadStream should read a file`, async () => {
+ const stream = fileReadStream({ path: testFile });
+ const output = await streamToString(stream);
+ strictEqual(output, testContent);
+});
+
+// *** Path traversal *** //
+test(`${variant}: fileReadStream should reject path traversal`, () => {
+ throws(() => fileReadStream({ path: "/etc/passwd", basePath: testDir }), {
+ message: "Path traversal detected",
+ });
+});
+
+test(`${variant}: fileReadStream should reject relative path traversal`, () => {
+ throws(
+ () =>
+ fileReadStream({
+ path: join(testDir, "../../etc/passwd"),
+ basePath: testDir,
+ }),
+ { message: "Path traversal detected" },
+ );
+});
+
+test(`${variant}: fileWriteStream should reject path traversal`, () => {
+ throws(() => fileWriteStream({ path: "/etc/shadow", basePath: testDir }), {
+ message: "Path traversal detected",
+ });
+});
+
+// *** Symlink rejection *** //
+test(`${variant}: fileReadStream should reject symlinks`, () => {
+ const linkPath = join(testDir, "link.csv");
+ symlinkSync(testFile, linkPath);
+ throws(() => fileReadStream({ path: linkPath, basePath: testDir }), {
+ message: "Symbolic links are not allowed",
+ });
+});
+
+// *** Extension enforcement *** //
+test(`${variant}: fileReadStream should accept matching extension`, async () => {
+ const stream = fileReadStream({ path: testFile, types: csvTypes });
+ await streamToString(stream);
+});
+
+test(`${variant}: fileReadStream should reject non-matching extension`, () => {
+ throws(() => fileReadStream({ path: testFile, types: jsonTypes }), {
+ message: "Invalid extension",
+ });
+});
+
+test(`${variant}: fileReadStream should allow any extension when types is empty`, async () => {
+ const stream = fileReadStream({ path: testFile, types: [] });
+ await streamToString(stream);
+});
+
+test(`${variant}: fileWriteStream should reject non-matching extension`, () => {
+ throws(
+ () =>
+ fileWriteStream({
+ path: join(testDir, "out.csv"),
+ types: jsonTypes,
+ }),
+ { message: "Invalid extension" },
+ );
+});
+
+// *** No basePath = no path checks *** //
+test(`${variant}: fileReadStream allows any path without basePath`, async () => {
+ const stream = fileReadStream({ path: testFile });
+ await streamToString(stream);
+});
+
+// *** default export *** //
+test(`${variant}: default export should include all stream functions`, () => {
+ deepStrictEqual(Object.keys(fileDefault).sort(), [
+ "readStream",
+ "writeStream",
+ ]);
+});
diff --git a/packages/file/index.tst.ts b/packages/file/index.tst.ts
new file mode 100644
index 0000000..e393569
--- /dev/null
+++ b/packages/file/index.tst.ts
@@ -0,0 +1,28 @@
+import _default, { fileReadStream, fileWriteStream } from "@datastream/file";
+import { describe, expect, test } from "tstyche";
+
+describe("fileReadStream", () => {
+ test("accepts options", () => {
+ expect(
+ fileReadStream({ types: [{ accept: { "text/csv": [".csv"] } }] }),
+ ).type.not.toBeAssignableTo();
+ });
+});
+
+describe("fileWriteStream", () => {
+ test("accepts options", () => {
+ expect(
+ fileWriteStream({ path: "test.csv" }),
+ ).type.not.toBeAssignableTo();
+ });
+});
+
+describe("default export", () => {
+ test("has readStream", () => {
+ expect(_default.readStream).type.toBe();
+ });
+
+ test("has writeStream", () => {
+ expect(_default.writeStream).type.toBe();
+ });
+});
diff --git a/packages/file/package.json b/packages/file/package.json
index 587fc75..c1d9cf0 100644
--- a/packages/file/package.json
+++ b/packages/file/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/file",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "File system readable and writable streams with extension type enforcement",
"type": "module",
"engines": {
@@ -60,6 +60,6 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
}
}
diff --git a/packages/indexeddb/index.fuzz.js b/packages/indexeddb/index.fuzz.js
new file mode 100644
index 0000000..153c17d
--- /dev/null
+++ b/packages/indexeddb/index.fuzz.js
@@ -0,0 +1,68 @@
+import test from "node:test";
+import {
+ indexedDBReadStream,
+ indexedDBWriteStream,
+} from "@datastream/indexeddb";
+import fc from "fast-check";
+
+const catchError = (input, e) => {
+ const expectedErrors = [
+ "indexedDBReadStream: Not supported",
+ "indexedDBWriteStream: Not supported",
+ ];
+ if (expectedErrors.includes(e.message)) {
+ return;
+ }
+ console.error(input, e);
+ throw e;
+};
+
+// *** indexedDBReadStream *** //
+test("fuzz indexedDBReadStream w/ random options", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.record({
+ db: fc.option(fc.anything()),
+ store: fc.option(fc.string({ minLength: 0, maxLength: 100 })),
+ index: fc.option(fc.string({ minLength: 0, maxLength: 100 })),
+ key: fc.option(fc.anything()),
+ }),
+ async (options) => {
+ try {
+ await indexedDBReadStream(options);
+ } catch (e) {
+ catchError(options, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** indexedDBWriteStream *** //
+test("fuzz indexedDBWriteStream w/ random options", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.record({
+ db: fc.option(fc.anything()),
+ store: fc.option(fc.string({ minLength: 0, maxLength: 100 })),
+ }),
+ async (options) => {
+ try {
+ await indexedDBWriteStream(options);
+ } catch (e) {
+ catchError(options, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
diff --git a/packages/indexeddb/package.json b/packages/indexeddb/package.json
index 0cfc051..6f73ab6 100644
--- a/packages/indexeddb/package.json
+++ b/packages/indexeddb/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/indexeddb",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "IndexedDB readable and writable streams for browser storage",
"type": "module",
"engines": {
@@ -60,7 +60,7 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6",
+ "@datastream/core": "0.2.0",
"idb": "8.0.3"
}
}
diff --git a/packages/ipfs/index.d.ts b/packages/ipfs/index.d.ts
index 8d40456..4b6e9e5 100644
--- a/packages/ipfs/index.d.ts
+++ b/packages/ipfs/index.d.ts
@@ -2,9 +2,14 @@
// SPDX-License-Identifier: MIT
import type { StreamOptions, StreamResult } from "@datastream/core";
+export interface IpfsNode {
+ get(cid: string): unknown;
+ add(data: unknown[]): Promise<{ cid: string }>;
+}
+
export function ipfsGetStream(
options: {
- node: unknown;
+ node: IpfsNode;
cid: string;
},
streamOptions?: StreamOptions,
@@ -12,7 +17,7 @@ export function ipfsGetStream(
export function ipfsAddStream(
options?: {
- node?: unknown;
+ node?: IpfsNode;
resultKey?: string;
},
streamOptions?: StreamOptions,
@@ -22,4 +27,8 @@ export function ipfsAddStream(
}
>;
-export default ipfsGetStream;
+declare const _default: {
+ getStream: typeof ipfsGetStream;
+ addStream: typeof ipfsAddStream;
+};
+export default _default;
diff --git a/packages/ipfs/index.fuzz.js b/packages/ipfs/index.fuzz.js
new file mode 100644
index 0000000..8923800
--- /dev/null
+++ b/packages/ipfs/index.fuzz.js
@@ -0,0 +1,75 @@
+import test from "node:test";
+import { ipfsAddStream, ipfsGetStream } from "@datastream/ipfs";
+import fc from "fast-check";
+
+const catchError = (input, e) => {
+ const expectedErrors = [];
+ if (expectedErrors.includes(e.message)) {
+ return;
+ }
+ console.error(input, e);
+ throw e;
+};
+
+// *** ipfsGetStream *** //
+test("fuzz ipfsGetStream w/ random cid", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.string({ minLength: 1, maxLength: 100 }),
+ async (cid) => {
+ try {
+ const node = {
+ get(_cid) {
+ return Buffer.from(`data-${_cid}`);
+ },
+ add(_stream) {
+ return { cid: "QmFuzz" };
+ },
+ };
+ await ipfsGetStream({ node, cid });
+ } catch (e) {
+ catchError(cid, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** ipfsAddStream *** //
+test("fuzz ipfsAddStream w/ random resultKey", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.option(fc.string({ minLength: 1, maxLength: 50 })),
+ async (resultKey) => {
+ try {
+ const node = {
+ get(_cid) {
+ return Buffer.from("data");
+ },
+ add(_stream) {
+ return { cid: "QmFuzzAdd" };
+ },
+ };
+ const options = { node };
+ if (resultKey !== null) {
+ options.resultKey = resultKey;
+ }
+ const stream = await ipfsAddStream(options);
+ stream.result();
+ } catch (e) {
+ catchError(resultKey, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
diff --git a/packages/ipfs/index.js b/packages/ipfs/index.js
index 262df6e..e82382b 100644
--- a/packages/ipfs/index.js
+++ b/packages/ipfs/index.js
@@ -2,22 +2,26 @@
// SPDX-License-Identifier: MIT
import { createPassThroughStream } from "@datastream/core";
-export const ipfsGetStream = async (
- { node, _repo, cid },
- _streamOptions = {},
-) => {
- // node ??= await create({ repo })
+export const ipfsGetStream = async ({ node, cid }, _streamOptions = {}) => {
return node.get(cid);
};
export const ipfsAddStream = async (
- { node, _repo, resultKey } = {},
+ { node, resultKey } = {},
streamOptions = {},
) => {
- // node ??= await create({ repo })
-
- const stream = createPassThroughStream(() => {}, streamOptions);
- const { cid } = node.add(stream);
+ const chunks = [];
+ let cid;
+ const stream = createPassThroughStream(
+ (chunk) => {
+ chunks.push(chunk);
+ },
+ async () => {
+ const result = await node.add(chunks);
+ cid = result.cid;
+ },
+ streamOptions,
+ );
stream.result = () => ({
key: resultKey ?? "cid",
diff --git a/packages/ipfs/index.perf.js b/packages/ipfs/index.perf.js
new file mode 100644
index 0000000..360e47d
--- /dev/null
+++ b/packages/ipfs/index.perf.js
@@ -0,0 +1,82 @@
+import test from "node:test";
+import {
+ createReadableStream,
+ pipeline,
+ streamToArray,
+} from "@datastream/core";
+import { ipfsAddStream, ipfsGetStream } from "@datastream/ipfs";
+import { Bench } from "tinybench";
+
+// -- Data generators --
+
+const time = Number(process.env.BENCH_TIME ?? 5_000);
+
+const generateChunks = (count, size) =>
+ Array.from({ length: count }, () => "x".repeat(size));
+
+const smallChunks = generateChunks(100, 1_024); // 100 × 1KB
+const largeChunks = generateChunks(1_000, 1_024); // 1000 × 1KB
+
+// -- Tests --
+
+test("perf: ipfsGetStream", async () => {
+ const bench = new Bench({ name: "ipfsGetStream", time });
+
+ bench.add("100 × 1KB chunks", async () => {
+ const node = {
+ get(_cid) {
+ return createReadableStream(smallChunks);
+ },
+ };
+ const stream = await ipfsGetStream({ node, cid: "QmPerf" });
+ await streamToArray(stream);
+ });
+
+ bench.add("1000 × 1KB chunks", async () => {
+ const node = {
+ get(_cid) {
+ return createReadableStream(largeChunks);
+ },
+ };
+ const stream = await ipfsGetStream({ node, cid: "QmPerf" });
+ await streamToArray(stream);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: ipfsAddStream", async () => {
+ const bench = new Bench({ name: "ipfsAddStream", time });
+
+ bench.add("100 × 1KB chunks", async () => {
+ const node = {
+ async add(_data) {
+ return { cid: "QmResult" };
+ },
+ };
+ const streams = [
+ createReadableStream(smallChunks),
+ await ipfsAddStream({ node }),
+ ];
+ await pipeline(streams);
+ });
+
+ bench.add("1000 × 1KB chunks", async () => {
+ const node = {
+ async add(_data) {
+ return { cid: "QmResult" };
+ },
+ };
+ const streams = [
+ createReadableStream(largeChunks),
+ await ipfsAddStream({ node }),
+ ];
+ await pipeline(streams);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
diff --git a/packages/ipfs/index.test.js b/packages/ipfs/index.test.js
new file mode 100644
index 0000000..fc24dd7
--- /dev/null
+++ b/packages/ipfs/index.test.js
@@ -0,0 +1,109 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import { deepStrictEqual, strictEqual } from "node:assert";
+import test from "node:test";
+import {
+ createReadableStream,
+ pipejoin,
+ pipeline,
+ streamToArray,
+} from "@datastream/core";
+import ipfsDefault, { ipfsAddStream, ipfsGetStream } from "@datastream/ipfs";
+
+let variant = "unknown";
+for (const execArgv of process.execArgv) {
+ const flag = "--conditions=";
+ if (execArgv.includes("--conditions=")) {
+ variant = execArgv.replace(flag, "");
+ }
+}
+
+// *** ipfsGetStream *** //
+test(`${variant}: ipfsGetStream should return readable stream from node.get`, async () => {
+ const chunks = ["chunk1", "chunk2", "chunk3"];
+ const node = {
+ get(_cid) {
+ return createReadableStream(chunks);
+ },
+ };
+ const stream = await ipfsGetStream({ node, cid: "QmTest123" });
+ const output = await streamToArray(stream);
+ deepStrictEqual(output, chunks);
+});
+
+test(`${variant}: ipfsGetStream should pass cid to node.get`, async () => {
+ let receivedCid;
+ const node = {
+ get(cid) {
+ receivedCid = cid;
+ return createReadableStream(["data"]);
+ },
+ };
+ await ipfsGetStream({ node, cid: "bafyTestCidV1" });
+ strictEqual(receivedCid, "bafyTestCidV1");
+});
+
+test(`${variant}: ipfsGetStream should work in a pipeline`, async () => {
+ const chunks = ["hello", "world"];
+ const node = {
+ get(_cid) {
+ return createReadableStream(chunks);
+ },
+ };
+ const streams = [await ipfsGetStream({ node, cid: "QmTest123" })];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+ deepStrictEqual(output, chunks);
+});
+
+// *** ipfsAddStream *** //
+test(`${variant}: ipfsAddStream should pipe data through and call node.add on flush`, async () => {
+ const input = ["chunk1", "chunk2"];
+ let addedData;
+ const node = {
+ async add(data) {
+ addedData = data;
+ return { cid: "QmResult123" };
+ },
+ };
+ const streams = [createReadableStream(input), await ipfsAddStream({ node })];
+ await pipeline(streams);
+ const { key, value } = streams[1].result();
+ strictEqual(key, "cid");
+ strictEqual(value, "QmResult123");
+ deepStrictEqual(addedData, input);
+});
+
+test(`${variant}: ipfsAddStream should use custom resultKey`, async () => {
+ const node = {
+ async add(_data) {
+ return { cid: "QmResult123" };
+ },
+ };
+ const streams = [
+ createReadableStream(["data"]),
+ await ipfsAddStream({ node, resultKey: "ipfsCid" }),
+ ];
+ await pipeline(streams);
+ const { key } = streams[1].result();
+ strictEqual(key, "ipfsCid");
+});
+
+test(`${variant}: ipfsAddStream result should be collected by pipeline`, async () => {
+ const node = {
+ async add(_data) {
+ return { cid: "bafyResult456" };
+ },
+ };
+ const streams = [
+ createReadableStream(["data"]),
+ await ipfsAddStream({ node }),
+ ];
+ const result = await pipeline(streams);
+ strictEqual(result.cid, "bafyResult456");
+});
+
+// *** default export *** //
+test(`${variant}: default export should include all stream functions`, () => {
+ deepStrictEqual(Object.keys(ipfsDefault).sort(), ["addStream", "getStream"]);
+});
diff --git a/packages/ipfs/index.tst.ts b/packages/ipfs/index.tst.ts
new file mode 100644
index 0000000..ed276ad
--- /dev/null
+++ b/packages/ipfs/index.tst.ts
@@ -0,0 +1,41 @@
+import type { IpfsNode } from "@datastream/ipfs";
+import _default, { ipfsAddStream, ipfsGetStream } from "@datastream/ipfs";
+import { describe, expect, test } from "tstyche";
+
+const mockNode: IpfsNode = {
+ get(_cid: string) {
+ return {};
+ },
+ async add(_data: unknown[]) {
+ return { cid: "QmTest" };
+ },
+};
+
+describe("ipfsGetStream", () => {
+ test("accepts node and cid", () => {
+ expect(
+ ipfsGetStream({ node: mockNode, cid: "QmTest" }),
+ ).type.not.toBeAssignableTo();
+ });
+});
+
+describe("ipfsAddStream", () => {
+ test("accepts options", () => {
+ expect(
+ ipfsAddStream({
+ node: mockNode,
+ resultKey: "cid",
+ }),
+ ).type.not.toBeAssignableTo();
+ });
+});
+
+describe("default export", () => {
+ test("has getStream", () => {
+ expect(_default.getStream).type.toBe();
+ });
+
+ test("has addStream", () => {
+ expect(_default.addStream).type.toBe();
+ });
+});
diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json
index 37a63ac..197a4f0 100644
--- a/packages/ipfs/package.json
+++ b/packages/ipfs/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/ipfs",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "IPFS get and add streaming operations",
"type": "module",
"engines": {
@@ -61,6 +61,6 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
}
}
diff --git a/packages/json/index.d.ts b/packages/json/index.d.ts
new file mode 100644
index 0000000..ee5fc0a
--- /dev/null
+++ b/packages/json/index.d.ts
@@ -0,0 +1,45 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import type { StreamOptions, StreamResult } from "@datastream/core";
+
+export interface JsonError {
+ id: string;
+ message: string;
+ idx: number[];
+}
+
+export function ndjsonParseStream(
+ options?: {
+ maxBufferSize?: number;
+ resultKey?: string;
+ },
+ streamOptions?: StreamOptions,
+): unknown & {
+ result: () => StreamResult>;
+};
+
+export function ndjsonFormatStream(
+ options?: {
+ space?: number | string;
+ resultKey?: string;
+ },
+ streamOptions?: StreamOptions,
+): unknown;
+
+export function jsonParseStream(
+ options?: {
+ maxBufferSize?: number;
+ maxValueSize?: number;
+ resultKey?: string;
+ },
+ streamOptions?: StreamOptions,
+): unknown & {
+ result: () => StreamResult>;
+};
+
+export function jsonFormatStream(
+ options?: {
+ space?: number | string;
+ },
+ streamOptions?: StreamOptions,
+): unknown;
diff --git a/packages/json/index.fuzz.js b/packages/json/index.fuzz.js
new file mode 100644
index 0000000..c1bd028
--- /dev/null
+++ b/packages/json/index.fuzz.js
@@ -0,0 +1,154 @@
+import test from "node:test";
+import {
+ createReadableStream,
+ pipejoin,
+ streamToArray,
+} from "@datastream/core";
+import {
+ jsonFormatStream,
+ jsonParseStream,
+ ndjsonFormatStream,
+ ndjsonParseStream,
+} from "@datastream/json";
+import fc from "fast-check";
+
+const catchError = (input, e) => {
+ const expectedErrors = [];
+ if (expectedErrors.includes(e.message)) {
+ return;
+ }
+ console.error(input, e);
+ throw e;
+};
+
+// *** ndjsonParseStream *** //
+test("fuzz ndjsonParseStream w/ string input", async () => {
+ await fc.assert(
+ fc.asyncProperty(fc.string(), async (input) => {
+ try {
+ const streams = [createReadableStream(input), ndjsonParseStream()];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(input, e);
+ }
+ }),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+test("fuzz ndjsonParseStream w/ ndjson-like input", async () => {
+ const ndjsonArb = fc
+ .array(fc.jsonValue(), { minLength: 1, maxLength: 20 })
+ .map((values) => values.map((v) => JSON.stringify(v)).join("\n"));
+
+ await fc.assert(
+ fc.asyncProperty(ndjsonArb, async (input) => {
+ try {
+ const streams = [createReadableStream(input), ndjsonParseStream()];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(input, e);
+ }
+ }),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** ndjsonFormatStream *** //
+test("fuzz ndjsonFormatStream w/ object input", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(fc.object({ maxDepth: 2 }), { minLength: 1, maxLength: 20 }),
+ async (input) => {
+ try {
+ const streams = [createReadableStream(input), ndjsonFormatStream()];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(input, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** jsonParseStream *** //
+test("fuzz jsonParseStream w/ string input", async () => {
+ await fc.assert(
+ fc.asyncProperty(fc.string(), async (input) => {
+ try {
+ const streams = [createReadableStream(input), jsonParseStream()];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(input, e);
+ }
+ }),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+test("fuzz jsonParseStream w/ json array input", async () => {
+ const jsonArrayArb = fc
+ .array(fc.object({ maxDepth: 2 }), { minLength: 0, maxLength: 20 })
+ .map((arr) => JSON.stringify(arr));
+
+ await fc.assert(
+ fc.asyncProperty(jsonArrayArb, async (input) => {
+ try {
+ const streams = [createReadableStream(input), jsonParseStream()];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(input, e);
+ }
+ }),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
+
+// *** jsonFormatStream *** //
+test("fuzz jsonFormatStream w/ object input", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.array(fc.object({ maxDepth: 2 }), { minLength: 1, maxLength: 20 }),
+ async (input) => {
+ try {
+ const streams = [createReadableStream(input), jsonFormatStream()];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ } catch (e) {
+ catchError(input, e);
+ }
+ },
+ ),
+ {
+ numRuns: 1_000,
+ verbose: 2,
+ examples: [],
+ },
+ );
+});
diff --git a/packages/json/index.js b/packages/json/index.js
new file mode 100644
index 0000000..45eae1a
--- /dev/null
+++ b/packages/json/index.js
@@ -0,0 +1,260 @@
+// Copyright 2026 will Farrell, and datastream contributors.
+// SPDX-License-Identifier: MIT
+import { createTransformStream } from "@datastream/core";
+
+// --- NDJSON ---
+
+export const ndjsonParseStream = (options = {}, streamOptions = {}) => {
+ const { maxBufferSize = 16_777_216, resultKey } = options;
+ let buffer = "";
+ let idx = 0;
+ const errors = {};
+
+ const trackError = (id, message) => {
+ if (!errors[id]) errors[id] = { id, message, idx: [] };
+ errors[id].idx.push(idx);
+ };
+
+ const transform = (chunk, enqueue) => {
+ buffer += chunk;
+ let pos = 0;
+ while (true) {
+ const nlIdx = buffer.indexOf("\n", pos);
+ if (nlIdx === -1) {
+ buffer = buffer.substring(pos);
+ break;
+ }
+ const line = buffer.substring(pos, nlIdx).trimEnd();
+ pos = nlIdx + 1;
+ if (line.length === 0) continue;
+ try {
+ enqueue(JSON.parse(line));
+ } catch {
+ trackError("ParseError", "Invalid JSON");
+ }
+ idx++;
+ }
+ if (buffer.length > maxBufferSize) {
+ throw new Error(
+ `ndjsonParseStream buffer (${buffer.length}) exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ };
+
+ const flush = (enqueue) => {
+ const line = buffer.trimEnd();
+ if (line.length > 0) {
+ try {
+ enqueue(JSON.parse(line));
+ } catch {
+ trackError("ParseError", "Invalid JSON");
+ }
+ idx++;
+ }
+ buffer = "";
+ };
+
+ const stream = createTransformStream(transform, flush, streamOptions);
+ stream.result = () => ({ key: resultKey ?? "jsonErrors", value: errors });
+ return stream;
+};
+
+export const ndjsonFormatStream = (options = {}, streamOptions = {}) => {
+ const { space } = options;
+ const batch = [];
+
+ const transform = (chunk, enqueue) => {
+ batch.push(JSON.stringify(chunk, null, space));
+ if (batch.length >= 64) {
+ enqueue(`${batch.join("\n")}\n`);
+ batch.length = 0;
+ }
+ };
+
+ const flush = (enqueue) => {
+ if (batch.length > 0) {
+ enqueue(`${batch.join("\n")}\n`);
+ batch.length = 0;
+ }
+ };
+
+ return createTransformStream(transform, flush, streamOptions);
+};
+
+// --- JSON Array ---
+
+export const jsonParseStream = (options = {}, streamOptions = {}) => {
+ const {
+ maxBufferSize = 16_777_216,
+ maxValueSize = 16_777_216,
+ resultKey,
+ } = options;
+
+ let buffer = "";
+ let scanPos = 0;
+ let depth = 0;
+ let inString = false;
+ let escaped = false;
+ let started = false;
+ let elementStart = -1;
+ let idx = 0;
+ const errors = {};
+
+ const trackError = (id, message) => {
+ if (!errors[id]) errors[id] = { id, message, idx: [] };
+ errors[id].idx.push(idx);
+ };
+
+ const emitElement = (text, enqueue) => {
+ const trimmed = text.trim();
+ if (trimmed.length === 0) return;
+ if (trimmed.length > maxValueSize) {
+ throw new Error(
+ `jsonParseStream value size (${trimmed.length}) exceeds maxValueSize (${maxValueSize})`,
+ );
+ }
+ try {
+ enqueue(JSON.parse(trimmed));
+ } catch {
+ trackError("ParseError", "Invalid JSON");
+ }
+ idx++;
+ };
+
+ const scan = (enqueue) => {
+ const len = buffer.length;
+
+ while (scanPos < len) {
+ const ch = buffer.charCodeAt(scanPos);
+
+ if (escaped) {
+ escaped = false;
+ scanPos++;
+ continue;
+ }
+
+ if (inString) {
+ if (ch === 0x5c) {
+ escaped = true;
+ } else if (ch === 0x22) {
+ inString = false;
+ }
+ scanPos++;
+ continue;
+ }
+
+ if (ch === 0x22) {
+ inString = true;
+ if (started && elementStart === -1) {
+ elementStart = scanPos;
+ }
+ scanPos++;
+ continue;
+ }
+
+ if (!started) {
+ if (ch === 0x5b) {
+ started = true;
+ }
+ scanPos++;
+ continue;
+ }
+
+ if (ch === 0x5b || ch === 0x7b) {
+ if (elementStart === -1) elementStart = scanPos;
+ depth++;
+ scanPos++;
+ continue;
+ }
+
+ if (ch === 0x5d || ch === 0x7d) {
+ if (depth > 0) {
+ depth--;
+ if (depth === 0 && elementStart !== -1) {
+ emitElement(buffer.substring(elementStart, scanPos + 1), enqueue);
+ elementStart = -1;
+ }
+ } else {
+ // Closing ] of top-level array
+ if (elementStart !== -1) {
+ emitElement(buffer.substring(elementStart, scanPos), enqueue);
+ elementStart = -1;
+ }
+ }
+ scanPos++;
+ continue;
+ }
+
+ if (ch === 0x2c && depth === 0) {
+ if (elementStart !== -1) {
+ emitElement(buffer.substring(elementStart, scanPos), enqueue);
+ elementStart = -1;
+ }
+ scanPos++;
+ continue;
+ }
+
+ if (
+ elementStart === -1 &&
+ ch !== 0x20 &&
+ ch !== 0x09 &&
+ ch !== 0x0a &&
+ ch !== 0x0d
+ ) {
+ elementStart = scanPos;
+ }
+ scanPos++;
+ }
+
+ // Trim processed portion from buffer
+ const trimFrom = elementStart !== -1 ? elementStart : scanPos;
+ if (trimFrom > 0) {
+ buffer = buffer.substring(trimFrom);
+ scanPos -= trimFrom;
+ if (elementStart !== -1) {
+ elementStart = 0;
+ }
+ }
+ };
+
+ const transform = (chunk, enqueue) => {
+ buffer += chunk;
+ if (buffer.length > maxBufferSize) {
+ throw new Error(
+ `jsonParseStream buffer (${buffer.length}) exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
+ scan(enqueue);
+ };
+
+ const flush = (enqueue) => {
+ if (elementStart !== -1 && buffer.length > 0) {
+ const trimmed = buffer.substring(elementStart).trim();
+ if (trimmed.length > 0 && trimmed !== "]") {
+ emitElement(trimmed, enqueue);
+ }
+ }
+ buffer = "";
+ };
+
+ const stream = createTransformStream(transform, flush, streamOptions);
+ stream.result = () => ({ key: resultKey ?? "jsonErrors", value: errors });
+ return stream;
+};
+
+export const jsonFormatStream = (options = {}, streamOptions = {}) => {
+ const { space } = options;
+ let first = true;
+
+ const transform = (chunk, enqueue) => {
+ const json = JSON.stringify(chunk, null, space);
+ enqueue(first ? `[${json}` : `,\n${json}`);
+ first = false;
+ };
+
+ const flush = (enqueue) => {
+ enqueue(first ? "[]" : "\n]");
+ };
+
+ return createTransformStream(transform, flush, streamOptions);
+};
diff --git a/packages/json/index.perf.js b/packages/json/index.perf.js
new file mode 100644
index 0000000..d7b490a
--- /dev/null
+++ b/packages/json/index.perf.js
@@ -0,0 +1,119 @@
+import test from "node:test";
+import {
+ createReadableStream,
+ pipejoin,
+ pipeline,
+ streamToArray,
+} from "@datastream/core";
+import {
+ jsonFormatStream,
+ jsonParseStream,
+ ndjsonFormatStream,
+ ndjsonParseStream,
+} from "@datastream/json";
+import { Bench } from "tinybench";
+
+// -- Data generators --
+
+const generateNdjsonString = (rows) => {
+ const lines = Array.from({ length: rows }, (_, i) =>
+ JSON.stringify({ id: i, name: `item_${i}`, value: Math.random() }),
+ );
+ return `${lines.join("\n")}\n`;
+};
+
+const generateJsonArrayString = (rows) => {
+ const objects = Array.from({ length: rows }, (_, i) => ({
+ id: i,
+ name: `item_${i}`,
+ value: Math.random(),
+ }));
+ return JSON.stringify(objects);
+};
+
+const generateObjects = (rows) =>
+ Array.from({ length: rows }, (_, i) => ({
+ id: i,
+ name: `item_${i}`,
+ value: Math.random(),
+ }));
+
+// -- Benchmark config --
+
+const ROWS = 100_000;
+const time = Number(process.env.BENCH_TIME ?? 5_000);
+
+const ndjsonString = generateNdjsonString(ROWS);
+const jsonArrayString = generateJsonArrayString(ROWS);
+const objects = generateObjects(ROWS);
+
+// -- Tests --
+
+test("perf: ndjsonParseStream", async () => {
+ const bench = new Bench({ name: "ndjsonParseStream", time });
+
+ bench.add(`${ROWS} rows`, async () => {
+ const streams = [createReadableStream(ndjsonString), ndjsonParseStream()];
+ await streamToArray(pipejoin(streams));
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: ndjsonFormatStream", async () => {
+ const bench = new Bench({ name: "ndjsonFormatStream", time });
+
+ bench.add(`${ROWS} rows`, async () => {
+ const streams = [createReadableStream(objects), ndjsonFormatStream()];
+ await pipeline(streams);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: jsonParseStream", async () => {
+ const bench = new Bench({ name: "jsonParseStream", time });
+
+ bench.add(`${ROWS} rows`, async () => {
+ const streams = [createReadableStream(jsonArrayString), jsonParseStream()];
+ await streamToArray(pipejoin(streams));
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: jsonFormatStream", async () => {
+ const bench = new Bench({ name: "jsonFormatStream", time });
+
+ bench.add(`${ROWS} rows`, async () => {
+ const streams = [createReadableStream(objects), jsonFormatStream()];
+ await pipeline(streams);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
+
+test("perf: ndjson roundtrip (format → parse)", async () => {
+ const bench = new Bench({ name: "ndjson roundtrip", time });
+
+ bench.add(`${ROWS} rows`, async () => {
+ const streams = [
+ createReadableStream(objects),
+ ndjsonFormatStream(),
+ ndjsonParseStream(),
+ ];
+ await pipeline(streams);
+ });
+
+ await bench.run();
+ console.log(`\n${bench.name}`);
+ console.table(bench.table());
+});
diff --git a/packages/json/index.test.js b/packages/json/index.test.js
new file mode 100644
index 0000000..111d5df
--- /dev/null
+++ b/packages/json/index.test.js
@@ -0,0 +1,307 @@
+import { deepStrictEqual } from "node:assert";
+import test from "node:test";
+
+import {
+ createReadableStream,
+ pipejoin,
+ pipeline,
+ streamToArray,
+} from "@datastream/core";
+
+import {
+ jsonFormatStream,
+ jsonParseStream,
+ ndjsonFormatStream,
+ ndjsonParseStream,
+} from "@datastream/json";
+
+let variant = "unknown";
+for (const execArgv of process.execArgv) {
+ const flag = "--conditions=";
+ if (execArgv.includes("--conditions=")) {
+ variant = execArgv.replace(flag, "");
+ }
+}
+
+// *** ndjsonParseStream *** //
+test(`${variant}: ndjsonParseStream should parse single NDJSON line`, async (_t) => {
+ const streams = [createReadableStream('{"a":1}\n'), ndjsonParseStream()];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }]);
+});
+
+test(`${variant}: ndjsonParseStream should parse multiple NDJSON lines`, async (_t) => {
+ const streams = [
+ createReadableStream('{"a":1}\n{"b":2}\n{"c":3}\n'),
+ ndjsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }, { c: 3 }]);
+});
+
+test(`${variant}: ndjsonParseStream should handle chunk boundaries`, async (_t) => {
+ const streams = [
+ createReadableStream(['{"a":', "1}\n", '{"b":2}\n']),
+ ndjsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+});
+
+test(`${variant}: ndjsonParseStream should skip empty lines`, async (_t) => {
+ const streams = [
+ createReadableStream('{"a":1}\n\n\n{"b":2}\n'),
+ ndjsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+});
+
+test(`${variant}: ndjsonParseStream should handle no trailing newline`, async (_t) => {
+ const streams = [
+ createReadableStream('{"a":1}\n{"b":2}'),
+ ndjsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+});
+
+test(`${variant}: ndjsonParseStream should track parse errors in result`, async (_t) => {
+ const parse = ndjsonParseStream();
+ const streams = [createReadableStream('{"a":1}\nnot json\n{"b":2}\n'), parse];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+ const { key, value } = parse.result();
+ deepStrictEqual(key, "jsonErrors");
+ deepStrictEqual(value.ParseError.id, "ParseError");
+ deepStrictEqual(value.ParseError.idx, [1]);
+});
+
+test(`${variant}: ndjsonParseStream should throw when buffer exceeds maxBufferSize`, async (_t) => {
+ let error;
+ try {
+ await pipeline([
+ createReadableStream("a".repeat(200)),
+ ndjsonParseStream({ maxBufferSize: 100 }),
+ ]);
+ } catch (e) {
+ error = e;
+ }
+ deepStrictEqual(error?.message?.includes("maxBufferSize"), true);
+});
+
+test(`${variant}: ndjsonParseStream should handle \\r\\n line endings`, async (_t) => {
+ const streams = [
+ createReadableStream('{"a":1}\r\n{"b":2}\r\n'),
+ ndjsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+});
+
+// *** ndjsonFormatStream *** //
+test(`${variant}: ndjsonFormatStream should format objects as NDJSON`, async (_t) => {
+ const streams = [
+ createReadableStream([{ a: 1 }, { b: 2 }]),
+ ndjsonFormatStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+ const combined = output.join("");
+
+ deepStrictEqual(combined, '{"a":1}\n{"b":2}\n');
+});
+
+test(`${variant}: ndjsonFormatStream roundtrip with ndjsonParseStream`, async (_t) => {
+ const input = [{ a: 1 }, { b: "hello" }, { c: [1, 2, 3] }];
+ const streams = [
+ createReadableStream(input),
+ ndjsonFormatStream(),
+ ndjsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, input);
+});
+
+// *** jsonParseStream *** //
+test(`${variant}: jsonParseStream should parse JSON array into objects`, async (_t) => {
+ const streams = [
+ createReadableStream('[{"a":1},{"b":2}]'),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+});
+
+test(`${variant}: jsonParseStream should handle nested objects and arrays`, async (_t) => {
+ const streams = [
+ createReadableStream('[{"a":{"b":1}},{"c":[1,2,3]}]'),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: { b: 1 } }, { c: [1, 2, 3] }]);
+});
+
+test(`${variant}: jsonParseStream should handle strings with brackets and braces`, async (_t) => {
+ const streams = [
+ createReadableStream('[{"a":"{not json}"},{"b":"[1,2]"}]'),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: "{not json}" }, { b: "[1,2]" }]);
+});
+
+test(`${variant}: jsonParseStream should handle strings with escaped quotes`, async (_t) => {
+ const streams = [
+ createReadableStream('[{"a":"hello \\"world\\""},{"b":"test"}]'),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 'hello "world"' }, { b: "test" }]);
+});
+
+test(`${variant}: jsonParseStream should handle chunk boundaries mid-object`, async (_t) => {
+ const streams = [
+ createReadableStream(['[{"a":', "1},", '{"b":2}]']),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+});
+
+test(`${variant}: jsonParseStream should handle empty array`, async (_t) => {
+ const streams = [createReadableStream("[]"), jsonParseStream()];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, []);
+});
+
+test(`${variant}: jsonParseStream should handle single element`, async (_t) => {
+ const streams = [createReadableStream('[{"a":1}]'), jsonParseStream()];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }]);
+});
+
+test(`${variant}: jsonParseStream should handle non-object elements`, async (_t) => {
+ const streams = [
+ createReadableStream('[1, "hello", true, null, false]'),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [1, "hello", true, null, false]);
+});
+
+test(`${variant}: jsonParseStream should handle whitespace between elements`, async (_t) => {
+ const streams = [
+ createReadableStream('[ {"a":1} , \n {"b":2} \n]'),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+});
+
+test(`${variant}: jsonParseStream should track parse errors in result`, async (_t) => {
+ const parse = jsonParseStream();
+ const streams = [createReadableStream('[{"a":1},{invalid},{"b":2}]'), parse];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, [{ a: 1 }, { b: 2 }]);
+ const { key, value } = parse.result();
+ deepStrictEqual(key, "jsonErrors");
+ deepStrictEqual(value.ParseError.id, "ParseError");
+ deepStrictEqual(value.ParseError.idx, [1]);
+});
+
+test(`${variant}: jsonParseStream should throw when buffer exceeds maxBufferSize`, async (_t) => {
+ let error;
+ try {
+ await pipeline([
+ createReadableStream(`[{"a":"${"x".repeat(200)}"}]`),
+ jsonParseStream({ maxBufferSize: 100 }),
+ ]);
+ } catch (e) {
+ error = e;
+ }
+ deepStrictEqual(error?.message?.includes("maxBufferSize"), true);
+});
+
+// *** jsonFormatStream *** //
+test(`${variant}: jsonFormatStream should format objects as JSON array`, async (_t) => {
+ const streams = [
+ createReadableStream([{ a: 1 }, { b: 2 }]),
+ jsonFormatStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+ const combined = output.join("");
+
+ deepStrictEqual(combined, '[{"a":1},\n{"b":2}\n]');
+});
+
+test(`${variant}: jsonFormatStream should handle empty input`, async (_t) => {
+ const streams = [createReadableStream([]), jsonFormatStream()];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+ const combined = output.join("");
+
+ deepStrictEqual(combined, "[]");
+});
+
+test(`${variant}: jsonFormatStream should handle pretty-print with space option`, async (_t) => {
+ const streams = [
+ createReadableStream([{ a: 1 }]),
+ jsonFormatStream({ space: 2 }),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+ const combined = output.join("");
+
+ deepStrictEqual(combined, '[{\n "a": 1\n}\n]');
+});
+
+test(`${variant}: jsonFormatStream roundtrip with jsonParseStream`, async (_t) => {
+ const input = [{ a: 1 }, { b: "hello" }, { c: [1, 2, 3] }];
+ const streams = [
+ createReadableStream(input),
+ jsonFormatStream(),
+ jsonParseStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+
+ deepStrictEqual(output, input);
+});
diff --git a/packages/json/index.tst.ts b/packages/json/index.tst.ts
new file mode 100644
index 0000000..6c3acc2
--- /dev/null
+++ b/packages/json/index.tst.ts
@@ -0,0 +1,70 @@
+import type { JsonError } from "@datastream/json";
+import {
+ jsonFormatStream,
+ jsonParseStream,
+ ndjsonFormatStream,
+ ndjsonParseStream,
+} from "@datastream/json";
+import { describe, expect, test } from "tstyche";
+
+describe("JsonError", () => {
+ test("has required fields", () => {
+ expect().type.toBeAssignableTo<{
+ id: string;
+ message: string;
+ idx: number[];
+ }>();
+ });
+});
+
+describe("ndjsonParseStream", () => {
+ test("returns stream with result", () => {
+ const stream = ndjsonParseStream();
+ expect(stream.result).type.not.toBeAssignableTo();
+ });
+
+ test("accepts maxBufferSize", () => {
+ expect(
+ ndjsonParseStream({ maxBufferSize: 1024 }),
+ ).type.not.toBeAssignableTo();
+ });
+
+ test("accepts resultKey", () => {
+ expect(
+ ndjsonParseStream({ resultKey: "myErrors" }),
+ ).type.not.toBeAssignableTo();
+ });
+});
+
+describe("ndjsonFormatStream", () => {
+ test("accepts no options", () => {
+ expect(ndjsonFormatStream()).type.not.toBeAssignableTo();
+ });
+
+ test("accepts space option", () => {
+ expect(ndjsonFormatStream({ space: 2 })).type.not.toBeAssignableTo();
+ });
+});
+
+describe("jsonParseStream", () => {
+ test("returns stream with result", () => {
+ const stream = jsonParseStream();
+ expect(stream.result).type.not.toBeAssignableTo();
+ });
+
+ test("accepts maxBufferSize and maxValueSize", () => {
+ expect(
+ jsonParseStream({ maxBufferSize: 1024, maxValueSize: 512 }),
+ ).type.not.toBeAssignableTo();
+ });
+});
+
+describe("jsonFormatStream", () => {
+ test("accepts no options", () => {
+ expect(jsonFormatStream()).type.not.toBeAssignableTo();
+ });
+
+ test("accepts space option", () => {
+ expect(jsonFormatStream({ space: 2 })).type.not.toBeAssignableTo();
+ });
+});
diff --git a/packages/json/package.json b/packages/json/package.json
new file mode 100644
index 0000000..bc11be6
--- /dev/null
+++ b/packages/json/package.json
@@ -0,0 +1,67 @@
+{
+ "name": "@datastream/json",
+ "version": "0.1.6",
+ "description": "JSON and NDJSON (JSON Lines) parsing and formatting transform streams",
+ "type": "module",
+ "engines": {
+ "node": ">=24"
+ },
+ "engineStrict": true,
+ "publishConfig": {
+ "access": "public"
+ },
+ "main": "./index.node.mjs",
+ "module": "./index.web.mjs",
+ "exports": {
+ ".": {
+ "node": {
+ "import": {
+ "types": "./index.d.ts",
+ "default": "./index.node.mjs"
+ }
+ },
+ "import": {
+ "types": "./index.d.ts",
+ "default": "./index.web.mjs"
+ }
+ },
+ "./webstream": {
+ "types": "./index.d.ts",
+ "default": "./index.web.mjs"
+ }
+ },
+ "types": "index.d.ts",
+ "files": [
+ "*.mjs",
+ "*.map",
+ "*.d.ts"
+ ],
+ "scripts": {
+ "test": "npm run test:unit",
+ "test:unit": "node --test"
+ },
+ "license": "MIT",
+ "keywords": [
+ "Web Stream API",
+ "Node Stream API",
+ "JSON",
+ "NDJSON",
+ "JSON Lines"
+ ],
+ "author": {
+ "name": "datastream contributors",
+ "url": "https://github.com/willfarrell/datastream/graphs/contributors"
+ },
+ "repository": {
+ "type": "git",
+ "url": "github:willfarrell/datastream",
+ "directory": "packages/json"
+ },
+ "bugs": {
+ "url": "https://github.com/willfarrell/datastream/issues"
+ },
+ "homepage": "https://datastream.js.org",
+ "dependencies": {
+ "@datastream/core": "0.2.0"
+ }
+}
diff --git a/packages/object/index.d.ts b/packages/object/index.d.ts
index 4d683b4..ea1ff4f 100644
--- a/packages/object/index.d.ts
+++ b/packages/object/index.d.ts
@@ -37,6 +37,7 @@ export function objectPivotWideToLongStream(
keys: string[];
keyParam?: string;
valueParam?: string;
+ isNestedObject?: boolean;
},
streamOptions?: StreamOptions,
): unknown;
@@ -61,6 +62,7 @@ export function objectKeyJoinStream(
options: {
keys: Record;
separator: string;
+ isNestedObject?: boolean;
},
streamOptions?: StreamOptions,
): unknown;
diff --git a/packages/object/index.js b/packages/object/index.js
index 307d4e6..f253a35 100644
--- a/packages/object/index.js
+++ b/packages/object/index.js
@@ -70,21 +70,16 @@ export const objectPivotLongToWideStream = (
};
export const objectPivotWideToLongStream = (
- { keys, keyParam, valueParam },
+ { keys, keyParam, valueParam, isNestedObject },
streamOptions = {},
) => {
keyParam ??= "keyParam";
valueParam ??= "valueParam";
+ const clone = isNestedObject ? deepClone : shallowClone;
+
const transform = (chunk, enqueue) => {
- let value;
- try {
- value = structuredClone(chunk);
- } catch (e) {
- throw new Error("Failed to clone chunk, possibly circular reference", {
- cause: e,
- });
- }
+ const value = clone(chunk);
for (const key of keys) {
delete value[key];
}
@@ -124,20 +119,13 @@ export const objectKeyValuesStream = ({ key, values }, streamOptions = {}) => {
};
export const objectKeyJoinStream = (
- { keys, separator },
+ { keys, separator, isNestedObject },
streamOptions = {},
) => {
+ const clone = isNestedObject ? deepClone : shallowClone;
const transform = (chunk, enqueue) => {
- let value;
- try {
- value = structuredClone(chunk);
- } catch (e) {
- throw new Error("Failed to clone chunk, possibly circular reference", {
- cause: e,
- });
- }
+ const value = clone(chunk);
for (const newKey of Object.keys(keys)) {
- // perf opportunity
value[newKey] = keys[newKey]
.map((oldKey) => {
delete value[oldKey];
@@ -225,26 +213,49 @@ export const objectToEntriesStream = ({ keys }, streamOptions = {}) => {
return createTransformStream(transform, streamOptions);
};
+const deepClone = (obj) => {
+ try {
+ return structuredClone(obj);
+ } catch (e) {
+ throw new Error("Failed to clone chunk, possibly circular reference", {
+ cause: e,
+ });
+ }
+};
+const shallowClone = (obj) => ({ ...obj });
+
+const shallowEqual = (a, b) => {
+ if (a === b) return true;
+ if (a == null || b == null) return false;
+ const keysA = Object.keys(a);
+ if (keysA.length !== Object.keys(b).length) return false;
+ for (const key of keysA) {
+ if (a[key] !== b[key]) return false;
+ }
+ return true;
+};
+
+const deepEqual = (a, b) => {
+ try {
+ return JSON.stringify(a) === JSON.stringify(b);
+ } catch (e) {
+ throw new Error("Failed to stringify chunk, possibly circular reference", {
+ cause: e,
+ });
+ }
+};
+
export const objectSkipConsecutiveDuplicatesStream = (
- _options = {},
+ options = {},
streamOptions = {},
) => {
+ const { isNestedObject } = options;
+ const equal = isNestedObject ? deepEqual : shallowEqual;
let previousChunk;
const transform = (chunk, enqueue) => {
- let chunkStringified;
- try {
- chunkStringified = JSON.stringify(chunk);
- } catch (e) {
- throw new Error(
- "Failed to stringify chunk, possibly circular reference",
- {
- cause: e,
- },
- );
- }
- if (chunkStringified !== previousChunk) {
+ if (!equal(chunk, previousChunk)) {
enqueue(chunk);
- previousChunk = chunkStringified;
+ previousChunk = isNestedObject ? deepClone(chunk) : chunk;
}
};
return createTransformStream(transform, streamOptions);
diff --git a/packages/object/index.test.js b/packages/object/index.test.js
index 8a0600a..5eaf66b 100644
--- a/packages/object/index.test.js
+++ b/packages/object/index.test.js
@@ -471,3 +471,66 @@ test(`${variant}: objectToEntriesStream should return undefined for missing keys
deepStrictEqual(output, [[1, undefined, 3]]);
});
+
+// *** objectSkipConsecutiveDuplicatesStream shallow equality regression *** //
+test(`${variant}: objectSkipConsecutiveDuplicatesStream should use shallow equality by default`, async (_t) => {
+ const input = [{ a: 1 }, { a: 1 }, { a: 2 }, { a: 2 }, { a: 1 }];
+ const streams = [
+ createReadableStream(input),
+ objectSkipConsecutiveDuplicatesStream(),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+ deepStrictEqual(output, [{ a: 1 }, { a: 2 }, { a: 1 }]);
+});
+
+test(`${variant}: objectSkipConsecutiveDuplicatesStream isNestedObject should use deep comparison`, async (_t) => {
+ const input = [
+ { a: 1, b: { c: 2 } },
+ { a: 1, b: { c: 2 } },
+ { a: 1, b: { c: 3 } },
+ ];
+ const streams = [
+ createReadableStream(input),
+ objectSkipConsecutiveDuplicatesStream({ isNestedObject: true }),
+ ];
+ const stream = pipejoin(streams);
+ const output = await streamToArray(stream);
+ deepStrictEqual(output, [
+ { a: 1, b: { c: 2 } },
+ { a: 1, b: { c: 3 } },
+ ]);
+});
+
+// *** objectPivotWideToLongStream shallow copy regression *** //
+test(`${variant}: objectPivotWideToLongStream should not mutate input chunks`, async (_t) => {
+ const input = [{ id: 1, x: 10, y: 20 }];
+ const original = { ...input[0] };
+ const streams = [
+ createReadableStream(input),
+ objectPivotWideToLongStream({
+ keys: ["x", "y"],
+ keyParam: "axis",
+ valueParam: "val",
+ }),
+ ];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ deepStrictEqual(input[0], original);
+});
+
+// *** objectKeyJoinStream shallow copy regression *** //
+test(`${variant}: objectKeyJoinStream should not mutate input chunks`, async (_t) => {
+ const input = [{ first: "a", last: "b", other: "c" }];
+ const original = { ...input[0] };
+ const streams = [
+ createReadableStream(input),
+ objectKeyJoinStream({
+ keys: { full: ["first", "last"] },
+ separator: " ",
+ }),
+ ];
+ const stream = pipejoin(streams);
+ await streamToArray(stream);
+ deepStrictEqual(input[0], original);
+});
diff --git a/packages/object/package.json b/packages/object/package.json
index 0e44e5f..62105de 100644
--- a/packages/object/package.json
+++ b/packages/object/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/object",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "Object transform streams for picking, omitting, pivoting, batching, and key mapping",
"type": "module",
"engines": {
@@ -60,6 +60,6 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
}
}
diff --git a/packages/string/index.d.ts b/packages/string/index.d.ts
index 18ab737..cb7a95a 100644
--- a/packages/string/index.d.ts
+++ b/packages/string/index.d.ts
@@ -49,6 +49,7 @@ export function stringReplaceStream(
options: {
pattern: string | RegExp;
replacement: string;
+ maxBufferSize?: number;
},
streamOptions?: StreamOptions,
): unknown;
@@ -56,6 +57,7 @@ export function stringReplaceStream(
export function stringSplitStream(
options: {
separator: string;
+ maxBufferSize?: number;
},
streamOptions?: StreamOptions,
): unknown;
diff --git a/packages/string/index.js b/packages/string/index.js
index ae32736..f53d9cc 100644
--- a/packages/string/index.js
+++ b/packages/string/index.js
@@ -70,21 +70,15 @@ export const stringMinimumFirstChunkSize = (
export const stringMinimumChunkSize = (options = {}, streamOptions = {}) => {
const { chunkSize = 1024 } = options;
let buffer = "";
- let done = false;
const transform = (chunk, enqueue) => {
- if (done) {
- enqueue(chunk);
- return;
- }
buffer += chunk;
if (buffer.length >= chunkSize) {
- done = true;
enqueue(buffer);
buffer = "";
}
};
const flush = (enqueue) => {
- if (!done && buffer.length > 0) {
+ if (buffer.length > 0) {
enqueue(buffer);
}
};
@@ -107,12 +101,21 @@ export const stringSkipConsecutiveDuplicates = (
};
export const stringReplaceStream = (options, streamOptions = {}) => {
- const { pattern, replacement } = options;
+ const {
+ pattern,
+ replacement,
+ maxBufferSize = 16_777_216, // 16MB
+ } = options;
let previousChunk = "";
const transform = (chunk, enqueue) => {
const newChunk = (previousChunk + chunk).replace(pattern, replacement);
enqueue(newChunk.substring(0, previousChunk.length));
previousChunk = newChunk.substring(previousChunk.length);
+ if (previousChunk.length > maxBufferSize) {
+ throw new Error(
+ `stringReplaceStream buffer (${previousChunk.length}) exceeds maxBufferSize (${maxBufferSize})`,
+ );
+ }
};
const flush = (enqueue) => {
enqueue(previousChunk);
@@ -121,7 +124,10 @@ export const stringReplaceStream = (options, streamOptions = {}) => {
};
export const stringSplitStream = (options, streamOptions = {}) => {
- const { separator } = options;
+ const {
+ separator,
+ maxBufferSize = 16_777_216, // 16MB
+ } = options;
let previousChunk = "";
const transform = (chunk, enqueue) => {
chunk = previousChunk + chunk;
@@ -136,6 +142,11 @@ export const stringSplitStream = (options, streamOptions = {}) => {
break;
}
}
+ if (previousChunk.length > maxBufferSize) {
+ throw new Error(
+ `stringSplitStream buffer (${previousChunk.length}) exceeds maxBufferSize (${maxBufferSize}), separator not found`,
+ );
+ }
};
const flush = (enqueue) => {
enqueue(previousChunk);
diff --git a/packages/string/index.test.js b/packages/string/index.test.js
index 056e14b..748d904 100644
--- a/packages/string/index.test.js
+++ b/packages/string/index.test.js
@@ -1,4 +1,4 @@
-import { deepStrictEqual, strictEqual } from "node:assert";
+import { deepStrictEqual, ok, strictEqual } from "node:assert";
import test from "node:test";
import {
createReadableStream,
@@ -259,7 +259,7 @@ test(`${variant}: stringMinimumChunkSize should flush small input`, async (_t) =
deepStrictEqual(output, ["ab"]);
});
-test(`${variant}: stringMinimumChunkSize should pass through after first chunk met`, async (_t) => {
+test(`${variant}: stringMinimumChunkSize should buffer all chunks to minimum size`, async (_t) => {
const input = ["abcdef", "gh", "ij"];
const streams = [
createReadableStream(input),
@@ -268,7 +268,41 @@ test(`${variant}: stringMinimumChunkSize should pass through after first chunk m
const stream = pipejoin(streams);
const output = await streamToArray(stream);
- deepStrictEqual(output, ["abcdef", "gh", "ij"]);
+ deepStrictEqual(output, ["abcdef", "ghij"]);
+});
+
+// *** stringReplaceStream buffer limit regression *** //
+test(`${variant}: stringReplaceStream should throw when buffer exceeds maxBufferSize`, async (_t) => {
+ const input = ["aaaa", "bbbb", "cccc"];
+ const streams = [
+ createReadableStream(input),
+ stringReplaceStream({
+ pattern: "zzz",
+ replacement: "yyy",
+ maxBufferSize: 3,
+ }),
+ ];
+ try {
+ await pipeline(streams);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxBufferSize"));
+ }
+});
+
+// *** stringSplitStream buffer limit regression *** //
+test(`${variant}: stringSplitStream should throw when buffer exceeds maxBufferSize`, async (_t) => {
+ const input = ["aaaaaa", "bbbbbb", "cccccc"];
+ const streams = [
+ createReadableStream(input),
+ stringSplitStream({ separator: "zzz", maxBufferSize: 10 }),
+ ];
+ try {
+ await pipeline(streams);
+ throw new Error("Should have thrown");
+ } catch (e) {
+ ok(e.message.includes("maxBufferSize"));
+ }
});
// *** default export *** //
diff --git a/packages/string/package.json b/packages/string/package.json
index 12dfb70..2a7c0d3 100644
--- a/packages/string/package.json
+++ b/packages/string/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/string",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "String transform streams for splitting, replacing, counting, and deduplication",
"type": "module",
"engines": {
@@ -60,6 +60,6 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6"
+ "@datastream/core": "0.2.0"
}
}
diff --git a/packages/validate/index.tst.ts b/packages/validate/index.tst.ts
index 47bb9a7..ff00992 100644
--- a/packages/validate/index.tst.ts
+++ b/packages/validate/index.tst.ts
@@ -29,7 +29,7 @@ describe("validateStream", () => {
test("accepts compiled schema function", () => {
expect(
- validateStream({ schema: (data: unknown) => true }),
+ validateStream({ schema: (_data: unknown) => true }),
).type.not.toBeAssignableTo();
});
diff --git a/packages/validate/package.json b/packages/validate/package.json
index ab56526..e17f138 100644
--- a/packages/validate/package.json
+++ b/packages/validate/package.json
@@ -1,6 +1,6 @@
{
"name": "@datastream/validate",
- "version": "0.1.6",
+ "version": "0.2.0",
"description": "JSON Schema validation transform streams using Ajv",
"type": "module",
"engines": {
@@ -60,7 +60,7 @@
},
"homepage": "https://datastream.js.org",
"dependencies": {
- "@datastream/core": "0.1.6",
- "ajv-cmd": "0.10.0"
+ "@datastream/core": "0.2.0",
+ "ajv-cmd": "0.11.0"
}
}
diff --git a/websites/datastream.js.org/package.json b/websites/datastream.js.org/package.json
index 031d224..2c1722a 100644
--- a/websites/datastream.js.org/package.json
+++ b/websites/datastream.js.org/package.json
@@ -2,7 +2,7 @@
"name": "datastream.js.org",
"description": "SvelteKit SSR",
"private": true,
- "version": "0.1.6",
+ "version": "0.2.0",
"type": "module",
"scripts": {
"start": "vite dev",
@@ -19,8 +19,8 @@
},
"dependencies": {
"@plausible-analytics/tracker": "0.4.4",
- "@willfarrell-ds/svelte": "0.0.0-alpha.4",
- "@willfarrell-ds/vanilla": "0.0.0-alpha.4",
+ "@willfarrell-ds/svelte": "0.0.0-alpha.6",
+ "@willfarrell-ds/vanilla": "0.0.0-alpha.6",
"hast-util-to-string": "3.0.1",
"mdast-util-to-string": "4.0.0",
"uuid": "13.0.0"
@@ -28,15 +28,15 @@
"devDependencies": {
"@sveltejs/adapter-cloudflare": "^7.0.0",
"@sveltejs/kit": "^2.0.0",
- "@sveltejs/vite-plugin-svelte": "^6.0.0",
- "@willfarrell-ds/cli": "0.0.0-alpha.4",
- "esbuild": "^0.27.0",
+ "@sveltejs/vite-plugin-svelte": "^7.0.0",
+ "@willfarrell-ds/cli": "0.0.0-alpha.6",
+ "esbuild": "^0.28.0",
"mdsvex": "^0.12.0",
"svelte": "^5.0.0",
"svgo": "^4.0.0",
- "vite": "^7.3.2",
+ "vite": "^8.0.0",
"vite-plugin-llms": "^1.0.0",
- "vite-plugin-mkcert": "^1.0.0",
+ "vite-plugin-mkcert": "^2.0.0",
"vite-plugin-sitemap": "^0.8.0",
"vite-plugin-sri": "^0.0.2",
"wrangler": "^4.0.0"
diff --git a/websites/datastream.js.org/src/components/docs/AsideNav.svelte b/websites/datastream.js.org/src/components/docs/AsideNav.svelte
index 9ea93a7..3d46123 100644
--- a/websites/datastream.js.org/src/components/docs/AsideNav.svelte
+++ b/websites/datastream.js.org/src/components/docs/AsideNav.svelte
@@ -20,6 +20,7 @@ const nav = {
},
"Data Formats": {
csv: "/docs/packages/csv",
+ json: "/docs/packages/json",
string: "/docs/packages/string",
object: "/docs/packages/object",
base64: "/docs/packages/base64",
@@ -29,6 +30,7 @@ const nav = {
validate: "/docs/packages/validate",
compress: "/docs/packages/compress",
digest: "/docs/packages/digest",
+ encrypt: "/docs/packages/encrypt",
},
Examples: {
"CSV ETL": "/docs/examples/csv-etl",
@@ -36,6 +38,7 @@ const nav = {
"S3 to S3": "/docs/examples/s3-transform",
"Browser files": "/docs/examples/browser-file-processing",
"Checksum & compress": "/docs/examples/checksum-compress",
+ Parquet: "/docs/examples/parquet",
},
};
diff --git a/websites/datastream.js.org/src/lib/remark-extract-headings.js b/websites/datastream.js.org/src/lib/remark-extract-headings.js
index 2114bcf..ef22fd9 100644
--- a/websites/datastream.js.org/src/lib/remark-extract-headings.js
+++ b/websites/datastream.js.org/src/lib/remark-extract-headings.js
@@ -11,7 +11,7 @@ export function remarkExtractHeadings() {
visit(tree, "heading", (node) => {
// Only extract H2 headings
if (node.depth === 2) {
- const text = nodetoString(node).replace(/[<>]/g, "");
+ const text = nodetoString(node).replaceAll("<", "").replaceAll(">", "");
// Create slug from heading text
const id = text
.toLowerCase()
diff --git a/websites/datastream.js.org/src/routes/+error.svelte b/websites/datastream.js.org/src/routes/+error.svelte
index b93c633..8f96a82 100644
--- a/websites/datastream.js.org/src/routes/+error.svelte
+++ b/websites/datastream.js.org/src/routes/+error.svelte
@@ -1,11 +1,11 @@
@@ -27,25 +27,25 @@
diff --git a/websites/datastream.js.org/src/routes/docs/+layout.svelte b/websites/datastream.js.org/src/routes/docs/+layout.svelte
index 617b774..163c02b 100644
--- a/websites/datastream.js.org/src/routes/docs/+layout.svelte
+++ b/websites/datastream.js.org/src/routes/docs/+layout.svelte
@@ -1,6 +1,6 @@
{@render children?.()}
diff --git a/websites/datastream.js.org/src/routes/docs/core-concepts/+page.md b/websites/datastream.js.org/src/routes/docs/core-concepts/+page.md
index a0b7a64..7c5126d 100644
--- a/websites/datastream.js.org/src/routes/docs/core-concepts/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/core-concepts/+page.md
@@ -95,7 +95,7 @@ All stream factory functions accept a `streamOptions` parameter:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `highWaterMark` | `number` | — | Backpressure threshold — how many chunks to buffer before pausing |
-| `chunkSize` | `number` | `16384` | Size hint for chunking strategies |
+| `chunkSize` | `number` | `16384` (16KB) | Size hint for chunking strategies |
| `signal` | `AbortSignal` | — | Signal to abort the pipeline |
```javascript
diff --git a/websites/datastream.js.org/src/routes/docs/examples/parquet/+page.md b/websites/datastream.js.org/src/routes/docs/examples/parquet/+page.md
new file mode 100644
index 0000000..745d9aa
--- /dev/null
+++ b/websites/datastream.js.org/src/routes/docs/examples/parquet/+page.md
@@ -0,0 +1,91 @@
+---
+title: Parquet — read and write
+description: Read and write Apache Parquet files using datastream with hyparquet and parquet-wasm.
+---
+
+### Read Parquet file into CSV
+
+Read a Parquet file from S3, extract specific columns, and write as CSV:
+
+```javascript
+import { pipeline, createReadableStream, streamToBuffer } from '@datastream/core'
+import { awsS3GetObjectStream } from '@datastream/aws'
+import { objectReadableStream } from '@datastream/object'
+import { csvFormatStream } from '@datastream/csv'
+import { fileWriteStream } from '@datastream/file'
+import { parquetRead } from 'hyparquet'
+
+const buffer = await streamToBuffer(
+ await awsS3GetObjectStream({ Bucket: 'data-lake', Key: 'users.parquet' }),
+)
+
+const rows = []
+await parquetRead({
+ file: {
+ byteLength: buffer.byteLength,
+ read: (start, end) => buffer.slice(start, end),
+ },
+ columns: ['id', 'name', 'email'],
+ onComplete: (data) => rows.push(...data),
+})
+
+const result = await pipeline([
+ objectReadableStream(rows),
+ csvFormatStream({ header: true }),
+ fileWriteStream({ path: './users.csv' }),
+])
+```
+
+### Write CSV to Parquet
+
+Read a CSV file, parse into objects, and write as Parquet to S3:
+
+```javascript
+import { pipeline, streamToArray } from '@datastream/core'
+import { fileReadStream } from '@datastream/file'
+import {
+ csvDetectDelimitersStream,
+ csvDetectHeaderStream,
+ csvParseStream,
+ csvCoerceValuesStream,
+} from '@datastream/csv'
+import { objectFromEntriesStream } from '@datastream/object'
+import { createReadableStreamFromArrayBuffer } from '@datastream/core'
+import { awsS3PutObjectStream } from '@datastream/aws'
+import { tableFromJSON, tableToIPC } from 'apache-arrow'
+
+const detectDelimiters = csvDetectDelimitersStream()
+const detectHeader = csvDetectHeaderStream({
+ delimiterChar: () => detectDelimiters.result().value.delimiterChar,
+ newlineChar: () => detectDelimiters.result().value.newlineChar,
+ quoteChar: () => detectDelimiters.result().value.quoteChar,
+ escapeChar: () => detectDelimiters.result().value.escapeChar,
+})
+
+const rows = await streamToArray(
+ await pipeline([
+ fileReadStream({ path: './users.csv' }),
+ detectDelimiters,
+ detectHeader,
+ csvParseStream({
+ delimiterChar: () => detectDelimiters.result().value.delimiterChar,
+ newlineChar: () => detectDelimiters.result().value.newlineChar,
+ quoteChar: () => detectDelimiters.result().value.quoteChar,
+ escapeChar: () => detectDelimiters.result().value.escapeChar,
+ }),
+ objectFromEntriesStream({
+ keys: () => detectHeader.result().value.header,
+ }),
+ csvCoerceValuesStream(),
+ ]),
+)
+
+const table = tableFromJSON(rows)
+const { writeParquet } = await import('parquet-wasm')
+const parquetBuffer = writeParquet(table)
+
+await pipeline([
+ createReadableStreamFromArrayBuffer(parquetBuffer),
+ awsS3PutObjectStream({ Bucket: 'data-lake', Key: 'users.parquet' }),
+])
+```
diff --git a/websites/datastream.js.org/src/routes/docs/packages/aws/+page.md b/websites/datastream.js.org/src/routes/docs/packages/aws/+page.md
index 263c726..6d6bf4f 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/aws/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/aws/+page.md
@@ -1,9 +1,9 @@
---
title: aws
-description: AWS service streams for S3, DynamoDB, Lambda, SNS, and SQS.
+description: AWS service streams for CloudWatch Logs, DynamoDB, Kinesis, Lambda, S3, SNS, and SQS.
---
-AWS service streams for S3, DynamoDB, Lambda, SNS, and SQS. Node.js only.
+AWS service streams for CloudWatch Logs, DynamoDB, Kinesis, Lambda, S3, SNS, and SQS. Node.js only.
## Install
@@ -14,18 +14,88 @@ npm install @datastream/aws
Requires the corresponding AWS SDK v3 client packages:
```bash
-npm install @aws-sdk/client-s3 @aws-sdk/lib-storage
+npm install @aws-sdk/client-cloudwatch-logs
npm install @aws-sdk/client-dynamodb
+npm install @aws-sdk/client-kinesis
npm install @aws-sdk/client-lambda
+npm install @aws-sdk/client-s3 @aws-sdk/lib-storage
npm install @aws-sdk/client-sns
npm install @aws-sdk/client-sqs
```
+## CloudWatch Logs
+
+### `awsCloudWatchLogsSetClient`
+
+Mutates module-level state — not safe for concurrent multi-tenant use.
+
+```javascript
+import { CloudWatchLogsClient } from '@aws-sdk/client-cloudwatch-logs'
+import { awsCloudWatchLogsSetClient } from '@datastream/aws'
+
+awsCloudWatchLogsSetClient(new CloudWatchLogsClient({ region: 'us-east-1' }))
+```
+
+### `awsCloudWatchLogsGetLogEventsStream` Readable async
+
+Gets log events from a CloudWatch Logs log stream. Auto-paginates until no new events are returned.
+
+#### Options
+
+Accepts `GetLogEventsCommand` parameters plus:
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `logGroupName` | `string` | — | Log group name |
+| `logStreamName` | `string` | — | Log stream name |
+| `pollingActive` | `boolean` | `false` | Keep polling for new events |
+| `pollingDelay` | `number` | `1000` | Delay (ms) between polls when no new events |
+
+#### Example
+
+```javascript
+import { pipeline, createReadableStream } from '@datastream/core'
+import { awsCloudWatchLogsGetLogEventsStream } from '@datastream/aws'
+
+await pipeline([
+ createReadableStream(await awsCloudWatchLogsGetLogEventsStream({
+ logGroupName: '/aws/lambda/my-function',
+ logStreamName: 'stream-id',
+ })),
+])
+```
+
+### `awsCloudWatchLogsFilterLogEventsStream` Readable async
+
+Filters log events across log streams in a log group. Auto-paginates through all matching results.
+
+#### Options
+
+Accepts `FilterLogEventsCommand` parameters:
+
+| Option | Type | Description |
+|--------|------|-------------|
+| `logGroupName` | `string` | Log group name |
+| `filterPattern` | `string` | CloudWatch Logs filter pattern |
+| `startTime` | `number` | Start of time range (epoch ms) |
+| `endTime` | `number` | End of time range (epoch ms) |
+
+#### Example
+
+```javascript
+import { awsCloudWatchLogsFilterLogEventsStream } from '@datastream/aws'
+
+const events = await awsCloudWatchLogsFilterLogEventsStream({
+ logGroupName: '/aws/lambda/my-function',
+ filterPattern: 'ERROR',
+})
+```
+
## S3
### `awsS3SetClient`
-Set a custom S3 client. By default, FIPS endpoints are enabled for US and CA regions.
+Set a custom S3 client. By default, FIPS endpoints are enabled for US and CA regions. Mutates module-level state — not safe for concurrent multi-tenant use.
```javascript
import { S3Client } from '@aws-sdk/client-s3'
@@ -113,6 +183,8 @@ Computes a multi-part S3 checksum while data passes through. Designed for pre-si
### `awsDynamoDBSetClient`
+Mutates module-level state — not safe for concurrent multi-tenant use.
+
```javascript
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
import { awsDynamoDBSetClient } from '@datastream/aws'
@@ -159,6 +231,33 @@ import { awsDynamoDBScanStream } from '@datastream/aws'
const items = await awsDynamoDBScanStream({ TableName: 'Users' })
```
+### `awsDynamoDBExecuteStatementStream` Readable async
+
+Executes a PartiQL statement against DynamoDB with automatic pagination.
+
+#### Options
+
+Accepts `ExecuteStatementCommand` parameters:
+
+| Option | Type | Description |
+|--------|------|-------------|
+| `Statement` | `string` | PartiQL statement |
+| `Parameters` | `object[]` | Statement parameters |
+
+#### Example
+
+```javascript
+import { pipeline, createReadableStream } from '@datastream/core'
+import { awsDynamoDBExecuteStatementStream } from '@datastream/aws'
+
+await pipeline([
+ createReadableStream(await awsDynamoDBExecuteStatementStream({
+ Statement: 'SELECT * FROM "Users" WHERE PK = ?',
+ Parameters: [{ S: 'USER#123' }],
+ })),
+])
+```
+
### `awsDynamoDBGetItemStream` Readable async
Batch gets items by keys. Automatically retries unprocessed keys with exponential backoff.
@@ -221,10 +320,74 @@ awsDynamoDBDeleteItemStream({ TableName: 'Users' })
// Input chunks: { PK: { S: 'USER#1' }, SK: { S: 'PROFILE' } }
```
+## Kinesis
+
+### `awsKinesisSetClient`
+
+Mutates module-level state — not safe for concurrent multi-tenant use.
+
+```javascript
+import { KinesisClient } from '@aws-sdk/client-kinesis'
+import { awsKinesisSetClient } from '@datastream/aws'
+
+awsKinesisSetClient(new KinesisClient({ region: 'us-east-1' }))
+```
+
+### `awsKinesisGetRecordsStream` Readable async
+
+Gets records from a Kinesis shard. Polls until no more records are returned.
+
+#### Options
+
+Accepts `GetRecordsCommand` parameters plus:
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `ShardIterator` | `string` | — | Shard iterator |
+| `pollingActive` | `boolean` | `false` | Keep polling for new records |
+| `pollingDelay` | `number` | `1000` | Delay (ms) between polls when no records |
+
+#### Example
+
+```javascript
+import { pipeline, createReadableStream } from '@datastream/core'
+import { awsKinesisGetRecordsStream } from '@datastream/aws'
+
+await pipeline([
+ createReadableStream(await awsKinesisGetRecordsStream({
+ ShardIterator: 'AAA...',
+ })),
+])
+```
+
+### `awsKinesisPutRecordsStream` Writable
+
+Writes records to a Kinesis stream. Batches 500 records per `PutRecordsCommand`.
+
+#### Options
+
+| Option | Type | Description |
+|--------|------|-------------|
+| `StreamName` | `string` | Kinesis stream name |
+
+#### Example
+
+```javascript
+import { pipeline, createReadableStream } from '@datastream/core'
+import { awsKinesisPutRecordsStream } from '@datastream/aws'
+
+await pipeline([
+ createReadableStream(records),
+ awsKinesisPutRecordsStream({ StreamName: 'my-stream' }),
+])
+```
+
## Lambda
### `awsLambdaSetClient`
+Mutates module-level state — not safe for concurrent multi-tenant use.
+
```javascript
import { LambdaClient } from '@aws-sdk/client-lambda'
import { awsLambdaSetClient } from '@datastream/aws'
@@ -267,6 +430,8 @@ await pipeline([
### `awsSNSSetClient`
+Mutates module-level state — not safe for concurrent multi-tenant use.
+
```javascript
import { SNSClient } from '@aws-sdk/client-sns'
import { awsSNSSetClient } from '@datastream/aws'
@@ -306,6 +471,8 @@ await pipeline([
### `awsSQSSetClient`
+Mutates module-level state — not safe for concurrent multi-tenant use.
+
```javascript
import { SQSClient } from '@aws-sdk/client-sqs'
import { awsSQSSetClient } from '@datastream/aws'
@@ -319,12 +486,14 @@ Polls an SQS queue and yields messages until the queue is empty.
#### Options
-Accepts `ReceiveMessageCommand` parameters:
+Accepts `ReceiveMessageCommand` parameters plus:
-| Option | Type | Description |
-|--------|------|-------------|
-| `QueueUrl` | `string` | SQS queue URL |
-| `MaxNumberOfMessages` | `number` | Max messages per poll (1-10) |
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `QueueUrl` | `string` | — | SQS queue URL |
+| `MaxNumberOfMessages` | `number` | — | Max messages per poll (1-10) |
+| `pollingActive` | `boolean` | `false` | Keep polling even when queue is empty |
+| `pollingDelay` | `number` | `1000` | Delay (ms) between polls when queue is empty |
#### Example
diff --git a/websites/datastream.js.org/src/routes/docs/packages/compress/+page.md b/websites/datastream.js.org/src/routes/docs/packages/compress/+page.md
index 7ae6638..a0b3d1c 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/compress/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/compress/+page.md
@@ -21,7 +21,9 @@ npm install @datastream/compress
### `gzipDecompressStream` Transform
-No options required.
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `maxOutputSize` | `number` | — | Maximum decompressed output in bytes. Destroys the stream with an error when exceeded |
### Example
@@ -55,7 +57,9 @@ await pipeline([
### `deflateDecompressStream` Transform
-No options required.
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `maxOutputSize` | `number` | — | Maximum decompressed output in bytes. Destroys the stream with an error when exceeded |
## brotli
@@ -67,7 +71,9 @@ No options required.
### `brotliDecompressStream` Transform
-No options required.
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `maxOutputSize` | `number` | — | Maximum decompressed output in bytes. Destroys the stream with an error when exceeded |
## zstd Node.js only
@@ -81,7 +87,20 @@ Requires Node.js with zstd support.
### `zstdDecompressStream` Transform
-No options required.
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `maxOutputSize` | `number` | — | Maximum decompressed output in bytes. Destroys the stream with an error when exceeded |
+
+## Decompression bomb protection
+
+A malicious compressed payload known as a "decompression bomb" can be as small as a few kilobytes but expand to gigabytes when decompressed, exhausting memory and crashing the process. Setting `maxOutputSize` ensures decompression is aborted before memory is exhausted. Always set this when decompressing untrusted input.
+
+```javascript
+import { gzipDecompressStream } from '@datastream/compress'
+
+// Limit decompressed output to 100MB
+gzipDecompressStream({ maxOutputSize: 100 * 1024 * 1024 })
+```
## Platform support
diff --git a/websites/datastream.js.org/src/routes/docs/packages/core/+page.md b/websites/datastream.js.org/src/routes/docs/packages/core/+page.md
index 920568b..864de49 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/core/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/core/+page.md
@@ -145,7 +145,7 @@ Creates a stream that observes each chunk without modifying it. The chunk is aut
|-----------|------|-------------|
| `fn` | `(chunk) => void` | Called for each chunk, return value ignored |
| `flush` | `() => void` | Optional, called when stream ends |
-| `streamOptions` | `object` | Stream configuration |
+| `streamOptions` | `object` | Stream configuration (supports `signal` for abort) |
#### Example
@@ -169,7 +169,7 @@ Creates a stream that modifies chunks. Use `enqueue` to emit output — you can
|-----------|------|-------------|
| `fn` | `(chunk, enqueue) => void` | Transform each chunk, call `enqueue(output)` to emit |
| `flush` | `(enqueue) => void` | Optional, emit final chunks when stream ends |
-| `streamOptions` | `object` | Stream configuration |
+| `streamOptions` | `object` | Stream configuration (supports `signal` for abort) |
#### Example
@@ -199,7 +199,7 @@ Creates a stream that consumes chunks at the end of a pipeline.
|-----------|------|-------------|
| `fn` | `(chunk) => void` | Called for each chunk |
| `close` | `() => void` | Optional, called when stream ends |
-| `streamOptions` | `object` | Stream configuration |
+| `streamOptions` | `object` | Stream configuration (supports `signal` for abort) |
#### Example
diff --git a/websites/datastream.js.org/src/routes/docs/packages/csv/+page.md b/websites/datastream.js.org/src/routes/docs/packages/csv/+page.md
index 245969f..4307442 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/csv/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/csv/+page.md
@@ -19,7 +19,7 @@ Auto-detects the delimiter, newline, quote, and escape characters from the first
| Option | Type | Default | Description |
|--------|------|---------|-------------|
-| `chunkSize` | `number` | `1024` | Minimum bytes to buffer before detecting |
+| `chunkSize` | `number` | `1024` (1KB) | Minimum bytes to buffer before detecting |
| `resultKey` | `string` | `"csvDetectDelimiters"` | Key in pipeline result |
### Result
@@ -53,7 +53,7 @@ Detects and strips the header row. Outputs data rows only (without the header).
| Option | Type | Default | Description |
|--------|------|---------|-------------|
-| `chunkSize` | `number` | `1024` | Minimum bytes to buffer before detecting |
+| `chunkSize` | `number` | `1024` (1KB) | Minimum bytes to buffer before detecting |
| `delimiterChar` | `string \| () => string` | `","` | Delimiter character or lazy function |
| `newlineChar` | `string \| () => string` | `"\r\n"` | Newline character or lazy function |
| `quoteChar` | `string \| () => string` | `'"'` | Quote character or lazy function |
@@ -90,6 +90,7 @@ Parses CSV text into arrays of field values (string arrays). Each output chunk i
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `chunkSize` | `number` | `2097152` (2MB) | Input buffer size before first parse |
+| `fieldMaxSize` | `number` | `16777216` (16MB) | Maximum size of a single field in bytes |
| `delimiterChar` | `string \| () => string` | `","` | Delimiter character or lazy function |
| `newlineChar` | `string \| () => string` | `"\r\n"` | Newline character or lazy function |
| `quoteChar` | `string \| () => string` | `'"'` | Quote character or lazy function |
@@ -97,6 +98,15 @@ Parses CSV text into arrays of field values (string arrays). Each output chunk i
| `parser` | `function` | `csvQuotedParser` | Custom parser function |
| `resultKey` | `string` | `"csvErrors"` | Key in pipeline result |
+#### Field size protection
+
+A crafted CSV with an unterminated quoted field causes the parser to buffer the entire remaining input into a single field, consuming unbounded memory. An attacker can exploit this to exhaust process memory with a relatively small file. Setting `fieldMaxSize` caps per-field memory and aborts parsing with an error when exceeded. Always set this when parsing untrusted CSV input, and lower it from the default if your data has known field size bounds.
+
+```javascript
+// Parse with a 1MB field limit for untrusted input
+csvParseStream({ fieldMaxSize: 1 * 1024 * 1024 })
+```
+
### Result
Parse errors collected during processing:
diff --git a/websites/datastream.js.org/src/routes/docs/packages/encrypt/+page.md b/websites/datastream.js.org/src/routes/docs/packages/encrypt/+page.md
new file mode 100644
index 0000000..62db652
--- /dev/null
+++ b/websites/datastream.js.org/src/routes/docs/packages/encrypt/+page.md
@@ -0,0 +1,157 @@
+---
+title: encrypt
+description: Symmetric encryption and decryption streams for AES-GCM, AES-CTR, and ChaCha20-Poly1305.
+---
+
+Symmetric encryption and decryption streams. Defaults to AES-256-GCM (authenticated encryption).
+
+## Install
+
+```bash
+npm install @datastream/encrypt
+```
+
+For ChaCha20-Poly1305 in browser environments:
+
+```bash
+npm install libsodium-wrappers
+```
+
+## `encryptStream` Transform async (browser)
+
+Encrypts data passing through. On Node.js, wraps `node:crypto` for true streaming. In the browser, uses Web Crypto API (AES-GCM buffers; AES-CTR streams).
+
+### Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `algorithm` | `string` | `"AES-256-GCM"` | Encryption algorithm |
+| `key` | `Uint8Array\|Buffer` | — | 32-byte encryption key |
+| `iv` | `Uint8Array\|Buffer` | auto-generated | Initialization vector |
+| `aad` | `Uint8Array\|Buffer` | — | Additional Authenticated Data (GCM/ChaCha only) |
+| `maxInputSize` | `number` | `67108864` | Max input bytes for web AES-GCM (64MB) |
+
+### Supported algorithms
+
+| Algorithm | Auth | Node.js | Browser | IV size |
+|-----------|------|---------|---------|---------|
+| `AES-256-GCM` | authTag | `node:crypto` (streaming) | `crypto.subtle` (buffered) | 12 bytes |
+| `AES-256-CTR` | none | `node:crypto` (streaming) | `crypto.subtle` (streaming) | 16 bytes |
+| `CHACHA20-POLY1305` | authTag | `node:crypto` (streaming) | `libsodium-wrappers` (buffered) | 12 bytes |
+
+### Result
+
+```javascript
+{
+ algorithm: 'AES-256-GCM',
+ iv: Uint8Array(12),
+ authTag: Uint8Array(16) // only for GCM and ChaCha20
+}
+```
+
+### Example
+
+```javascript
+import { createReadableStream, pipeline } from '@datastream/core'
+import { encryptStream, generateEncryptionKey } from '@datastream/encrypt'
+
+const key = generateEncryptionKey()
+
+// Node.js — synchronous
+const enc = encryptStream({ key })
+
+const result = await pipeline([
+ createReadableStream(data),
+ enc,
+])
+
+const { iv, authTag } = result.encrypt
+```
+
+```javascript
+// Browser — async, must await
+const enc = await encryptStream({ key })
+```
+
+## `decryptStream` Transform async (browser)
+
+Decrypts data encrypted by `encryptStream`.
+
+### Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `algorithm` | `string` | `"AES-256-GCM"` | Must match encryption algorithm |
+| `key` | `Uint8Array\|Buffer` | — | Same key used for encryption |
+| `iv` | `Uint8Array\|Buffer` | — | IV from `encryptStream` result |
+| `authTag` | `Uint8Array\|Buffer` | — | Auth tag from result (GCM/ChaCha) |
+| `aad` | `Uint8Array\|Buffer` | — | Must match encryption AAD |
+| `maxOutputSize` | `number` | — | Max decrypted output bytes |
+
+### Example
+
+```javascript
+import { createReadableStream, pipeline, streamToString } from '@datastream/core'
+import { decryptStream } from '@datastream/encrypt'
+
+const dec = decryptStream({ key, iv, authTag })
+
+const plaintext = await streamToString(
+ createReadableStream(ciphertext).pipe(dec)
+)
+```
+
+## `generateEncryptionKey`
+
+Generate a cryptographically random encryption key.
+
+```javascript
+import { generateEncryptionKey } from '@datastream/encrypt'
+
+const key = generateEncryptionKey() // 32 bytes (AES-256)
+const key = generateEncryptionKey({ bits: 128 }) // 16 bytes (AES-128)
+```
+
+## Patterns
+
+### Encrypt with plaintext and ciphertext digests
+
+```javascript
+import { pipeline } from '@datastream/core'
+import { fileReadStream, fileWriteStream } from '@datastream/file'
+import { encryptStream } from '@datastream/encrypt'
+import { digestStream } from '@datastream/digest'
+
+const result = await pipeline([
+ fileReadStream({ path: './data.csv' }),
+ digestStream({ algorithm: 'SHA2-256', resultKey: 'plaintextDigest' }),
+ encryptStream({ key }),
+ digestStream({ algorithm: 'SHA2-256', resultKey: 'ciphertextDigest' }),
+ fileWriteStream({ path: './data.csv.enc' }),
+])
+
+// result.plaintextDigest — verify correct decryption
+// result.ciphertextDigest — verify file integrity on disk
+// result.encrypt — { algorithm, iv, authTag }
+```
+
+### Large file streaming with AES-CTR
+
+AES-256-CTR supports true streaming on both Node.js and browser. Use it for large files where AES-GCM's buffering would cause memory issues. Pair with `digestStream` for integrity verification.
+
+```javascript
+import { encryptStream } from '@datastream/encrypt'
+
+const enc = await encryptStream({ key, algorithm: 'AES-256-CTR' })
+```
+
+### With Additional Authenticated Data (AAD)
+
+Bind encryption to metadata so ciphertext can't be reused in a different context.
+
+```javascript
+const aad = new TextEncoder().encode(JSON.stringify({ userId: '123' }))
+const enc = encryptStream({ key, aad })
+// Decryption must provide the same aad
+const dec = decryptStream({ key, iv, authTag, aad })
+```
diff --git a/websites/datastream.js.org/src/routes/docs/packages/fetch/+page.md b/websites/datastream.js.org/src/routes/docs/packages/fetch/+page.md
index af53c92..185e966 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/fetch/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/fetch/+page.md
@@ -13,7 +13,7 @@ npm install @datastream/fetch
## `fetchSetDefaults`
-Set global defaults for all fetch streams.
+Set global defaults for all fetch streams. Mutates module-level state — not safe for concurrent multi-tenant use.
### Defaults
@@ -89,7 +89,11 @@ fetchReadableStream({
### 429 retry
-When receiving a `429 Too Many Requests` response, the request is automatically retried after respecting the rate limit delay.
+When receiving a `429 Too Many Requests` response, the request is automatically retried with exponential backoff. If a `Retry-After` header is present, its value (in seconds) is used as the delay. Otherwise, the delay follows `min(1000 × 2^(attempt-1), 30000)` ms. Retries are capped at `retryMaxCount` (default: 10).
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `retryMaxCount` | `number` | `10` | Maximum retry attempts on 429 |
### Example
diff --git a/websites/datastream.js.org/src/routes/docs/packages/file/+page.md b/websites/datastream.js.org/src/routes/docs/packages/file/+page.md
index f370e5a..88efb8f 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/file/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/file/+page.md
@@ -23,6 +23,7 @@ Reads a file as a stream.
| Option | Type | Description |
|--------|------|-------------|
| `path` | `string` | File path (Node.js) |
+| `basePath` | `string` | When provided, enforces that `path` resolves within `basePath`. Prevents path traversal and rejects symbolic links |
| `types` | `object[]` | File type filter for the file picker (see below) |
### Example — Node.js
@@ -58,6 +59,7 @@ Writes a stream to a file.
| Option | Type | Description |
|--------|------|-------------|
| `path` | `string` | File path (Node.js), suggested file name (Browser) |
+| `basePath` | `string` | When provided, enforces that `path` resolves within `basePath`. Prevents path traversal and rejects symbolic links |
| `types` | `object[]` | File type filter |
### Example — Node.js
@@ -99,3 +101,18 @@ const types = [
```
On Node.js, if `types` is provided and the file extension doesn't match, an `"Invalid extension"` error is thrown.
+
+## Security
+
+When accepting file paths from user input, always use an absolute `path` or set `basePath` to prevent path traversal attacks (e.g., `../../etc/passwd`). Relative paths without a `basePath` constraint can resolve outside the intended directory.
+
+`basePath` is opt-in. When provided, paths are resolved and checked with `path.resolve().startsWith(basePath)`, and symbolic links are rejected. When omitted, no path restriction is applied.
+
+```javascript
+// Restrict reads to a specific directory
+fileReadStream({ path: userInput, basePath: '/data/uploads', types })
+
+// Convenience helper for cwd-scoped reads
+const safeFileRead = (path, types) =>
+ fileReadStream({ path, basePath: process.cwd(), types })
+```
diff --git a/websites/datastream.js.org/src/routes/docs/packages/json/+page.md b/websites/datastream.js.org/src/routes/docs/packages/json/+page.md
new file mode 100644
index 0000000..59f5af6
--- /dev/null
+++ b/websites/datastream.js.org/src/routes/docs/packages/json/+page.md
@@ -0,0 +1,179 @@
+---
+title: json
+description: JSON and NDJSON (JSON Lines) parsing and formatting streams.
+---
+
+JSON and NDJSON (Newline-Delimited JSON / JSON Lines) parsing and formatting streams.
+
+## Install
+
+```bash
+npm install @datastream/json
+```
+
+## `ndjsonParseStream` Transform
+
+Parses NDJSON (one JSON value per line) into individual JavaScript values. Splits on `\n`, parses each line with `JSON.parse`, and skips empty lines.
+
+### Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `maxBufferSize` | `number` | `16777216` (16MB) | Maximum buffer size for incomplete lines |
+| `resultKey` | `string` | `"jsonErrors"` | Key in pipeline result |
+
+### Result
+
+Parse errors collected during processing:
+
+```javascript
+{
+ ParseError: { id: 'ParseError', message: 'Invalid JSON', idx: [3, 7] }
+}
+```
+
+### Example
+
+```javascript
+import { pipeline, createReadableStream } from '@datastream/core'
+import { ndjsonParseStream } from '@datastream/json'
+
+const parse = ndjsonParseStream()
+
+const result = await pipeline([
+ createReadableStream('{"name":"Alice"}\n{"name":"Bob"}\n'),
+ parse,
+])
+
+console.log(result.jsonErrors)
+// {}
+```
+
+## `ndjsonFormatStream` Transform
+
+Formats objects as NDJSON text (one `JSON.stringify` per line). Batches output for throughput.
+
+### Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `space` | `number \| string` | — | Passed to `JSON.stringify` for pretty-printing each line |
+
+### Example
+
+```javascript
+import { pipeline, createReadableStream } from '@datastream/core'
+import { ndjsonFormatStream } from '@datastream/json'
+
+await pipeline([
+ createReadableStream([
+ { name: 'Alice', age: 30 },
+ { name: 'Bob', age: 25 },
+ ]),
+ ndjsonFormatStream(),
+])
+
+// Output: {"name":"Alice","age":30}\n{"name":"Bob","age":25}\n
+```
+
+## `jsonParseStream` Transform
+
+Parses a streaming JSON array (`[{...},{...}]`) into individual elements. Uses a state machine to track nesting depth, strings, and escapes across chunk boundaries — no external dependencies.
+
+### Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `maxBufferSize` | `number` | `16777216` (16MB) | Maximum buffer size for incomplete elements |
+| `maxValueSize` | `number` | `16777216` (16MB) | Maximum size of a single JSON element |
+| `resultKey` | `string` | `"jsonErrors"` | Key in pipeline result |
+
+#### Buffer size protection
+
+A JSON array with deeply nested or very large objects can cause the parser to buffer significant amounts of data. Setting `maxBufferSize` caps total memory and `maxValueSize` caps per-element memory. Lower these from defaults when parsing untrusted input.
+
+```javascript
+// Parse with a 1MB buffer limit for untrusted input
+jsonParseStream({ maxBufferSize: 1 * 1024 * 1024 })
+```
+
+### Result
+
+Parse errors collected during processing:
+
+```javascript
+{
+ ParseError: { id: 'ParseError', message: 'Invalid JSON', idx: [2] }
+}
+```
+
+### Example
+
+```javascript
+import { pipeline, createReadableStream, streamToArray } from '@datastream/core'
+import { jsonParseStream } from '@datastream/json'
+
+const streams = [
+ createReadableStream('[{"name":"Alice"},{"name":"Bob"}]'),
+ jsonParseStream(),
+]
+
+const output = await streamToArray(pipejoin(streams))
+// [{ name: 'Alice' }, { name: 'Bob' }]
+```
+
+## `jsonFormatStream` Transform
+
+Formats objects as a JSON array string (`[{...},{...}]`). Emits `[` with the first element, `,\n` between elements, and `]` on flush. Outputs `[]` if no elements.
+
+### Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `space` | `number \| string` | — | Passed to `JSON.stringify` for pretty-printing |
+
+### Example
+
+```javascript
+import { pipeline, createReadableStream } from '@datastream/core'
+import { jsonFormatStream } from '@datastream/json'
+
+await pipeline([
+ createReadableStream([
+ { name: 'Alice', age: 30 },
+ { name: 'Bob', age: 25 },
+ ]),
+ jsonFormatStream({ space: 2 }),
+])
+
+// Output: [{\n "name": "Alice",\n "age": 30\n},\n{\n "name": "Bob",\n "age": 25\n}\n]
+```
+
+## Full pipeline example
+
+Fetch NDJSON API, validate, and write as JSON array:
+
+```javascript
+import { pipeline } from '@datastream/core'
+import { fetchResponseStream } from '@datastream/fetch'
+import { ndjsonParseStream } from '@datastream/json'
+import { validateStream } from '@datastream/validate'
+import { objectCountStream } from '@datastream/object'
+import { jsonFormatStream } from '@datastream/json'
+import { fileWriteStream } from '@datastream/file'
+
+const count = objectCountStream()
+const parse = ndjsonParseStream()
+
+const result = await pipeline([
+ fetchResponseStream({ url: 'https://api.example.com/data.ndjson' }),
+ parse,
+ validateStream({ schema }),
+ count,
+ jsonFormatStream(),
+ fileWriteStream({ path: './output.json' }),
+])
+
+console.log(result.count) // number of objects processed
+console.log(result.jsonErrors) // any parse errors
+```
diff --git a/websites/datastream.js.org/src/routes/docs/packages/object/+page.md b/websites/datastream.js.org/src/routes/docs/packages/object/+page.md
index beecbc6..880078a 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/object/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/object/+page.md
@@ -158,6 +158,7 @@ Joins multiple keys into new combined keys.
|--------|------|---------|-------------|
| `keys` | `object` | — | Map of `{ newKey: ['key1', 'key2'] }` |
| `separator` | `string` | — | Separator for joined values |
+| `isNestedObject` | `boolean` | `false` | Use `structuredClone` instead of shallow spread for cloning |
### Example
@@ -266,6 +267,7 @@ Pivots wide format to long format. Emits multiple chunks per input object.
| `keys` | `string[]` | — | Columns to unpivot |
| `keyParam` | `string` | `"keyParam"` | Name for the new key column |
| `valueParam` | `string` | `"valueParam"` | Name for the new value column |
+| `isNestedObject` | `boolean` | `false` | Use `structuredClone` instead of shallow spread for cloning |
### Example
@@ -283,13 +285,26 @@ objectPivotWideToLongStream({
## `objectSkipConsecutiveDuplicatesStream` Transform
-Skips consecutive duplicate objects (compared via `JSON.stringify`).
+Skips consecutive duplicate objects. Uses shallow equality by default (compares top-level values with `===`).
+
+### Options
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `isNestedObject` | `boolean` | `false` | Use `JSON.stringify` for deep comparison instead of shallow equality |
### Example
```javascript
import { objectSkipConsecutiveDuplicatesStream } from '@datastream/object'
+// Shallow (default, fast) — compares top-level values
// Input: [{a:1}, {a:1}, {a:2}, {a:1}]
// Output: [{a:1}, {a:2}, {a:1}]
+objectSkipConsecutiveDuplicatesStream()
+
+// Deep — compares nested objects via JSON.stringify
+// Input: [{a:{b:1}}, {a:{b:1}}, {a:{b:2}}]
+// Output: [{a:{b:1}}, {a:{b:2}}]
+objectSkipConsecutiveDuplicatesStream({ isNestedObject: true })
```
diff --git a/websites/datastream.js.org/src/routes/docs/packages/string/+page.md b/websites/datastream.js.org/src/routes/docs/packages/string/+page.md
index 7b59d68..4c3e663 100644
--- a/websites/datastream.js.org/src/routes/docs/packages/string/+page.md
+++ b/websites/datastream.js.org/src/routes/docs/packages/string/+page.md
@@ -126,17 +126,17 @@ Buffers data until the first chunk meets a minimum size, then passes all subsequ
| Option | Type | Default | Description |
|--------|------|---------|-------------|
-| `chunkSize` | `number` | `1024` | Minimum first chunk size in characters |
+| `chunkSize` | `number` | `1024` (1KB) | Minimum first chunk size in characters |
## `stringMinimumChunkSize` Transform
-Buffers data until chunks meet a minimum size before emitting. Useful when downstream requires a minimum data size for processing.
+Buffers every chunk to meet a minimum size before emitting. Unlike `stringMinimumFirstChunkSize` which only buffers the first chunk then passes through, this continues buffering all subsequent chunks that are smaller than `chunkSize`.
### Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
-| `chunkSize` | `number` | `1024` | Minimum chunk size in characters |
+| `chunkSize` | `number` | `1024` (1KB) | Minimum chunk size in characters |
## `stringSkipConsecutiveDuplicates` Transform
diff --git a/websites/datastream.js.org/svgo.config.mjs b/websites/datastream.js.org/svgo.config.mjs
new file mode 100644
index 0000000..4ac8a94
--- /dev/null
+++ b/websites/datastream.js.org/svgo.config.mjs
@@ -0,0 +1,14 @@
+export default {
+ plugins: [
+ // 1. Minify the path data (the "d" attribute)
+ "convertPathData",
+ // 2. Remove comments
+ "removeComments",
+ // 3. Remove metadata/editors junk
+ "removeMetadata",
+ "removeEditorsNSData",
+ // 4. Clean up attributes but DO NOT touch IDs or Symbols
+ "removeUnknownsAndDefaults",
+ "removeUnusedNS",
+ ],
+};
diff --git a/websites/datastream.js.org/vite.config.js b/websites/datastream.js.org/vite.config.js
index 0b93ebb..415f9fc 100644
--- a/websites/datastream.js.org/vite.config.js
+++ b/websites/datastream.js.org/vite.config.js
@@ -1,6 +1,6 @@
import { mkdirSync } from "node:fs";
import { sveltekit } from "@sveltejs/kit/vite";
-import { createLogger, defineConfig } from "vite";
+import { defineConfig } from "vite";
import mkcert from "vite-plugin-mkcert";
import sitemap from "vite-plugin-sitemap";
import sriPrerendered from "vite-plugin-sri";
@@ -8,14 +8,6 @@ import sriPrerendered from "vite-plugin-sri";
const sitemapOutDir = ".svelte-kit/cloudflare/";
mkdirSync(sitemapOutDir, { recursive: true });
-// TODO remove after vite 8 — https://github.com/vitejs/vite/issues/19498
-const logger = createLogger();
-const originalWarn = logger.warn.bind(logger);
-logger.warn = (msg, options) => {
- if (msg.includes("node:async_hooks")) return;
- originalWarn(msg, options);
-};
-
export default defineConfig({
plugins: [
sveltekit(),
@@ -26,7 +18,6 @@ export default defineConfig({
build: {
assetsInlineLimit: 0,
},
- customLogger: logger,
ssr: {
noExternal: ["prismjs"],
},