diff --git a/CHANGES.md b/CHANGES.md index 8d4e68889..07589106c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -250,6 +250,10 @@ To be released. ### @fedify/netlify + - Added `NetlifyBlobsKvStore`, a Netlify Blobs-backed key–value store with + expiration, prefix listing, and atomic compare-and-set operations. Netlify + deployments can now persist Fedify state and preserve ordered queue + delivery without a separate database. [[#1010], [#1029] by Jiwon Kwon\] - Added the new *@fedify/netlify* package for processing Fedify message queue jobs with Netlify Async Workloads. It provides `NetlifyMessageQueue` for durable event submission and `createNetlifyQueueHandler()` for Netlify @@ -258,6 +262,9 @@ To be released. explicit recovery for unobservable dead-letter failures. [[#930], [#934]] +[#1010]: https://github.com/fedify-dev/fedify/issues/1010 +[#1029]: https://github.com/fedify-dev/fedify/pull/1029 + ### @fedify/pglite - Added the `@fedify/pglite` package with `PgliteKvStore`, a `KvStore` backed diff --git a/changes.d/netlify/blobs-kv-store.md b/changes.d/netlify/blobs-kv-store.md new file mode 100644 index 000000000..2e71283a2 --- /dev/null +++ b/changes.d/netlify/blobs-kv-store.md @@ -0,0 +1,8 @@ +--- +links: + '#1029': https://github.com/fedify-dev/fedify/pull/1029 +--- + - Added `NetlifyBlobsKvStore`, a Netlify Blobs-backed key–value store with + expiration, prefix listing, and atomic compare-and-set operations. Netlify + deployments can now persist Fedify state and preserve ordered queue + delivery without a separate database. [[#1010], [#1029] by Jiwon Kwon] diff --git a/deno.lock b/deno.lock index 1290bf2b3..c67c8b4e4 100644 --- a/deno.lock +++ b/deno.lock @@ -62,6 +62,7 @@ "jsr:@std/net@^1.0.6": "1.0.6", "jsr:@std/path@0.224": "0.224.0", "jsr:@std/path@1": "1.1.5", + "jsr:@std/path@^1.0.4": "1.1.5", "jsr:@std/path@^1.0.6": "1.1.5", "jsr:@std/path@^1.1.0": "1.1.5", "jsr:@std/path@^1.1.1": "1.1.5", @@ -69,16 +70,18 @@ "jsr:@std/path@^1.1.5": "1.1.5", "jsr:@std/semver@^1.0.6": "1.0.8", "jsr:@std/testing@0.224": "0.224.0", + "jsr:@std/url@~0.225.1": "0.225.1", "jsr:@std/uuid@^1.0.9": "1.1.1", "jsr:@std/yaml@^1.0.8": "1.1.0", "jsr:@valibot/valibot@^1.4.0": "1.4.1", "npm:@alinea/suite@~0.6.3": "0.6.3", - "npm:@astrojs/node@^11.0.2": "11.0.2_astro@7.0.9__@electric-sql+pglite@0.5.8_@electric-sql+pglite@0.5.8", + "npm:@astrojs/node@^11.0.2": "11.0.2_astro@7.0.9__@netlify+blobs@11.0.3_@netlify+blobs@11.0.3", + "npm:@babel/core@^7.28.0": "7.29.7", "npm:@babel/preset-react@^7.27.1": "7.28.5_@babel+core@7.29.7", "npm:@cfworker/json-schema@^4.1.1": "4.1.1", "npm:@cloudflare/vitest-pool-workers@~0.8.31": "0.8.71_vitest@3.2.4__@types+node@24.12.2__yaml@2.9.0_@cloudflare+workers-types@4.20260511.1", "npm:@cloudflare/workers-types@^4.20260511.1": "4.20260511.1", - "npm:@deno/astro-adapter@0.6": "0.6.0_@opentelemetry+api@1.9.1_astro@7.0.9__@electric-sql+pglite@0.5.8_@electric-sql+pglite@0.5.8", + "npm:@deno/astro-adapter@0.6": "0.6.0_@opentelemetry+api@1.9.1_astro@7.0.9__@netlify+blobs@11.0.3_@netlify+blobs@11.0.3", "npm:@electric-sql/pglite@~0.5.8": "0.5.8", "npm:@fxts/core@^1.21.1": "1.26.0", "npm:@hongminhee/localtunnel@0.5": "0.5.0", @@ -90,22 +93,22 @@ "npm:@multiformats/base-x@^4.0.1": "4.0.1", "npm:@nestjs/common@^11.0.1": "11.1.19_reflect-metadata@0.2.2_rxjs@7.8.2", "npm:@netlify/async-workloads@^0.0.106": "0.0.106_@google-cloud+storage@5.20.5_@trpc+server@11.18.0__typescript@5.9.3_@types+react@19.2.17_autoprefixer@10.5.2__postcss@8.5.19_graphql@16.14.2_postcss@8.5.19_react@19.2.7_react-dom@19.2.7__react@19.2.7_rollup@4.60.1_tailwindcss@3.4.19__tsx@4.21.0__yaml@2.9.0_tsx@4.21.0_yaml@2.9.0", - "npm:@netlify/database@^1.1.0": "1.1.0_@electric-sql+pglite@0.5.8", + "npm:@netlify/blobs@^11.0.3": "11.0.3", "npm:@nuxt/kit@4": "4.4.2", "npm:@nuxt/schema@4": "4.4.2", "npm:@opentelemetry/api@^1.9.0": "1.9.1", "npm:@opentelemetry/api@^1.9.1": "1.9.1", - "npm:@opentelemetry/context-async-hooks@^2.7.1": "2.7.1_@opentelemetry+api@1.9.1", - "npm:@opentelemetry/core@^2.7.1": "2.7.1_@opentelemetry+api@1.9.1", + "npm:@opentelemetry/context-async-hooks@^2.7.1": "2.10.0_@opentelemetry+api@1.9.1", + "npm:@opentelemetry/core@^2.7.1": "2.10.0_@opentelemetry+api@1.9.1", "npm:@opentelemetry/sdk-metrics@2.7.1": "2.7.1_@opentelemetry+api@1.9.1", - "npm:@opentelemetry/sdk-trace-base@^2.7.1": "2.7.1_@opentelemetry+api@1.9.1", + "npm:@opentelemetry/sdk-trace-base@^2.7.1": "2.10.0_@opentelemetry+api@1.9.1", "npm:@opentelemetry/semantic-conventions@^1.40.0": "1.40.0", "npm:@poppanator/http-constants@^1.1.1": "1.1.1", "npm:@preact/signals@^2.3.2": "2.9.1_preact@10.29.2", "npm:@preact/signals@^2.5.1": "2.9.1_preact@10.29.2", "npm:@prefresh/vite@^2.4.8": "2.4.12_preact@10.29.2_vite@7.3.2__@types+node@24.12.2__tsx@4.21.0__yaml@2.9.0", "npm:@remix-run/node-fetch-server@0.12": "0.12.0", - "npm:@solidjs/start@^1.3.0": "1.3.2_@electric-sql+pglite@0.5.8_vite@7.3.2__@types+node@24.12.2__tsx@4.21.0__yaml@2.9.0", + "npm:@solidjs/start@^1.3.0": "1.3.2_@netlify+blobs@11.0.3_vite@7.3.2__@types+node@24.12.2__tsx@4.21.0__yaml@2.9.0", "npm:@standard-schema/spec@^1.1.0": "1.1.0", "npm:@sveltejs/kit@2": "2.57.1_@opentelemetry+api@1.9.1_typescript@6.0.3_vite@7.3.2__@types+node@24.12.2__tsx@4.21.0__yaml@2.9.0", "npm:@types/amqplib@*": "0.10.8", @@ -122,7 +125,7 @@ "npm:@typescript-eslint/utils@8": "8.58.2_eslint@9.39.4_typescript@6.0.3", "npm:amqplib@~0.10.9": "0.10.9", "npm:asn1js@^3.0.10": "3.0.10", - "npm:astro@7": "7.0.9_@electric-sql+pglite@0.5.8", + "npm:astro@7": "7.0.9_@netlify+blobs@11.0.3", "npm:byte-encodings@^1.0.11": "1.0.11", "npm:chalk@^5.6.2": "5.6.2", "npm:cli-highlight@^2.1.11": "2.1.11", @@ -282,6 +285,7 @@ "jsr:@std/fmt@^1.0.7", "jsr:@std/media-types@1", "jsr:@std/path@1", + "npm:@babel/core", "npm:@babel/preset-react", "npm:@prefresh/vite", "npm:@remix-run/node-fetch-server", @@ -483,6 +487,12 @@ "jsr:@std/path@0.224" ] }, + "@std/url@0.225.1": { + "integrity": "7961f62f0a3cd2c7aa5b785822874132760b50bbf5ed0ccfded8668f203e7a95", + "dependencies": [ + "jsr:@std/path@^1.0.4" + ] + }, "@std/uuid@1.1.1": { "integrity": "7b49060282d90f72fec64952f8c7a2914cbe6fdba3eca665f8cedc90830154a7", "dependencies": [ @@ -602,7 +612,7 @@ "satteri" ] }, - "@astrojs/node@11.0.2_astro@7.0.9__@electric-sql+pglite@0.5.8_@electric-sql+pglite@0.5.8": { + "@astrojs/node@11.0.2_astro@7.0.9__@netlify+blobs@11.0.3_@netlify+blobs@11.0.3": { "integrity": "sha512-/ijULxT+A5Cm8wSwWZ2vgqfim1b05D6B8n/a9l6MMA4FCotIH73g7fL7y76XojKXpTe75FVvQH92OxsMqea9kQ==", "dependencies": [ "@astrojs/internal-helpers", @@ -980,7 +990,7 @@ "@vitest/runner", "@vitest/snapshot", "birpc@0.2.14", - "cjs-module-lexer", + "cjs-module-lexer@1.4.3", "devalue", "miniflare", "semver@7.8.5", @@ -1049,7 +1059,7 @@ "kuler" ] }, - "@deno/astro-adapter@0.6.0_@opentelemetry+api@1.9.1_astro@7.0.9__@electric-sql+pglite@0.5.8_@electric-sql+pglite@0.5.8": { + "@deno/astro-adapter@0.6.0_@opentelemetry+api@1.9.1_astro@7.0.9__@netlify+blobs@11.0.3_@netlify+blobs@11.0.3": { "integrity": "sha512-zltNm5I7MME7Udb5TtAGIfLrfOHiuDG1FrKWDqYbFQ+AurmwxHvfwVCca4f+jfGQY3DnwYLDvb0tnmeI8aUWfg==", "dependencies": [ "@opentelemetry/api", @@ -3602,9 +3612,6 @@ "@tybys/wasm-util" ] }, - "@neondatabase/serverless@1.1.0": { - "integrity": "sha512-r3ZZhRjEcfEdKIZnoB1RusNgvHuaBRqfCzV4Gi+5A9yUX0S4HTws/ASWqt13wL4y4I+0rqsWGdA2w7EQXHi3+Q==" - }, "@nestjs/common@11.1.19_reflect-metadata@0.2.2_rxjs@7.8.2": { "integrity": "sha512-qeiTt2tv+e5QyDKqG8HlVZb2wx64FEaSGFJouqTSRs+kG44iTfl3xlz1XqVped+rihx4hmjWgL5gkhtdK3E6+Q==", "dependencies": [ @@ -3652,6 +3659,14 @@ "@netlify/runtime-utils@2.2.0" ] }, + "@netlify/blobs@11.0.3": { + "integrity": "sha512-Z8IXQtQC8BQjm76i1bN+l12TTyKQ/s1R92Ajhou7+fpP0KSxnJ65QzLEb5WuFuFutn8ORrcd4mlF8A2xhw8dzA==", + "dependencies": [ + "@netlify/dev-utils@6.0.1", + "@netlify/otel", + "@netlify/runtime-utils@3.0.0" + ] + }, "@netlify/blobs@8.2.0": { "integrity": "sha512-9djLZHBKsoKk8XCgwWSEPK9QnT8qqxEQGuYh48gFIcNLvpBKkLnHbDZuyUxmNemCfDz7h0HnMXgSPnnUVgARhg==" }, @@ -3866,16 +3881,6 @@ ], "scripts": true }, - "@netlify/database@1.1.0_@electric-sql+pglite@0.5.8": { - "integrity": "sha512-Y36JMyQfxwHxvtFzF8K+2PyooGFQXzPNINw/guujQfMujfAwUTwv7f6XiSL3c5orNy8YZTqVVWVjkbFarhDRjw==", - "dependencies": [ - "@neondatabase/serverless", - "@netlify/runtime-utils@2.3.0", - "pg", - "waddler", - "ws@8.21.0" - ] - }, "@netlify/dev-utils@2.2.0": { "integrity": "sha512-5XUvZuffe3KetyhbWwd4n2ktd7wraocCYw10tlM+/u/95iAz29GjNiuNxbCD1T6Bn1MyGc4QLVNKOWhzJkVFAw==", "dependencies": [ @@ -3930,6 +3935,22 @@ "write-file-atomic@5.0.1" ] }, + "@netlify/dev-utils@6.0.1": { + "integrity": "sha512-q5g70dO3q/M/XTBQz7uIECJxVlJoS8UBlzpjf22DV6q61UzXa8EONTPXPmvisrFcUi1I3AUKplPcHGQYZZj+Vw==", + "dependencies": [ + "@whatwg-node/server@0.11.0", + "ansis", + "atomically", + "chokidar@5.0.0", + "decache", + "dettle", + "dot-prop@9.0.0", + "empathic", + "env-paths", + "parse-gitignore", + "semver@7.8.5" + ] + }, "@netlify/functions@1.6.0": { "integrity": "sha512-6G92AlcpFrQG72XU8YH8pg94eDnq7+Q0YJhb8x4qNpdGsvuzvrfHWBmqFGp/Yshmv4wex9lpsTRZOocdrA2erQ==", "dependencies": [ @@ -4002,6 +4023,16 @@ "@netlify/open-api@2.57.0": { "integrity": "sha512-hgJrSxfzr7ShaVACGr17Ci3a7Y7vO+a75Fwn9fNe2+1aIbVx4aVSLP3cv9Vv9yfy1JbW563AwcveBq9lr9KKzA==" }, + "@netlify/otel@7.0.2": { + "integrity": "sha512-MHEsRJTZtOCrLa2fR+Y3GN51rvgxUHazuRVxuWuG7R1qzwynXAZB20Ufwp7BxKSTKcp7LNVEnKAZ/k2ytVmYvQ==", + "dependencies": [ + "@opentelemetry/api", + "@opentelemetry/core@2.10.0_@opentelemetry+api@1.9.1", + "@opentelemetry/instrumentation", + "@opentelemetry/resources@2.10.0_@opentelemetry+api@1.9.1", + "@opentelemetry/sdk-trace-node" + ] + }, "@netlify/runtime-utils@1.3.1": { "integrity": "sha512-7/vIJlMYrPJPlEW84V2yeRuG3QBu66dmlv9neTmZ5nXzwylhBEOhy11ai+34A8mHCSZI4mKns25w3HM9kaDdJg==" }, @@ -4011,8 +4042,8 @@ "@netlify/runtime-utils@2.2.0": { "integrity": "sha512-K3kWIxIMucibzQsATU2xw2JI+OpS9PZfPW/a+81gmeLC8tLv5YAxTVT0NFY/3imk1kcOJb9g7658jPLqDJaiAw==" }, - "@netlify/runtime-utils@2.3.0": { - "integrity": "sha512-cW8weDvsKV7zfia2m5EcBy6KILGoPD+eYZ3qWNGnIo05DGF28goPES0xKSDkNYgAF/2rRSIhie2qcBhbGVgSRg==" + "@netlify/runtime-utils@3.0.0": { + "integrity": "sha512-OHo40+V3QZkR+UrDjqhN+LekrAby/dSSJxsvyYs9i88E/mSl3goB/ysoL+VYROm190egxmQyRYlHK7vL4GeHBQ==" }, "@netlify/sdk--extension-api-client@0.1.1": { "integrity": "sha512-gl4K9VJg0+MLBZCAjfKvySXs1Dv5l/Y5YEXsFQZIJIgHKCmPiNOEz8SLzF7YgRNqlgIapjcBu52kif82J5HUpA==", @@ -4523,15 +4554,28 @@ "@octokit/openapi-types" ] }, + "@opentelemetry/api-logs@0.221.0": { + "integrity": "sha512-OlanaW1vv7ufTqQ3/fPLI4arGt5ZoM+P8abOMki6uEYnpRazepSWDwDnnw+la7kE26SHVC18//SMccrDvLKOXQ==", + "dependencies": [ + "@opentelemetry/api" + ] + }, "@opentelemetry/api@1.9.1": { "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==" }, - "@opentelemetry/context-async-hooks@2.7.1_@opentelemetry+api@1.9.1": { - "integrity": "sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ==", + "@opentelemetry/context-async-hooks@2.10.0_@opentelemetry+api@1.9.1": { + "integrity": "sha512-bvyMcgLEkozzSzpEEEo1OMoeQ97bxj6Qs2uN3mPrSdDvObMI1myffD/BPqcLlzZO9//d1SqQA/WPw7Cz2AiqhA==", "dependencies": [ "@opentelemetry/api" ] }, + "@opentelemetry/core@2.10.0_@opentelemetry+api@1.9.1": { + "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", + "dependencies": [ + "@opentelemetry/api", + "@opentelemetry/semantic-conventions" + ] + }, "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1": { "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", "dependencies": [ @@ -4539,11 +4583,28 @@ "@opentelemetry/semantic-conventions" ] }, + "@opentelemetry/instrumentation@0.221.0_@opentelemetry+api@1.9.1": { + "integrity": "sha512-cCk80Z/iRDf/5gfsKMB4f74LqVA5yKETB/9ojPzVW/6/f70iu89nJvGxsFCxx4XfSohaOofkU19kiYm84AiAlw==", + "dependencies": [ + "@opentelemetry/api", + "@opentelemetry/api-logs", + "import-in-the-middle", + "require-in-the-middle" + ] + }, + "@opentelemetry/resources@2.10.0_@opentelemetry+api@1.9.1": { + "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", + "dependencies": [ + "@opentelemetry/api", + "@opentelemetry/core@2.10.0_@opentelemetry+api@1.9.1", + "@opentelemetry/semantic-conventions" + ] + }, "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1": { "integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==", "dependencies": [ "@opentelemetry/api", - "@opentelemetry/core", + "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1", "@opentelemetry/semantic-conventions" ] }, @@ -4551,16 +4612,35 @@ "integrity": "sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ==", "dependencies": [ "@opentelemetry/api", - "@opentelemetry/core", - "@opentelemetry/resources" + "@opentelemetry/core@2.7.1_@opentelemetry+api@1.9.1", + "@opentelemetry/resources@2.7.1_@opentelemetry+api@1.9.1" + ] + }, + "@opentelemetry/sdk-trace-base@2.10.0_@opentelemetry+api@1.9.1": { + "integrity": "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==", + "dependencies": [ + "@opentelemetry/api", + "@opentelemetry/core@2.10.0_@opentelemetry+api@1.9.1", + "@opentelemetry/resources@2.10.0_@opentelemetry+api@1.9.1", + "@opentelemetry/sdk-trace", + "@opentelemetry/semantic-conventions" + ] + }, + "@opentelemetry/sdk-trace-node@2.10.0_@opentelemetry+api@1.9.1": { + "integrity": "sha512-GZK/G6oZyBLGlH1pUgeDch7D91KoHd2uotUGIkWCPi9GI5T9X0p4L7nNAMDR1BQjkRYoDqo+ddfVx9t5Uhys+Q==", + "dependencies": [ + "@opentelemetry/api", + "@opentelemetry/context-async-hooks", + "@opentelemetry/core@2.10.0_@opentelemetry+api@1.9.1", + "@opentelemetry/sdk-trace-base" ] }, - "@opentelemetry/sdk-trace-base@2.7.1_@opentelemetry+api@1.9.1": { - "integrity": "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==", + "@opentelemetry/sdk-trace@2.10.0_@opentelemetry+api@1.9.1": { + "integrity": "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==", "dependencies": [ "@opentelemetry/api", - "@opentelemetry/core", - "@opentelemetry/resources", + "@opentelemetry/core@2.10.0_@opentelemetry+api@1.9.1", + "@opentelemetry/resources@2.10.0_@opentelemetry+api@1.9.1", "@opentelemetry/semantic-conventions" ] }, @@ -5431,7 +5511,7 @@ "@socket.io/component-emitter@3.1.2": { "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" }, - "@solidjs/start@1.3.2_@electric-sql+pglite@0.5.8_vite@7.3.2__@types+node@24.12.2__tsx@4.21.0__yaml@2.9.0": { + "@solidjs/start@1.3.2_@netlify+blobs@11.0.3_vite@7.3.2__@types+node@24.12.2__tsx@4.21.0__yaml@2.9.0": { "integrity": "sha512-tasDl3utVbtP0rr4InB3ntBIFV2upvEiFrOOCkRrAA3yBfjx9elpxnc94sJQXo65PNYdAAAkPIC6h93vLrtwHg==", "dependencies": [ "@tanstack/server-functions-plugin", @@ -6333,7 +6413,7 @@ ], "bin": true }, - "@vinxi/plugin-directives@0.5.1_vinxi@0.5.11__@electric-sql+pglite@0.5.8_@electric-sql+pglite@0.5.8": { + "@vinxi/plugin-directives@0.5.1_vinxi@0.5.11__@netlify+blobs@11.0.3_@netlify+blobs@11.0.3": { "integrity": "sha512-pH/KIVBvBt7z7cXrUH/9uaqcdxjegFC7+zvkZkdOyWzs+kQD5KPf3cl8kC+5ayzXHT+OMlhGhyitytqN3cGmHg==", "dependencies": [ "@babel/parser@7.29.7", @@ -6348,7 +6428,7 @@ "vinxi" ] }, - "@vinxi/server-components@0.5.1_vinxi@0.5.11__@electric-sql+pglite@0.5.8_@electric-sql+pglite@0.5.8": { + "@vinxi/server-components@0.5.1_vinxi@0.5.11__@netlify+blobs@11.0.3_@netlify+blobs@11.0.3": { "integrity": "sha512-0BsG95qac3dkhfdRZxqzqYWJE4NvPL7ILlV43B6K6ho1etXWB2e5b0IxsUAUbyqpqiXM7mSRivojuXjb2G4OsQ==", "dependencies": [ "@vinxi/plugin-directives", @@ -6499,6 +6579,16 @@ "tslib@2.8.1" ] }, + "@whatwg-node/server@0.11.0": { + "integrity": "sha512-VSdkwnJRr8Yv9UgB2aXB3VUPWwd6Oqnn0hycFwhg9pZgWxJXb7JmhsiXe9tmpMwjHFxli12PGcz9aI63YYloGQ==", + "dependencies": [ + "@envelop/instrumentation", + "@whatwg-node/disposablestack", + "@whatwg-node/fetch", + "@whatwg-node/promise-helpers", + "tslib@2.8.1" + ] + }, "@whatwg-node/server@0.9.71": { "integrity": "sha512-ueFCcIPaMgtuYDS9u0qlUoEvj6GiSsKrwnOLPp9SshqjtcRaR1IEHRjoReq3sXNydsF5i0ZnmuYgXq9dV53t0g==", "dependencies": [ @@ -6801,7 +6891,7 @@ "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", "bin": true }, - "astro@7.0.9_@electric-sql+pglite@0.5.8": { + "astro@7.0.9_@netlify+blobs@11.0.3": { "integrity": "sha512-WB5pA4LLQnmqjBh6EIu0z8aUV4q2/AoThgSZq57Rsp+oqqvPu7OwZ5eF+W4ku20TUTxIhiJW8dccuGvJPiW2UA==", "dependencies": [ "@astrojs/compiler-rs", @@ -6896,11 +6986,17 @@ "atomic-sleep@1.0.0": { "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" }, + "atomically@2.1.1": { + "integrity": "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==", + "dependencies": [ + "stubborn-fs", + "when-exit" + ] + }, "autoprefixer@10.5.2_postcss@8.5.19": { "integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==", "dependencies": [ - "browserslist", - "caniuse-lite", + "caniuse-lite@1.0.30001805", "fraction.js", "picocolors", "postcss", @@ -7053,8 +7149,8 @@ "base64id@2.0.0": { "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, - "baseline-browser-mapping@2.10.43": { - "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==", + "baseline-browser-mapping@2.11.21": { + "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", "bin": true }, "before-after-hook@2.2.3": { @@ -7171,11 +7267,11 @@ "fill-range" ] }, - "browserslist@4.28.6": { - "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==", + "browserslist@4.28.9": { + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", "dependencies": [ "baseline-browser-mapping", - "caniuse-lite", + "caniuse-lite@1.0.30001810", "electron-to-chromium", "node-releases", "update-browserslist-db" @@ -7333,6 +7429,9 @@ "caniuse-lite@1.0.30001805": { "integrity": "sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA==" }, + "caniuse-lite@1.0.30001810": { + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==" + }, "canonicalize@2.1.0": { "integrity": "sha512-F705O3xrsUtgt98j7leetNhTWPe+5S72rlL5O4jA1pKqBVQ/dT1O1D6PFxmSXvc0SUOinWS57DKx0I3CHrXJHQ==", "bin": true @@ -7446,6 +7545,9 @@ "cjs-module-lexer@1.4.3": { "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==" }, + "cjs-module-lexer@2.2.1": { + "integrity": "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==" + }, "cli-boxes@3.0.0": { "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==" }, @@ -8535,8 +8637,8 @@ "ee-first@1.1.1": { "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, - "electron-to-chromium@1.5.389": { - "integrity": "sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==" + "electron-to-chromium@1.5.423": { + "integrity": "sha512-rRZfTSY8ptHYMQxa+uIycJMFKmY1T0GIApNMXJYGehguTZa56TEEl19pKPCoBqk5Gpf7QizZn/jt7xur+DYxag==" }, "elysia@1.4.29_typescript@6.0.3": { "integrity": "sha512-GwMRGGwSdjfPt+w3LA0fqTuYJtS8uVRJicvoar98/HrO5qdFKDc9CwjIb6Kja+v39lkY+58hr2JvdR9jQzlUuA==", @@ -9204,6 +9306,7 @@ "natural-compare", "optionator" ], + "deprecated": true, "bin": true }, "esm-env@1.2.2": { @@ -10633,6 +10736,14 @@ "import-from@4.0.0": { "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==" }, + "import-in-the-middle@3.4.0": { + "integrity": "sha512-Xfjwfarhe+LGmoaof+sexeNo3sGRysb5x56WrZLwHtmqT0OilSKtVWkv0lrCcMgSKyKP9oBogBAisHZvtJH0aw==", + "dependencies": [ + "cjs-module-lexer@2.2.1", + "es-module-lexer@2.3.1", + "module-details-from-path" + ] + }, "import-without-cache@0.4.0": { "integrity": "sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ==" }, @@ -12324,6 +12435,9 @@ ], "bin": true }, + "module-details-from-path@1.0.4": { + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==" + }, "moize@6.1.7": { "integrity": "sha512-8/9XgYooMo7/q5tf6zGF4+Wp1jx5sbxV87uK6YvTq9rgDtusLWZCZ8c5C0EhYZbNGudul5EMeMsObO4Ug/gszg==", "dependencies": [ @@ -12439,7 +12553,7 @@ "next-tick@1.1.0": { "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, - "nitropack@2.13.3_@electric-sql+pglite@0.5.8": { + "nitropack@2.13.3_@netlify+blobs@11.0.3": { "integrity": "sha512-C8vO7RxkU0AQ3HbYUumuG6MVM5JjRaBchke/rYFOp3EvrLtTBHZYhDVGECdpa27vNuOYRzm3GtQMn2YDOjDJLA==", "dependencies": [ "@cloudflare/kv-asset-handler@0.4.2", @@ -12596,8 +12710,8 @@ "node-object-hash@2.3.10": { "integrity": "sha512-jY5dPJzw6NHd/KPSfPKJ+IHoFS81/tJ43r34ZeNMXGzCOM8jwQDCD12HYayKIB6MuznrnqIYy2e891NA2g0ibA==" }, - "node-releases@2.0.51": { - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==" + "node-releases@2.0.54": { + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==" }, "node-source-walk@7.0.2": { "integrity": "sha512-71kFFjYaSshDTA8/a2HiTYPLdASWjLJxUyJxGE+ffxU+KhxSBtM9kiLUX+R2yooFdSFKMFpi4n3PFtDy6qXv8A==", @@ -13139,53 +13253,6 @@ "perfect-debounce@2.1.0": { "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==" }, - "pg-cloudflare@1.4.0": { - "integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==" - }, - "pg-connection-string@2.14.0": { - "integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==" - }, - "pg-int8@1.0.1": { - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - }, - "pg-pool@3.14.0_pg@8.22.0": { - "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==", - "dependencies": [ - "pg" - ] - }, - "pg-protocol@1.15.0": { - "integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==" - }, - "pg-types@2.2.0": { - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "dependencies": [ - "pg-int8", - "postgres-array", - "postgres-bytea", - "postgres-date", - "postgres-interval" - ] - }, - "pg@8.22.0": { - "integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==", - "dependencies": [ - "pg-connection-string", - "pg-pool", - "pg-protocol", - "pg-types", - "pgpass" - ], - "optionalDependencies": [ - "pg-cloudflare" - ] - }, - "pgpass@1.0.5": { - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "dependencies": [ - "split2" - ] - }, "piccolore@0.1.3": { "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==" }, @@ -13355,21 +13422,6 @@ "source-map-js" ] }, - "postgres-array@2.0.0": { - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-bytea@1.0.1": { - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==" - }, - "postgres-date@1.0.7": { - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" - }, - "postgres-interval@1.2.0": { - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "dependencies": [ - "xtend" - ] - }, "postgres@3.4.9": { "integrity": "sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==" }, @@ -13867,6 +13919,13 @@ "require-from-string@2.0.2": { "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, + "require-in-the-middle@8.0.1": { + "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", + "dependencies": [ + "debug@4.4.3", + "module-details-from-path" + ] + }, "require-package-name@2.0.1": { "integrity": "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==" }, @@ -14851,6 +14910,15 @@ "structured-field-values@2.0.4": { "integrity": "sha512-5zpJXYLPwW3WYUD/D58tQjIBs10l3Yx64jZfcKGs/RH79E2t9Xm/b9+ydwdMNVSksnsIY+HR/2IlQmgo0AcTAg==" }, + "stubborn-fs@2.0.0": { + "integrity": "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==", + "dependencies": [ + "stubborn-utils" + ] + }, + "stubborn-utils@1.0.2": { + "integrity": "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==" + }, "stubs@3.0.0": { "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==" }, @@ -15675,9 +15743,10 @@ "webpack-virtual-modules" ] }, - "unstorage@1.17.5_ioredis@5.10.1_@electric-sql+pglite@0.5.8": { + "unstorage@1.17.5_@netlify+blobs@11.0.3_ioredis@5.10.1": { "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", "dependencies": [ + "@netlify/blobs@11.0.3", "anymatch", "chokidar@5.0.0", "db0", @@ -15690,6 +15759,7 @@ "ufo" ], "optionalPeers": [ + "@netlify/blobs@11.0.3", "db0", "ioredis" ] @@ -15728,8 +15798,8 @@ "pkg-types@2.3.0" ] }, - "update-browserslist-db@1.2.3_browserslist@4.28.6": { - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "update-browserslist-db@1.3.2_browserslist@4.28.9": { + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "dependencies": [ "browserslist", "escalade", @@ -15846,7 +15916,7 @@ "vfile-message" ] }, - "vinxi@0.5.11_@electric-sql+pglite@0.5.8": { + "vinxi@0.5.11_@netlify+blobs@11.0.3": { "integrity": "sha512-82Qm+EG/b2PRFBvXBbz1lgWBGcd9totIL6SJhnrZYfakjloTVG9+5l6gfO6dbCCtztm5pqWFzLY0qpZ3H3ww/w==", "dependencies": [ "@babel/plugin-syntax-jsx@7.28.6_@babel+core@7.29.7", @@ -16023,23 +16093,6 @@ "xml-name-validator" ] }, - "waddler@0.1.1_@electric-sql+pglite@0.5.8_@neondatabase+serverless@1.1.0_mysql2@3.22.3__@types+node@24.12.2_pg@8.22.0_postgres@3.4.9": { - "integrity": "sha512-lBJXYFBLEpYe+scAeCJmLj6Iqweuq1whM6Am3I9WfopOCFxvKz8Nq5hXoy8/b3zwJqHIQMglFIvM4skRydSpZg==", - "dependencies": [ - "@electric-sql/pglite", - "@neondatabase/serverless", - "mysql2", - "pg", - "postgres" - ], - "optionalPeers": [ - "@electric-sql/pglite", - "@neondatabase/serverless", - "mysql2", - "pg", - "postgres" - ] - }, "wasm-feature-detect@1.8.0": { "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==" }, @@ -16088,6 +16141,9 @@ "webidl-conversions@3.0.1" ] }, + "when-exit@2.1.5": { + "integrity": "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==" + }, "which-boxed-primitive@1.1.1": { "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dependencies": [ @@ -16749,8 +16805,8 @@ "packages/netlify": { "dependencies": [ "npm:@netlify/async-workloads@^0.0.106", - "npm:@netlify/database@^1.1.0", - "npm:postgres@^3.4.7" + "npm:@netlify/blobs@^11.0.3", + "npm:byte-encodings@^1.0.11" ] }, "packages/nuxt": { diff --git a/docs/manual/kv.md b/docs/manual/kv.md index 542428fb0..dd9d261dc 100644 --- a/docs/manual/kv.md +++ b/docs/manual/kv.md @@ -511,6 +511,79 @@ export default { [Cloudflare Workers]: https://workers.cloudflare.com/ [Cloudflare Workers KV]: https://developers.cloudflare.com/kv/ +### `NetlifyBlobsKvStore` + +*This API is available since Fedify 2.4.0.* + +To use the [`NetlifyBlobsKvStore`], you need to install *@fedify/netlify* and +*@netlify/blobs*. + +::: code-group + +~~~~ bash [Deno] +deno add jsr:@fedify/netlify npm:@netlify/blobs +~~~~ + +~~~~ bash [npm] +npm add @fedify/netlify @netlify/blobs +~~~~ + +~~~~ bash [pnpm] +pnpm add @fedify/netlify @netlify/blobs +~~~~ + +~~~~ bash [Yarn] +yarn add @fedify/netlify @netlify/blobs +~~~~ + +~~~~ bash [Bun] +bun add @fedify/netlify @netlify/blobs +~~~~ + +::: + +`NetlifyBlobsKvStore` from `@fedify/netlify` stores federation state in +[Netlify Blobs] +without requiring a separate database. It supports expiration, prefix +listing, and atomic compare-and-set (CAS) operations. + +Best for +: Small Fedify applications on [Netlify Functions]. + +Pros +: Persistent storage and atomic CAS without a separate database. + +Cons +: 600-byte encoded key limit; expired blobs and tombstones are not + automatically removed. + +~~~~ typescript +import { createFederation } from "@fedify/fedify"; +import { NetlifyBlobsKvStore } from "@fedify/netlify"; +import { getStore } from "@netlify/blobs"; + +const federation = createFederation({ + kv: new NetlifyBlobsKvStore(getStore({ + name: "fedify", + consistency: "strong", + })), +}); +~~~~ + +CAS operations always use strong reads and conditional writes. Configuring +the Blobs store with `consistency: "strong"` also enables strong consistency +for ordinary reads and listings. + +> [!NOTE] +> If your Netlify application already uses PostgreSQL, you can use +> [`PostgresKvStore`](#postgreskvstore) from `@fedify/postgres` instead. +> Netlify Blobs is optional; choose the store that matches your application's +> storage setup. + +[`NetlifyBlobsKvStore`]: https://jsr.io/@fedify/netlify/doc/~/NetlifyBlobsKvStore +[Netlify Blobs]: https://docs.netlify.com/build/data-and-storage/netlify-blobs/ +[Netlify Functions]: https://docs.netlify.com/build/functions/overview/ + Implementing a custom `KvStore` ------------------------------- diff --git a/package.json b/package.json index 8ffc9bdd0..6d4f0c2df 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,13 @@ { "scripts": { "prepare": "pnpm -r run build:self" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild" + ], + "patchedDependencies": { + "@netlify/blobs@11.0.3": "patches/@netlify__blobs@11.0.3.patch" + } } } diff --git a/packages/netlify/README.md b/packages/netlify/README.md index bd5dd47b9..a564f2e79 100644 --- a/packages/netlify/README.md +++ b/packages/netlify/README.md @@ -1,7 +1,7 @@ -@fedify/netlify: Run Fedify queues with Netlify Async Workloads -=============================================================== +@fedify/netlify: Run Fedify with Netlify blobs and async workloads +================================================================== [![JSR][JSR badge]][JSR] [![npm][npm badge]][npm] @@ -9,10 +9,11 @@ *This package is available since Fedify 2.4.0.* -This package connects [Fedify]'s [`MessageQueue`] API to -[Netlify Async Workloads]. `NetlifyMessageQueue` publishes durable events, -while `createNetlifyQueueHandler()` turns a Netlify Function into their -consumer. +This package connects [Fedify]'s [`KvStore`] and [`MessageQueue`] APIs to +Netlify. `NetlifyBlobsKvStore` stores federation state in [Netlify Blobs], +`NetlifyMessageQueue` publishes durable events through +[Netlify Async Workloads], and `createNetlifyQueueHandler()` turns a Netlify +Function into their consumer. The initial release targets Netlify Functions, not Netlify Edge Functions. @@ -23,13 +24,17 @@ The initial release targets Netlify Functions, not Netlify Edge Functions. [@fedify@hackers.pub badge]: https://fedi-badge.minhee.org/@fedify@hackers.pub/followers.svg [@fedify@hackers.pub]: https://hackers.pub/@fedify [Fedify]: https://fedify.dev/ +[`KvStore`]: https://jsr.io/@fedify/fedify/doc/federation/~/KvStore [`MessageQueue`]: https://jsr.io/@fedify/fedify/doc/federation/~/MessageQueue +[Netlify Blobs]: https://docs.netlify.com/build/data-and-storage/netlify-blobs/ [Netlify Async Workloads]: https://docs.netlify.com/build/async-workloads/get-started/ Installation ------------ +For queue-only usage, install the package with Netlify Async Workloads: + ~~~~ sh deno add jsr:@fedify/netlify npm:@netlify/async-workloads # Deno npm add @fedify/netlify @netlify/async-workloads # npm @@ -38,8 +43,62 @@ yarn add @fedify/netlify @netlify/async-workloads # Yarn bun add @fedify/netlify @netlify/async-workloads # Bun ~~~~ -The PostgreSQL-backed `orderingKv` example below also needs -`@fedify/postgres`, `@netlify/database`, and `postgres`: + +Usage +----- + +To use `NetlifyBlobsKvStore`, also install Netlify Blobs: + +~~~~ sh +deno add npm:@netlify/blobs # Deno +npm add @netlify/blobs # npm +pnpm add @netlify/blobs # pnpm +yarn add @netlify/blobs # Yarn +bun add @netlify/blobs # Bun +~~~~ + +Create one store and queue for both the web application and the workload +function. `NetlifyBlobsKvStore` provides the compare-and-set (CAS) support +required when Fedify emits messages with an `orderingKey`, without requiring a +separate database: + +~~~~ typescript +import { AsyncWorkloadsClient } from "@netlify/async-workloads"; +import { getStore } from "@netlify/blobs"; +import { + NetlifyBlobsKvStore, + NetlifyMessageQueue, +} from "@fedify/netlify"; + +export const kv = new NetlifyBlobsKvStore(getStore({ + name: "fedify", + consistency: "strong", +})); +export const queue = new NetlifyMessageQueue({ + client: new AsyncWorkloadsClient(), + orderingKv: kv, +}); +~~~~ + +CAS operations always use strong reads and conditional writes. The +`consistency: "strong"` setting above also gives ordinary `get()` calls and +listings strong consistency. You can omit it when lower-latency, eventually +consistent ordinary reads are acceptable. + +TTL expiration is logical: expired blobs remain in Netlify Blobs but are +hidden by `get()` and `list()`. CAS deletion similarly writes a tombstone so +that a concurrent writer cannot recreate the key undetected. Tombstones are +also hidden and can be replaced by a later CAS operation, but they are not +removed automatically. Use a dedicated Netlify Blobs store and account for +these retained blobs. Only remove them during maintenance when concurrent CAS +operations for those keys have stopped; physical deletion during a race would +remove the version token that protects the key. + +### PostgreSQL alternative + +If the application already uses PostgreSQL, `PostgresKvStore` can provide the +same CAS-capable ordering storage. Install `@fedify/postgres`, +`@netlify/database`, and `postgres` in addition to the base dependencies: ~~~~ sh deno add jsr:@fedify/postgres npm:@netlify/database npm:postgres # Deno @@ -49,29 +108,20 @@ yarn add @fedify/postgres @netlify/database postgres # Yarn bun add @fedify/postgres @netlify/database postgres # Bun ~~~~ - -Usage ------ - -Create one queue for both the web application and the workload function. A -CAS-capable `KvStore`, such as `PostgresKvStore`, is required if Fedify emits -messages with an `orderingKey`: +Then replace the `kv` declaration from the main example: ~~~~ typescript -import { AsyncWorkloadsClient } from "@netlify/async-workloads"; import { getConnectionString } from "@netlify/database"; -import { NetlifyMessageQueue } from "@fedify/netlify"; import { PostgresKvStore } from "@fedify/postgres"; import postgres from "postgres"; const sql = postgres(getConnectionString()); export const kv = new PostgresKvStore(sql); -export const queue = new NetlifyMessageQueue({ - client: new AsyncWorkloadsClient(), - orderingKv: kv, -}); ~~~~ +Ordering state must use crash-safe storage. `PostgresKvStore` creates a logged +table by default; do not pass `unlogged: true` for `orderingKv`. + Pass the queue to Fedify with `manuallyStartQueue: true`. Async Workloads invokes the consumer, so `NetlifyMessageQueue.listen()` is intentionally not available: @@ -142,9 +192,6 @@ because a lost response does not prove that the router rejected the event. Use the error's `orderingKey` and `orderingSequence` for manual recovery only after ruling out delivery. -Ordering state must use crash-safe storage. `PostgresKvStore` creates a logged -table by default; do not pass `unlogged: true` for `orderingKv`. - Netlify limits an event payload to 500 KB. Fedify messages, including any embedded activity, must remain below that limit. @@ -156,7 +203,7 @@ Fedify rejects a multi-message `enqueueTaskMany()` call with one batch enqueue so a failed partial send cannot produce duplicates on retry. See the [deployment manual] and the [Netlify Astro example] for a complete -setup with Netlify Database. +setup using the PostgreSQL alternative with Netlify Database. [deployment manual]: https://fedify.dev/manual/deploy#netlify-functions [Netlify Astro example]: https://github.com/fedify-dev/fedify/tree/main/examples/netlify-astro diff --git a/packages/netlify/deno.json b/packages/netlify/deno.json index a2805d55b..489721a06 100644 --- a/packages/netlify/deno.json +++ b/packages/netlify/deno.json @@ -3,9 +3,9 @@ "version": "2.4.0", "license": "MIT", "imports": { - "@netlify/database": "npm:@netlify/database@^1.1.0", "@netlify/async-workloads": "npm:@netlify/async-workloads@^0.0.106", - "postgres": "npm:postgres@^3.4.7" + "@netlify/blobs": "npm:@netlify/blobs@^11.0.3", + "byte-encodings": "npm:byte-encodings@^1.0.11" }, "exports": { ".": "./src/mod.ts" diff --git a/packages/netlify/fixtures/netlify-dev/netlify/functions/blob-kv.mts b/packages/netlify/fixtures/netlify-dev/netlify/functions/blob-kv.mts new file mode 100644 index 000000000..0bbf00830 --- /dev/null +++ b/packages/netlify/fixtures/netlify-dev/netlify/functions/blob-kv.mts @@ -0,0 +1,48 @@ +import { createServices } from "../lib/runtime.ts"; + +interface BlobKvBody { + readonly action?: unknown; + readonly expectedValue?: unknown; + readonly id?: unknown; + readonly newValue?: unknown; + readonly value?: unknown; +} + +export default async function blobKv(request: Request): Promise { + const body = await request.json() as BlobKvBody; + if ( + typeof body.id !== "string" || body.id.length < 1 || + typeof body.action !== "string" + ) { + return new Response("Invalid payload.", { status: 400 }); + } + + const { kv } = createServices(); + const key = ["integration", "blob-kv", body.id] as const; + switch (body.action) { + case "set": + if (!("value" in body)) { + return new Response("Missing value.", { status: 400 }); + } + await kv.set(key, body.value); + return Response.json({ written: true }); + case "get": { + const value = await kv.get(key); + return value === undefined + ? Response.json({ found: false }) + : Response.json({ found: true, value }); + } + case "delete": + await kv.delete(key); + return Response.json({ deleted: true }); + case "cas": + if (kv.cas == null) { + return new Response("CAS is unavailable.", { status: 500 }); + } + return Response.json({ + swapped: await kv.cas(key, body.expectedValue, body.newValue), + }); + default: + return new Response("Invalid action.", { status: 400 }); + } +} diff --git a/packages/netlify/fixtures/netlify-dev/netlify/lib/runtime.ts b/packages/netlify/fixtures/netlify-dev/netlify/lib/runtime.ts index d39b8284f..9780a69c3 100644 --- a/packages/netlify/fixtures/netlify-dev/netlify/lib/runtime.ts +++ b/packages/netlify/fixtures/netlify-dev/netlify/lib/runtime.ts @@ -4,12 +4,13 @@ import { type KvKey, type KvStore, } from "@fedify/fedify/federation"; -import { NetlifyMessageQueue } from "../../../../src/mod.ts"; -import { PostgresKvStore } from "@fedify/postgres"; +import { + NetlifyBlobsKvStore, + NetlifyMessageQueue, +} from "../../../../src/mod.ts"; import { AsyncWorkloadsClient } from "@netlify/async-workloads"; -import { getConnectionString } from "@netlify/database"; +import { getStore } from "@netlify/blobs"; import type { StandardSchemaV1 } from "@standard-schema/spec"; -import postgres from "postgres"; export interface TaskPayload { readonly id: string; @@ -46,10 +47,10 @@ const taskSchema: StandardSchemaV1 = { }; export function createServices() { - const sql = postgres(getConnectionString()); - const kv = new PostgresKvStore(sql, { - tableName: "fedify_netlify_integration_kv", - }); + const kv = new NetlifyBlobsKvStore(getStore({ + name: "fedify-integration", + consistency: "strong", + })); const baseUrl = process.env.URL ?? process.env.DEPLOY_URL; const queue = new NetlifyMessageQueue({ client: new AsyncWorkloadsClient(baseUrl == null ? undefined : { baseUrl }), diff --git a/packages/netlify/fixtures/public-types.ts b/packages/netlify/fixtures/public-types.ts new file mode 100644 index 000000000..ea866da87 --- /dev/null +++ b/packages/netlify/fixtures/public-types.ts @@ -0,0 +1,7 @@ +import { getStore } from "@netlify/blobs"; +import { NetlifyBlobsKvStore } from "../dist/mod.js"; + +new NetlifyBlobsKvStore(getStore({ + name: "fedify", + consistency: "strong", +})); diff --git a/packages/netlify/package.json b/packages/netlify/package.json index 16b0a1199..fab4d0726 100644 --- a/packages/netlify/package.json +++ b/packages/netlify/package.json @@ -47,6 +47,8 @@ "package.json" ], "dependencies": { + "byte-encodings": "catalog:", + "es-toolkit": "catalog:", "temporal-polyfill": "catalog:" }, "peerDependencies": { @@ -54,13 +56,11 @@ "@netlify/async-workloads": "catalog:" }, "devDependencies": { - "@fedify/postgres": "workspace:^", "@js-temporal/polyfill": "catalog:", - "@netlify/database": "catalog:", "@standard-schema/spec": "catalog:", + "@netlify/blobs": "catalog:", "@types/node": "catalog:", "netlify-cli": "catalog:", - "postgres": "catalog:", "tsdown": "catalog:", "typescript": "catalog:" }, diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts new file mode 100644 index 000000000..afd3c7c53 --- /dev/null +++ b/packages/netlify/src/kv.ts @@ -0,0 +1,187 @@ +import type { + KvKey, + KvStore, + KvStoreListEntry, + KvStoreSetOptions, +} from "@fedify/fedify/federation"; +import { decodeBase64Url, encodeBase64Url } from "byte-encodings/base64url"; +import { isEqual } from "es-toolkit"; +import type { NetlifyBlobsStore } from "./types.ts"; + +const MAX_BLOB_KEY_BYTES = 600; +const BLOB_KEY_PREFIX = "fedify1."; +const BLOB_KEY_SEPARATOR = "."; +const textDecoder = new TextDecoder(); + +/** + * A key-value store that uses Netlify Blobs. + * + * @since 2.4.0 + */ +export class NetlifyBlobsKvStore implements KvStore { + readonly #store: NetlifyBlobsStore; + + /** + * Creates a new Netlify Blobs-backed key-value store. + * @param store The Netlify Blobs store to use. + */ + constructor(store: NetlifyBlobsStore) { + this.#store = store; + } + + private serializeKey(key: KvKey): string { + const serialized = BLOB_KEY_PREFIX + + key.map((part) => encodeBase64Url(part)).join(BLOB_KEY_SEPARATOR) + + BLOB_KEY_SEPARATOR; + if (new TextEncoder().encode(serialized).byteLength > MAX_BLOB_KEY_BYTES) { + throw new RangeError( + "The encoded key exceeds Netlify Blobs' 600-byte key limit.", + ); + } + return serialized; + } + + private deserializeKey(key: string): KvKey { + const encodedParts = key.slice(BLOB_KEY_PREFIX.length, -1).split( + BLOB_KEY_SEPARATOR, + ); + return encodedParts.map((part) => + textDecoder.decode(decodeBase64Url(part)) + ) as [string, ...string[]]; + } + + private serializePrefix(prefix?: KvKey): string { + return prefix == null ? BLOB_KEY_PREFIX : this.serializeKey(prefix); + } + + private isAbsent(metadata: Record): boolean { + if (metadata.tombstone === true) return true; + const expireIn = metadata.expireIn; + return typeof expireIn === "number" && + expireIn <= Temporal.Now.instant().epochMilliseconds; + } + + private getEtag(entry: { readonly etag?: string } | null): string { + if (entry?.etag == null) { + throw new Error("Netlify Blobs did not return an ETag."); + } + return entry.etag; + } + + /** + * {@inheritDoc KvStore.get} + */ + async get(key: KvKey): Promise { + const result = await this.#store.getWithMetadata(this.serializeKey(key), { + type: "json", + }); + + if (result === null || this.isAbsent(result.metadata)) return undefined; + return result.data as T; + } + + /** + * {@inheritDoc KvStore.set} + */ + async set( + key: KvKey, + value: unknown, + options?: KvStoreSetOptions | undefined, + ): Promise { + const expireIn = options?.ttl == null + ? null + : Temporal.Now.instant().epochMilliseconds + + options.ttl.total("millisecond"); + + await this.#store.setJSON(this.serializeKey(key), value, { + metadata: { "expireIn": expireIn }, + }); + } + + /** + * {@inheritDoc KvStore.delete} + */ + delete(key: KvKey): Promise { + return this.#store.delete(this.serializeKey(key)); + } + + /** + * {@inheritDoc KvStore.list} + */ + async *list(prefix?: KvKey): AsyncIterable { + const pages = this.#store.list({ + paginate: true, + prefix: this.serializePrefix(prefix), + }); + for await (const page of pages) { + for (const blob of page.blobs) { + const key = this.deserializeKey(blob.key); + const value = await this.get(key); + + if (value === undefined) continue; + + yield { + key: key, + value: value, + }; + } + } + } + + /** + * {@inheritDoc KvStore.cas} + */ + async cas( + key: KvKey, + expectedValue: unknown, + newValue: unknown, + options?: KvStoreSetOptions, + ): Promise { + while (true) { + const entry = await this.#store.getWithMetadata(this.serializeKey(key), { + consistency: "strong", + type: "json", + }); + + const currentValue = entry === null || this.isAbsent(entry.metadata) + ? undefined + : entry.data; + + if (!isEqual(currentValue, expectedValue)) return false; + + if (entry === null && newValue === undefined) { + return true; + } + + const serializedKey = this.serializeKey(key); + + if (newValue === undefined) { + const result = await this.#store.setJSON(serializedKey, null, { + onlyIfMatch: this.getEtag(entry), + metadata: { tombstone: true }, + }); + if (result.modified) return true; + continue; + } + + const metadata = { + "expireIn": options?.ttl == null + ? null + : Temporal.Now.instant().epochMilliseconds + + options.ttl.total("millisecond"), + }; + + const result = entry === null + ? await this.#store.setJSON(serializedKey, newValue, { + onlyIfNew: true, + metadata: metadata, + }) + : await this.#store.setJSON(serializedKey, newValue, { + onlyIfMatch: this.getEtag(entry), + metadata: metadata, + }); + + if (result.modified) return true; + } + } +} diff --git a/packages/netlify/src/mod.ts b/packages/netlify/src/mod.ts index 809b921a9..ba3d48a1c 100644 --- a/packages/netlify/src/mod.ts +++ b/packages/netlify/src/mod.ts @@ -6,15 +6,19 @@ * @since 2.4.0 */ +export { + createNetlifyQueueHandler, + type NetlifyQueueEvent, + type NetlifyQueueHandlerOptions, +} from "./handler.ts"; +export { NetlifyBlobsKvStore } from "./kv.ts"; export { NetlifyMessageQueue, type NetlifyMessageQueueOptions, NetlifyMessageQueueSendError, type NetlifyQueueEventData, } from "./mq.ts"; -export { - createNetlifyQueueHandler, - type NetlifyQueueEvent, - type NetlifyQueueHandlerOptions, -} from "./handler.ts"; -export type { NetlifyAsyncWorkloadsClient } from "./types.ts"; +export type { + NetlifyAsyncWorkloadsClient, + NetlifyBlobsStore, +} from "./types.ts"; diff --git a/packages/netlify/src/types.ts b/packages/netlify/src/types.ts index 5a821c423..286397013 100644 --- a/packages/netlify/src/types.ts +++ b/packages/netlify/src/types.ts @@ -1,5 +1,63 @@ import type { NetlifyQueueEventData } from "./mq.ts"; +/** + * The subset of Netlify's Blobs `Store` used by this package. + * + * The real Netlify Blobs `Store` satisfies this interface. The narrower + * interface also keeps Netlify Blobs optional and makes it possible to supply + * a test double. + * + * @since 2.4.0 + */ +export interface NetlifyBlobsStore { + getWithMetadata( + key: string, + options: { + readonly consistency?: "eventual" | "strong"; + readonly type: "json"; + }, + ): Promise< + { + readonly data: unknown; + readonly etag?: string; + readonly metadata: Record; + } | null + >; + + setJSON( + key: string, + data: unknown, + options?: + & { + readonly metadata?: Record; + } + & ( + | { + readonly onlyIfNew?: boolean; + readonly onlyIfMatch?: never; + } + | { + readonly onlyIfMatch?: string; + readonly onlyIfNew?: never; + } + ), + ): Promise<{ + readonly etag?: string; + readonly modified: boolean; + }>; + + delete(key: string): Promise; + + list(options: { + readonly paginate: true; + readonly prefix?: string; + }): AsyncIterable<{ + readonly blobs: readonly { + readonly key: string; + }[]; + }>; +} + /** * The subset of Netlify's `AsyncWorkloadsClient` used by this package. * diff --git a/packages/netlify/test/integration/netlify.test.ts b/packages/netlify/test/integration/netlify.test.ts index db611a315..66bf5f18b 100644 --- a/packages/netlify/test/integration/netlify.test.ts +++ b/packages/netlify/test/integration/netlify.test.ts @@ -74,7 +74,7 @@ async function waitForServer( child: ChildProcess, logs: () => string, ): Promise { - const deadline = Date.now() + 60_000; + const deadline = Date.now() + 120_000; const healthUrl = new URL("/.netlify/functions/status?id=health", baseUrl); while (Date.now() < deadline) { if (child.exitCode != null) { @@ -129,12 +129,28 @@ interface Status { }; } +async function callBlobKv( + baseUrl: URL, + body: Record, +): Promise> { + const response = await fetch( + new URL("/.netlify/functions/blob-kv", baseUrl), + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }, + ); + equal(response.status, 200, await response.clone().text()); + return await response.json() as Record; +} + const integrationTest = skipReason === false ? test : test.skip; integrationTest( "Netlify Dev delivers, retries, and orders Fedify queue tasks", { - timeout: 120_000, + timeout: 180_000, }, async (t) => { await rm(netlifyDirectory, { force: true, recursive: true }); @@ -190,6 +206,88 @@ integrationTest( await waitForServer(baseUrl, child, () => output); + await t.test( + "persists values and performs conditional writes", + async () => { + const id = crypto.randomUUID(); + try { + deepStrictEqual( + await callBlobKv(baseUrl, { + action: "set", + id, + value: { state: "persisted" }, + }), + { written: true }, + ); + deepStrictEqual(await callBlobKv(baseUrl, { action: "get", id }), { + found: true, + value: { state: "persisted" }, + }); + + await callBlobKv(baseUrl, { action: "delete", id }); + deepStrictEqual( + await callBlobKv(baseUrl, { + action: "cas", + id, + newValue: "created", + }), + { swapped: true }, + ); + deepStrictEqual( + await callBlobKv(baseUrl, { + action: "cas", + id, + newValue: "duplicate", + }), + { swapped: false }, + ); + deepStrictEqual( + await callBlobKv(baseUrl, { + action: "cas", + expectedValue: "created", + id, + newValue: "updated", + }), + { swapped: true }, + ); + deepStrictEqual( + await callBlobKv(baseUrl, { + action: "cas", + expectedValue: "created", + id, + newValue: "stale", + }), + { swapped: false }, + ); + deepStrictEqual( + await callBlobKv(baseUrl, { + action: "cas", + expectedValue: "updated", + id, + }), + { swapped: true }, + ); + deepStrictEqual(await callBlobKv(baseUrl, { action: "get", id }), { + found: false, + }); + deepStrictEqual( + await callBlobKv(baseUrl, { + action: "cas", + id, + newValue: "recreated", + }), + { swapped: true }, + ); + deepStrictEqual(await callBlobKv(baseUrl, { action: "get", id }), { + found: true, + value: "recreated", + }); + } finally { + await callBlobKv(baseUrl, { action: "delete", id }); + } + }, + ); + await t.test("delivers a task through the workload function", async () => { const id = crypto.randomUUID(); const response = await fetch( diff --git a/packages/netlify/test/kv.test.ts b/packages/netlify/test/kv.test.ts new file mode 100644 index 000000000..62fd669de --- /dev/null +++ b/packages/netlify/test/kv.test.ts @@ -0,0 +1,484 @@ +import "temporal-polyfill/global"; +import { deepStrictEqual, equal, ok, rejects } from "node:assert/strict"; +import { describe, it } from "node:test"; +import type { KvKey } from "@fedify/fedify/federation"; +import { getStore, type SetOptions } from "@netlify/blobs"; +import { encodeBase64Url } from "byte-encodings/base64url"; +import { NetlifyBlobsKvStore } from "../src/kv.ts"; + +interface Entry { + readonly data: unknown; + readonly etag?: string; + readonly metadata: Record; +} + +class MockStore { + readonly entries = new Map(); + readonly getCalls: { + readonly key: string; + readonly consistency?: "eventual" | "strong"; + readonly type?: string; + }[] = []; + readonly setCalls: { + readonly key: string; + readonly data: unknown; + readonly options: SetOptions; + }[] = []; + readonly deleteCalls: string[] = []; + readonly listPrefixes: string[] = []; + beforeNextSet?: () => void; + #version = 0; + + getWithMetadata( + key: string, + options: { + consistency?: "eventual" | "strong"; + type?: string; + } = {}, + ): Promise { + this.getCalls.push({ + key, + consistency: options.consistency, + type: options.type, + }); + return Promise.resolve(this.entries.get(key) ?? null); + } + + setJSON( + key: string, + data: unknown, + options: SetOptions = {}, + ): Promise<{ etag?: string; modified: boolean }> { + this.setCalls.push({ key, data, options }); + const beforeSet = this.beforeNextSet; + this.beforeNextSet = undefined; + beforeSet?.(); + + const current = this.entries.get(key); + if ( + (options.onlyIfNew === true && current != null) || + (options.onlyIfMatch != null && current?.etag !== options.onlyIfMatch) + ) { + return Promise.resolve({ modified: false }); + } + + const entry = { + data, + etag: `${++this.#version}`, + metadata: options.metadata ?? {}, + }; + this.entries.set(key, entry); + return Promise.resolve({ etag: entry.etag, modified: true }); + } + + delete(key: string): Promise { + this.deleteCalls.push(key); + this.entries.delete(key); + return Promise.resolve(); + } + + async *list(options: { prefix?: string }) { + const prefix = options.prefix ?? ""; + this.listPrefixes.push(prefix); + const blobs = [...this.entries] + .filter(([key]) => key.startsWith(prefix)) + .map(([key, entry]) => ({ key, etag: entry.etag ?? "" })); + for (const blob of blobs) { + yield { blobs: [blob], directories: [] }; + } + } +} + +function createKv(store: MockStore): NetlifyBlobsKvStore { + return new NetlifyBlobsKvStore(store); +} + +function encodeKey(key: KvKey): string { + return `fedify1.${key.map((part) => encodeBase64Url(part)).join(".")}.`; +} + +async function collect( + entries: AsyncIterable<{ key: KvKey; value: unknown }>, +) { + return await Array.fromAsync(entries); +} + +describe("NetlifyBlobsKvStore", () => { + it("gets, sets, and overwrites JSON values", async () => { + const store = new MockStore(); + const kv = createKv(store); + deepStrictEqual(await kv.get(["missing"]), undefined); + equal(store.getCalls[0].type, "json"); + + const values = [null, false, 0, "", [1, 2], { nested: true }]; + for (const [index, value] of values.entries()) { + const key: KvKey = ["value", `${index}`]; + await kv.set(key, value); + deepStrictEqual(await kv.get(key), value); + } + + await kv.set(["overwrite"], "first"); + await kv.set(["overwrite"], "second"); + deepStrictEqual(await kv.get(["overwrite"]), "second"); + }); + + it("deletes existing and missing keys", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["delete"], "value"); + + await kv.delete(["delete"]); + await kv.delete(["missing"]); + + deepStrictEqual(await kv.get(["delete"]), undefined); + deepStrictEqual(store.deleteCalls, [ + encodeKey(["delete"]), + encodeKey(["missing"]), + ]); + }); + + it("stores TTL metadata and hides expired values", async () => { + const store = new MockStore(); + const kv = createKv(store); + const before = Date.now(); + await kv.set(["future"], "visible", { + ttl: Temporal.Duration.from({ seconds: 1 }), + }); + const expires = store.entries.get(encodeKey(["future"]))?.metadata.expireIn; + ok(typeof expires === "number"); + ok(expires >= before + 1_000); + + store.entries.set(encodeKey(["expired"]), { + data: "hidden", + etag: "expired", + metadata: { expireIn: Date.now() - 1 }, + }); + deepStrictEqual(await kv.get(["future"]), "visible"); + deepStrictEqual(await kv.get(["expired"]), undefined); + deepStrictEqual(await collect(kv.list()), [ + { key: ["future"], value: "visible" }, + ]); + }); + + it("clears TTL metadata when overwriting without a TTL", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["ttl-overwrite"], "expiring", { + ttl: Temporal.Duration.from({ seconds: 1 }), + }); + + await kv.set(["ttl-overwrite"], "persistent"); + + deepStrictEqual(store.entries.get(encodeKey(["ttl-overwrite"]))?.metadata, { + expireIn: null, + }); + deepStrictEqual(await kv.get(["ttl-overwrite"]), "persistent"); + }); +}); + +describe("NetlifyBlobsKvStore key encoding", () => { + it("round-trips structured keys across paginated listings", async () => { + const store = new MockStore(); + const kv = createKv(store); + const entries = [ + { key: ["actor"] as KvKey, value: 1 }, + { key: ["actor", "alice"] as KvKey, value: 2 }, + { key: ["actor", 'quoted"],comma'] as KvKey, value: 3 }, + { key: ["", "雪"] as KvKey, value: 4 }, + ]; + for (const { key, value } of entries) await kv.set(key, value); + store.entries.set("unrelated-blob", { + data: "ignored", + etag: "unrelated", + metadata: {}, + }); + + deepStrictEqual(await collect(kv.list()), entries); + deepStrictEqual(store.listPrefixes, ["fedify1."]); + }); + + it("preserves tuple prefixes without matching partial components", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["actor"], "exact"); + await kv.set(["actor", "alice"], "child"); + await kv.set(["actor", "alice", "inbox"], "descendant"); + await kv.set(["actors"], "different"); + + deepStrictEqual(await collect(kv.list(["actor"])), [ + { key: ["actor"], value: "exact" }, + { key: ["actor", "alice"], value: "child" }, + { key: ["actor", "alice", "inbox"], value: "descendant" }, + ]); + deepStrictEqual(await collect(kv.list(["actor", "alice"])), [ + { key: ["actor", "alice"], value: "child" }, + { key: ["actor", "alice", "inbox"], value: "descendant" }, + ]); + deepStrictEqual(store.listPrefixes, [ + encodeKey(["actor"]), + encodeKey(["actor", "alice"]), + ]); + }); + + it("keeps URL delimiters out of Netlify SDK request URLs", async () => { + const requestUrls: URL[] = []; + const store = getStore({ + name: "test", + siteID: "site", + token: "token", + edgeURL: "https://example.com", + fetch: (input) => { + const url = input instanceof Request ? input.url : input.toString(); + requestUrls.push(new URL(url)); + return Promise.resolve(new Response(null, { status: 404 })); + }, + }); + const kv = new NetlifyBlobsKvStore(store); + const keys: KvKey[] = [ + ["cache", "https://example.com/actor#key-1"], + ["cache", "https://example.com/actor#key-2"], + ["cache", "https://example.com/actor?key=1"], + ["cache", "https://example.com/actor?key=2"], + ]; + + for (const key of keys) deepStrictEqual(await kv.get(key), undefined); + + equal(requestUrls.length, keys.length); + equal(new Set(requestUrls.map((url) => url.pathname)).size, keys.length); + for (const url of requestUrls) { + equal(url.hash, ""); + equal(url.search, ""); + } + }); + + it("enforces the 600-byte UTF-8 key limit", async () => { + const store = new MockStore(); + const kv = createKv(store); + + await kv.set(["a".repeat(443)], "exactly 600 encoded bytes"); + deepStrictEqual( + await kv.get(["a".repeat(443)]), + "exactly 600 encoded bytes", + ); + equal( + new TextEncoder().encode(store.setCalls[0].key).byteLength, + 600, + ); + + await rejects( + kv.set(["a".repeat(444)], "too long"), + new RangeError( + "The encoded key exceeds Netlify Blobs' 600-byte key limit.", + ), + ); + await rejects( + kv.set(["한".repeat(200)], "too long in UTF-8"), + new RangeError( + "The encoded key exceeds Netlify Blobs' 600-byte key limit.", + ), + ); + }); + + it("filters expired values and tombstones across pages", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["listed", "visible"], "value"); + store.entries.set(encodeKey(["listed", "expired"]), { + data: "expired", + etag: "expired", + metadata: { expireIn: Date.now() - 1 }, + }); + store.entries.set(encodeKey(["listed", "deleted"]), { + data: null, + etag: "deleted", + metadata: { tombstone: true }, + }); + + deepStrictEqual(await collect(kv.list(["listed"])), [ + { key: ["listed", "visible"], value: "value" }, + ]); + }); +}); + +describe("NetlifyBlobsKvStore.cas()", () => { + it("creates a missing key only when undefined is expected", async () => { + const store = new MockStore(); + const kv = createKv(store); + + equal(await kv.cas(["create"], "wrong", "value"), false); + equal(await kv.cas(["create"], undefined, "value"), true); + deepStrictEqual(await kv.get(["create"]), "value"); + equal(store.setCalls.length, 1); + equal(store.setCalls[0].options.onlyIfNew, true); + equal(store.getCalls[0].consistency, "strong"); + equal(store.getCalls[0].type, "json"); + }); + + it("updates a matching value with its ETag", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["update"], { count: 1 }); + const etag = store.entries.get(encodeKey(["update"]))?.etag; + store.setCalls.length = 0; + + equal(await kv.cas(["update"], { count: 0 }, { count: 2 }), false); + equal(await kv.cas(["update"], { count: 1 }, { count: 2 }), true); + deepStrictEqual(await kv.get(["update"]), { count: 2 }); + equal(store.setCalls.length, 1); + equal(store.setCalls[0].options.onlyIfMatch, etag); + }); + + it("distinguishes null from an absent key", async () => { + const kv = createKv(new MockStore()); + await kv.set(["null"], null); + + equal(await kv.cas(["null"], undefined, "wrong"), false); + equal(await kv.cas(["null"], null, "updated"), true); + deepStrictEqual(await kv.get(["null"]), "updated"); + }); + + it("conditionally replaces a value with a tombstone", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["deleted"], "value"); + + deepStrictEqual(await kv.cas(["deleted"], "wrong", undefined), false); + deepStrictEqual(await kv.cas(["deleted"], "value", undefined), true); + deepStrictEqual(await kv.get(["deleted"]), undefined); + deepStrictEqual(await collect(kv.list(["deleted"])), []); + deepStrictEqual(store.entries.get(encodeKey(["deleted"]))?.data, null); + deepStrictEqual( + store.entries.get(encodeKey(["deleted"]))?.metadata, + { tombstone: true }, + ); + }); + + it("recreates a tombstoned key with its ETag", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["recreate"], "old"); + await kv.cas(["recreate"], "old", undefined); + const tombstoneEtag = store.entries.get(encodeKey(["recreate"]))?.etag; + store.setCalls.length = 0; + + equal(await kv.cas(["recreate"], undefined, "new"), true); + deepStrictEqual(await kv.get(["recreate"]), "new"); + equal(store.setCalls[0].options.onlyIfMatch, tombstoneEtag); + deepStrictEqual(store.setCalls[0].options.metadata, { expireIn: null }); + }); + + it("replaces an expired blob with its ETag", async () => { + const store = new MockStore(); + const kv = createKv(store); + store.entries.set(encodeKey(["expired-cas"]), { + data: "old", + etag: "expired-etag", + metadata: { expireIn: Date.now() - 1 }, + }); + + equal(await kv.cas(["expired-cas"], undefined, "new"), true); + deepStrictEqual(await kv.get(["expired-cas"]), "new"); + equal(store.setCalls[0].options.onlyIfMatch, "expired-etag"); + equal(store.setCalls[0].options.onlyIfNew, undefined); + }); + + it("applies TTL metadata to a successful write", async () => { + const store = new MockStore(); + const kv = createKv(store); + const before = Date.now(); + + equal( + await kv.cas(["ttl-cas"], undefined, "value", { + ttl: Temporal.Duration.from({ seconds: 1 }), + }), + true, + ); + const expires = store.setCalls[0].options.metadata?.expireIn; + ok(typeof expires === "number"); + ok(expires >= before + 1_000); + }); + + it("allows only one concurrent create", async () => { + const kv = createKv(new MockStore()); + const results = await Promise.all( + Array.from( + { length: 10 }, + (_, index) => kv.cas(["create-race"], undefined, index), + ), + ); + + equal(results.filter(Boolean).length, 1); + }); + + it("allows only one concurrent update from the same value", async () => { + const kv = createKv(new MockStore()); + await kv.set(["update-race"], "old"); + const results = await Promise.all( + Array.from( + { length: 10 }, + (_, index) => kv.cas(["update-race"], "old", index), + ), + ); + + equal(results.filter(Boolean).length, 1); + }); + + it("retries when the ETag changes but the value does not", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["retry"], "old"); + store.setCalls.length = 0; + store.beforeNextSet = () => { + store.entries.set(encodeKey(["retry"]), { + data: "old", + etag: "competing-etag", + metadata: { expireIn: null }, + }); + }; + + equal(await kv.cas(["retry"], "old", "new"), true); + equal(store.setCalls.length, 2); + equal(store.setCalls[1].options.onlyIfMatch, "competing-etag"); + }); + + it("does not delete a value changed by a concurrent writer", async () => { + const store = new MockStore(); + const kv = createKv(store); + await kv.set(["delete-conflict"], "old"); + store.setCalls.length = 0; + store.beforeNextSet = () => { + store.entries.set(encodeKey(["delete-conflict"]), { + data: "new", + etag: "competing-etag", + metadata: { expireIn: null }, + }); + }; + + equal(await kv.cas(["delete-conflict"], "old", undefined), false); + deepStrictEqual(await kv.get(["delete-conflict"]), "new"); + equal(store.setCalls.length, 1); + deepStrictEqual(store.setCalls[0].options.metadata, { tombstone: true }); + }); + + it("does not write when deleting a missing key", async () => { + const store = new MockStore(); + const kv = createKv(store); + + equal(await kv.cas(["missing-delete"], undefined, undefined), true); + equal(store.setCalls.length, 0); + }); + + it("rejects conditional writes when the ETag is missing", async () => { + const store = new MockStore(); + const kv = createKv(store); + store.entries.set(encodeKey(["missing-etag"]), { + data: "old", + metadata: {}, + }); + + await rejects( + kv.cas(["missing-etag"], "old", "new"), + new Error("Netlify Blobs did not return an ETag."), + ); + }); +}); diff --git a/packages/netlify/test/package.test.ts b/packages/netlify/test/package.test.ts index 005ca2b90..bef6d4132 100644 --- a/packages/netlify/test/package.test.ts +++ b/packages/netlify/test/package.test.ts @@ -1,6 +1,11 @@ +import { execFileSync } from "node:child_process"; import { createRequire } from "node:module"; import assert from "node:assert/strict"; import { describe, it } from "node:test"; +import process from "node:process"; +import { fileURLToPath } from "node:url"; + +const canRunTypeScript = !("Deno" in globalThis); describe("package exports", () => { it("loads the ESM distribution", async () => { @@ -15,4 +20,30 @@ describe("package exports", () => { assert.equal(typeof module.NetlifyMessageQueue, "function"); assert.equal(typeof module.createNetlifyQueueHandler, "function"); }); + + it("accepts the Netlify Blobs Store in the public types", { + skip: !canRunTypeScript, + timeout: 60_000, + }, () => { + const require = createRequire(import.meta.url); + const tsc = require.resolve("typescript/bin/tsc"); + const fixture = fileURLToPath( + new URL("../fixtures/public-types.ts", import.meta.url), + ); + + execFileSync(process.execPath, [ + tsc, + "--noEmit", + "--strict", + "--types", + "node", + "--module", + "NodeNext", + "--moduleResolution", + "NodeNext", + "--target", + "ESNext", + fixture, + ], { timeout: 55_000 }); + }); }); diff --git a/patches/@netlify__blobs@11.0.3.patch b/patches/@netlify__blobs@11.0.3.patch new file mode 100644 index 000000000..13368e30a --- /dev/null +++ b/patches/@netlify__blobs@11.0.3.patch @@ -0,0 +1,70 @@ +diff --git a/dist/server.cjs b/dist/server.cjs +index bb2212317ddd2eb8a258a22c32924dd416d42582..89b2e1aa8a7ab7518d6855f1149d45994ed981d8 100644 +--- a/dist/server.cjs ++++ b/dist/server.cjs +@@ -211,7 +211,8 @@ var BlobsServer = class _BlobsServer { + return this.listBlobs({ dataPath, metadataPath, rootPath, req, url }); + } + this.dispatchOnRequestEvent("get" /* GET */, url); +- const headers = {}; ++ const etag = await _BlobsServer.generateETag(dataPath); ++ const headers = { etag }; + try { + const rawData = await import_node_fs.promises.readFile(metadataPath, "utf8"); + const metadata = JSON.parse(rawData); +@@ -224,6 +225,9 @@ var BlobsServer = class _BlobsServer { + this.logDebug("Could not read metadata file:", error); + } + } ++ if (req.headers.get("if-none-match") === etag) { ++ return new Response(null, { headers, status: 304 }); ++ } + try { + const fileStream = (0, import_node_fs.createReadStream)(dataPath); + const chunks = []; +@@ -250,8 +254,10 @@ var BlobsServer = class _BlobsServer { + const rawData = await import_node_fs.promises.readFile(metadataPath, "utf8"); + const metadata = JSON.parse(rawData); + const encodedMetadata = encodeMetadata(metadata); ++ const etag = await _BlobsServer.generateETag(dataPath); + return new Response(null, { + headers: { ++ etag, + [METADATA_HEADER_INTERNAL]: encodedMetadata ?? "" + } + }); +diff --git a/dist/server.js b/dist/server.js +index 5c8a2b809f1d9b7ad32b8e00ba77b153bfa285de..c4e2f16648ff8d557b17bab236d76dfa63285c0b 100644 +--- a/dist/server.js ++++ b/dist/server.js +@@ -121,7 +121,8 @@ var BlobsServer = class _BlobsServer { + return this.listBlobs({ dataPath, metadataPath, rootPath, req, url }); + } + this.dispatchOnRequestEvent("get" /* GET */, url); +- const headers = {}; ++ const etag = await _BlobsServer.generateETag(dataPath); ++ const headers = { etag }; + try { + const rawData = await fs.readFile(metadataPath, "utf8"); + const metadata = JSON.parse(rawData); +@@ -134,6 +135,9 @@ var BlobsServer = class _BlobsServer { + this.logDebug("Could not read metadata file:", error); + } + } ++ if (req.headers.get("if-none-match") === etag) { ++ return new Response(null, { headers, status: 304 }); ++ } + try { + const fileStream = createReadStream(dataPath); + const chunks = []; +@@ -160,8 +164,10 @@ var BlobsServer = class _BlobsServer { + const rawData = await fs.readFile(metadataPath, "utf8"); + const metadata = JSON.parse(rawData); + const encodedMetadata = encodeMetadata(metadata); ++ const etag = await _BlobsServer.generateETag(dataPath); + return new Response(null, { + headers: { ++ etag, + [METADATA_HEADER_INTERNAL]: encodedMetadata ?? "" + } + }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be4f9f20c..7556b1d2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,9 @@ catalogs: '@netlify/async-workloads': specifier: ^0.0.106 version: 0.0.106 + '@netlify/blobs': + specifier: 11.0.3 + version: 11.0.3 '@netlify/database': specifier: ^1.1.0 version: 1.1.0 @@ -175,8 +178,8 @@ catalogs: specifier: ^3.22.3 version: 3.22.3 netlify-cli: - specifier: ^26.2.0 - version: 26.2.0 + specifier: ^27.4.2 + version: 27.5.1 next: specifier: '>=15.4.6 <17' version: 16.2.4 @@ -205,6 +208,11 @@ catalogs: specifier: ^10.1.0 version: 10.1.0 +patchedDependencies: + '@netlify/blobs@11.0.3': + hash: b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f + path: patches/@netlify__blobs@11.0.3.patch + importers: .: {} @@ -1650,19 +1658,22 @@ importers: '@netlify/async-workloads': specifier: 'catalog:' version: 0.0.106(@google-cloud/storage@5.20.5)(@trpc/server@11.18.0(typescript@6.0.3))(@types/react@19.1.8)(autoprefixer@10.5.0(postcss@8.5.19))(graphql@16.14.2)(postcss@8.5.19)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.2)(tailwindcss@4.1.12) + byte-encodings: + specifier: 'catalog:' + version: 1.0.11 + es-toolkit: + specifier: 'catalog:' + version: 1.46.1 temporal-polyfill: specifier: 'catalog:' version: 1.0.1 devDependencies: - '@fedify/postgres': - specifier: workspace:^ - version: link:../postgres '@js-temporal/polyfill': specifier: 'catalog:' version: 0.5.1 - '@netlify/database': + '@netlify/blobs': specifier: 'catalog:' - version: 1.1.0(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(postgres@3.4.7) + version: 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) '@standard-schema/spec': specifier: 'catalog:' version: 1.1.0 @@ -1671,10 +1682,7 @@ importers: version: 22.19.1 netlify-cli: specifier: 'catalog:' - version: 26.2.0(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(picomatch@4.0.5)(rollup@4.60.2) - postgres: - specifier: 'catalog:' - version: 3.4.7 + version: 27.5.1(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(picomatch@4.0.5)(rollup@4.60.2) tsdown: specifier: 'catalog:' version: 0.22.0(tsx@4.21.0)(typescript@6.0.3)(unrun@0.2.34(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)) @@ -3964,8 +3972,8 @@ packages: '@fastify/send@4.1.0': resolution: {integrity: sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==} - '@fastify/static@9.3.0': - resolution: {integrity: sha512-9YMYRpCOtMBrqKYWcqiw7ykOrn4D0jogHpJrFS0KGeSuOwzKMM5/mjj7B0CFLVoQ6htqKYw//Zs7APn9DBq05w==} + '@fastify/static@10.1.3': + resolution: {integrity: sha512-W6jqajYS974XjPjB5hQWoxPM8NKM4+p8YmQT6G5IbCa4uhdWSVadZUv75siy1wEA/3ty8RYdpBydfWeu9AqAqQ==} '@floating-ui/core@1.7.2': resolution: {integrity: sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==} @@ -5005,10 +5013,18 @@ packages: resolution: {integrity: sha512-PWHLAEKG16KCUE+O+je+aoXEUs/tUsXPoMcHfzYxFgJ4xczTIY97iaqu62cW9kf9KzZ27TV/t6gqTAX5NKO6ww==} engines: {node: '>=20.6.1'} + '@netlify/ai@1.0.1': + resolution: {integrity: sha512-jicymJwSK2/PPi0c3TjWRSp2h1Q/R+SrDd2NMY6bjckFYJJ6jyfToJj+gaypMycknSWI5LCgFwnJS209CMXtMw==} + engines: {node: '>=22.12.0'} + '@netlify/api@14.0.19': resolution: {integrity: sha512-oJ+7K+ioZ8sNoNzJbx+uIDmRynf5A+0ler2t9nHhhfwrrhx7mWgFaX5vGiEjvkpIxBAwfW8XyedhEdsm2OCK+w==} engines: {node: '>=18.14.0'} + '@netlify/api@15.1.2': + resolution: {integrity: sha512-mwDpddsem/KJw0CDAKUBnzKsM9UUfgUgRntvL3yyOZ+L12amaXmj38T/1ndnxmRIx1rIJtfbq4eEzxloaniylA==} + engines: {node: '>=22.12.0'} + '@netlify/async-workloads@0.0.106': resolution: {integrity: sha512-G5FBVc8qIHKgg3F4VGVBfd4IUHyIo6+0Ojx/f2RoAwsqgtMRmi3hPK597i4NxnOu67aCNzyXmibLkyqpcNiIoA==} hasBin: true @@ -5027,6 +5043,10 @@ packages: resolution: {integrity: sha512-NEM8aNAMZCCWBWymomMM/fn5wmPGyGE8pendgsSu5mL7UNz+aXqGcHS0MiHWU/osyg+geiZuS+Rx956SVrMM/w==} engines: {node: ^14.16.0 || >=16.0.0} + '@netlify/blobs@11.0.3': + resolution: {integrity: sha512-Z8IXQtQC8BQjm76i1bN+l12TTyKQ/s1R92Ajhou7+fpP0KSxnJ65QzLEb5WuFuFutn8ORrcd4mlF8A2xhw8dzA==} + engines: {node: '>=22.12.0'} + '@netlify/blobs@8.2.0': resolution: {integrity: sha512-9djLZHBKsoKk8XCgwWSEPK9QnT8qqxEQGuYh48gFIcNLvpBKkLnHbDZuyUxmNemCfDz7h0HnMXgSPnnUVgARhg==} engines: {node: ^14.16.0 || >=16.0.0} @@ -5039,35 +5059,44 @@ packages: resolution: {integrity: sha512-RR3t5fv7CkGVJiylOTLf/YaHPyrcWmhHW3zX3EK/9UQsnTi8jPxP7B2nyjgRjAx5S4YTzJQP+FmbQlGKdogALQ==} engines: {node: ^14.16.0 || >=16.0.0} - '@netlify/build-info@10.5.1': - resolution: {integrity: sha512-AQqI6S7bMazA/wYnsuE8Lp95ldeKO5RsYvQEboKAjGV2NiwDqw44Z1n7cKj8OALdp8coTvIKLcbAounx6ERbiA==} - engines: {node: '>=18.14.0'} + '@netlify/build-info@11.3.0': + resolution: {integrity: sha512-xhoPqbfTSroUtFElUR6Wsw0+XlSihtLxvuaNQKv5+JTkvNqpBNIVPdo9drqwhh1eqlUeHJszfCGc1P6950yL0w==} + engines: {node: '>=22.12.0'} hasBin: true - '@netlify/build@35.15.0': - resolution: {integrity: sha512-Ig/EiLjLn3tKJ6+YobKwdOQtpnrpJobB+BZpZBOeeFJq4GX3452709VDaqnGb5X5nDrRcrqabHUglZ72FgdQFw==} - engines: {node: '>=18.14.0'} + '@netlify/build@36.4.7': + resolution: {integrity: sha512-6pBATJQP4S5Qv2USPxtRE5x79bsgrI6qbVvyJ8WGEFsGoZHvWe+88wp/moWbvpMymeP0XVDuKCM/RTDiQU/8bQ==} + engines: {node: '>=22.12.0'} hasBin: true peerDependencies: - '@netlify/opentelemetry-sdk-setup': ^2.0.0 + '@netlify/opentelemetry-sdk-setup': ^2.0.0 || ^3.0.0 '@opentelemetry/api': ~1.8.0 peerDependenciesMeta: '@netlify/opentelemetry-sdk-setup': optional: true - '@netlify/cache-utils@6.0.5': - resolution: {integrity: sha512-MZmTLVR+KabjCFOvSGZj2ZbGPCutqKVWuyAihJHQ8f8BGGOzu6vzuBmXf6L5nT1d2u8ZifjDXrHhCH4SNxdb1g==} - engines: {node: '>=18.14.0'} + '@netlify/cache-utils@7.1.2': + resolution: {integrity: sha512-QlBvQfBTbr+ti4MQcO7PUuA+moeQ93Gs1W5eFS7cnEMGv1kQjO3n6rZGGPqWO8Vol0gRXJJGUEnPxC20+KR8vA==} + engines: {node: '>=22.12.0'} '@netlify/cache@3.4.8': resolution: {integrity: sha512-20zPmLS8x2VXSNQHwxj1+jJgKAec/EoeKJahIgPmTolXq2X6nEdyulHTTHHA4KzxqGTkrzTcfNzZjEkjvRyj9Q==} engines: {node: '>=20.6.1'} + '@netlify/cache@4.0.0': + resolution: {integrity: sha512-tRWkLmO6pyqZetFkhYgtX6LH1umqaJAZN5mRNOJubca/+Mqm0VTUyl51FeS0UbVfetLwiwgpzbGmABpc5gGHyg==} + engines: {node: '>=22.12.0'} + '@netlify/config@24.6.0': resolution: {integrity: sha512-bR2FhZiWFz+EIQBl/T9p9lRNBuInYqWtqtGQywwM1dkvNI2ViSQBmeEDY/qXh9EECB8g2f7ZBC2sF4KeNGtX0w==} engines: {node: '>=18.14.0'} hasBin: true + '@netlify/config@25.2.4': + resolution: {integrity: sha512-8sAA1Ql+Vi9YYU3tDVOaV3k2KwTkcFtqYFgqYtRmidrKiNIh40PwuumHpenaNUQPxni4Xzhq89ryORJRJAc7nA==} + engines: {node: '>=22.12.0'} + hasBin: true + '@netlify/content-engine-graphiql-explorer@0.0.4': resolution: {integrity: sha512-FsCo+Q2oIh+kwl4Z43GIsJ1HhlHDvgeBKhlBE8Zb7BrdKNtq6gTDetsQy2O7IvWMJdx7W1Ltuxsgz7U60IOLCQ==} engines: {node: '>=16.0.0'} @@ -5090,6 +5119,10 @@ packages: resolution: {integrity: sha512-kHLdS6r45TsDiS5aBrHUmzqPvoaWQEUZnaZeMwnIrLMwX8f2bIa6YAMOJJYJhyKm2drVo3C/T92/lJ5iGV/VBQ==} engines: {node: '>=20.6.1'} + '@netlify/database-dev@1.0.1': + resolution: {integrity: sha512-Zu8cM4AeXNuQI/cNAI6vrammtdDnWIGO6PYKDAECDMzsb3IcoTsVOZAePup7cGdjaGcBBVdi1qx/PoI5hNZcxg==} + engines: {node: '>=22.12.0'} + '@netlify/database@1.1.0': resolution: {integrity: sha512-Y36JMyQfxwHxvtFzF8K+2PyooGFQXzPNINw/guujQfMujfAwUTwv7f6XiSL3c5orNy8YZTqVVWVjkbFarhDRjw==} engines: {node: '>=20.6.1'} @@ -5110,47 +5143,59 @@ packages: resolution: {integrity: sha512-P6X+xS3glvhiTX6AAocYvnZtqXtWhvxMX4AdPgv2iw6cXjGL2criUveX7bSjp6DiyHfvQpNdG0ZRpeBEVAFf1g==} engines: {node: ^18.14.0 || >=20} + '@netlify/dev-utils@6.0.1': + resolution: {integrity: sha512-q5g70dO3q/M/XTBQz7uIECJxVlJoS8UBlzpjf22DV6q61UzXa8EONTPXPmvisrFcUi1I3AUKplPcHGQYZZj+Vw==} + engines: {node: '>=22.12.0'} + '@netlify/dev@4.18.7': resolution: {integrity: sha512-BeXz9dis2Iid5EcOItVj2srdC30R4RwDhsk/N/h+T2WYrJbyhOj6b1IS+6fVGe5JbKe9fDiGANH1cujplX1+rw==} engines: {node: '>=20.6.1'} - '@netlify/dev@4.18.9': - resolution: {integrity: sha512-cHXktcJQuVHGukRhMkdfYvN8/bsvkILh5wEKeVRmmlML6oCZnxnii9mcNjhQbQ5NotsbW6/NShuuEH3caufG6Q==} - engines: {node: '>=20.6.1'} + '@netlify/dev@5.0.5': + resolution: {integrity: sha512-/u9rKpfO86udlbRdWi3Gkox/plWd1uoGSqRBB9qZUARKBg3KvNpPkQA49YvEsrDH0GVHMhCbyrsREwVrxdtJmQ==} + engines: {node: '>=22.12.0'} '@netlify/edge-bundler@14.10.3': resolution: {integrity: sha512-o+ww3ZUsdkdDEdeIhX6yT4wCNt99ar3JUreQowgXPCAyQeiXWf2i3xkoVwm5bQb77BhFmTTMp0kIeRMiGEqU4g==} engines: {node: '>=18.14.0'} + '@netlify/edge-bundler@16.0.4': + resolution: {integrity: sha512-J7joSRuOIwg7bSMQBc+zq7Lb3p6gwsLMU/NYSFbXNIZtk6gSQnY3ZwnAncEhRqvN8lKsKx+27bn+4B2+B0N8ag==} + engines: {node: '>=22.12.0'} + '@netlify/edge-functions-bootstrap@2.16.0': resolution: {integrity: sha512-v8QQihSbBHj3JxtJsHoepXALpNumD9M7egHoc8z62FYl5it34dWczkaJoFFopEyhiBVKi4K/n0ZYpdzwfujd6g==} - '@netlify/edge-functions-bootstrap@2.17.1': - resolution: {integrity: sha512-KyNJbDhK1rC5wEeI7bXPgfl8QvADMHqNy2nwNJG60EHVRXTF0zxFnOpt/p0m2C512gcMXRrKZxaOZQ032RHVbw==} + '@netlify/edge-functions-bootstrap@3.2.0': + resolution: {integrity: sha512-j1xNt9DLG3l2m5lfkJfF1cTmof9sLp9v60kvB8+PORTqg4ngzCmfA4dxJHAibGbcjOT8kECG4oxmcEfET7FFag==} '@netlify/edge-functions-dev@1.0.20': resolution: {integrity: sha512-bk05M+nuafsc4JjYEhwTKI8kpnK7EPOf6sreUbdNCi+17JUNvl6D959Hxheq0Ke2nT5UPqIcJRuNvjvI+ocT+Q==} engines: {node: '>=20.6.1'} - '@netlify/edge-functions-dev@1.0.22': - resolution: {integrity: sha512-FmN7aikLn1fs+GUpcxgyM+MgEhwRfwz6XoGF+pAjDMO27eA3Vt8IeV/gx/hZfCeehMFHev4X2vENC1WXlmtKhQ==} - engines: {node: '>=20.6.1'} + '@netlify/edge-functions-dev@2.0.1': + resolution: {integrity: sha512-IIIBoBhbqoOeOQLEfYLmW55IHOAxXc9athsUH7ZHKUUs3agi7ehVaZYZwhkQxB+l/K9/vRYHUnAZD715auIDpA==} + engines: {node: '>=22.12.0'} '@netlify/edge-functions@3.0.8': resolution: {integrity: sha512-ml1oCDsRTTRmZS2nUj8XRD1b6+foEiZT3lPk7qQ4nv/jnxylHJ20ooPzPDH+cJmGjXFrMeR14/91W1o6D2ftBg==} engines: {node: '>=18.0.0'} + '@netlify/edge-functions@4.0.0': + resolution: {integrity: sha512-0jerPQQ5mLczl7jwCRfTJsLcaiXbvPOC+Whtxxk7IHdz24OvZGjUtVHAxhppjT8wcX48I7C6oAff04QdQDMTfw==} + engines: {node: '>=22.12.0'} + '@netlify/functions-dev@1.3.0': resolution: {integrity: sha512-3CMb4GDuh8vzc2F7bUFw73QtCA+TEfcS9RQ6Z8Zkz4oAdTLN8W/73QeY50eWslWqkA2cUj87OLEYaTnC4Rj8EA==} engines: {node: '>=20.6.1'} - '@netlify/functions-dev@1.3.1': - resolution: {integrity: sha512-zoJ/Q1ODjQLMQN2zvtPpDBqLUjE0gRCahQcj9w+IJ/5k9ys9bK0hb5a7ar/LjUsXWA5o9bNqHbJFy3a4RgDl6Q==} - engines: {node: '>=20.6.1'} + '@netlify/functions-dev@2.0.5': + resolution: {integrity: sha512-SSlmwe5GMfQmTDPbHfVTPe4h6lI3kbcepRxT2CKN30L9gx0NmwTGoMgns36DV64fHvabT5gNzzRxOx5sxYgzNg==} + engines: {node: '>=22.12.0'} - '@netlify/functions-utils@6.2.35': - resolution: {integrity: sha512-PvJljLaZt1Tq3hwNmddnmN51J6w8v77iOdKwQaMA9jyINno8y6PP+uabb0kvAGO+KQ9r380IuUFPiHVv3VgKzw==} - engines: {node: '>=18.14.0'} + '@netlify/functions-utils@7.1.9': + resolution: {integrity: sha512-W3ainnUjWRMmBHRHuJ/7r8+C1mrPUgtDvED1QCFTEvDDOH6+usruxSLdQFVi0d12YkLqk7zLqRIhBnpSRtuQaw==} + engines: {node: '>=22.12.0'} '@netlify/functions@1.6.0': resolution: {integrity: sha512-6G92AlcpFrQG72XU8YH8pg94eDnq7+Q0YJhb8x4qNpdGsvuzvrfHWBmqFGp/Yshmv4wex9lpsTRZOocdrA2erQ==} @@ -5172,9 +5217,17 @@ packages: resolution: {integrity: sha512-FP+xCoZMkMOUsKa4UdG/oiK/2md1/TxuXvqqieaMVMgDbFFMaHI8h0oHCViUY73kPbKV6HyzayaSXGYXKpBSoQ==} engines: {node: '>=18.0.0'} - '@netlify/git-utils@6.0.4': - resolution: {integrity: sha512-yp5WucNt1PGV+qG9Bq/qXPHZyl375s2AfB7bdoCFi7VeHZzCJ4bZJB9OpWf8lwNKqzkc2njYygNo5kwKavzY/w==} - engines: {node: '>=18.14.0'} + '@netlify/functions@6.0.0': + resolution: {integrity: sha512-Pee+FoFnAtdejTkl62a7mZxj6Wx4eqVNuYyDc5T4XPJN9GaAWaUf4cZQFlf2m4Fqq0HoghjtcPKo+BZviVPPKA==} + engines: {node: '>=22.12.0'} + + '@netlify/git-utils@7.1.1': + resolution: {integrity: sha512-zo5Ej+aUYOINJMBrCT9Vb0ZoqN29U0QLfoa07B83p0DSKcLp75XO3vh9zAydTjygud5DcLuH83uoxYlTNNOuBQ==} + engines: {node: '>=22.12.0'} + + '@netlify/headers-parser@10.1.1': + resolution: {integrity: sha512-ooiSc/eN/ktuugZmY4GVPh6nBYz2um0zpemokDvTLLQPF12QyXil8N6fr82wdLi03WNowwiL98eultZkTyHlyw==} + engines: {node: '>=22.12.0'} '@netlify/headers-parser@9.0.3': resolution: {integrity: sha512-KNzC9RaKDwJVS44iTK6JxNA6LeXH0PUw0pLktWpmMVI/0FR98bvxaHcAisjHqbThAjxL9QjL1UZh0KzHCkxpNQ==} @@ -5184,10 +5237,18 @@ packages: resolution: {integrity: sha512-pWqoovsTBKlSfM7HKT0KnZ3x5ael2P+smiAogH5zuGU+ncQA7zBRHwLDi3nBy4iBM1MQAZ9BEjAXE42/yn/GQg==} engines: {node: '>=20.6.1'} + '@netlify/headers@3.0.1': + resolution: {integrity: sha512-LcEu16gy28dkEp2+pa5EafauTfmFl6hkwiPqmoMBY+GiLLWQC00X8L4O1ZUrPqbKynsraSqEeKEfocC2FktrEQ==} + engines: {node: '>=22.12.0'} + '@netlify/images@1.3.10': resolution: {integrity: sha512-3ZlN8PNBaZFNr+uERzOtb9rQkb23xxS4k4iW188mgvSrMhxdVXPS5pkpOxAHPEunatSlT/a6oCuy3fsltrtr6A==} engines: {node: '>=20.6.1'} + '@netlify/images@2.0.1': + resolution: {integrity: sha512-47DzR/PqIJqbUIef6P7EmhbNQbUOD4IuGNhTG7h3+xcynhQdBLBkCaBwY2DXOzUloA1MxYhKGYV2z4R3pO36hg==} + engines: {node: '>=22.12.0'} + '@netlify/integrations@0.6.0': resolution: {integrity: sha512-UYXhr6gArBppzbPINkd1gvRF7G6htbT04c05zGnfAEpc43pL5SNQIVHh7/KPuiic07xjSKAGUAezMz2QLenndg==} engines: {node: ^14.16.0 || >=16.0.0} @@ -5282,9 +5343,9 @@ packages: resolution: {integrity: sha512-hgJrSxfzr7ShaVACGr17Ci3a7Y7vO+a75Fwn9fNe2+1aIbVx4aVSLP3cv9Vv9yfy1JbW563AwcveBq9lr9KKzA==} engines: {node: '>=14.8.0'} - '@netlify/opentelemetry-utils@2.0.2': - resolution: {integrity: sha512-ZnSw1AV/7kBWOwwXjobcd/LXhy576qrnla0PnKs/U4zBa5R3X9YNnFq29251l/nJ8GmnBzJI7dt9dfTfn8Z80w==} - engines: {node: '>=18.14.0'} + '@netlify/opentelemetry-utils@3.1.0': + resolution: {integrity: sha512-mrud7UuxcvABKKvw1ZF8Y04oFvjkjZV7JCKe8ZxoMBi96dIUFCptGPeJuX1RBVP1w7VLOFhtVKZjNGW/8vmcWA==} + engines: {node: '>=22.12.0'} peerDependencies: '@opentelemetry/api': ~1.8.0 @@ -5292,6 +5353,10 @@ packages: resolution: {integrity: sha512-NIjIjB/aItiXKB6+wzSwfSyYqbNsVSzzlEPryxxTC5ZJiYSYSm82wAOcQ+9VdiufQyZO5t8jzHVPULo7a9L9sQ==} engines: {node: ^18.14.0 || >=20.6.1} + '@netlify/otel@7.0.2': + resolution: {integrity: sha512-MHEsRJTZtOCrLa2fR+Y3GN51rvgxUHazuRVxuWuG7R1qzwynXAZB20Ufwp7BxKSTKcp7LNVEnKAZ/k2ytVmYvQ==} + engines: {node: '>=22.12.0'} + '@netlify/plugins-list@6.81.8': resolution: {integrity: sha512-ur/f3aO+TaBI1OQEmWnHcYaenizj0hAgoB1n3Pff+S1dddqSwwFmw5Z7MWaXqvaRrkVUyxiRT5IgeKdt4CW7Hg==} engines: {node: ^14.14.0 || >=16.0.0} @@ -5300,13 +5365,21 @@ packages: resolution: {integrity: sha512-UYHRCO4HZI6WMpf8RheaCWnGafeJeFTsp/5yK887fyGqohDmFbc26NuFUvRl7J6sNu+di/1lLmRXP+yJ1X9TDA==} engines: {node: '>=18.14.0'} + '@netlify/redirect-parser@16.1.1': + resolution: {integrity: sha512-2Wg2em5rUi9EXKz5z4MAUb2Pfoyxm+jJpERYyIuYOwm6pfQHQCBjOD+HoW2CzDS859c0FlxNdnxq50bkfdKiLA==} + engines: {node: '>=22.12.0'} + '@netlify/redirects@3.1.13': resolution: {integrity: sha512-28M4pyahGHf5kIqhdA6Y687g/QBmW0clPHmh/xGvxmwHIW+fN5aMzCO4JrM2v9bA/yDFoGjSQynckAG1MGr0/g==} engines: {node: '>=20.6.1'} - '@netlify/run-utils@6.0.3': - resolution: {integrity: sha512-ooXXGQKtTJEYxCgwcwpr3a/cHYv+oIuKgswzAMCTOnE/lm4DU9+kz42vMXA+hXoMJFS6kSnuKsSIL9GePaJ0gQ==} - engines: {node: '>=18.14.0'} + '@netlify/redirects@4.0.2': + resolution: {integrity: sha512-4Qpz6FpwrLITrScg34zjK9Iv0BiyyPVAGO7HvUZg0txihHPgKBRtLMByEwfP6mhuzTExoxMXYklqgHg2xtbPxA==} + engines: {node: '>=22.12.0'} + + '@netlify/run-utils@7.1.0': + resolution: {integrity: sha512-rw23CsFVxZ3Q0F/7jGGfOL87fhfuPKbS7EMYO+7q7W1xZDW/Z5T+JsOGTiue3Pa7tEIzTPiIMTERZp3aV6I+tg==} + engines: {node: '>=22.12.0'} '@netlify/runtime-utils@1.3.1': resolution: {integrity: sha512-7/vIJlMYrPJPlEW84V2yeRuG3QBu66dmlv9neTmZ5nXzwylhBEOhy11ai+34A8mHCSZI4mKns25w3HM9kaDdJg==} @@ -5324,10 +5397,18 @@ packages: resolution: {integrity: sha512-cW8weDvsKV7zfia2m5EcBy6KILGoPD+eYZ3qWNGnIo05DGF28goPES0xKSDkNYgAF/2rRSIhie2qcBhbGVgSRg==} engines: {node: ^18.14.0 || >=20} + '@netlify/runtime-utils@3.0.0': + resolution: {integrity: sha512-OHo40+V3QZkR+UrDjqhN+LekrAby/dSSJxsvyYs9i88E/mSl3goB/ysoL+VYROm190egxmQyRYlHK7vL4GeHBQ==} + engines: {node: '>=22.12.0'} + '@netlify/runtime@4.1.25': resolution: {integrity: sha512-+RKE+oaygMDyp1ybcseQRT/OMVkiNOgUDfM0Q4+Nwl+vMGCZavmHKIAkGWRWlduw8UUcA094xSoHNcLQWCFgjg==} engines: {node: '>=20.6.1'} + '@netlify/runtime@5.0.3': + resolution: {integrity: sha512-MGoAWvFDuD0BbpIo8pwYPxxWsfMGBiiI4HetQOMkrx7ytnEZjq/qKKfzNCQKJg0Ed86XdQefKToVcP10wc38IQ==} + engines: {node: '>=22.12.0'} + '@netlify/sdk--extension-api-client@0.1.1': resolution: {integrity: sha512-gl4K9VJg0+MLBZCAjfKvySXs1Dv5l/Y5YEXsFQZIJIgHKCmPiNOEz8SLzF7YgRNqlgIapjcBu52kif82J5HUpA==} @@ -5398,10 +5479,18 @@ packages: resolution: {integrity: sha512-THDZja3NJgvQeyd8o5KYiNzwGAvE4n7o20wF9COfANxDZ03qd5lGjwNySeojapSGky5+OBwDdfk5X5tO144nwg==} engines: {node: '>=18.0.0'} + '@netlify/serverless-functions-api@2.18.0': + resolution: {integrity: sha512-Uo5XyMFZOinq6AonHu6dUOkLvVydn+SaldoVkB4yQSpDrtqYWi56CoA26IIOur1EMJqRdt6JIzjzIe4jpzYdhQ==} + engines: {node: '>=18.0.0'} + '@netlify/static@3.1.10': resolution: {integrity: sha512-DOEVJ8SawvQ/ddWCSzfjqsQOE4GfF+LvxhWuB1OHSFvWnDEyBpobrLO6YWUG3lKq+0OhPBu50XFtKfdQNpUiFA==} engines: {node: '>=20.6.1'} + '@netlify/static@4.0.0': + resolution: {integrity: sha512-YJcyaByknJ/JMmcqUFb9XId2NLgZitJlQC2FGP1a6mqndiMzAd9qoKtHxNRHX4NefI49+UABGtKF4UkL5rM8tw==} + engines: {node: '>=22.12.0'} + '@netlify/tailwind-config@2.1.0': resolution: {integrity: sha512-szc+wQjsG7NqWasjEzUe8+OKv/1w6FOEFkMAwTD7+JC6UuVFReop+dhoFERWUrm6xEKl5ug/dVjWiPTsu9A0Ng==} @@ -5413,6 +5502,10 @@ packages: resolution: {integrity: sha512-8/g0Pt6y6wXj5Ia5eeYLiXhRfWeqZXGXpGFeCiiQdUOem+FPtXdA4+YdGxqzWc7D0AvptKSO01KGeeVWHSu8Kg==} engines: {node: ^18.14.0 || >=20} + '@netlify/types@3.0.0': + resolution: {integrity: sha512-zRCidsQgI4CZWrZB/kmwdPf0QbSNljakfNSLizFvrsSA3UcUrTWSBNMVKmZnob92/8ESeUN0ewXLOlffJU+ATQ==} + engines: {node: '>=22.12.0'} + '@netlify/ui@0.0.23': resolution: {integrity: sha512-QqLcs02GwetH78YOdtDpUys3fq9sykmgbJJMuI2xWzxEGhqxrTrRwE64kFNtzKsklqB2mfvVHbVafipzPkH1Ug==} peerDependencies: @@ -5434,6 +5527,11 @@ packages: engines: {node: '>=18.14.0'} hasBin: true + '@netlify/zip-it-and-ship-it@15.5.1': + resolution: {integrity: sha512-ECHwLIHkSgfkxqF+q40xLMTTSxir1/pDGK6d55oKvwKidrW4qyTyHCAkuKtjOTJ30A+E238X2iiRyI+SCDjTuA==} + engines: {node: '>=22.12.0'} + hasBin: true + '@next/env@14.2.30': resolution: {integrity: sha512-KBiBKrDY6kxTQWGzKjQB7QirL3PiiOkV7KW98leHFjtVRKtft76Ra5qSA/SL75xT44dp6hOcqiiJ6iievLOYug==} @@ -5804,6 +5902,10 @@ packages: resolution: {integrity: sha512-Cdq0jW2lknrNfrAm92MyEAvpe2cRsKjdnQLHUL6xRA4IVUnsWx6P65E7NcUO0Y+L4w1Aee5iV8FvjSwd+lrs9A==} engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.221.0': + resolution: {integrity: sha512-OlanaW1vv7ufTqQ3/fPLI4arGt5ZoM+P8abOMki6uEYnpRazepSWDwDnnw+la7kE26SHVC18//SMccrDvLKOXQ==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.53.0': resolution: {integrity: sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw==} engines: {node: '>=14'} @@ -5816,6 +5918,10 @@ packages: resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==} engines: {node: '>=14'} + '@opentelemetry/api@1.8.0': + resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} @@ -5836,6 +5942,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/context-async-hooks@2.10.0': + resolution: {integrity: sha512-bvyMcgLEkozzSzpEEEo1OMoeQ97bxj6Qs2uN3mPrSdDvObMI1myffD/BPqcLlzZO9//d1SqQA/WPw7Cz2AiqhA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/context-async-hooks@2.5.0': resolution: {integrity: sha512-uOXpVX0ZjO7heSVjhheW2XEPrhQAWr2BScDPoZ9UDycl5iuHG+Usyc3AIfG6kZeC1GyLpMInpQ6X5+9n69yOFw==} engines: {node: ^18.19.0 || >=20.6.0} @@ -5854,6 +5966,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@2.10.0': + resolution: {integrity: sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@2.5.0': resolution: {integrity: sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6088,6 +6206,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation@0.221.0': + resolution: {integrity: sha512-cCk80Z/iRDf/5gfsKMB4f74LqVA5yKETB/9ojPzVW/6/f70iu89nJvGxsFCxx4XfSohaOofkU19kiYm84AiAlw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation@0.53.0': resolution: {integrity: sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A==} engines: {node: '>=14'} @@ -6146,6 +6270,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/resources@2.10.0': + resolution: {integrity: sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/resources@2.5.0': resolution: {integrity: sha512-F8W52ApePshpoSrfsSk1H2yJn9aKjCrbpQF1M9Qii0GHzbfVeFUB+rc3X4aggyZD8x9Gu3Slua+s6krmq6Dt8g==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6188,6 +6318,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/sdk-trace-base@2.10.0': + resolution: {integrity: sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-trace-base@2.5.0': resolution: {integrity: sha512-VzRf8LzotASEyNDUxTdaJ9IRJ1/h692WyArDBInf5puLCjxbICD6XkHgpuudis56EndyS7LYFmtTMny6UABNdQ==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6200,6 +6336,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-trace-node@2.10.0': + resolution: {integrity: sha512-GZK/G6oZyBLGlH1pUgeDch7D91KoHd2uotUGIkWCPi9GI5T9X0p4L7nNAMDR1BQjkRYoDqo+ddfVx9t5Uhys+Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/sdk-trace-node@2.5.0': resolution: {integrity: sha512-O6N/ejzburFm2C84aKNrwJVPpt6HSTSq8T0ZUMq3xT2XmqT4cwxUItcL5UWGThYuq8RTcbH8u1sfj6dmRci0Ow==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6212,6 +6354,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/sdk-trace@2.10.0': + resolution: {integrity: sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/semantic-conventions@1.27.0': resolution: {integrity: sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==} engines: {node: '>=14'} @@ -7579,10 +7727,6 @@ packages: resolution: {integrity: sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ==} engines: {node: '>=18'} - '@sindresorhus/merge-streams@2.3.0': - resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} - engines: {node: '>=18'} - '@sindresorhus/merge-streams@4.0.0': resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} @@ -7653,6 +7797,11 @@ packages: peerDependencies: acorn: ^8.9.0 + '@sveltejs/acorn-typescript@1.0.13': + resolution: {integrity: sha512-wgKggnhZVL9Bfx1OaKKTrYY9BFRk6C8UAkQNUcIv1+llzYrIqy+RZm5HPKzn0NpEBvTVhTqB4kQyllZywsRBRQ==} + peerDependencies: + acorn: ^8.9.0 + '@sveltejs/acorn-typescript@1.0.5': resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==} peerDependencies: @@ -8755,6 +8904,11 @@ packages: engines: {node: '>=18'} hasBin: true + '@vercel/nft@1.3.1': + resolution: {integrity: sha512-ihNT1rswiq3cy4WKQAV5kJi6UjWX1vLUzlLc+Vvq83G8CU9nMgfDWz5f1tOnSlS8LeC4Wp4qTB3+HGj/ccUrFQ==} + engines: {node: '>=20'} + hasBin: true + '@vercel/nft@1.5.0': resolution: {integrity: sha512-IWTDeIoWhQ7ZtRO/JRKH+jhmeQvZYhtGPmzw/QGDY+wDCQqfm25P9yIdoAFagu4fWsK4IwZXDFIjrmp5rRm/sA==} engines: {node: '>=20'} @@ -9006,6 +9160,10 @@ packages: resolution: {integrity: sha512-kMwLlxUbduttIgaPdSkmEarFpP+mSY8FEm+QWMBRJwxOHWkri+cxd8KZHO9EMrB9vgUuz+5WEaCawaL5wGVoXg==} engines: {node: '>=18.0.0'} + '@whatwg-node/server@0.11.0': + resolution: {integrity: sha512-VSdkwnJRr8Yv9UgB2aXB3VUPWwd6Oqnn0hycFwhg9pZgWxJXb7JmhsiXe9tmpMwjHFxli12PGcz9aI63YYloGQ==} + engines: {node: '>=18.0.0'} + '@whatwg-node/server@0.9.71': resolution: {integrity: sha512-ueFCcIPaMgtuYDS9u0qlUoEvj6GiSsKrwnOLPp9SshqjtcRaR1IEHRjoReq3sXNydsF5i0ZnmuYgXq9dV53t0g==} engines: {node: '>=18.0.0'} @@ -9214,6 +9372,10 @@ packages: resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} engines: {node: '>= 14'} + archiver@8.0.0: + resolution: {integrity: sha512-fV1orZfsnPn9BaSByR/qE67rJCLJEy2Ox5bq7nJh+jquWaNh6Sfec75kJ2T6PtdGUbPQlrVoSVCEOa5SdiTQ1g==} + engines: {node: '>=18'} + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -9760,6 +9922,10 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chalk@6.0.0: + resolution: {integrity: sha512-2uNTXIuTTxk7ciZgAU1BQcgnchcG0xXnrs6jzkQfj9SsRa9M2s5zE8WT96hS6KmG4MzWHSrvH43DF1m4XRkrFg==} + engines: {node: '>=22'} + chance@1.1.13: resolution: {integrity: sha512-V6lQCljcLznE7tUYUM9EOAnnKXbctE6j/rdQkYOHIWbfGQbrzTsAXNW9CdU5XCo4ArXQCj/rb6HgxPlmGJcaUg==} @@ -9835,10 +10001,6 @@ packages: resolution: {integrity: sha512-Lo78NV5ItJL/jl+B5w0BycAisaieJGXK1qYi/9m4SjR8zbqmrUtO7Yhro40wEShGmmxs/aJLI/A+jNhdkXK8mw==} engines: {node: '>=4'} - clean-stack@5.3.0: - resolution: {integrity: sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==} - engines: {node: '>=14.16'} - cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} @@ -9989,8 +10151,8 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - comment-json@4.6.2: - resolution: {integrity: sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==} + comment-json@5.0.0: + resolution: {integrity: sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==} engines: {node: '>= 6'} common-ancestor-path@2.0.0: @@ -10014,6 +10176,10 @@ packages: resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} engines: {node: '>= 14'} + compress-commons@7.0.1: + resolution: {integrity: sha512-g0S8KAD8qf4+V//pr3BfB1aBnARLXNz2Gx+jmHU0LEriUuoQUOPOulVquHKTJ8+EAIIO7fhseNDr9wK5Q9FKBQ==} + engines: {node: '>=18'} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -10061,6 +10227,10 @@ packages: resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} + content-disposition@2.0.1: + resolution: {integrity: sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==} + engines: {node: '>=18'} + content-engine-graphiql-explorer@0.0.1: resolution: {integrity: sha512-ZeWPqWrwkap3VyyYGRyNLiIzslgNAgDVd1LTX5Jv3IxpL3FPaJhV05/8LK7ONdp9LJpWWhnmdQOU8iq9NKurXA==} engines: {node: '>=16.0.0'} @@ -10143,6 +10313,10 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + cookie@2.0.1: + resolution: {integrity: sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==} + engines: {node: '>=22'} + cookies@0.9.1: resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} engines: {node: '>= 0.8'} @@ -10168,10 +10342,6 @@ packages: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} - cpy@11.1.0: - resolution: {integrity: sha512-QGHetPSSuprVs+lJmMDcivvrBwTKASzXQ5qxFvRC2RFESjjod71bDvFvhxTjDgkNjrrb72AI6JPjfYwxrIy33A==} - engines: {node: '>=18'} - crc-32@1.2.2: resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} engines: {node: '>=0.8'} @@ -10181,6 +10351,10 @@ packages: resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} engines: {node: '>= 14'} + crc32-stream@7.0.1: + resolution: {integrity: sha512-IBWsY8xznyQrcHn8h4bC8/4ErNke5elzgG8GcqF4RFPw6aHkWWRc7Tgw6upjaTX/CT/yQgqYENkxYsTYN+hW2g==} + engines: {node: '>=18'} + create-error-class@3.0.2: resolution: {integrity: sha512-gYTKKexFO3kh200H1Nit76sRwRtOY32vQd3jpAQKpLtZqyNsSQNfI4N7o3eP2wUjV35pTWKRYqFUDBvUha/Pkw==} engines: {node: '>=0.10.0'} @@ -10192,6 +10366,10 @@ packages: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} + cron-parser@5.10.0: + resolution: {integrity: sha512-izNAxJyRWUP8ljBoDSub5WyrVOUlT4SLGShswE7eoRBpp6QUsSycYxLBMJlbshgPBMcPT/nrfgjNY2918ayv2A==} + engines: {node: '>=18'} + croner@10.0.1: resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==} engines: {node: '>=18.0'} @@ -11577,9 +11755,15 @@ packages: fast-string-truncated-width@1.2.1: resolution: {integrity: sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow==} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + fast-string-width@1.1.0: resolution: {integrity: sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==} + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + fast-stringify@4.0.1: resolution: {integrity: sha512-Cpr1Vsu/L/PyXL24thmEnAWauHhXzvBdbRzoD3YmxhDBTXLtYpo49Cpn6w+darUXz6g8qsPNLnVYOWkOq6QIng==} @@ -12058,10 +12242,6 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - globby@14.1.0: - resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} - engines: {node: '>=18'} - globby@16.2.0: resolution: {integrity: sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==} engines: {node: '>=20'} @@ -13314,6 +13494,9 @@ packages: resolution: {integrity: sha512-XT9ewWAC43tiAV7xDAPflMkG0qOPn2QjHqlgX8FOqmWa/rxnyYDulF9T0F7tRy1u+TVTmK/M//6VIOye+2zDXg==} engines: {node: '>=20'} + lockparse@0.5.2: + resolution: {integrity: sha512-iu19W86kvrT2MLpvyXoIn/351Rb3PO7v7ljgFRQYj8tGpBRvNO9cZEI8x/7GGN+WN6BbrWpXc5CPrgPUjgX6Iw==} + lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} @@ -13458,9 +13641,9 @@ packages: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} - log-update@7.2.0: - resolution: {integrity: sha512-iLs7dGSyjZiUgvrUvuD3FndAxVJk+TywBkkkwUSm9HdYoskJalWg5qVsEiXeufPvRVPbCUmNQewg798rx+sPXg==} - engines: {node: '>=20'} + log-update@8.0.0: + resolution: {integrity: sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg==} + engines: {node: '>=22'} logform@2.7.0: resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} @@ -13910,8 +14093,8 @@ packages: mocked-exports@0.1.1: resolution: {integrity: sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==} - modern-tar@0.7.6: - resolution: {integrity: sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==} + modern-tar@0.8.5: + resolution: {integrity: sha512-snEhs+6G5Tjd4I7tLCDOaoln2RgE0bD19RzEKgvgK2hZ5VKy3MpLhLTZ2fWpXSTg4K2cyPwp+VHATFJhxfnOeA==} engines: {node: '>=18.0.0'} module-definition@6.0.2: @@ -13929,10 +14112,6 @@ packages: moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - move-file@3.1.0: - resolution: {integrity: sha512-4aE3U7CCBWgrQlQDMq8da4woBWDGHioJFiOZ8Ie6Yq2uwYQ9V2kGhTz4x3u6Wc+OU17nw0yc3rJ/lQ4jIiPe3A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -14038,9 +14217,9 @@ packages: resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} engines: {node: '>= 10'} - netlify-cli@26.2.0: - resolution: {integrity: sha512-3jQg9WQoa1H74478fHZisj3T8dLM67x4F4Sgi7kROBHzJD9NNCYYw99dKRYWJOtEa1dUNyZu2W4VTdPzA1kjiw==} - engines: {node: '>=20.12.2'} + netlify-cli@27.5.1: + resolution: {integrity: sha512-k55Iq+/Q54pb07+5ninj6sOnNO9qDDSPOzD0Hlz5cGxcOddhTHsOKscdwEzfMnx27I0dLT/z8v043mrm+2U69g==} + engines: {node: '>=22.13.0'} hasBin: true netlify-redirector@0.5.0: @@ -15381,6 +15560,10 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + raw-body@4.0.0: + resolution: {integrity: sha512-TMHtwexrgOt9VJ2E5JF9RO8mRXGNgC5wXvKkc5AVSJUt1L5gxvjg7eiCQl96EqUEpCWrnNEkCnbAplYtyuq1IA==} + engines: {node: '>=22'} + rc9@3.0.1: resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} @@ -15490,6 +15673,10 @@ packages: readdir-glob@1.1.3: resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdir-glob@3.0.0: + resolution: {integrity: sha512-AhNB2KgKeVJr16nK9LLZbJNWnYoT23ZrumNKFDebHBdkC8KHSqWo871JAUhoWC/RtjEVdqNMFpM6qrwRbaUqpw==} + engines: {node: '>=18'} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -16039,9 +16226,9 @@ packages: slashes@3.0.12: resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==} - slice-ansi@8.0.0: - resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} - engines: {node: '>=20'} + slice-ansi@9.0.0: + resolution: {integrity: sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==} + engines: {node: '>=22'} slugify@1.6.9: resolution: {integrity: sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==} @@ -16409,6 +16596,10 @@ packages: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} + supports-color@11.0.0: + resolution: {integrity: sha512-/zyImLdxhdygBIaVX0xTlQhKaCDLCrm665aqHk8xqK/Pa6k61fL6gwQGQq1k31yNyz6x55PppQgF2DMyPQa5xw==} + engines: {node: '>=22'} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -16600,6 +16791,10 @@ packages: resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -16679,6 +16874,10 @@ packages: toml@3.0.0: resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + toml@4.3.0: + resolution: {integrity: sha512-lVb8X9BsPVuH0M4BKeS91tXAmJvCjQ5UIyAbQFaxkKGyUFK2RPkhwaFSQH8vbpl1d23eu/IBH+dwVMHWaq9A5A==} + engines: {node: '>=20'} + tomlify-j0.4@3.0.0: resolution: {integrity: sha512-2Ulkc8T7mXJ2l0W476YC/A209PR38Nw8PuaCNtk9uI3t1zzFdGQeWYGQvmj2PZkVvRC/Yoi4xQKMRnWc/N29tQ==} @@ -18176,6 +18375,10 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} + zip-stream@7.0.5: + resolution: {integrity: sha512-dSvYKdvLsAHCDqPOhIwk/q5CvuWtTB3Dgpoe0uVEFjTzIOAmsQpprX25InCvrvJsirEbu1OHyy67n/kAj1Sw/w==} + engines: {node: '>=18'} + zod-metadata@1.1.2: resolution: {integrity: sha512-3PB0SX74jNAvSLvj03Fxpgl98kWJevW1Wa/AnQJ3ToOJ7m9Vi90bMVxveKCWre8btVRDqw449P8hpdTijkSNNA==} peerDependencies: @@ -18344,7 +18547,7 @@ snapshots: dependencies: '@astrojs/internal-helpers': 0.7.6 '@astrojs/underscore-redirects': 1.0.0 - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.9 '@netlify/functions': 5.3.0 '@netlify/vite-plugin': 2.12.8(babel-plugin-macros@3.1.0)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1)(rollup@4.60.2)(vite@6.4.2(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) '@vercel/nft': 0.30.4(rollup@4.60.2) @@ -18443,7 +18646,7 @@ snapshots: '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -18603,7 +18806,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.28.6 '@babel/types': 7.29.7 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -19638,11 +19841,12 @@ snapshots: http-errors: 2.0.1 mime: 3.0.0 - '@fastify/static@9.3.0': + '@fastify/static@10.1.3': dependencies: '@fastify/accept-negotiator': 2.0.1 + '@fastify/error': 4.2.0 '@fastify/send': 4.1.0 - content-disposition: 1.1.0 + content-disposition: 2.0.1 fastify-plugin: 6.0.0 fastq: 1.19.1 glob: 13.0.6 @@ -20646,7 +20850,7 @@ snapshots: '@kwsites/file-exists@1.1.1': dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -20686,11 +20890,11 @@ snapshots: '@lukeed/ms@2.0.2': {} - '@mapbox/node-pre-gyp@2.0.3(supports-color@10.2.2)': + '@mapbox/node-pre-gyp@2.0.3(supports-color@11.0.0)': dependencies: consola: 3.4.2 detect-libc: 2.1.2 - https-proxy-agent: 7.0.6(supports-color@10.2.2) + https-proxy-agent: 7.0.6(supports-color@11.0.0) node-fetch: 2.7.0 nopt: 8.1.0 semver: 7.8.0 @@ -20766,6 +20970,10 @@ snapshots: dependencies: '@netlify/api': 14.0.19 + '@netlify/ai@1.0.1': + dependencies: + '@netlify/api': 15.1.2 + '@netlify/api@14.0.19': dependencies: '@netlify/open-api': 2.57.0 @@ -20773,6 +20981,12 @@ snapshots: p-wait-for: 5.0.2 picoquery: 2.5.0 + '@netlify/api@15.1.2': + dependencies: + '@netlify/open-api': 2.57.0 + node-fetch: 3.3.2 + picoquery: 2.5.0 + '@netlify/async-workloads@0.0.106(@google-cloud/storage@5.20.5)(@trpc/server@11.18.0(typescript@6.0.3))(@types/react@19.1.8)(autoprefixer@10.5.0(postcss@8.5.19))(debug@4.4.1)(graphql@16.14.2)(postcss@8.5.19)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.2)(tailwindcss@4.1.12)': dependencies: '@lukeed/ms': 2.0.2 @@ -20904,14 +21118,22 @@ snapshots: '@netlify/dev-utils': 4.3.0 '@netlify/runtime-utils': 2.2.0 - '@netlify/blobs@10.7.9(supports-color@10.2.2)': + '@netlify/blobs@10.7.9': dependencies: '@netlify/dev-utils': 4.4.6 - '@netlify/otel': 6.0.3(supports-color@10.2.2) + '@netlify/otel': 6.0.3 '@netlify/runtime-utils': 2.3.0 transitivePeerDependencies: - supports-color + '@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0)': + dependencies: + '@netlify/dev-utils': 6.0.1 + '@netlify/otel': 7.0.2(supports-color@11.0.0) + '@netlify/runtime-utils': 3.0.0 + transitivePeerDependencies: + - supports-color + '@netlify/blobs@8.2.0': {} '@netlify/blobs@9.1.2': @@ -20924,56 +21146,49 @@ snapshots: '@netlify/dev-utils': 3.2.0 '@netlify/runtime-utils': 2.1.0 - '@netlify/build-info@10.5.1': + '@netlify/build-info@11.3.0': dependencies: '@bugsnag/js': 8.10.0 - '@iarna/toml': 2.2.5 dot-prop: 9.0.0 find-up: 7.0.0 + lockparse: 0.5.2 minimatch: 10.2.5 read-pkg: 9.0.1 semver: 7.8.0 + smol-toml: 1.6.1 yaml: 2.9.0 yargs: 17.7.2 - '@netlify/build@35.15.0(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(picomatch@4.0.5)(rollup@4.60.2)': + '@netlify/build@36.4.7(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(picomatch@4.0.5)(rollup@4.60.2)': dependencies: '@bugsnag/js': 8.10.0 - '@netlify/blobs': 10.7.9(supports-color@10.2.2) - '@netlify/cache-utils': 6.0.5 - '@netlify/config': 24.6.0 - '@netlify/edge-bundler': 14.10.3 - '@netlify/functions-utils': 6.2.35(rollup@4.60.2)(supports-color@10.2.2) - '@netlify/git-utils': 6.0.4 - '@netlify/opentelemetry-utils': 2.0.2(@opentelemetry/api@1.9.1) + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) + '@netlify/cache-utils': 7.1.2 + '@netlify/config': 25.2.4 + '@netlify/edge-bundler': 16.0.4 + '@netlify/functions-utils': 7.1.9(rollup@4.60.2)(supports-color@11.0.0) + '@netlify/git-utils': 7.1.1 + '@netlify/opentelemetry-utils': 3.1.0(@opentelemetry/api@1.9.1) '@netlify/plugins-list': 6.81.8 - '@netlify/run-utils': 6.0.3 - '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2)(supports-color@10.2.2) + '@netlify/run-utils': 7.1.0 + '@netlify/zip-it-and-ship-it': 15.5.1(rollup@4.60.2)(supports-color@11.0.0) '@opentelemetry/api': 1.9.1 '@sindresorhus/slugify': 2.2.1 - ansi-escapes: 7.3.0 ansis: 4.3.0 - clean-stack: 5.3.0 execa: 8.0.1 + fast-string-width: 3.0.2 fdir: 6.5.0(picomatch@4.0.5) figures: 6.1.0 - filter-obj: 6.1.0 hot-shots: 11.4.0 ignore: 7.0.5 indent-string: 5.0.0 - is-plain-obj: 4.1.0 keep-func-props: 6.0.0 log-process-errors: 11.0.1 memoize-one: 6.0.0 minimatch: 10.2.5 os-name: 6.1.0 - p-event: 6.0.1 - p-filter: 4.1.0 - p-locate: 6.0.0 - p-map: 7.0.5 p-reduce: 3.0.0 package-directory: 8.2.0 - path-exists: 5.0.0 pretty-ms: 9.3.0 ps-list: 8.1.1 read-package-up: 11.0.0 @@ -20982,14 +21197,13 @@ snapshots: rfdc: 1.4.1 safe-json-stringify: 1.2.0 semver: 7.8.0 - string-width: 7.2.0 - supports-color: 10.2.2 + supports-color: 11.0.0 terminal-link: 4.0.0 ts-node: 10.9.2(@types/node@22.19.1)(typescript@5.9.3) typescript: 5.9.3 yaml: 2.9.0 yargs: 17.7.2 - zod: 3.25.76 + zod: 4.3.6 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -21001,20 +21215,19 @@ snapshots: - react-native-b4a - rollup - '@netlify/cache-utils@6.0.5': + '@netlify/cache-utils@7.1.2': dependencies: - cpy: 11.1.0 get-stream: 9.0.1 - globby: 14.1.0 junk: 4.0.1 - locate-path: 7.2.0 - move-file: 3.1.0 - readdirp: 4.1.2 '@netlify/cache@3.4.8': dependencies: '@netlify/runtime-utils': 2.3.0 + '@netlify/cache@4.0.0': + dependencies: + '@netlify/runtime-utils': 3.0.0 + '@netlify/config@24.6.0': dependencies: '@iarna/toml': 2.2.5 @@ -21043,6 +21256,33 @@ snapshots: yargs: 17.7.2 zod: 4.3.6 + '@netlify/config@25.2.4': + dependencies: + '@netlify/api': 15.1.2 + '@netlify/headers-parser': 10.1.1 + '@netlify/redirect-parser': 16.1.1 + chalk: 6.0.0 + cron-parser: 5.10.0 + deepmerge: 4.3.1 + dot-prop: 9.0.0 + execa: 8.0.1 + fast-safe-stringify: 2.1.1 + figures: 6.1.0 + filter-obj: 6.1.0 + find-up: 7.0.0 + indent-string: 5.0.0 + is-plain-obj: 4.1.0 + map-obj: 5.0.2 + p-locate: 6.0.0 + path-type: 6.0.0 + read-package-up: 11.0.0 + smol-toml: 1.6.1 + tomlify-j0.4: 3.0.0 + validate-npm-package-name: 5.0.1 + yaml: 2.9.0 + yargs: 17.7.2 + zod: 4.3.6 + '@netlify/content-engine-graphiql-explorer@0.0.4': {} '@netlify/content-engine-graphiql-explorer@1.1.0': {} @@ -21434,35 +21674,10 @@ snapshots: '@electric-sql/pglite': 0.3.16 pg-gateway: 0.3.0-beta.4 - '@netlify/database@1.1.0(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(postgres@3.4.7)': + '@netlify/database-dev@1.0.1': dependencies: - '@neondatabase/serverless': 1.1.0 - '@netlify/runtime-utils': 2.3.0 - pg: 8.22.0 - waddler: 0.1.1(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7) - ws: 8.21.0 - transitivePeerDependencies: - - '@clickhouse/client' - - '@cloudflare/workers-types' - - '@duckdb/node-api' - - '@electric-sql/pglite' - - '@libsql/client' - - '@libsql/client-wasm' - - '@op-engineering/op-sqlite' - - '@planetscale/database' - - '@tidbcloud/serverless' - - '@vercel/postgres' - - '@xata.io/client' - - better-sqlite3 - - bufferutil - - bun-types - - duckdb - - gel - - mysql2 - - pg-native - - pg-query-stream - - postgres - - utf-8-validate + '@electric-sql/pglite': 0.3.16 + pg-gateway: 0.3.0-beta.4 '@netlify/database@1.1.0(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(postgres@3.4.7)': dependencies: @@ -21559,10 +21774,24 @@ snapshots: semver: 7.8.0 tmp-promise: 3.0.3 + '@netlify/dev-utils@6.0.1': + dependencies: + '@whatwg-node/server': 0.11.0 + ansis: 4.3.0 + atomically: 2.1.1 + chokidar: 5.0.0 + decache: 4.6.2 + dettle: 1.0.5 + dot-prop: 9.0.0 + empathic: 2.0.1 + env-paths: 3.0.0 + parse-gitignore: 2.0.0 + semver: 7.8.0 + '@netlify/dev@4.18.7(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1)(rollup@4.60.2)': dependencies: '@netlify/ai': 0.4.2 - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.9 '@netlify/config': 24.6.0 '@netlify/database-dev': 0.10.1 '@netlify/dev-utils': 4.4.6 @@ -21600,20 +21829,20 @@ snapshots: - supports-color - uploadthing - '@netlify/dev@4.18.9(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(rollup@4.60.2)': - dependencies: - '@netlify/ai': 0.4.2 - '@netlify/blobs': 10.7.9(supports-color@10.2.2) - '@netlify/config': 24.6.0 - '@netlify/database-dev': 0.10.1 - '@netlify/dev-utils': 4.4.6 - '@netlify/edge-functions-dev': 1.0.22 - '@netlify/functions-dev': 1.3.1(rollup@4.60.2) - '@netlify/headers': 2.1.11 - '@netlify/images': 1.3.10(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) - '@netlify/redirects': 3.1.13 - '@netlify/runtime': 4.1.25 - '@netlify/static': 3.1.10 + '@netlify/dev@5.0.5(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(rollup@4.60.2)': + dependencies: + '@netlify/ai': 1.0.1 + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) + '@netlify/config': 25.2.4 + '@netlify/database-dev': 1.0.1 + '@netlify/dev-utils': 6.0.1 + '@netlify/edge-functions-dev': 2.0.1 + '@netlify/functions-dev': 2.0.5(rollup@4.60.2) + '@netlify/headers': 3.0.1 + '@netlify/images': 2.0.1(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) + '@netlify/redirects': 4.0.2 + '@netlify/runtime': 5.0.3 + '@netlify/static': 4.0.0 ulid: 3.0.2 transitivePeerDependencies: - '@azure/app-configuration' @@ -21665,9 +21894,29 @@ snapshots: tmp-promise: 3.0.3 urlpattern-polyfill: 8.0.2 + '@netlify/edge-bundler@16.0.4': + dependencies: + '@import-maps/resolve': 2.0.0 + '@sveltejs/acorn-typescript': 1.0.13(acorn@8.16.0) + acorn: 8.16.0 + ajv: 8.17.1 + ajv-errors: 3.0.0(ajv@8.17.1) + better-ajv-errors: 1.2.0(ajv@8.17.1) + common-path-prefix: 3.0.0 + esbuild: 0.28.1 + execa: 8.0.1 + find-up: 7.0.0 + node-stream-zip: 1.15.0 + p-retry: 6.2.1 + parse-imports: 2.2.1 + semver: 7.8.0 + tar: 7.5.20 + tmp-promise: 3.0.3 + urlpattern-polyfill: 8.0.2 + '@netlify/edge-functions-bootstrap@2.16.0': {} - '@netlify/edge-functions-bootstrap@2.17.1': {} + '@netlify/edge-functions-bootstrap@3.2.0': {} '@netlify/edge-functions-dev@1.0.20': dependencies: @@ -21678,25 +21927,29 @@ snapshots: '@netlify/runtime-utils': 2.3.0 get-port: 7.2.0 - '@netlify/edge-functions-dev@1.0.22': + '@netlify/edge-functions-dev@2.0.1': dependencies: - '@netlify/dev-utils': 4.4.6 - '@netlify/edge-bundler': 14.10.3 - '@netlify/edge-functions': 3.0.8 + '@netlify/dev-utils': 6.0.1 + '@netlify/edge-bundler': 16.0.4 + '@netlify/edge-functions': 4.0.0 '@netlify/edge-functions-bootstrap': 2.16.0 - '@netlify/runtime-utils': 2.3.0 + '@netlify/runtime-utils': 3.0.0 get-port: 7.2.0 '@netlify/edge-functions@3.0.8': dependencies: '@netlify/types': 2.8.0 + '@netlify/edge-functions@4.0.0': + dependencies: + '@netlify/types': 3.0.0 + '@netlify/functions-dev@1.3.0(rollup@4.60.2)': dependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.9 '@netlify/dev-utils': 4.4.6 '@netlify/functions': 5.3.0 - '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2)(supports-color@10.2.2) + '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2) cron-parser: 4.9.0 decache: 4.6.2 extract-zip: 2.0.1 @@ -21714,21 +21967,21 @@ snapshots: - rollup - supports-color - '@netlify/functions-dev@1.3.1(rollup@4.60.2)': + '@netlify/functions-dev@2.0.5(rollup@4.60.2)': dependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) - '@netlify/dev-utils': 4.4.6 - '@netlify/functions': 5.3.0 - '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2)(supports-color@10.2.2) - cron-parser: 4.9.0 + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) + '@netlify/dev-utils': 6.0.1 + '@netlify/functions': 6.0.0 + '@netlify/zip-it-and-ship-it': 15.5.1(rollup@4.60.2)(supports-color@11.0.0) + cron-parser: 5.10.0 decache: 4.6.2 - extract-zip: 2.0.1 is-stream: 4.0.1 jwt-decode: 4.0.0 lambda-local: 2.2.0 - read-package-up: 11.0.0 + read-package-up: 12.0.0 semver: 7.8.0 source-map-support: 0.5.21 + yauzl: 3.4.0 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -21737,11 +21990,10 @@ snapshots: - rollup - supports-color - '@netlify/functions-utils@6.2.35(rollup@4.60.2)(supports-color@10.2.2)': + '@netlify/functions-utils@7.1.9(rollup@4.60.2)(supports-color@11.0.0)': dependencies: - '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2)(supports-color@10.2.2) - cpy: 11.1.0 - path-exists: 5.0.0 + '@netlify/zip-it-and-ship-it': 15.5.1(rollup@4.60.2)(supports-color@11.0.0) + junk: 4.0.1 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -21785,7 +22037,7 @@ snapshots: '@netlify/blobs': 10.1.0 '@netlify/dev-utils': 4.3.0 '@netlify/types': 2.1.0 - '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2)(supports-color@10.2.2) + '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2) cron-parser: 4.9.0 decache: 4.6.2 extract-zip: 2.0.1 @@ -21806,12 +22058,20 @@ snapshots: dependencies: '@netlify/types': 2.8.0 - '@netlify/git-utils@6.0.4': + '@netlify/functions@6.0.0': + dependencies: + '@netlify/types': 3.0.0 + + '@netlify/git-utils@7.1.1': dependencies: - execa: 8.0.1 - map-obj: 5.0.2 micro-memoize: 5.1.2 micromatch: 4.0.8 + tinyexec: 1.3.1 + + '@netlify/headers-parser@10.1.1': + dependencies: + escape-string-regexp: 5.0.0 + smol-toml: 1.6.1 '@netlify/headers-parser@9.0.3': dependencies: @@ -21826,9 +22086,13 @@ snapshots: dependencies: '@netlify/headers-parser': 9.0.3 - '@netlify/images@1.3.10(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)': + '@netlify/headers@3.0.1': dependencies: - ipx: 3.1.1(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) + '@netlify/headers-parser': 10.1.1 + + '@netlify/images@1.3.10(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1)': + dependencies: + ipx: 3.1.1(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21850,9 +22114,9 @@ snapshots: - ioredis - uploadthing - '@netlify/images@1.3.10(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1)': + '@netlify/images@2.0.1(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)': dependencies: - ipx: 3.1.1(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1) + ipx: 3.1.1(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21944,20 +22208,30 @@ snapshots: '@netlify/open-api@2.57.0': {} - '@netlify/opentelemetry-utils@2.0.2(@opentelemetry/api@1.9.1)': + '@netlify/opentelemetry-utils@3.1.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@netlify/otel@6.0.3(supports-color@10.2.2)': + '@netlify/otel@6.0.3': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.217.0(@opentelemetry/api@1.9.0)(supports-color@10.2.2) + '@opentelemetry/instrumentation': 0.217.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 2.7.1(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color + '@netlify/otel@7.0.2(supports-color@11.0.0)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.221.0(@opentelemetry/api@1.9.1)(supports-color@11.0.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-node': 2.10.0(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + '@netlify/plugins-list@6.81.8': {} '@netlify/redirect-parser@15.0.4': @@ -21967,6 +22241,11 @@ snapshots: is-plain-obj: 4.1.0 path-exists: 5.0.0 + '@netlify/redirect-parser@16.1.1': + dependencies: + fast-safe-stringify: 2.1.1 + smol-toml: 1.6.1 + '@netlify/redirects@3.1.13': dependencies: '@netlify/dev-utils': 4.4.6 @@ -21975,7 +22254,15 @@ snapshots: jsonwebtoken: 9.0.3 netlify-redirector: 0.5.0 - '@netlify/run-utils@6.0.3': + '@netlify/redirects@4.0.2': + dependencies: + '@netlify/dev-utils': 6.0.1 + '@netlify/redirect-parser': 16.1.1 + cookie: 2.0.1 + jsonwebtoken: 9.0.3 + netlify-redirector: 0.5.0 + + '@netlify/run-utils@7.1.0': dependencies: execa: 8.0.1 @@ -21987,15 +22274,26 @@ snapshots: '@netlify/runtime-utils@2.3.0': {} + '@netlify/runtime-utils@3.0.0': {} + '@netlify/runtime@4.1.25': dependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.9 '@netlify/cache': 3.4.8 '@netlify/runtime-utils': 2.3.0 '@netlify/types': 2.8.0 transitivePeerDependencies: - supports-color + '@netlify/runtime@5.0.3': + dependencies: + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) + '@netlify/cache': 4.0.0 + '@netlify/runtime-utils': 3.0.0 + '@netlify/types': 3.0.0 + transitivePeerDependencies: + - supports-color + '@netlify/sdk--extension-api-client@0.1.1': dependencies: wretch: 2.11.1 @@ -22012,7 +22310,7 @@ snapshots: '@netlify/sdk--extension-api-client@2.12.6': dependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.9 camelize-ts: 3.0.0 openapi-fetch: 0.13.8 snakify-ts: 2.3.0 @@ -22480,10 +22778,18 @@ snapshots: dependencies: '@netlify/types': 2.8.0 + '@netlify/serverless-functions-api@2.18.0': + dependencies: + '@netlify/types': 2.8.0 + '@netlify/static@3.1.10': dependencies: mime-types: 3.0.2 + '@netlify/static@4.0.0': + dependencies: + mime-types: 3.0.2 + '@netlify/tailwind-config@2.1.0': dependencies: '@netlify/netlify-design-tokens': 7.1.0 @@ -22496,6 +22802,8 @@ snapshots: '@netlify/types@2.8.0': {} + '@netlify/types@3.0.0': {} + '@netlify/ui@0.0.23(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@netlify/netlify-design-tokens': 7.1.0 @@ -22551,7 +22859,7 @@ snapshots: '@babel/types': 7.28.0 '@netlify/binary-info': 1.0.0 '@netlify/serverless-functions-api': 2.17.2 - '@vercel/nft': 0.29.4(rollup@4.60.2)(supports-color@10.2.2) + '@vercel/nft': 0.29.4(rollup@4.60.2) archiver: 7.0.1 common-path-prefix: 3.0.0 copy-file: 11.1.0 @@ -22570,7 +22878,7 @@ snapshots: normalize-path: 3.0.0 p-map: 7.0.5 path-exists: 5.0.0 - precinct: 12.3.2(supports-color@10.2.2) + precinct: 12.3.2(supports-color@11.0.0) require-package-name: 2.0.1 resolve: 2.0.0-next.5 semver: 7.8.0 @@ -22588,13 +22896,13 @@ snapshots: - rollup - supports-color - '@netlify/zip-it-and-ship-it@14.7.1(rollup@4.60.2)(supports-color@10.2.2)': + '@netlify/zip-it-and-ship-it@14.7.1(rollup@4.60.2)': dependencies: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 '@netlify/binary-info': 1.0.0 '@netlify/serverless-functions-api': 2.16.0 - '@vercel/nft': 0.29.4(rollup@4.60.2)(supports-color@10.2.2) + '@vercel/nft': 0.29.4(rollup@4.60.2) archiver: 7.0.1 common-path-prefix: 3.0.0 copy-file: 11.1.0 @@ -22612,7 +22920,7 @@ snapshots: normalize-path: 3.0.0 p-map: 7.0.5 path-exists: 5.0.0 - precinct: 12.3.2(supports-color@10.2.2) + precinct: 12.3.2(supports-color@11.0.0) require-package-name: 2.0.1 resolve: 2.0.0-next.5 semver: 7.8.0 @@ -22630,6 +22938,49 @@ snapshots: - rollup - supports-color + '@netlify/zip-it-and-ship-it@15.5.1(rollup@4.60.2)(supports-color@11.0.0)': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@netlify/binary-info': 1.0.0 + '@netlify/serverless-functions-api': 2.18.0 + '@opentelemetry/api': 1.8.0 + '@vercel/nft': 1.3.1(rollup@4.60.2)(supports-color@11.0.0) + archiver: 8.0.0 + common-path-prefix: 3.0.0 + copy-file: 11.1.0 + es-module-lexer: 1.7.0 + esbuild: 0.28.1 + execa: 8.0.1 + fast-glob: 3.3.3 + filter-obj: 6.1.0 + find-up: 7.0.0 + is-path-inside: 4.0.0 + junk: 4.0.1 + locate-path: 7.2.0 + merge-options: 3.0.4 + minimatch: 10.2.5 + normalize-path: 3.0.0 + p-map: 7.0.5 + path-exists: 5.0.0 + precinct: 12.3.2(supports-color@11.0.0) + require-package-name: 2.0.1 + resolve: 2.0.0-next.5 + semver: 7.8.0 + tmp-promise: 3.0.3 + toml: 4.3.0 + unixify: 1.0.0 + urlpattern-polyfill: 8.0.2 + yargs: 17.7.2 + zod: 4.3.6 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - encoding + - react-native-b4a + - rollup + - supports-color + '@next/env@14.2.30': {} '@next/env@15.3.1': {} @@ -22747,7 +23098,7 @@ snapshots: citty: 0.2.2 confbox: 0.2.4 consola: 3.4.2 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) defu: 6.1.7 exsolve: 1.0.8 fuse.js: 7.3.0 @@ -23159,6 +23510,10 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs@0.221.0': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs@0.53.0': dependencies: '@opentelemetry/api': 1.9.1 @@ -23171,6 +23526,8 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 + '@opentelemetry/api@1.8.0': {} + '@opentelemetry/api@1.9.0': {} '@opentelemetry/api@1.9.1': {} @@ -23185,6 +23542,10 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks@2.10.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks@2.5.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23202,6 +23563,11 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23535,16 +23901,25 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/api-logs': 0.211.0 import-in-the-middle: 2.0.1 - require-in-the-middle: 8.0.1(supports-color@10.2.2) + require-in-the-middle: 8.0.1(supports-color@11.0.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.217.0(@opentelemetry/api@1.9.0)(supports-color@10.2.2)': + '@opentelemetry/instrumentation@0.217.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/api-logs': 0.217.0 import-in-the-middle: 3.3.1 - require-in-the-middle: 8.0.1(supports-color@10.2.2) + require-in-the-middle: 8.0.1(supports-color@11.0.0) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.221.0(@opentelemetry/api@1.9.1)(supports-color@11.0.0)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.221.0 + import-in-the-middle: 3.3.1 + require-in-the-middle: 8.0.1(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -23627,6 +24002,12 @@ snapshots: '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/resources@2.5.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23701,6 +24082,14 @@ snapshots: '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23722,6 +24111,13 @@ snapshots: '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sdk-trace-node@2.10.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-node@2.5.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23736,6 +24132,13 @@ snapshots: '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace@2.10.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/semantic-conventions@1.27.0': {} '@opentelemetry/semantic-conventions@1.28.0': {} @@ -24123,7 +24526,7 @@ snapshots: '@pnpm/tabtab@0.5.4': dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) enquirer: 2.4.1 minimist: 1.2.8 untildify: 4.0.0 @@ -24764,8 +25167,6 @@ snapshots: '@sindresorhus/is@7.1.1': {} - '@sindresorhus/merge-streams@2.3.0': {} - '@sindresorhus/merge-streams@4.0.0': {} '@sindresorhus/slugify@2.2.1': @@ -25216,6 +25617,10 @@ snapshots: dependencies: acorn: 8.16.0 + '@sveltejs/acorn-typescript@1.0.13(acorn@8.16.0)': + dependencies: + acorn: 8.16.0 + '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)': dependencies: acorn: 8.15.0 @@ -25269,7 +25674,7 @@ snapshots: '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.1.3(svelte@5.38.3)(vite@7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.38.3)(vite@7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@sveltejs/vite-plugin-svelte': 6.1.3(svelte@5.38.3)(vite@7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) svelte: 5.38.3 vite: 7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: @@ -25278,7 +25683,7 @@ snapshots: '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.1.3(svelte@5.38.3)(vite@8.1.4(@types/node@24.3.0)(esbuild@0.28.1)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)))(svelte@5.38.3)(vite@8.1.4(@types/node@24.3.0)(esbuild@0.28.1)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@sveltejs/vite-plugin-svelte': 6.1.3(svelte@5.38.3)(vite@8.1.4(@types/node@24.3.0)(esbuild@0.28.1)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) svelte: 5.38.3 vite: 8.1.4(@types/node@24.3.0)(esbuild@0.28.1)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: @@ -25532,7 +25937,7 @@ snapshots: '@tokenizer/inflate@0.2.7': dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) fflate: 0.8.2 token-types: 6.1.2 transitivePeerDependencies: @@ -25540,7 +25945,7 @@ snapshots: '@tokenizer/inflate@0.4.1': dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) token-types: 6.1.2 transitivePeerDependencies: - supports-color @@ -26143,7 +26548,7 @@ snapshots: '@typescript-eslint/types': 8.41.0 '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.41.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) eslint: 9.32.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: @@ -26167,7 +26572,7 @@ snapshots: '@typescript-eslint/types': 8.59.0 '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.59.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) eslint: 9.32.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: @@ -26177,7 +26582,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@6.0.3) '@typescript-eslint/types': 8.41.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -26186,7 +26591,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@5.9.2) '@typescript-eslint/types': 8.41.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -26195,7 +26600,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@6.0.3) '@typescript-eslint/types': 8.41.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -26204,16 +26609,16 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@6.0.3) '@typescript-eslint/types': 8.50.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.0(supports-color@10.2.2)(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.0(supports-color@11.0.0)(typescript@5.9.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) '@typescript-eslint/types': 8.59.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -26222,7 +26627,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.2) '@typescript-eslint/types': 8.59.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -26280,7 +26685,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@6.0.3) '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@6.0.3) - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) eslint: 8.57.1 ts-api-utils: 1.4.3(typescript@6.0.3) optionalDependencies: @@ -26293,7 +26698,7 @@ snapshots: '@typescript-eslint/types': 8.38.0 '@typescript-eslint/typescript-estree': 8.38.0(typescript@6.0.3) '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.6.1))(typescript@6.0.3) - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) eslint: 9.32.0(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@6.0.3) typescript: 6.0.3 @@ -26305,7 +26710,7 @@ snapshots: '@typescript-eslint/types': 8.41.0 '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) '@typescript-eslint/utils': 8.41.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2) - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) eslint: 9.32.0(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 @@ -26317,7 +26722,7 @@ snapshots: '@typescript-eslint/types': 8.59.0 '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.2) '@typescript-eslint/utils': 8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2) - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) eslint: 9.32.0(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@5.9.2) typescript: 5.9.2 @@ -26338,7 +26743,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -26355,7 +26760,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@6.0.3) '@typescript-eslint/types': 8.38.0 '@typescript-eslint/visitor-keys': 8.38.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -26371,7 +26776,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@5.9.2) '@typescript-eslint/types': 8.41.0 '@typescript-eslint/visitor-keys': 8.41.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -26387,7 +26792,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@6.0.3) '@typescript-eslint/types': 8.41.0 '@typescript-eslint/visitor-keys': 8.41.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -26403,7 +26808,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@6.0.3) '@typescript-eslint/types': 8.50.0 '@typescript-eslint/visitor-keys': 8.50.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) minimatch: 9.0.5 semver: 7.8.0 tinyglobby: 0.2.17 @@ -26412,13 +26817,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.59.0(supports-color@10.2.2)(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.0(supports-color@11.0.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.59.0(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/project-service': 8.59.0(supports-color@11.0.0)(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) '@typescript-eslint/types': 8.59.0 '@typescript-eslint/visitor-keys': 8.59.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) minimatch: 10.2.5 semver: 7.8.0 tinyglobby: 0.2.17 @@ -26433,7 +26838,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.2) '@typescript-eslint/types': 8.59.0 '@typescript-eslint/visitor-keys': 8.59.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) minimatch: 10.2.5 semver: 7.8.0 tinyglobby: 0.2.17 @@ -26524,7 +26929,7 @@ snapshots: '@typescript/vfs@1.6.4(typescript@6.0.3)': dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -26596,9 +27001,9 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/nft@0.29.4(rollup@4.60.2)(supports-color@10.2.2)': + '@vercel/nft@0.29.4(rollup@4.60.2)': dependencies: - '@mapbox/node-pre-gyp': 2.0.3(supports-color@10.2.2) + '@mapbox/node-pre-gyp': 2.0.3(supports-color@11.0.0) '@rollup/pluginutils': 5.3.0(rollup@4.60.2) acorn: 8.16.0 acorn-import-attributes: 1.9.5(acorn@8.16.0) @@ -26617,7 +27022,7 @@ snapshots: '@vercel/nft@0.30.4(rollup@4.60.2)': dependencies: - '@mapbox/node-pre-gyp': 2.0.3(supports-color@10.2.2) + '@mapbox/node-pre-gyp': 2.0.3(supports-color@11.0.0) '@rollup/pluginutils': 5.3.0(rollup@4.60.2) acorn: 8.16.0 acorn-import-attributes: 1.9.5(acorn@8.16.0) @@ -26634,9 +27039,28 @@ snapshots: - rollup - supports-color + '@vercel/nft@1.3.1(rollup@4.60.2)(supports-color@11.0.0)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.3(supports-color@11.0.0) + '@rollup/pluginutils': 5.3.0(rollup@4.60.2) + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 13.0.6 + graceful-fs: 4.2.11 + node-gyp-build: 4.8.4 + picomatch: 4.0.5 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + '@vercel/nft@1.5.0(rollup@4.60.2)': dependencies: - '@mapbox/node-pre-gyp': 2.0.3(supports-color@10.2.2) + '@mapbox/node-pre-gyp': 2.0.3(supports-color@11.0.0) '@rollup/pluginutils': 5.3.0(rollup@4.60.2) acorn: 8.16.0 acorn-import-attributes: 1.9.5(acorn@8.16.0) @@ -27003,6 +27427,14 @@ snapshots: '@whatwg-node/promise-helpers': 1.3.2 tslib: 2.8.1 + '@whatwg-node/server@0.11.0': + dependencies: + '@envelop/instrumentation': 1.0.0 + '@whatwg-node/disposablestack': 0.0.6 + '@whatwg-node/fetch': 0.10.13 + '@whatwg-node/promise-helpers': 1.3.2 + tslib: 2.8.1 + '@whatwg-node/server@0.9.71': dependencies: '@whatwg-node/disposablestack': 0.0.6 @@ -27063,7 +27495,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -27189,6 +27621,22 @@ snapshots: - bare-buffer - react-native-b4a + archiver@8.0.0: + dependencies: + async: 3.2.6 + buffer-crc32: 1.0.0 + is-stream: 4.0.1 + lazystream: 1.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + readdir-glob: 3.0.0 + tar-stream: 3.1.8 + zip-stream: 7.0.5 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + arg@4.1.3: {} arg@5.0.2: {} @@ -27682,7 +28130,7 @@ snapshots: dependencies: bytes: 3.1.2 content-type: 2.0.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -27898,6 +28346,8 @@ snapshots: chalk@5.6.2: {} + chalk@6.0.0: {} + chance@1.1.13: {} character-entities-html4@2.1.0: {} @@ -27972,10 +28422,6 @@ snapshots: lodash.isplainobject: 4.0.6 lodash.transform: 4.6.0 - clean-stack@5.3.0: - dependencies: - escape-string-regexp: 5.0.0 - cli-boxes@3.0.0: {} cli-cursor@3.1.0: @@ -28108,7 +28554,7 @@ snapshots: commander@8.3.0: {} - comment-json@4.6.2: + comment-json@5.0.0: dependencies: array-timsort: 1.0.3 esprima: 4.0.1 @@ -28131,6 +28577,14 @@ snapshots: normalize-path: 3.0.0 readable-stream: 4.7.0 + compress-commons@7.0.1: + dependencies: + crc-32: 1.2.2 + crc32-stream: 7.0.1 + is-stream: 4.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + compressible@2.0.18: dependencies: mime-db: 1.54.0 @@ -28192,6 +28646,8 @@ snapshots: content-disposition@1.1.0: {} + content-disposition@2.0.1: {} + content-engine-graphiql-explorer@0.0.1: {} content-engine@0.0.29: @@ -28446,6 +28902,8 @@ snapshots: cookie@1.1.1: {} + cookie@2.0.1: {} + cookies@0.9.1: dependencies: depd: 2.0.0 @@ -28479,15 +28937,6 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - cpy@11.1.0: - dependencies: - copy-file: 11.1.0 - globby: 14.1.0 - junk: 4.0.1 - micromatch: 4.0.8 - p-filter: 4.1.0 - p-map: 7.0.5 - crc-32@1.2.2: {} crc32-stream@6.0.0: @@ -28495,6 +28944,11 @@ snapshots: crc-32: 1.2.2 readable-stream: 4.7.0 + crc32-stream@7.0.1: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.7.0 + create-error-class@3.0.2: dependencies: capture-stack-trace: 1.0.2 @@ -28505,6 +28959,10 @@ snapshots: dependencies: luxon: 3.7.2 + cron-parser@5.10.0: + dependencies: + luxon: 3.7.2 + croner@10.0.1: {} cross-inspect@1.0.1: @@ -28885,11 +29343,11 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.3(supports-color@10.2.2): + debug@4.4.3(supports-color@11.0.0): dependencies: ms: 2.1.3 optionalDependencies: - supports-color: 10.2.2 + supports-color: 11.0.0 decache@4.6.2: dependencies: @@ -29006,7 +29464,7 @@ snapshots: detect-port@1.6.1: dependencies: address: 1.2.2 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -29044,16 +29502,16 @@ snapshots: detective-stylus@5.0.1: {} - detective-typescript@14.1.2(supports-color@10.2.2)(typescript@5.9.3): + detective-typescript@14.1.2(supports-color@11.0.0)(typescript@5.9.3): dependencies: - '@typescript-eslint/typescript-estree': 8.59.0(supports-color@10.2.2)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.0(supports-color@11.0.0)(typescript@5.9.3) ast-module-types: 6.0.2 node-source-walk: 7.0.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color - detective-vue2@2.3.0(supports-color@10.2.2)(typescript@5.9.3): + detective-vue2@2.3.0(supports-color@11.0.0)(typescript@5.9.3): dependencies: '@dependents/detective-less': 5.0.3 '@vue/compiler-sfc': 3.5.40 @@ -29061,7 +29519,7 @@ snapshots: detective-sass: 6.0.2 detective-scss: 5.0.2 detective-stylus: 5.0.1 - detective-typescript: 14.1.2(supports-color@10.2.2)(typescript@5.9.3) + detective-typescript: 14.1.2(supports-color@11.0.0)(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -29311,7 +29769,7 @@ snapshots: base64id: 2.0.0 cookie: 0.7.2 cors: 2.8.6 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) engine.io-parser: 5.2.3 ws: 8.21.0 transitivePeerDependencies: @@ -30380,7 +30838,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -30425,7 +30883,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -30499,10 +30957,16 @@ snapshots: fast-string-truncated-width@1.2.1: {} + fast-string-truncated-width@3.0.3: {} + fast-string-width@1.1.0: dependencies: fast-string-truncated-width: 1.2.1 + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + fast-stringify@4.0.1: {} fast-text-encoding@1.0.6: {} @@ -30644,7 +31108,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -30720,7 +31184,7 @@ snapshots: follow-redirects@1.16.0(debug@4.4.3): optionalDependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) fontace@0.4.1: dependencies: @@ -31076,15 +31540,6 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@14.1.0: - dependencies: - '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.3 - ignore: 7.0.5 - path-type: 6.0.0 - slash: 5.1.0 - unicorn-magic: 0.3.0 - globby@16.2.0: dependencies: '@sindresorhus/merge-streams': 4.0.0 @@ -31387,7 +31842,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.1 agent-base: 6.0.2 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -31412,7 +31867,7 @@ snapshots: http-proxy-middleware@3.0.7: dependencies: '@types/http-proxy': 1.17.17 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) http-proxy: 1.18.1(debug@4.4.3) is-glob: 4.0.3 is-plain-object: 5.0.0 @@ -31446,21 +31901,21 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.6(supports-color@10.2.2): + https-proxy-agent@7.0.6(supports-color@11.0.0): dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color https-proxy-agent@8.0.0: dependencies: agent-base: 8.0.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -31655,7 +32110,7 @@ snapshots: dependencies: '@ioredis/commands': 1.5.1 cluster-key-slot: 1.1.2 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -31669,7 +32124,7 @@ snapshots: ipaddr.js@2.2.0: {} - ipx@3.1.1(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1): + ipx@3.1.1(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1): dependencies: '@fastify/accept-negotiator': 2.0.1 citty: 0.1.6 @@ -31685,7 +32140,7 @@ snapshots: sharp: 0.34.5 svgo: 4.0.1 ufo: 1.6.3 - unstorage: 1.17.5(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) + unstorage: 1.17.5(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1) xss: 1.0.15 transitivePeerDependencies: - '@azure/app-configuration' @@ -31708,7 +32163,7 @@ snapshots: - ioredis - uploadthing - ipx@3.1.1(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1): + ipx@3.1.1(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1): dependencies: '@fastify/accept-negotiator': 2.0.1 citty: 0.1.6 @@ -31724,7 +32179,7 @@ snapshots: sharp: 0.34.5 svgo: 4.0.1 ufo: 1.6.3 - unstorage: 1.17.5(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)))(ioredis@5.10.1) + unstorage: 1.17.5(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) xss: 1.0.15 transitivePeerDependencies: - '@azure/app-configuration' @@ -32302,7 +32757,7 @@ snapshots: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -32562,6 +33017,8 @@ snapshots: dependencies: p-locate: 6.0.0 + lockparse@0.5.2: {} + lodash-es@4.17.21: {} lodash.camelcase@4.3.0: {} @@ -32665,11 +33122,12 @@ snapshots: chalk: 5.6.2 is-unicode-supported: 1.3.0 - log-update@7.2.0: + log-update@8.0.0: dependencies: ansi-escapes: 7.3.0 cli-cursor: 5.0.0 - slice-ansi: 8.0.0 + slice-ansi: 9.0.0 + string-width: 8.2.2 strip-ansi: 7.2.0 wrap-ansi: 10.0.0 @@ -33204,7 +33662,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) decode-named-character-reference: 1.2.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -33353,7 +33811,7 @@ snapshots: mocked-exports@0.1.1: {} - modern-tar@0.7.6: {} + modern-tar@0.8.5: {} module-definition@6.0.2: dependencies: @@ -33369,10 +33827,6 @@ snapshots: moment@2.30.1: {} - move-file@3.1.0: - dependencies: - path-exists: 5.0.0 - mri@1.2.0: {} mrmime@2.0.1: {} @@ -33476,25 +33930,25 @@ snapshots: neotraverse@0.6.18: {} - netlify-cli@26.2.0(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(picomatch@4.0.5)(rollup@4.60.2): - dependencies: - '@fastify/static': 9.3.0 - '@netlify/ai': 0.4.2 - '@netlify/api': 14.0.19 - '@netlify/blobs': 10.7.9(supports-color@10.2.2) - '@netlify/build': 35.15.0(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(picomatch@4.0.5)(rollup@4.60.2) - '@netlify/build-info': 10.5.1 - '@netlify/config': 24.6.0 - '@netlify/dev': 4.18.9(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(rollup@4.60.2) - '@netlify/dev-utils': 4.4.6 - '@netlify/edge-bundler': 14.10.3 - '@netlify/edge-functions': 3.0.8 - '@netlify/edge-functions-bootstrap': 2.17.1 - '@netlify/headers-parser': 9.0.3 - '@netlify/images': 1.3.10(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) + netlify-cli@27.5.1(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(picomatch@4.0.5)(rollup@4.60.2): + dependencies: + '@fastify/static': 10.1.3 + '@netlify/ai': 1.0.1 + '@netlify/api': 15.1.2 + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) + '@netlify/build': 36.4.7(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(picomatch@4.0.5)(rollup@4.60.2) + '@netlify/build-info': 11.3.0 + '@netlify/config': 25.2.4 + '@netlify/dev': 5.0.5(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1)(rollup@4.60.2) + '@netlify/dev-utils': 6.0.1 + '@netlify/edge-bundler': 16.0.4 + '@netlify/edge-functions': 4.0.0 + '@netlify/edge-functions-bootstrap': 3.2.0 + '@netlify/headers-parser': 10.1.1 + '@netlify/images': 2.0.1(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1) '@netlify/local-functions-proxy': 2.0.3 - '@netlify/redirect-parser': 15.0.4 - '@netlify/zip-it-and-ship-it': 14.7.1(rollup@4.60.2)(supports-color@10.2.2) + '@netlify/redirect-parser': 16.1.1 + '@netlify/zip-it-and-ship-it': 15.5.1(rollup@4.60.2)(supports-color@11.0.0) '@octokit/rest': 22.0.1 '@opentelemetry/api': 1.9.1 '@pnpm/tabtab': 0.5.4 @@ -33503,16 +33957,16 @@ snapshots: ascii-table: 0.0.9 backoff: 2.5.0 boxen: 8.0.1 - chalk: 5.6.2 - chokidar: 4.0.3 + chalk: 6.0.0 + chokidar: 5.0.0 ci-info: 4.4.0 clean-deep: 3.4.0 commander: 12.1.0 - comment-json: 4.6.2 + comment-json: 5.0.0 content-type: 1.0.5 - cookie: 1.1.1 - cron-parser: 4.9.0 - debug: 4.4.3(supports-color@10.2.2) + cookie: 2.0.1 + cron-parser: 5.10.0 + debug: 4.4.3(supports-color@11.0.0) decache: 4.6.2 dot-prop: 10.1.0 dotenv: 17.4.2 @@ -33543,10 +33997,10 @@ snapshots: jwt-decode: 4.0.0 lambda-local: 2.2.0 locate-path: 8.0.0 - log-update: 7.2.0 + log-update: 8.0.0 maxstache: 1.0.7 maxstache-stream: 1.0.4 - modern-tar: 0.7.6 + modern-tar: 0.8.5 multiparty: 4.3.0 nanospinner: 1.2.2 netlify-redirector: 0.5.0 @@ -33561,13 +34015,13 @@ snapshots: parse-github-url: 1.0.4 pg: 8.22.0 prettyjson: 1.2.5 - raw-body: 3.0.2 + raw-body: 4.0.0 read-package-up: 12.0.0 - readdirp: 4.1.2 + readdirp: 5.0.0 semver: 7.8.0 source-map-support: 0.5.21 terminal-link: 5.0.0 - toml: 3.0.0 + toml: 4.3.0 tomlify-j0.4: 3.0.0 ulid: 3.0.2 update-notifier: 7.3.1 @@ -35076,7 +35530,7 @@ snapshots: tar-fs: 2.1.4 tunnel-agent: 0.6.0 - precinct@12.3.2(supports-color@10.2.2): + precinct@12.3.2(supports-color@11.0.0): dependencies: '@dependents/detective-less': 5.0.3 commander: 12.1.0 @@ -35087,8 +35541,8 @@ snapshots: detective-sass: 6.0.2 detective-scss: 5.0.2 detective-stylus: 5.0.1 - detective-typescript: 14.1.2(supports-color@10.2.2)(typescript@5.9.3) - detective-vue2: 2.3.0(supports-color@10.2.2)(typescript@5.9.3) + detective-typescript: 14.1.2(supports-color@11.0.0)(typescript@5.9.3) + detective-vue2: 2.3.0(supports-color@11.0.0)(typescript@5.9.3) module-definition: 6.0.2 node-source-walk: 7.0.2 postcss: 8.5.19 @@ -35291,6 +35745,11 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + raw-body@4.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + rc9@3.0.1: dependencies: defu: 6.1.7 @@ -35435,6 +35894,10 @@ snapshots: dependencies: minimatch: 5.1.9 + readdir-glob@3.0.0: + dependencies: + minimatch: 10.2.5 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -35577,15 +36040,15 @@ snapshots: require-in-the-middle@7.5.2: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) module-details-from-path: 1.0.4 resolve: 1.22.10 transitivePeerDependencies: - supports-color - require-in-the-middle@8.0.1(supports-color@10.2.2): + require-in-the-middle@8.0.1(supports-color@11.0.0): dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) module-details-from-path: 1.0.4 transitivePeerDependencies: - supports-color @@ -35640,7 +36103,7 @@ snapshots: retry-request@4.2.2: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) extend: 3.0.2 transitivePeerDependencies: - supports-color @@ -35801,7 +36264,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -35940,7 +36403,7 @@ snapshots: send@1.2.1: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -36214,7 +36677,7 @@ snapshots: '@kwsites/promise-deferred': 1.1.1 '@simple-git/args-pathspec': 1.0.3 '@simple-git/argv-parser': 1.1.1 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -36244,7 +36707,7 @@ snapshots: slashes@3.0.12: {} - slice-ansi@8.0.0: + slice-ansi@9.0.0: dependencies: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 @@ -36261,7 +36724,7 @@ snapshots: socket.io-adapter@2.5.8: dependencies: - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) ws: 8.21.0 transitivePeerDependencies: - bufferutil @@ -36271,7 +36734,7 @@ snapshots: socket.io-parser@4.2.6: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -36280,7 +36743,7 @@ snapshots: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.6 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) engine.io: 6.6.9 socket.io-adapter: 2.5.8 socket.io-parser: 4.2.6 @@ -36625,6 +37088,8 @@ snapshots: supports-color@10.2.2: {} + supports-color@11.0.0: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -36895,6 +37360,8 @@ snapshots: tinyexec@1.1.2: {} + tinyexec@1.3.1: {} + tinyglobby@0.2.14: dependencies: fdir: 6.5.0(picomatch@4.0.5) @@ -36964,6 +37431,8 @@ snapshots: toml@3.0.0: {} + toml@4.3.0: {} + tomlify-j0.4@3.0.0: {} totalist@3.0.1: {} @@ -37526,7 +37995,7 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 optionalDependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.9 db0: 0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)) ioredis: 5.10.1 @@ -37541,10 +38010,25 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 optionalDependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.9 db0: 0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@24.3.0)) ioredis: 5.10.1 + unstorage@1.17.5(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)))(ioredis@5.10.1): + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.3.5 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + optionalDependencies: + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) + db0: 0.3.4(@electric-sql/pglite@0.5.8)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.6.1)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7))(mysql2@3.22.3(@types/node@22.19.1)) + ioredis: 5.10.1 + untildify@4.0.0: {} untun@0.1.3: @@ -37807,7 +38291,7 @@ snapshots: vite-plugin-inspect@11.3.3(@nuxt/kit@4.4.2(magicast@0.5.2))(vite@8.1.4(@types/node@22.19.1)(esbuild@0.28.1)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)): dependencies: ansis: 4.3.0 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.3(supports-color@11.0.0) error-stack-parser-es: 1.0.5 ohash: 2.0.11 open: 10.2.0 @@ -38244,17 +38728,6 @@ snapshots: dependencies: xml-name-validator: 4.0.0 - waddler@0.1.1(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@22.19.1))(pg@8.22.0)(postgres@3.4.7): - optionalDependencies: - '@cloudflare/workers-types': 4.20260511.1 - '@electric-sql/pglite': 0.5.8 - '@neondatabase/serverless': 1.1.0 - better-sqlite3: 12.9.0 - bun-types: 1.3.3 - mysql2: 3.22.3(@types/node@22.19.1) - pg: 8.22.0 - postgres: 3.4.7 - waddler@0.1.1(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(better-sqlite3@12.9.0)(bun-types@1.3.3)(mysql2@3.22.3(@types/node@24.3.0))(pg@8.22.0)(postgres@3.4.7): optionalDependencies: '@cloudflare/workers-types': 4.20260511.1 @@ -38662,6 +39135,12 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 + zip-stream@7.0.5: + dependencies: + compress-commons: 7.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + zod-metadata@1.1.2(zod@3.25.76): dependencies: zod: 3.25.76 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f414b1210..c701c71b9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -80,6 +80,7 @@ catalog: "@multiformats/base-x": ^4.0.1 "@nestjs/common": ^11.0.1 "@netlify/async-workloads": ^0.0.106 + "@netlify/blobs": 11.0.3 "@netlify/database": ^1.1.0 "@nuxt/kit": ^4.4.2 "@nuxt/schema": ^4.4.2 @@ -107,7 +108,7 @@ catalog: "@types/express": ^4.0.0 "@types/koa": ^2.15.0 "@types/node": ^22.17.0 - netlify-cli: ^26.2.0 + netlify-cli: ^27.4.2 astro: ^7.0.0 amqplib: ^0.10.9 asn1js: ^3.0.10