From 58765c833772aed3d9309074f2cecea8b14e7218 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Sun, 30 Aug 2026 15:45:17 +0900 Subject: [PATCH 01/22] Add @netlify/blob as a dependency --- deno.lock | 193 +++++++++++++++++++++++++++++----- packages/netlify/deno.json | 1 + packages/netlify/package.json | 1 + pnpm-lock.yaml | 168 +++++++++++++++++++++++++++++ pnpm-workspace.yaml | 4 + 5 files changed, 341 insertions(+), 26 deletions(-) diff --git a/deno.lock b/deno.lock index 1290bf2b3..c734ab9d1 100644 --- a/deno.lock +++ b/deno.lock @@ -73,12 +73,12 @@ "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.2_@netlify+blobs@11.0.2", "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.2_@netlify+blobs@11.0.2", "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 +90,23 @@ "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/blobs@^11.0.1": "11.0.2", "npm:@netlify/database@^1.1.0": "1.1.0_@electric-sql+pglite@0.5.8", "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.2_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 +123,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.2", "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", @@ -602,7 +603,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.2_@netlify+blobs@11.0.2": { "integrity": "sha512-/ijULxT+A5Cm8wSwWZ2vgqfim1b05D6B8n/a9l6MMA4FCotIH73g7fL7y76XojKXpTe75FVvQH92OxsMqea9kQ==", "dependencies": [ "@astrojs/internal-helpers", @@ -980,7 +981,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 +1050,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.2_@netlify+blobs@11.0.2": { "integrity": "sha512-zltNm5I7MME7Udb5TtAGIfLrfOHiuDG1FrKWDqYbFQ+AurmwxHvfwVCca4f+jfGQY3DnwYLDvb0tnmeI8aUWfg==", "dependencies": [ "@opentelemetry/api", @@ -3652,6 +3653,14 @@ "@netlify/runtime-utils@2.2.0" ] }, + "@netlify/blobs@11.0.2": { + "integrity": "sha512-raH28PHHQ1OPAYBCkE+DOnUTS/1nYFTRiFhvO6kuowkdhPiOsvX3XR/IjhePhP8aUsH5quBwcqQ3GaOgnIwmEw==", + "dependencies": [ + "@netlify/dev-utils@6.0.1", + "@netlify/otel", + "@netlify/runtime-utils@3.0.0" + ] + }, "@netlify/blobs@8.2.0": { "integrity": "sha512-9djLZHBKsoKk8XCgwWSEPK9QnT8qqxEQGuYh48gFIcNLvpBKkLnHbDZuyUxmNemCfDz7h0HnMXgSPnnUVgARhg==" }, @@ -3930,6 +3939,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 +4027,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==" }, @@ -4014,6 +4049,9 @@ "@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==", "dependencies": [ @@ -4523,15 +4561,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 +4590,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 +4619,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 +5518,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.2_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 +6420,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.2_@netlify+blobs@11.0.2": { "integrity": "sha512-pH/KIVBvBt7z7cXrUH/9uaqcdxjegFC7+zvkZkdOyWzs+kQD5KPf3cl8kC+5ayzXHT+OMlhGhyitytqN3cGmHg==", "dependencies": [ "@babel/parser@7.29.7", @@ -6348,7 +6435,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.2_@netlify+blobs@11.0.2": { "integrity": "sha512-0BsG95qac3dkhfdRZxqzqYWJE4NvPL7ILlV43B6K6ho1etXWB2e5b0IxsUAUbyqpqiXM7mSRivojuXjb2G4OsQ==", "dependencies": [ "@vinxi/plugin-directives", @@ -6499,6 +6586,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 +6898,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.2": { "integrity": "sha512-WB5pA4LLQnmqjBh6EIu0z8aUV4q2/AoThgSZq57Rsp+oqqvPu7OwZ5eF+W4ku20TUTxIhiJW8dccuGvJPiW2UA==", "dependencies": [ "@astrojs/compiler-rs", @@ -6896,6 +6993,13 @@ "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": [ @@ -7446,6 +7550,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==" }, @@ -9204,6 +9311,7 @@ "natural-compare", "optionator" ], + "deprecated": true, "bin": true }, "esm-env@1.2.2": { @@ -10633,6 +10741,14 @@ "import-from@4.0.0": { "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==" }, + "import-in-the-middle@3.3.3": { + "integrity": "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA==", + "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 +12440,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 +12558,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.2": { "integrity": "sha512-C8vO7RxkU0AQ3HbYUumuG6MVM5JjRaBchke/rYFOp3EvrLtTBHZYhDVGECdpa27vNuOYRzm3GtQMn2YDOjDJLA==", "dependencies": [ "@cloudflare/kv-asset-handler@0.4.2", @@ -13867,6 +13986,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 +14977,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 +15810,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.2_ioredis@5.10.1": { "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", "dependencies": [ + "@netlify/blobs@11.0.2", "anymatch", "chokidar@5.0.0", "db0", @@ -15690,6 +15826,7 @@ "ufo" ], "optionalPeers": [ + "@netlify/blobs@11.0.2", "db0", "ioredis" ] @@ -15846,7 +15983,7 @@ "vfile-message" ] }, - "vinxi@0.5.11_@electric-sql+pglite@0.5.8": { + "vinxi@0.5.11_@netlify+blobs@11.0.2": { "integrity": "sha512-82Qm+EG/b2PRFBvXBbz1lgWBGcd9totIL6SJhnrZYfakjloTVG9+5l6gfO6dbCCtztm5pqWFzLY0qpZ3H3ww/w==", "dependencies": [ "@babel/plugin-syntax-jsx@7.28.6_@babel+core@7.29.7", @@ -16088,6 +16225,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,6 +16889,7 @@ "packages/netlify": { "dependencies": [ "npm:@netlify/async-workloads@^0.0.106", + "npm:@netlify/blobs@^11.0.1", "npm:@netlify/database@^1.1.0", "npm:postgres@^3.4.7" ] diff --git a/packages/netlify/deno.json b/packages/netlify/deno.json index a2805d55b..9ab87cb1d 100644 --- a/packages/netlify/deno.json +++ b/packages/netlify/deno.json @@ -5,6 +5,7 @@ "imports": { "@netlify/database": "npm:@netlify/database@^1.1.0", "@netlify/async-workloads": "npm:@netlify/async-workloads@^0.0.106", + "@netlify/blobs": "npm:@netlify/blobs@^11.0.1", "postgres": "npm:postgres@^3.4.7" }, "exports": { diff --git a/packages/netlify/package.json b/packages/netlify/package.json index 16b0a1199..c99848efb 100644 --- a/packages/netlify/package.json +++ b/packages/netlify/package.json @@ -58,6 +58,7 @@ "@js-temporal/polyfill": "catalog:", "@netlify/database": "catalog:", "@standard-schema/spec": "catalog:", + "@netlify/blobs": "catalog:", "@types/node": "catalog:", "netlify-cli": "catalog:", "postgres": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be4f9f20c..40f647aeb 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.1 + version: 11.0.2 '@netlify/database': specifier: ^1.1.0 version: 1.1.0 @@ -1660,6 +1663,9 @@ importers: '@js-temporal/polyfill': specifier: 'catalog:' version: 0.5.1 + '@netlify/blobs': + specifier: 'catalog:' + version: 11.0.2 '@netlify/database': 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) @@ -5027,6 +5033,10 @@ packages: resolution: {integrity: sha512-NEM8aNAMZCCWBWymomMM/fn5wmPGyGE8pendgsSu5mL7UNz+aXqGcHS0MiHWU/osyg+geiZuS+Rx956SVrMM/w==} engines: {node: ^14.16.0 || >=16.0.0} + '@netlify/blobs@11.0.2': + resolution: {integrity: sha512-raH28PHHQ1OPAYBCkE+DOnUTS/1nYFTRiFhvO6kuowkdhPiOsvX3XR/IjhePhP8aUsH5quBwcqQ3GaOgnIwmEw==} + engines: {node: '>=22.12.0'} + '@netlify/blobs@8.2.0': resolution: {integrity: sha512-9djLZHBKsoKk8XCgwWSEPK9QnT8qqxEQGuYh48gFIcNLvpBKkLnHbDZuyUxmNemCfDz7h0HnMXgSPnnUVgARhg==} engines: {node: ^14.16.0 || >=16.0.0} @@ -5110,6 +5120,10 @@ 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'} @@ -5292,6 +5306,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} @@ -5324,6 +5342,10 @@ 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'} @@ -5804,6 +5826,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'} @@ -5836,6 +5862,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 +5886,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 +6126,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 +6190,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 +6238,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 +6256,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 +6274,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'} @@ -9006,6 +9074,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'} @@ -20912,6 +20984,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@netlify/blobs@11.0.2': + dependencies: + '@netlify/dev-utils': 6.0.1 + '@netlify/otel': 7.0.2 + '@netlify/runtime-utils': 3.0.0 + transitivePeerDependencies: + - supports-color + '@netlify/blobs@8.2.0': {} '@netlify/blobs@9.1.2': @@ -21559,7 +21639,25 @@ snapshots: semver: 7.8.0 tmp-promise: 3.0.3 +<<<<<<< HEAD '@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)': +======= + '@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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)': +>>>>>>> 7e7e269b (Add @netlify/blob as a dependency) dependencies: '@netlify/ai': 0.4.2 '@netlify/blobs': 10.7.9(supports-color@10.2.2) @@ -21958,6 +22056,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@netlify/otel@7.0.2': + 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) + '@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': @@ -21987,6 +22095,8 @@ 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) @@ -23159,6 +23269,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 @@ -23185,6 +23299,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 +23320,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 @@ -23548,6 +23671,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@opentelemetry/instrumentation@0.221.0(@opentelemetry/api@1.9.1)': + 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@10.2.2) + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23627,6 +23759,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 +23839,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 +23868,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 +23889,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': {} @@ -27003,6 +27163,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 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f414b1210..2bcae8e8f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -73,6 +73,10 @@ catalog: "@astrojs/netlify": ^6.6.5 "@cloudflare/workers-types": ^4.20260511.1 "@electric-sql/pglite": ^0.5.8 + "@netlify/database": ^1.1.0 + netlify-cli: ^26.2.0 + "@netlify/async-workloads": ^0.0.106 + "@netlify/blobs": "^11.0.1" "@fxts/core": ^1.21.1 "@js-temporal/polyfill": ^0.5.1 "@logtape/file": ^2.2.0 From 64dc9949de10529c26031246d6c403288910ac09 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Sun, 30 Aug 2026 22:44:09 +0900 Subject: [PATCH 02/22] Add basic functions for kv with netlify blob --- packages/netlify/src/kv.ts | 82 +++++++++++++++++++++++++++++++++++++ packages/netlify/src/mod.ts | 11 ++--- 2 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 packages/netlify/src/kv.ts diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts new file mode 100644 index 000000000..075422cc0 --- /dev/null +++ b/packages/netlify/src/kv.ts @@ -0,0 +1,82 @@ +import type { + KvKey, + KvStore, + KvStoreListEntry, + KvStoreSetOptions, +} from "@fedify/fedify"; +import type { Store } from "@netlify/blobs"; + +export class NetlifyBlobsKvStore implements KvStore { + readonly #store: Store; + + constructor(store: Store) { + this.#store = store; + } + + private serializeKey(key: KvKey): string { + return JSON.stringify(key); + } + + private deserializeKey(key: string): KvKey { + return JSON.parse(key) as KvKey; + } + + async get(key: KvKey): Promise { + const result = await this.#store.getWithMetadata(this.serializeKey(key), { + type: "json", + }); + + if (result === null) return undefined; + + const expiresIn = result.metadata.expiresIn; + + if ( + typeof expiresIn === "number" && + expiresIn <= Temporal.Now.instant().epochMilliseconds + ) { + return undefined; + } + return result.data as T; + } + + async set( + key: KvKey, + value: unknown, + options?: KvStoreSetOptions | undefined, + ): Promise { + const expiresIn = options?.ttl == null + ? null + : Temporal.Now.instant().epochMilliseconds + + options.ttl.total("millisecond"); + + await this.#store.setJSON(this.serializeKey(key), value, { + metadata: { "expiresIn": expiresIn }, + }); + } + + delete(key: KvKey): Promise { + return this.#store.delete(this.serializeKey(key)); + } + + async *list(prefix?: KvKey): AsyncIterable { + const serializedPrefix = prefix ? `${this.serializeKey(prefix)}` : ""; + + const pages = this.#store.list({ + paginate: true, + prefix: serializedPrefix, + }); + 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, + }; + } + } + } +} diff --git a/packages/netlify/src/mod.ts b/packages/netlify/src/mod.ts index 809b921a9..89e5af7bc 100644 --- a/packages/netlify/src/mod.ts +++ b/packages/netlify/src/mod.ts @@ -6,15 +6,16 @@ * @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"; From 336c8cac14b3cafe26fae6a9db9518050c6b8bc2 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Tue, 1 Sep 2026 14:35:05 +0900 Subject: [PATCH 03/22] Add Netlify Blobs-backed kv store comments --- packages/netlify/src/kv.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts index 075422cc0..c5ab02b8b 100644 --- a/packages/netlify/src/kv.ts +++ b/packages/netlify/src/kv.ts @@ -1,14 +1,23 @@ import type { - KvKey, - KvStore, - KvStoreListEntry, - KvStoreSetOptions, -} from "@fedify/fedify"; + KvKey, + KvStore, + KvStoreListEntry, + KvStoreSetOptions, +} from "@fedify/fedify/federation"; import type { Store } from "@netlify/blobs"; +/** + * A key-value store that uses Netlify Blobs. + * + * @since 2.4.0 + */ export class NetlifyBlobsKvStore implements KvStore { readonly #store: Store; + /** + * Creates a new Netlify Blobs-backed key-value store. + * @param store The Netlify Blobs store to use. + */ constructor(store: Store) { this.#store = store; } From 34da98f2ef034bdab22da8715072c6f6e396e901 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 2 Sep 2026 16:46:13 +0900 Subject: [PATCH 04/22] Add cas function and inherit doc comments --- packages/netlify/src/kv.ts | 98 +++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 12 deletions(-) diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts index c5ab02b8b..3e13b8a53 100644 --- a/packages/netlify/src/kv.ts +++ b/packages/netlify/src/kv.ts @@ -1,23 +1,24 @@ import type { - KvKey, - KvStore, - KvStoreListEntry, - KvStoreSetOptions, + KvKey, + KvStore, + KvStoreListEntry, + KvStoreSetOptions, } from "@fedify/fedify/federation"; import type { Store } from "@netlify/blobs"; +import { isEqual } from "es-toolkit"; /** * A key-value store that uses Netlify Blobs. - * + * * @since 2.4.0 */ export class NetlifyBlobsKvStore implements KvStore { readonly #store: Store; - /** + /** * Creates a new Netlify Blobs-backed key-value store. * @param store The Netlify Blobs store to use. - */ + */ constructor(store: Store) { this.#store = store; } @@ -30,6 +31,9 @@ export class NetlifyBlobsKvStore implements KvStore { return JSON.parse(key) as KvKey; } + /** + * {@inheritDoc KvStore.get} + */ async get(key: KvKey): Promise { const result = await this.#store.getWithMetadata(this.serializeKey(key), { type: "json", @@ -37,36 +41,45 @@ export class NetlifyBlobsKvStore implements KvStore { if (result === null) return undefined; - const expiresIn = result.metadata.expiresIn; + const expireIn = result.metadata.expiresIn; if ( - typeof expiresIn === "number" && - expiresIn <= Temporal.Now.instant().epochMilliseconds + typeof expireIn === "number" && + expireIn <= Temporal.Now.instant().epochMilliseconds ) { return undefined; } return result.data as T; } + /** + * {@inheritDoc KvStore.set} + */ async set( key: KvKey, value: unknown, options?: KvStoreSetOptions | undefined, ): Promise { - const expiresIn = options?.ttl == null + const expireIn = options?.ttl == null ? null : Temporal.Now.instant().epochMilliseconds + options.ttl.total("millisecond"); await this.#store.setJSON(this.serializeKey(key), value, { - metadata: { "expiresIn": expiresIn }, + 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 serializedPrefix = prefix ? `${this.serializeKey(prefix)}` : ""; @@ -88,4 +101,65 @@ export class NetlifyBlobsKvStore implements KvStore { } } } + + /** + * {@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", + }); + + let currentValue; + // Get only valid data from the fetched entry + if (entry === null) { + currentValue = undefined; + } else { + const expiresIn = entry.metadata.expiresIn; + + if ( + typeof expiresIn === "number" && + expiresIn <= Temporal.Now.instant().epochMilliseconds + ) { + currentValue = undefined; + } else { + currentValue = entry.data; + } + } + + if (!isEqual(currentValue ?? undefined, expectedValue)) return false; + + if (entry === null && newValue === undefined) { + return true; + } + + const storedValue = newValue === undefined ? null : newValue; + const serializedKey = this.serializeKey(key); + const metadata = { + "expireIn": options?.ttl == null + ? null + : Temporal.Now.instant().epochMilliseconds + + options.ttl.total("millisecond"), + }; + + const result = entry === null + ? await this.#store.setJSON(serializedKey, storedValue, { + onlyIfNew: true, + metadata: metadata, + }) + : await this.#store.setJSON(serializedKey, storedValue, { + onlyIfMatch: entry.etag, + metadata: metadata, + }); + + if (result.modified) return true; + } + } } From a97c7cc27c7fcc903de2846e150f776de929bf46 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 2 Sep 2026 17:03:20 +0900 Subject: [PATCH 05/22] Fix broken TTL calling --- packages/netlify/src/kv.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts index 3e13b8a53..af67e74d3 100644 --- a/packages/netlify/src/kv.ts +++ b/packages/netlify/src/kv.ts @@ -41,7 +41,7 @@ export class NetlifyBlobsKvStore implements KvStore { if (result === null) return undefined; - const expireIn = result.metadata.expiresIn; + const expireIn = result.metadata.expireIn; if ( typeof expireIn === "number" && @@ -122,11 +122,11 @@ export class NetlifyBlobsKvStore implements KvStore { if (entry === null) { currentValue = undefined; } else { - const expiresIn = entry.metadata.expiresIn; + const expireIn = entry.metadata.expireIn; if ( - typeof expiresIn === "number" && - expiresIn <= Temporal.Now.instant().epochMilliseconds + typeof expireIn === "number" && + expireIn <= Temporal.Now.instant().epochMilliseconds ) { currentValue = undefined; } else { From 16e24edee7eb05a29289ad99e9937f8efacba982 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 2 Sep 2026 17:28:41 +0900 Subject: [PATCH 06/22] Fix Netlify blob key encoding Derive listing prefixes from JSON-encoded tuple keys so exact keys and descendants are returned without partial-component matches. Reject keys that exceed Netlify Blobs' 600-byte UTF-8 limit and cover the behavior with portable tests. https://github.com/fedify-dev/fedify/issues/1010 Assisted-by: Codex:gpt-5.6-sol --- packages/netlify/src/kv.ts | 19 +++-- packages/netlify/test/kv.test.ts | 117 +++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 packages/netlify/test/kv.test.ts diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts index af67e74d3..663002a79 100644 --- a/packages/netlify/src/kv.ts +++ b/packages/netlify/src/kv.ts @@ -7,6 +7,8 @@ import type { import type { Store } from "@netlify/blobs"; import { isEqual } from "es-toolkit"; +const MAX_BLOB_KEY_BYTES = 600; + /** * A key-value store that uses Netlify Blobs. * @@ -24,13 +26,24 @@ export class NetlifyBlobsKvStore implements KvStore { } private serializeKey(key: KvKey): string { - return JSON.stringify(key); + const serialized = JSON.stringify(key); + 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 { return JSON.parse(key) as KvKey; } + private serializePrefix(prefix?: KvKey): string { + if (prefix == null) return "["; + return this.serializeKey(prefix).slice(0, -1); + } + /** * {@inheritDoc KvStore.get} */ @@ -81,11 +94,9 @@ export class NetlifyBlobsKvStore implements KvStore { * {@inheritDoc KvStore.list} */ async *list(prefix?: KvKey): AsyncIterable { - const serializedPrefix = prefix ? `${this.serializeKey(prefix)}` : ""; - const pages = this.#store.list({ paginate: true, - prefix: serializedPrefix, + prefix: this.serializePrefix(prefix), }); for await (const page of pages) { for (const blob of page.blobs) { diff --git a/packages/netlify/test/kv.test.ts b/packages/netlify/test/kv.test.ts new file mode 100644 index 000000000..d87dcd048 --- /dev/null +++ b/packages/netlify/test/kv.test.ts @@ -0,0 +1,117 @@ +import { deepStrictEqual, rejects } from "node:assert/strict"; +import { describe, it } from "node:test"; +import type { KvKey } from "@fedify/fedify/federation"; +import type { Store } from "@netlify/blobs"; +import { NetlifyBlobsKvStore } from "../src/kv.ts"; + +interface Entry { + readonly data: unknown; + readonly etag: string; + readonly metadata: Record; +} + +class MockStore { + readonly entries = new Map(); + readonly listPrefixes: string[] = []; + #version = 0; + + getWithMetadata(key: string): Promise { + return Promise.resolve(this.entries.get(key) ?? null); + } + + setJSON( + key: string, + data: unknown, + options: { metadata?: Record } = {}, + ): Promise<{ etag: string; modified: true }> { + 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.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 as unknown as Store); +} + +async function collect( + entries: AsyncIterable<{ key: KvKey; value: unknown }>, +) { + return await Array.fromAsync(entries); +} + +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, ["["]); + }); + + 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, [ + '["actor"', + '["actor","alice"', + ]); + }); + + it("rejects encoded keys longer than 600 UTF-8 bytes", async () => { + const kv = createKv(new MockStore()); + + await rejects( + kv.set(["한".repeat(200)], "too long"), + new RangeError( + "The encoded key exceeds Netlify Blobs' 600-byte key limit.", + ), + ); + }); +}); From 49f002aaae17ba873f6f3c5e8ff5a99ec7f483e8 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 2 Sep 2026 19:32:35 +0900 Subject: [PATCH 07/22] Add tombstones to Netlify blob CAS Represent conditional deletion with an ETag-guarded metadata tombstone. Treat tombstones and expired blobs as absent while preserving stored null values, and cover deletion through get and list with a focused test. https://github.com/fedify-dev/fedify/issues/1010 Assisted-by: Codex:gpt-5.6-sol --- packages/netlify/src/kv.ts | 63 ++++++++++++++++---------------- packages/netlify/test/kv.test.ts | 18 +++++++++ 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts index 663002a79..7dd596d9c 100644 --- a/packages/netlify/src/kv.ts +++ b/packages/netlify/src/kv.ts @@ -44,6 +44,20 @@ export class NetlifyBlobsKvStore implements KvStore { return this.serializeKey(prefix).slice(0, -1); } + 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} */ @@ -52,16 +66,7 @@ export class NetlifyBlobsKvStore implements KvStore { type: "json", }); - if (result === null) return undefined; - - const expireIn = result.metadata.expireIn; - - if ( - typeof expireIn === "number" && - expireIn <= Temporal.Now.instant().epochMilliseconds - ) { - return undefined; - } + if (result === null || this.isAbsent(result.metadata)) return undefined; return result.data as T; } @@ -128,31 +133,27 @@ export class NetlifyBlobsKvStore implements KvStore { type: "json", }); - let currentValue; - // Get only valid data from the fetched entry - if (entry === null) { - currentValue = undefined; - } else { - const expireIn = entry.metadata.expireIn; - - if ( - typeof expireIn === "number" && - expireIn <= Temporal.Now.instant().epochMilliseconds - ) { - currentValue = undefined; - } else { - currentValue = entry.data; - } - } + const currentValue = entry === null || this.isAbsent(entry.metadata) + ? undefined + : entry.data; - if (!isEqual(currentValue ?? undefined, expectedValue)) return false; + if (!isEqual(currentValue, expectedValue)) return false; if (entry === null && newValue === undefined) { return true; } - const storedValue = newValue === undefined ? null : newValue; 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 @@ -161,12 +162,12 @@ export class NetlifyBlobsKvStore implements KvStore { }; const result = entry === null - ? await this.#store.setJSON(serializedKey, storedValue, { + ? await this.#store.setJSON(serializedKey, newValue, { onlyIfNew: true, metadata: metadata, }) - : await this.#store.setJSON(serializedKey, storedValue, { - onlyIfMatch: entry.etag, + : await this.#store.setJSON(serializedKey, newValue, { + onlyIfMatch: this.getEtag(entry), metadata: metadata, }); diff --git a/packages/netlify/test/kv.test.ts b/packages/netlify/test/kv.test.ts index d87dcd048..8028c310c 100644 --- a/packages/netlify/test/kv.test.ts +++ b/packages/netlify/test/kv.test.ts @@ -115,3 +115,21 @@ describe("NetlifyBlobsKvStore key encoding", () => { ); }); }); + +describe("NetlifyBlobsKvStore.cas()", () => { + 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('["deleted"]')?.data, null); + deepStrictEqual( + store.entries.get('["deleted"]')?.metadata, + { tombstone: true }, + ); + }); +}); From 3c804c32570cb5cd71572408985cd8baaf4a6d32 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 2 Sep 2026 23:57:28 +0900 Subject: [PATCH 08/22] Expand Netlify blob KV coverage Model Netlify's conditional writes in the unit-test store and cover JSON reads, TTL handling, key boundaries, tombstones, ETag conflicts, and concurrent compare-and-swap operations. These cases protect the adapter's absence semantics and atomicity guarantees. https://github.com/fedify-dev/fedify/issues/1010 Assisted-by: Codex:gpt-5.6-sol --- packages/netlify/test/kv.test.ts | 323 ++++++++++++++++++++++++++++++- 1 file changed, 314 insertions(+), 9 deletions(-) diff --git a/packages/netlify/test/kv.test.ts b/packages/netlify/test/kv.test.ts index 8028c310c..e4fb7b302 100644 --- a/packages/netlify/test/kv.test.ts +++ b/packages/netlify/test/kv.test.ts @@ -1,29 +1,66 @@ -import { deepStrictEqual, rejects } from "node:assert/strict"; +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 type { Store } from "@netlify/blobs"; +import type { SetOptions, Store } from "@netlify/blobs"; import { NetlifyBlobsKvStore } from "../src/kv.ts"; interface Entry { readonly data: unknown; - readonly etag: string; + 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): Promise { + 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: { metadata?: Record } = {}, - ): Promise<{ etag: string; modified: true }> { + 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}`, @@ -34,6 +71,7 @@ class MockStore { } delete(key: string): Promise { + this.deleteCalls.push(key); this.entries.delete(key); return Promise.resolve(); } @@ -43,7 +81,7 @@ class MockStore { this.listPrefixes.push(prefix); const blobs = [...this.entries] .filter(([key]) => key.startsWith(prefix)) - .map(([key, entry]) => ({ key, etag: entry.etag })); + .map(([key, entry]) => ({ key, etag: entry.etag ?? "" })); for (const blob of blobs) { yield { blobs: [blob], directories: [] }; } @@ -60,6 +98,76 @@ async function collect( 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, ['["delete"]', '["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('["future"]')?.metadata.expireIn; + ok(typeof expires === "number"); + ok(expires >= before + 1_000); + + store.entries.set('["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('["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(); @@ -104,19 +212,87 @@ describe("NetlifyBlobsKvStore key encoding", () => { ]); }); - it("rejects encoded keys longer than 600 UTF-8 bytes", async () => { + it("enforces the 600-byte UTF-8 key limit", async () => { const kv = createKv(new MockStore()); + await kv.set(["a".repeat(596)], "exactly 600 bytes"); + deepStrictEqual( + await kv.get(["a".repeat(596)]), + "exactly 600 bytes", + ); + await rejects( - kv.set(["한".repeat(200)], "too long"), + kv.set(["a".repeat(597)], "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('["listed","expired"]', { + data: "expired", + etag: "expired", + metadata: { expireIn: Date.now() - 1 }, + }); + store.entries.set('["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('["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); @@ -132,4 +308,133 @@ describe("NetlifyBlobsKvStore.cas()", () => { { 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('["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('["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('["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('["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('["missing-etag"]', { + data: "old", + metadata: {}, + }); + + await rejects( + kv.cas(["missing-etag"], "old", "new"), + new Error("Netlify Blobs did not return an ETag."), + ); + }); }); From 11cd813e6aa3d303b7989839a87b255a86b7dd2d Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Thu, 3 Sep 2026 18:43:36 +0900 Subject: [PATCH 09/22] Use Blob KV in Netlify Dev fixture Replace the PostgreSQL store in the existing Netlify Dev fixture so its queue integration coverage exercises the database-free Netlify setup. Remove dependencies that were only needed by the PostgreSQL fixture and allow enough startup time for Netlify Dev to install extensions. https://github.com/fedify-dev/fedify/issues/1010 Changelog: none Assisted-by: Codex:gpt-5.6-sol --- deno.lock | 86 +++---------- packages/netlify/deno.json | 4 +- .../netlify-dev/netlify/lib/runtime.ts | 17 +-- packages/netlify/package.json | 3 - .../netlify/test/integration/netlify.test.ts | 4 +- pnpm-lock.yaml | 113 ++++++------------ 6 files changed, 61 insertions(+), 166 deletions(-) diff --git a/deno.lock b/deno.lock index c734ab9d1..7758bbf3e 100644 --- a/deno.lock +++ b/deno.lock @@ -91,7 +91,10 @@ "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/blobs@^11.0.1": "11.0.2", +<<<<<<< HEAD "npm:@netlify/database@^1.1.0": "1.1.0_@electric-sql+pglite@0.5.8", +======= +>>>>>>> fae6a8d2 (Use Blob KV in Netlify Dev fixture) "npm:@nuxt/kit@4": "4.4.2", "npm:@nuxt/schema@4": "4.4.2", "npm:@opentelemetry/api@^1.9.0": "1.9.1", @@ -3603,9 +3606,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": [ @@ -4046,9 +4046,6 @@ "@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==" }, @@ -13258,53 +13255,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==" }, @@ -13474,21 +13424,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==" }, @@ -16160,6 +16095,7 @@ "xml-name-validator" ] }, +<<<<<<< HEAD "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": [ @@ -16177,6 +16113,8 @@ "postgres" ] }, +======= +>>>>>>> fae6a8d2 (Use Blob KV in Netlify Dev fixture) "wasm-feature-detect@1.8.0": { "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==" }, @@ -16638,6 +16576,14 @@ "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" } }, + "remote": { + "https://edge.netlify.com/": "fd941d61d88673d5f28aab283fb86fcc50f08a3bc80ee5470498fcfa88c65cfb", + "https://edge.netlify.com/bootstrap/config.ts": "6a2ce0e544e15e8f8883a5c18da5948e37fd0f2619f68cb31f3af53c51817025", + "https://edge.netlify.com/bootstrap/context.ts": "e97240232121e2f369f6546ce961490f34d961ea1ea54be3ff09633e3f08373f", + "https://edge.netlify.com/bootstrap/cookie.ts": "8b0baae708989ca183c6f3b4ab3d029e6abcbc2e43f93edeb0ff447b3bbc3a05", + "https://edge.netlify.com/bootstrap/edge_function.ts": "b8253e86aa83c67341f5cfedeba5049d77fbf84dcab7eceff7566b7728ae9b39", + "https://edge.netlify.com/bootstrap/globals/types.ts": "eaa6148ded3121d8dee62dd91c86e7fe76601df0f3ca8d7962243a30f4c8935f" + }, "workspace": { "dependencies": [ "jsr:@david/dax@~0.46.1", @@ -16889,9 +16835,7 @@ "packages/netlify": { "dependencies": [ "npm:@netlify/async-workloads@^0.0.106", - "npm:@netlify/blobs@^11.0.1", - "npm:@netlify/database@^1.1.0", - "npm:postgres@^3.4.7" + "npm:@netlify/blobs@^11.0.1" ] }, "packages/nuxt": { diff --git a/packages/netlify/deno.json b/packages/netlify/deno.json index 9ab87cb1d..109826cc6 100644 --- a/packages/netlify/deno.json +++ b/packages/netlify/deno.json @@ -3,10 +3,8 @@ "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", - "@netlify/blobs": "npm:@netlify/blobs@^11.0.1", - "postgres": "npm:postgres@^3.4.7" + "@netlify/blobs": "npm:@netlify/blobs@^11.0.1" }, "exports": { ".": "./src/mod.ts" 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/package.json b/packages/netlify/package.json index c99848efb..7ec270937 100644 --- a/packages/netlify/package.json +++ b/packages/netlify/package.json @@ -54,14 +54,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/test/integration/netlify.test.ts b/packages/netlify/test/integration/netlify.test.ts index db611a315..7ac4d6b8f 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) { @@ -134,7 +134,7 @@ 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 }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40f647aeb..e94b2d488 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1657,9 +1657,6 @@ importers: specifier: 'catalog:' version: 1.0.1 devDependencies: - '@fedify/postgres': - specifier: workspace:^ - version: link:../postgres '@js-temporal/polyfill': specifier: 'catalog:' version: 0.5.1 @@ -21639,25 +21636,7 @@ snapshots: semver: 7.8.0 tmp-promise: 3.0.3 -<<<<<<< HEAD '@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)': -======= - '@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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)': ->>>>>>> 7e7e269b (Add @netlify/blob as a dependency) dependencies: '@netlify/ai': 0.4.2 '@netlify/blobs': 10.7.9(supports-color@10.2.2) @@ -22217,7 +22196,7 @@ snapshots: - supports-color - ts-node - '@netlify/sdk@1.67.0(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': + '@netlify/sdk@1.67.0(debug@4.4.1)(graphql@16.14.2)': dependencies: '@commander-js/extra-typings': 12.1.0(commander@12.1.0) '@graphql-tools/stitch': 9.4.29(graphql@16.14.2) @@ -22257,19 +22236,15 @@ snapshots: zod-to-json-schema: 3.25.2(zod@3.25.76) zod-validation-error: 2.1.0(zod@3.25.76) transitivePeerDependencies: - - '@types/react' - bare-abort-controller - bare-buffer - - bufferutil - - canvas - debug - encoding - graphql - react-native-b4a - supports-color - - utf-8-validate - '@netlify/sdk@1.67.0(@types/react@19.1.8)(graphql@16.14.2)': + '@netlify/sdk@1.67.0(graphql@16.14.2)': dependencies: '@commander-js/extra-typings': 12.1.0(commander@12.1.0) '@graphql-tools/stitch': 9.4.29(graphql@16.14.2) @@ -22309,17 +22284,13 @@ snapshots: zod-to-json-schema: 3.25.2(zod@3.25.76) zod-validation-error: 2.1.0(zod@3.25.76) transitivePeerDependencies: - - '@types/react' - bare-abort-controller - bare-buffer - - bufferutil - - canvas - debug - encoding - graphql - react-native-b4a - supports-color - - utf-8-validate '@netlify/sdk@2.26.3(@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: @@ -24979,7 +24950,7 @@ snapshots: '@stackbit/cms-contentful@0.4.56': dependencies: '@contentful/rich-text-types': 15.15.1 - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 contentful: 9.3.7 @@ -24996,7 +24967,7 @@ snapshots: '@stackbit/cms-contentful@0.4.56(debug@4.4.1)(graphql@16.14.2)': dependencies: '@contentful/rich-text-types': 15.15.1 - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 contentful: 9.3.7(debug@4.4.1) @@ -25011,12 +24982,12 @@ snapshots: - react-native-b4a - supports-color - '@stackbit/cms-core@2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': + '@stackbit/cms-core@2.0.1(debug@4.4.1)(graphql@16.14.2)': dependencies: '@babel/parser': 7.29.7 '@babel/traverse': 7.29.0 '@iarna/toml': 2.2.5 - '@netlify/sdk': 1.67.0(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@netlify/sdk': 1.67.0(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 @@ -25035,24 +25006,20 @@ snapshots: slugify: 1.6.9 uuid: 9.0.1 transitivePeerDependencies: - - '@types/react' - bare-abort-controller - bare-buffer - - bufferutil - - canvas - debug - encoding - graphql - react-native-b4a - supports-color - - utf-8-validate - '@stackbit/cms-core@2.0.1(@types/react@19.1.8)(graphql@16.14.2)': + '@stackbit/cms-core@2.0.1(graphql@16.14.2)': dependencies: '@babel/parser': 7.29.7 '@babel/traverse': 7.29.0 '@iarna/toml': 2.2.5 - '@netlify/sdk': 1.67.0(@types/react@19.1.8)(graphql@16.14.2) + '@netlify/sdk': 1.67.0(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 @@ -25071,69 +25038,56 @@ snapshots: slugify: 1.6.9 uuid: 9.0.1 transitivePeerDependencies: - - '@types/react' - bare-abort-controller - bare-buffer - - bufferutil - - canvas - debug - encoding - graphql - react-native-b4a - supports-color - - utf-8-validate - '@stackbit/cms-git@0.4.18(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': + '@stackbit/cms-git@0.4.18': dependencies: '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.24.0(debug@4.4.1) + axios: 0.24.0 fs-extra: 11.3.6 git-url-parse: 13.1.1 lodash: 4.18.1 micromatch: 4.0.8 slugify: 1.6.9 transitivePeerDependencies: - - '@types/react' - bare-abort-controller - bare-buffer - - bufferutil - - canvas - debug - encoding - - graphql - react-native-b4a - supports-color - - utf-8-validate - '@stackbit/cms-git@0.4.18(@types/react@19.1.8)(graphql@16.14.2)': + '@stackbit/cms-git@0.4.18(debug@4.4.1)(graphql@16.14.2)': dependencies: '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.24.0 + axios: 0.24.0(debug@4.4.1) fs-extra: 11.3.6 git-url-parse: 13.1.1 lodash: 4.18.1 micromatch: 4.0.8 slugify: 1.6.9 transitivePeerDependencies: - - '@types/react' - bare-abort-controller - bare-buffer - - bufferutil - - canvas - debug - encoding - graphql - react-native-b4a - supports-color - - utf-8-validate '@stackbit/cms-sanity@0.2.56(@types/react@19.1.8)': dependencies: @@ -25141,7 +25095,7 @@ snapshots: '@sanity/client': 3.4.1 '@sanity/schema': 2.36.6 '@sanity/types': 3.99.0(@types/react@19.1.8) - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 fs-extra: 9.1.0 @@ -25168,7 +25122,7 @@ snapshots: '@sanity/client': 3.4.1 '@sanity/schema': 2.36.6 '@sanity/types': 3.99.0(@types/react@19.1.8) - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 fs-extra: 9.1.0 @@ -25190,18 +25144,18 @@ snapshots: - supports-color - utf-8-validate - '@stackbit/dev-common@0.5.51(@types/react@19.1.8)': + '@stackbit/dev-common@0.5.51(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': dependencies: '@iarna/toml': 2.2.5 '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-contentful': 0.4.56 - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(graphql@16.14.2) - '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8) + '@stackbit/cms-contentful': 0.4.56(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.25.0 + axios: 0.25.0(debug@4.4.1) chalk: 4.1.2 configstore: 5.0.1 detect-port: 1.6.1 @@ -25226,22 +25180,23 @@ snapshots: - canvas - debug - encoding + - graphql - react-native-b4a - supports-color - utf-8-validate - '@stackbit/dev-common@0.5.51(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': + '@stackbit/dev-common@0.5.51(@types/react@19.1.8)(graphql@16.14.2)': dependencies: '@iarna/toml': 2.2.5 '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-contentful': 0.4.56(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-contentful': 0.4.56 + '@stackbit/cms-core': 2.0.1(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18 + '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.25.0(debug@4.4.1) + axios: 0.25.0 chalk: 4.1.2 configstore: 5.0.1 detect-port: 1.6.1 @@ -25273,8 +25228,8 @@ snapshots: '@stackbit/dev@1.0.35(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': dependencies: - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18(debug@4.4.1)(graphql@16.14.2) '@stackbit/dev-common': 0.5.51(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 axios: 0.25.0(debug@4.4.1) @@ -25308,9 +25263,9 @@ snapshots: '@stackbit/dev@1.0.35(@types/react@19.1.8)(graphql@16.14.2)': dependencies: - '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(graphql@16.14.2) - '@stackbit/dev-common': 0.5.51(@types/react@19.1.8) + '@stackbit/cms-core': 2.0.1(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18 + '@stackbit/dev-common': 0.5.51(@types/react@19.1.8)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 axios: 0.25.0 chalk: 4.1.2 From b1446f4ce07724aaea5371db3751a2c748834f7b Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 9 Sep 2026 16:21:42 +0900 Subject: [PATCH 10/22] Patch local Netlify Blobs ETags Apply the pending upstream fix to the filesystem-backed Blobs server so GET and HEAD responses include ETags and conditional GETs return 304. Upgrade the Netlify CLI and Blobs SDK, and add local and production reproducers that compare their ETag behavior. https://github.com/fedify-dev/fedify/issues/1010 https://github.com/sij411/primitives/tree/fix/blobs Changelog: none Assisted-by: Codex:gpt-5.6-sol --- deno.lock | 44 +- package.json | 8 + packages/netlify/deno.json | 2 +- .../test/integration/blobs-etag-production.ts | 67 ++ .../test/integration/blobs-etag-repro.ts | 72 ++ patches/@netlify__blobs@11.0.3.patch | 70 ++ pnpm-lock.yaml | 1009 ++++++++++++----- pnpm-workspace.yaml | 4 +- 8 files changed, 952 insertions(+), 324 deletions(-) create mode 100644 packages/netlify/test/integration/blobs-etag-production.ts create mode 100644 packages/netlify/test/integration/blobs-etag-repro.ts create mode 100644 patches/@netlify__blobs@11.0.3.patch diff --git a/deno.lock b/deno.lock index 7758bbf3e..4c4b1bc5c 100644 --- a/deno.lock +++ b/deno.lock @@ -73,7 +73,7 @@ "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__@netlify+blobs@11.0.2_@netlify+blobs@11.0.2", + "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/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", @@ -91,10 +91,7 @@ "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/blobs@^11.0.1": "11.0.2", -<<<<<<< HEAD "npm:@netlify/database@^1.1.0": "1.1.0_@electric-sql+pglite@0.5.8", -======= ->>>>>>> fae6a8d2 (Use Blob KV in Netlify Dev fixture) "npm:@nuxt/kit@4": "4.4.2", "npm:@nuxt/schema@4": "4.4.2", "npm:@opentelemetry/api@^1.9.0": "1.9.1", @@ -109,7 +106,7 @@ "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_@netlify+blobs@11.0.2_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", @@ -126,7 +123,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_@netlify+blobs@11.0.2", + "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", @@ -606,7 +603,7 @@ "satteri" ] }, - "@astrojs/node@11.0.2_astro@7.0.9__@netlify+blobs@11.0.2_@netlify+blobs@11.0.2": { + "@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", @@ -1053,7 +1050,7 @@ "kuler" ] }, - "@deno/astro-adapter@0.6.0_@opentelemetry+api@1.9.1_astro@7.0.9__@netlify+blobs@11.0.2_@netlify+blobs@11.0.2": { + "@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", @@ -3653,8 +3650,8 @@ "@netlify/runtime-utils@2.2.0" ] }, - "@netlify/blobs@11.0.2": { - "integrity": "sha512-raH28PHHQ1OPAYBCkE+DOnUTS/1nYFTRiFhvO6kuowkdhPiOsvX3XR/IjhePhP8aUsH5quBwcqQ3GaOgnIwmEw==", + "@netlify/blobs@11.0.3": { + "integrity": "sha512-Z8IXQtQC8BQjm76i1bN+l12TTyKQ/s1R92Ajhou7+fpP0KSxnJ65QzLEb5WuFuFutn8ORrcd4mlF8A2xhw8dzA==", "dependencies": [ "@netlify/dev-utils@6.0.1", "@netlify/otel", @@ -5515,7 +5512,7 @@ "@socket.io/component-emitter@3.1.2": { "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" }, - "@solidjs/start@1.3.2_@netlify+blobs@11.0.2_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", @@ -6417,7 +6414,7 @@ ], "bin": true }, - "@vinxi/plugin-directives@0.5.1_vinxi@0.5.11__@netlify+blobs@11.0.2_@netlify+blobs@11.0.2": { + "@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", @@ -6432,7 +6429,7 @@ "vinxi" ] }, - "@vinxi/server-components@0.5.1_vinxi@0.5.11__@netlify+blobs@11.0.2_@netlify+blobs@11.0.2": { + "@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", @@ -6895,7 +6892,7 @@ "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", "bin": true }, - "astro@7.0.9_@netlify+blobs@11.0.2": { + "astro@7.0.9_@netlify+blobs@11.0.3": { "integrity": "sha512-WB5pA4LLQnmqjBh6EIu0z8aUV4q2/AoThgSZq57Rsp+oqqvPu7OwZ5eF+W4ku20TUTxIhiJW8dccuGvJPiW2UA==", "dependencies": [ "@astrojs/compiler-rs", @@ -10738,8 +10735,8 @@ "import-from@4.0.0": { "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==" }, - "import-in-the-middle@3.3.3": { - "integrity": "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA==", + "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", @@ -12555,7 +12552,7 @@ "next-tick@1.1.0": { "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, - "nitropack@2.13.3_@netlify+blobs@11.0.2": { + "nitropack@2.13.3_@netlify+blobs@11.0.3": { "integrity": "sha512-C8vO7RxkU0AQ3HbYUumuG6MVM5JjRaBchke/rYFOp3EvrLtTBHZYhDVGECdpa27vNuOYRzm3GtQMn2YDOjDJLA==", "dependencies": [ "@cloudflare/kv-asset-handler@0.4.2", @@ -15745,10 +15742,10 @@ "webpack-virtual-modules" ] }, - "unstorage@1.17.5_@netlify+blobs@11.0.2_ioredis@5.10.1": { + "unstorage@1.17.5_@netlify+blobs@11.0.3_ioredis@5.10.1": { "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", "dependencies": [ - "@netlify/blobs@11.0.2", + "@netlify/blobs@11.0.3", "anymatch", "chokidar@5.0.0", "db0", @@ -15761,7 +15758,7 @@ "ufo" ], "optionalPeers": [ - "@netlify/blobs@11.0.2", + "@netlify/blobs@11.0.3", "db0", "ioredis" ] @@ -15918,7 +15915,7 @@ "vfile-message" ] }, - "vinxi@0.5.11_@netlify+blobs@11.0.2": { + "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", @@ -16095,7 +16092,6 @@ "xml-name-validator" ] }, -<<<<<<< HEAD "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": [ @@ -16113,8 +16109,6 @@ "postgres" ] }, -======= ->>>>>>> fae6a8d2 (Use Blob KV in Netlify Dev fixture) "wasm-feature-detect@1.8.0": { "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==" }, @@ -16835,7 +16829,7 @@ "packages/netlify": { "dependencies": [ "npm:@netlify/async-workloads@^0.0.106", - "npm:@netlify/blobs@^11.0.1" + "npm:@netlify/blobs@^11.0.3" ] }, "packages/nuxt": { 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/deno.json b/packages/netlify/deno.json index 109826cc6..6544e99c9 100644 --- a/packages/netlify/deno.json +++ b/packages/netlify/deno.json @@ -4,7 +4,7 @@ "license": "MIT", "imports": { "@netlify/async-workloads": "npm:@netlify/async-workloads@^0.0.106", - "@netlify/blobs": "npm:@netlify/blobs@^11.0.1" + "@netlify/blobs": "npm:@netlify/blobs@^11.0.3" }, "exports": { ".": "./src/mod.ts" diff --git a/packages/netlify/test/integration/blobs-etag-production.ts b/packages/netlify/test/integration/blobs-etag-production.ts new file mode 100644 index 000000000..0ed3398c6 --- /dev/null +++ b/packages/netlify/test/integration/blobs-etag-production.ts @@ -0,0 +1,67 @@ +import { ok } from "node:assert/strict"; +import { getStore } from "@netlify/blobs"; + +const siteID = process.env.NETLIFY_SITE_ID; +const token = process.env.NETLIFY_AUTH_TOKEN; +if (siteID == null || token == null) { + throw new Error("Missing NETLIFY_SITE_ID or NETLIFY_AUTH_TOKEN."); +} + +const loggingFetch: typeof fetch = async (input, init) => { + const response = await fetch(input, init); + const method = init?.method ?? + (input instanceof Request ? input.method : "GET"); + const requestUrl = new URL( + input instanceof Request ? input.url : input.toString(), + ); + console.log({ + method, + target: requestUrl.hostname === "api.netlify.com" + ? "Netlify API" + : "blob storage", + status: response.status, + etag: response.headers.get("etag"), + }); + return response; +}; + +const store = getStore({ + consistency: "strong", + fetch: loggingFetch, + name: "etag-production-reproduction", + siteID, + token, +}); +const key = `etag-test-${crypto.randomUUID()}`; + +let etags: { + readonly getMetadata: string | null; + readonly getWithMetadata: string | null; + readonly list: string | null; + readonly setJSON: string | null; +}; + +try { + const write = await store.setJSON(key, { value: 1 }); + const read = await store.getWithMetadata(key, { + consistency: "strong", + type: "json", + }); + const metadata = await store.getMetadata(key, { + consistency: "strong", + }); + const list = await store.list({ prefix: key }); + + etags = { + setJSON: write.etag ?? null, + getWithMetadata: read?.etag ?? null, + getMetadata: metadata?.etag ?? null, + list: list.blobs.find((blob) => blob.key === key)?.etag ?? null, + }; +} finally { + await store.delete(key); +} + +console.log(JSON.stringify(etags, null, 2)); +ok(etags.getWithMetadata, "getWithMetadata() did not return an ETag"); +ok(etags.getMetadata, "getMetadata() did not return an ETag"); diff --git a/packages/netlify/test/integration/blobs-etag-repro.ts b/packages/netlify/test/integration/blobs-etag-repro.ts new file mode 100644 index 000000000..64cf54f7c --- /dev/null +++ b/packages/netlify/test/integration/blobs-etag-repro.ts @@ -0,0 +1,72 @@ +import { deepStrictEqual, equal, ok } from "node:assert/strict"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { getStore } from "@netlify/blobs"; +import { BlobsServer } from "@netlify/blobs/server"; + +const directory = await mkdtemp(join(tmpdir(), "netlify-blobs-etag-")); +const token = "test-token"; +const server = new BlobsServer({ directory, token }); +const loggingFetch: typeof fetch = async (input, init) => { + const response = await fetch(input, init); + const method = init?.method ?? + (input instanceof Request ? input.method : "GET"); + const url = input instanceof Request ? input.url : input.toString(); + console.log(method, url, response.status, { + headers: Object.fromEntries(response.headers), + }); + return response; +}; + +let etags: { + readonly getMetadata: string | null; + readonly getWithMetadata: string | null; + readonly list: string | null; + readonly setJSON: string | null; +}; + +try { + const { address } = await server.start(); + const store = getStore({ + apiURL: address, + consistency: "strong", + fetch: loggingFetch, + name: "etag-reproduction", + siteID: "test-site", + token, + }); + const write = await store.setJSON("key", { value: 1 }); + const read = await store.getWithMetadata("key", { + consistency: "strong", + type: "json", + }); + const metadata = await store.getMetadata("key", { + consistency: "strong", + }); + const list = await store.list({ prefix: "key" }); + const unchanged = await store.getWithMetadata("key", { + consistency: "strong", + etag: write.etag, + type: "json", + }); + + etags = { + setJSON: write.etag ?? null, + getWithMetadata: read?.etag ?? null, + getMetadata: metadata?.etag ?? null, + list: list.blobs.find((blob) => blob.key === "key")?.etag ?? null, + }; + + console.log(JSON.stringify(etags, null, 2)); + ok(etags.getWithMetadata, "getWithMetadata() did not return an ETag"); + ok(etags.getMetadata, "getMetadata() did not return an ETag"); + equal(unchanged?.data, null); + equal(unchanged?.etag, write.etag); + deepStrictEqual(read?.data, { value: 1 }); + + console.log(); +} finally { + await server.stop(); + await rm(directory, { recursive: true, force: true }); +} 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 e94b2d488..7e4982cb5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,8 +37,8 @@ catalogs: specifier: ^0.0.106 version: 0.0.106 '@netlify/blobs': - specifier: ^11.0.1 - version: 11.0.2 + specifier: ^11.0.3 + version: 11.0.3 '@netlify/database': specifier: ^1.1.0 version: 1.1.0 @@ -178,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.4.2 next: specifier: '>=15.4.6 <17' version: 16.2.4 @@ -208,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: .: {} @@ -1674,10 +1679,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.4.2(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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)) @@ -3967,8 +3969,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==} @@ -5008,10 +5010,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 @@ -5026,12 +5036,16 @@ packages: resolution: {integrity: sha512-dFpqDc6/x5LEu9L7kblCQu00CFEchH8J42jmQoXPuhKoE7avajzeLTbVKA8Olk3S/c2m9ejegrgbhL8NRA2Jyw==} engines: {node: ^14.16.0 || >=16.0.0} + '@netlify/blobs@10.7.13': + resolution: {integrity: sha512-LJnmGtQQ2/NdTo0Cm+YP2xR1vtRle6V3kkzMrAOJgRm1SEFOJOcaAFQrth7RnbxCH/IzCM8QakTaCHHKY+K2qA==} + engines: {node: ^14.16.0 || >=16.0.0} + '@netlify/blobs@10.7.9': resolution: {integrity: sha512-NEM8aNAMZCCWBWymomMM/fn5wmPGyGE8pendgsSu5mL7UNz+aXqGcHS0MiHWU/osyg+geiZuS+Rx956SVrMM/w==} engines: {node: ^14.16.0 || >=16.0.0} - '@netlify/blobs@11.0.2': - resolution: {integrity: sha512-raH28PHHQ1OPAYBCkE+DOnUTS/1nYFTRiFhvO6kuowkdhPiOsvX3XR/IjhePhP8aUsH5quBwcqQ3GaOgnIwmEw==} + '@netlify/blobs@11.0.3': + resolution: {integrity: sha512-Z8IXQtQC8BQjm76i1bN+l12TTyKQ/s1R92Ajhou7+fpP0KSxnJ65QzLEb5WuFuFutn8ORrcd4mlF8A2xhw8dzA==} engines: {node: '>=22.12.0'} '@netlify/blobs@8.2.0': @@ -5046,35 +5060,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.4': + resolution: {integrity: sha512-U4gsV3+UOqRArj/cu/kz9XhWKv1Y1AZZySIik+TSSzzIz1CVtQTXI1NAi2VHekr5s3LKlPf4BsdBuAC+YEp/Vg==} + 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.3': + resolution: {integrity: sha512-1X4HFfC6y1gg1jg20FCt6HGkH4ifVfGrsNwe6tB3n3/t7QGM7Qje49EAhgn+EJHF0EoAF/xOiO4RG8CyWHhRyg==} + 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'} @@ -5097,6 +5120,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'} @@ -5117,6 +5144,10 @@ packages: resolution: {integrity: sha512-P6X+xS3glvhiTX6AAocYvnZtqXtWhvxMX4AdPgv2iw6cXjGL2criUveX7bSjp6DiyHfvQpNdG0ZRpeBEVAFf1g==} engines: {node: ^18.14.0 || >=20} + '@netlify/dev-utils@5.0.0': + resolution: {integrity: sha512-ICAsnvbJW9Dv9PGfmJGdjMBsX6uXdJxrA76QE3l3rnGKL5ZcyaA2cJZXacdEmE2ZmtkiVhEJogM15a9nK/ZxDw==} + engines: {node: ^18.14.0 || >=20} + '@netlify/dev-utils@6.0.1': resolution: {integrity: sha512-q5g70dO3q/M/XTBQz7uIECJxVlJoS8UBlzpjf22DV6q61UzXa8EONTPXPmvisrFcUi1I3AUKplPcHGQYZZj+Vw==} engines: {node: '>=22.12.0'} @@ -5125,43 +5156,51 @@ packages: 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.7': + resolution: {integrity: sha512-sXnve/KKrjJjaW9GuTVGTfkEtj3ytIb9xfcZk3dWbpb5vTfWxROWrc/q4harjkO6vYrYOwm3z0xWVP1qmpo5pQ==} + engines: {node: '>=22.12.0'} '@netlify/functions@1.6.0': resolution: {integrity: sha512-6G92AlcpFrQG72XU8YH8pg94eDnq7+Q0YJhb8x4qNpdGsvuzvrfHWBmqFGp/Yshmv4wex9lpsTRZOocdrA2erQ==} @@ -5183,9 +5222,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==} @@ -5195,10 +5242,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} @@ -5293,14 +5348,14 @@ 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 - '@netlify/otel@6.0.3': - resolution: {integrity: sha512-NIjIjB/aItiXKB6+wzSwfSyYqbNsVSzzlEPryxxTC5ZJiYSYSm82wAOcQ+9VdiufQyZO5t8jzHVPULo7a9L9sQ==} + '@netlify/otel@6.0.6': + resolution: {integrity: sha512-KpiJ8c4V4GvgpQH5E1axg43kYdIN9saToLbzvgrDzPun4XMGwz/tLfoIkwJ4jwrVmbPj35+8+dj3gkggQAtjtg==} engines: {node: ^18.14.0 || >=20.6.1} '@netlify/otel@7.0.2': @@ -5315,13 +5370,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==} @@ -5347,6 +5410,10 @@ packages: 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==} @@ -5417,10 +5484,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==} @@ -5432,6 +5507,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: @@ -5453,6 +5532,11 @@ packages: engines: {node: '>=18.14.0'} hasBin: true + '@netlify/zip-it-and-ship-it@15.4.2': + resolution: {integrity: sha512-cP8PzqffKqpdg6EXsRcrrrwCCywiiYGbqrzCfxb5nIflUFGwgC/EX3GzwDEAX4hpWfNKwIqYD/lVDhicT23kfA==} + engines: {node: '>=22.12.0'} + hasBin: true + '@next/env@14.2.30': resolution: {integrity: sha512-KBiBKrDY6kxTQWGzKjQB7QirL3PiiOkV7KW98leHFjtVRKtft76Ra5qSA/SL75xT44dp6hOcqiiJ6iievLOYug==} @@ -5819,8 +5903,8 @@ packages: resolution: {integrity: sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg==} engines: {node: '>=8.0.0'} - '@opentelemetry/api-logs@0.217.0': - resolution: {integrity: sha512-Cdq0jW2lknrNfrAm92MyEAvpe2cRsKjdnQLHUL6xRA4IVUnsWx6P65E7NcUO0Y+L4w1Aee5iV8FvjSwd+lrs9A==} + '@opentelemetry/api-logs@0.220.0': + resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==} engines: {node: '>=8.0.0'} '@opentelemetry/api-logs@0.221.0': @@ -5839,8 +5923,8 @@ packages: resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==} engines: {node: '>=14'} - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + '@opentelemetry/api@1.8.0': + resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==} engines: {node: '>=8.0.0'} '@opentelemetry/api@1.9.1': @@ -5877,6 +5961,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/context-async-hooks@2.9.0': + resolution: {integrity: sha512-OQ0vzvbZBiUhjqLnUaoNfYmP8553Crr3aggB4y0ZUi815mZ7idpdJXQmoKdeBKJelYttoBlLSSHubmyw3wvX4w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@1.30.1': resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} engines: {node: '>=14'} @@ -5901,6 +5991,18 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@2.8.0': + resolution: {integrity: sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.9.0': + resolution: {integrity: sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/exporter-logs-otlp-grpc@0.211.0': resolution: {integrity: sha512-UhOoWENNqyaAMP/dL1YXLkXt6ZBtovkDDs1p4rxto9YwJX1+wMjwg+Obfyg2kwpcMoaiIFT3KQIcLNW8nNGNfQ==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6117,8 +6219,8 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.217.0': - resolution: {integrity: sha512-24ucQMjz7Y34Kw3trbxL2ZrssbtgWnR+Clpaa+YdeWuuyH3Cvk23Q03PcQvqiZrDvt8AmQmjgg9v6Y9PHoxG7w==} + '@opentelemetry/instrumentation@0.220.0': + resolution: {integrity: sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -6205,6 +6307,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/resources@2.9.0': + resolution: {integrity: sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-logs@0.211.0': resolution: {integrity: sha512-O5nPwzgg2JHzo59kpQTPUOTzFi0Nv5LxryG27QoXBciX3zWM3z83g+SNOHhiQVYRWFSxoWn1JM2TGD5iNjOwdA==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6253,6 +6361,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-trace-base@2.9.0': + resolution: {integrity: sha512-cp9zmTl62R8PJrpvFcmc8N2JQU/xfa0S+61q511Nji+QxCfZ8Ifvg7H27G8cANe4crg4RTrWsVvanHiXjSp6ag==} + engines: {node: ^18.19.0 || >=20.6.0} + 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} @@ -6265,8 +6379,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/sdk-trace-node@2.7.1': - resolution: {integrity: sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg==} + '@opentelemetry/sdk-trace-node@2.9.0': + resolution: {integrity: sha512-ec9a7ps37huy5itYk0MalaZdSLlM6AXWp/FhtEjgMpp5leEGojBDvAl/UWttQnkMZOvFHKzRESn8TD3yKTF5nQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -6277,6 +6391,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-trace@2.9.0': + resolution: {integrity: sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==} + 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'} @@ -7644,10 +7764,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'} @@ -7718,6 +7834,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: @@ -8820,6 +8941,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'} @@ -9245,10 +9371,6 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -9283,6 +9405,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==} @@ -9904,10 +10030,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'} @@ -10083,6 +10205,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'} @@ -10130,6 +10256,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'} @@ -10212,6 +10342,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'} @@ -10237,10 +10371,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'} @@ -10250,6 +10380,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'} @@ -10260,6 +10394,11 @@ packages: cron-parser@4.9.0: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} + deprecated: v4 is no longer maintained, upgrade to v5 + + cron-parser@5.10.0: + resolution: {integrity: sha512-izNAxJyRWUP8ljBoDSub5WyrVOUlT4SLGShswE7eoRBpp6QUsSycYxLBMJlbshgPBMcPT/nrfgjNY2918ayv2A==} + engines: {node: '>=18'} croner@10.0.1: resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==} @@ -11646,9 +11785,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==} @@ -12127,10 +12272,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'} @@ -13383,6 +13524,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==} @@ -13527,9 +13671,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==} @@ -13979,8 +14123,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.4: + resolution: {integrity: sha512-gN54ddmyzEg10orwZ2u4OOv+bjpMWdIl5jIkodK97bMq8QBSL5c0D7YX0lT1Ooz+99S7+PvFbnxzdjgHo1r41g==} engines: {node: '>=18.0.0'} module-definition@6.0.2: @@ -13998,10 +14142,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'} @@ -14107,9 +14247,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.4.2: + resolution: {integrity: sha512-BZD75LNQvlMYQYY/YqCg2EEm8pHxXy+RSe7L21hKdLKrnK3VPX/sTfmOfVBXZq/VewhqsBVeoF692FsvBfoEog==} + engines: {node: '>=22.13.0'} hasBin: true netlify-redirector@0.5.0: @@ -15559,6 +15699,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'} @@ -16108,9 +16252,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==} @@ -16669,6 +16813,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'} @@ -18245,6 +18393,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: @@ -18413,7 +18565,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) @@ -19707,11 +19859,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 @@ -20835,6 +20988,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 @@ -20842,6 +20999,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 @@ -20973,15 +21136,23 @@ 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.13(supports-color@10.2.2)': + dependencies: + '@netlify/dev-utils': 5.0.0 + '@netlify/otel': 6.0.6(supports-color@10.2.2) + '@netlify/runtime-utils': 2.3.0 + transitivePeerDependencies: + - supports-color + + '@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.6(supports-color@10.2.2) '@netlify/runtime-utils': 2.3.0 transitivePeerDependencies: - supports-color - '@netlify/blobs@11.0.2': + '@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)': dependencies: '@netlify/dev-utils': 6.0.1 '@netlify/otel': 7.0.2 @@ -21001,56 +21172,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.4(@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': 10.7.13(supports-color@10.2.2) + '@netlify/cache-utils': 7.1.2 + '@netlify/config': 25.2.3 + '@netlify/edge-bundler': 16.0.4 + '@netlify/functions-utils': 7.1.7(rollup@4.60.2)(supports-color@10.2.2) + '@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.4.2(rollup@4.60.2)(supports-color@10.2.2) '@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 @@ -21059,14 +21223,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 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' @@ -21078,20 +21241,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 @@ -21120,6 +21282,33 @@ snapshots: yargs: 17.7.2 zod: 4.3.6 + '@netlify/config@25.2.3': + dependencies: + '@netlify/api': 15.1.2 + '@netlify/headers-parser': 10.1.1 + '@netlify/redirect-parser': 16.1.1 + chalk: 5.6.2 + cron-parser: 4.9.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': {} @@ -21639,7 +21828,7 @@ snapshots: '@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 @@ -21742,9 +21931,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: @@ -21755,25 +21964,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 @@ -21791,21 +22004,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) + '@netlify/dev-utils': 6.0.1 + '@netlify/functions': 6.0.0 + '@netlify/zip-it-and-ship-it': 15.4.2(rollup@4.60.2)(supports-color@10.2.2) + 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 @@ -21814,11 +22027,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.7(rollup@4.60.2)(supports-color@10.2.2)': 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.4.2(rollup@4.60.2)(supports-color@10.2.2) + junk: 4.0.1 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -21862,7 +22074,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 @@ -21883,12 +22095,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: @@ -21903,9 +22123,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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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' @@ -21927,9 +22151,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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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' @@ -22021,17 +22245,17 @@ 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.6(supports-color@10.2.2)': 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/resources': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-node': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-node': 2.9.0(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color @@ -22054,6 +22278,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 @@ -22062,7 +22291,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 @@ -22078,13 +22315,22 @@ snapshots: '@netlify/runtime@4.1.25': dependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) + '@netlify/blobs': 10.7.13(supports-color@10.2.2) '@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) + '@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 @@ -22101,7 +22347,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.13(supports-color@10.2.2) camelize-ts: 3.0.0 openapi-fetch: 0.13.8 snakify-ts: 2.3.0 @@ -22196,7 +22442,7 @@ snapshots: - supports-color - ts-node - '@netlify/sdk@1.67.0(debug@4.4.1)(graphql@16.14.2)': + '@netlify/sdk@1.67.0(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': dependencies: '@commander-js/extra-typings': 12.1.0(commander@12.1.0) '@graphql-tools/stitch': 9.4.29(graphql@16.14.2) @@ -22236,15 +22482,19 @@ snapshots: zod-to-json-schema: 3.25.2(zod@3.25.76) zod-validation-error: 2.1.0(zod@3.25.76) transitivePeerDependencies: + - '@types/react' - bare-abort-controller - bare-buffer + - bufferutil + - canvas - debug - encoding - graphql - react-native-b4a - supports-color + - utf-8-validate - '@netlify/sdk@1.67.0(graphql@16.14.2)': + '@netlify/sdk@1.67.0(@types/react@19.1.8)(graphql@16.14.2)': dependencies: '@commander-js/extra-typings': 12.1.0(commander@12.1.0) '@graphql-tools/stitch': 9.4.29(graphql@16.14.2) @@ -22284,13 +22534,17 @@ snapshots: zod-to-json-schema: 3.25.2(zod@3.25.76) zod-validation-error: 2.1.0(zod@3.25.76) transitivePeerDependencies: + - '@types/react' - bare-abort-controller - bare-buffer + - bufferutil + - canvas - debug - encoding - graphql - react-native-b4a - supports-color + - utf-8-validate '@netlify/sdk@2.26.3(@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: @@ -22561,10 +22815,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 @@ -22577,6 +22839,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 @@ -22632,7 +22896,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 @@ -22669,13 +22933,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 @@ -22711,6 +22975,49 @@ snapshots: - rollup - supports-color + '@netlify/zip-it-and-ship-it@15.4.2(rollup@4.60.2)(supports-color@10.2.2)': + 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@10.2.2) + 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@10.2.2) + require-package-name: 2.0.1 + resolve: 2.0.0-next.5 + semver: 7.8.0 + tmp-promise: 3.0.3 + toml: 3.0.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': {} @@ -23236,7 +23543,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs@0.217.0': + '@opentelemetry/api-logs@0.220.0': dependencies: '@opentelemetry/api': 1.9.1 @@ -23256,7 +23563,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api@1.9.0': {} + '@opentelemetry/api@1.8.0': {} '@opentelemetry/api@1.9.1': {} @@ -23278,11 +23585,11 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 + '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/context-async-hooks@2.9.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23301,12 +23608,17 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 + '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.40.0 + + '@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 @@ -23633,10 +23945,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.217.0(@opentelemetry/api@1.9.0)(supports-color@10.2.2)': + '@opentelemetry/instrumentation@0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.220.0 import-in-the-middle: 3.3.1 require-in-the-middle: 8.0.1(supports-color@10.2.2) transitivePeerDependencies: @@ -23742,16 +24054,16 @@ snapshots: '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@2.9.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@opentelemetry/sdk-logs@0.211.0(@opentelemetry/api@1.9.1)': @@ -23825,13 +24137,6 @@ snapshots: '@opentelemetry/resources': 2.5.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23839,6 +24144,14 @@ snapshots: '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace': 2.9.0(@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 @@ -23853,12 +24166,12 @@ snapshots: '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.5.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-node@2.7.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-node@2.9.0(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.9.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace@2.10.0(@opentelemetry/api@1.9.1)': dependencies: @@ -23867,6 +24180,13 @@ snapshots: '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/sdk-trace@2.9.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/semantic-conventions@1.27.0': {} '@opentelemetry/semantic-conventions@1.28.0': {} @@ -24895,8 +25215,6 @@ snapshots: '@sindresorhus/is@7.1.1': {} - '@sindresorhus/merge-streams@2.3.0': {} - '@sindresorhus/merge-streams@4.0.0': {} '@sindresorhus/slugify@2.2.1': @@ -24950,7 +25268,7 @@ snapshots: '@stackbit/cms-contentful@0.4.56': dependencies: '@contentful/rich-text-types': 15.15.1 - '@stackbit/cms-core': 2.0.1(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 contentful: 9.3.7 @@ -24967,7 +25285,7 @@ snapshots: '@stackbit/cms-contentful@0.4.56(debug@4.4.1)(graphql@16.14.2)': dependencies: '@contentful/rich-text-types': 15.15.1 - '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 contentful: 9.3.7(debug@4.4.1) @@ -24982,12 +25300,12 @@ snapshots: - react-native-b4a - supports-color - '@stackbit/cms-core@2.0.1(debug@4.4.1)(graphql@16.14.2)': + '@stackbit/cms-core@2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': dependencies: '@babel/parser': 7.29.7 '@babel/traverse': 7.29.0 '@iarna/toml': 2.2.5 - '@netlify/sdk': 1.67.0(debug@4.4.1)(graphql@16.14.2) + '@netlify/sdk': 1.67.0(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 @@ -25006,20 +25324,24 @@ snapshots: slugify: 1.6.9 uuid: 9.0.1 transitivePeerDependencies: + - '@types/react' - bare-abort-controller - bare-buffer + - bufferutil + - canvas - debug - encoding - graphql - react-native-b4a - supports-color + - utf-8-validate - '@stackbit/cms-core@2.0.1(graphql@16.14.2)': + '@stackbit/cms-core@2.0.1(@types/react@19.1.8)(graphql@16.14.2)': dependencies: '@babel/parser': 7.29.7 '@babel/traverse': 7.29.0 '@iarna/toml': 2.2.5 - '@netlify/sdk': 1.67.0(graphql@16.14.2) + '@netlify/sdk': 1.67.0(@types/react@19.1.8)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 @@ -25038,56 +25360,69 @@ snapshots: slugify: 1.6.9 uuid: 9.0.1 transitivePeerDependencies: + - '@types/react' - bare-abort-controller - bare-buffer + - bufferutil + - canvas - debug - encoding - graphql - react-native-b4a - supports-color + - utf-8-validate - '@stackbit/cms-git@0.4.18': + '@stackbit/cms-git@0.4.18(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': dependencies: '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-core': 2.0.1(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.24.0 + axios: 0.24.0(debug@4.4.1) fs-extra: 11.3.6 git-url-parse: 13.1.1 lodash: 4.18.1 micromatch: 4.0.8 slugify: 1.6.9 transitivePeerDependencies: + - '@types/react' - bare-abort-controller - bare-buffer + - bufferutil + - canvas - debug - encoding + - graphql - react-native-b4a - supports-color + - utf-8-validate - '@stackbit/cms-git@0.4.18(debug@4.4.1)(graphql@16.14.2)': + '@stackbit/cms-git@0.4.18(@types/react@19.1.8)(graphql@16.14.2)': dependencies: '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.24.0(debug@4.4.1) + axios: 0.24.0 fs-extra: 11.3.6 git-url-parse: 13.1.1 lodash: 4.18.1 micromatch: 4.0.8 slugify: 1.6.9 transitivePeerDependencies: + - '@types/react' - bare-abort-controller - bare-buffer + - bufferutil + - canvas - debug - encoding - graphql - react-native-b4a - supports-color + - utf-8-validate '@stackbit/cms-sanity@0.2.56(@types/react@19.1.8)': dependencies: @@ -25095,7 +25430,7 @@ snapshots: '@sanity/client': 3.4.1 '@sanity/schema': 2.36.6 '@sanity/types': 3.99.0(@types/react@19.1.8) - '@stackbit/cms-core': 2.0.1(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 fs-extra: 9.1.0 @@ -25122,7 +25457,7 @@ snapshots: '@sanity/client': 3.4.1 '@sanity/schema': 2.36.6 '@sanity/types': 3.99.0(@types/react@19.1.8) - '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 fs-extra: 9.1.0 @@ -25144,18 +25479,18 @@ snapshots: - supports-color - utf-8-validate - '@stackbit/dev-common@0.5.51(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': + '@stackbit/dev-common@0.5.51(@types/react@19.1.8)': dependencies: '@iarna/toml': 2.2.5 '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-contentful': 0.4.56(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-contentful': 0.4.56 + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.25.0(debug@4.4.1) + axios: 0.25.0 chalk: 4.1.2 configstore: 5.0.1 detect-port: 1.6.1 @@ -25180,23 +25515,22 @@ snapshots: - canvas - debug - encoding - - graphql - react-native-b4a - supports-color - utf-8-validate - '@stackbit/dev-common@0.5.51(@types/react@19.1.8)(graphql@16.14.2)': + '@stackbit/dev-common@0.5.51(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': dependencies: '@iarna/toml': 2.2.5 '@stackbit/artisanal-names': 1.0.1 - '@stackbit/cms-contentful': 0.4.56 - '@stackbit/cms-core': 2.0.1(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18 - '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8) + '@stackbit/cms-contentful': 0.4.56(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-sanity': 0.2.56(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 '@stackbit/types': 1.0.1 '@stackbit/utils': 0.4.19 - axios: 0.25.0 + axios: 0.25.0(debug@4.4.1) chalk: 4.1.2 configstore: 5.0.1 detect-port: 1.6.1 @@ -25228,8 +25562,8 @@ snapshots: '@stackbit/dev@1.0.35(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2)': dependencies: - '@stackbit/cms-core': 2.0.1(debug@4.4.1)(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/dev-common': 0.5.51(@types/react@19.1.8)(debug@4.4.1)(graphql@16.14.2) '@stackbit/sdk': 2.0.1 axios: 0.25.0(debug@4.4.1) @@ -25263,9 +25597,9 @@ snapshots: '@stackbit/dev@1.0.35(@types/react@19.1.8)(graphql@16.14.2)': dependencies: - '@stackbit/cms-core': 2.0.1(graphql@16.14.2) - '@stackbit/cms-git': 0.4.18 - '@stackbit/dev-common': 0.5.51(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/cms-core': 2.0.1(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/cms-git': 0.4.18(@types/react@19.1.8)(graphql@16.14.2) + '@stackbit/dev-common': 0.5.51(@types/react@19.1.8) '@stackbit/sdk': 2.0.1 axios: 0.25.0 chalk: 4.1.2 @@ -25331,6 +25665,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 @@ -26711,7 +27049,7 @@ 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) '@rollup/pluginutils': 5.3.0(rollup@4.60.2) @@ -26749,6 +27087,25 @@ snapshots: - rollup - supports-color + '@vercel/nft@1.3.1(rollup@4.60.2)(supports-color@10.2.2)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.3(supports-color@10.2.2) + '@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) @@ -27267,8 +27624,6 @@ snapshots: dependencies: color-convert: 2.0.1 - ansi-styles@6.2.1: {} - ansi-styles@6.2.3: {} ansi-to-html@0.7.2: @@ -27290,7 +27645,7 @@ snapshots: archiver-utils@5.0.2: dependencies: - glob: 10.4.5 + glob: 10.5.0 graceful-fs: 4.2.11 is-stream: 2.0.1 lazystream: 1.0.1 @@ -27312,6 +27667,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: {} @@ -28095,10 +28466,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: @@ -28254,6 +28621,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 @@ -28315,6 +28690,8 @@ snapshots: content-disposition@1.1.0: {} + content-disposition@2.0.1: {} + content-engine-graphiql-explorer@0.0.1: {} content-engine@0.0.29: @@ -28569,6 +28946,8 @@ snapshots: cookie@1.1.1: {} + cookie@2.0.1: {} + cookies@0.9.1: dependencies: depd: 2.0.0 @@ -28602,15 +28981,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: @@ -28618,6 +28988,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 @@ -28628,6 +29003,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: @@ -30622,10 +31001,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: {} @@ -31199,15 +31584,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 @@ -32685,6 +33061,8 @@ snapshots: dependencies: p-locate: 6.0.0 + lockparse@0.5.2: {} + lodash-es@4.17.21: {} lodash.camelcase@4.3.0: {} @@ -32788,11 +33166,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 @@ -33476,7 +33855,7 @@ snapshots: mocked-exports@0.1.1: {} - modern-tar@0.7.6: {} + modern-tar@0.8.4: {} module-definition@6.0.2: dependencies: @@ -33492,10 +33871,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: {} @@ -33599,25 +33974,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): + netlify-cli@27.4.2(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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) + '@fastify/static': 10.1.3 + '@netlify/ai': 1.0.1 + '@netlify/api': 15.1.2 + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f) + '@netlify/build': 36.4.4(@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.3 + '@netlify/dev': 5.0.5(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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.4.2(rollup@4.60.2)(supports-color@10.2.2) '@octokit/rest': 22.0.1 '@opentelemetry/api': 1.9.1 '@pnpm/tabtab': 0.5.4 @@ -33627,13 +34002,13 @@ snapshots: backoff: 2.5.0 boxen: 8.0.1 chalk: 5.6.2 - chokidar: 4.0.3 + chokidar: 5.0.0 ci-info: 4.4.0 clean-deep: 3.4.0 commander: 12.1.0 comment-json: 4.6.2 content-type: 1.0.5 - cookie: 1.1.1 + cookie: 2.0.1 cron-parser: 4.9.0 debug: 4.4.3(supports-color@10.2.2) decache: 4.6.2 @@ -33666,10 +34041,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.4 multiparty: 4.3.0 nanospinner: 1.2.2 netlify-redirector: 0.5.0 @@ -33686,7 +34061,7 @@ snapshots: prettyjson: 1.2.5 raw-body: 3.0.2 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 @@ -35558,6 +35933,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 @@ -36367,7 +36746,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 @@ -37018,6 +37397,8 @@ snapshots: tinyexec@1.1.2: {} + tinyexec@1.3.1: {} + tinyglobby@0.2.14: dependencies: fdir: 6.5.0(picomatch@4.0.5) @@ -37649,11 +38030,11 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 optionalDependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) - 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)) + '@netlify/blobs': 10.7.13(supports-color@10.2.2) + db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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): + unstorage@1.17.5(@netlify/blobs@10.7.13)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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: anymatch: 3.1.3 chokidar: 5.0.0 @@ -37664,8 +38045,38 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 optionalDependencies: - '@netlify/blobs': 10.7.9(supports-color@10.2.2) - 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)) + '@netlify/blobs': 10.7.13(supports-color@10.2.2) + db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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: + 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': 10.7.9 + db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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) + db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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: {} @@ -37873,7 +38284,7 @@ snapshots: vite-node@3.2.4(@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: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3(supports-color@10.2.2) es-module-lexer: 1.7.0 pathe: 2.0.3 vite: 7.3.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) @@ -38589,9 +39000,9 @@ snapshots: wrap-ansi@9.0.2: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 wrappy@1.0.2: {} @@ -38758,7 +39169,7 @@ snapshots: '@poppinss/colors': 4.1.6 '@poppinss/dumper': 0.6.5 '@speed-highlight/core': 1.2.15 - cookie: 1.0.2 + cookie: 1.1.1 youch-core: 0.3.3 youch@4.1.1: @@ -38785,6 +39196,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 2bcae8e8f..13a9beaa4 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -74,9 +74,9 @@ catalog: "@cloudflare/workers-types": ^4.20260511.1 "@electric-sql/pglite": ^0.5.8 "@netlify/database": ^1.1.0 - netlify-cli: ^26.2.0 + netlify-cli: ^27.4.2 "@netlify/async-workloads": ^0.0.106 - "@netlify/blobs": "^11.0.1" + "@netlify/blobs": "^11.0.3" "@fxts/core": ^1.21.1 "@js-temporal/polyfill": ^0.5.1 "@logtape/file": ^2.2.0 From 2cd0d4b9eb24fe3b1b3374b283d9277846d03553 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 9 Sep 2026 17:48:50 +0900 Subject: [PATCH 11/22] Test Netlify Blob persistence and CAS Exercise persistence across separate Netlify Function requests and verify conditional creation, updates, deletion, and recreation through the real Netlify Dev Blobs server. Remove the temporary ETag reproducers so Node's test discovery does not run diagnostic scripts as package tests. https://github.com/fedify-dev/fedify/issues/1010 Changelog: none Assisted-by: Codex:gpt-5.6-sol --- .../netlify-dev/netlify/functions/blob-kv.mts | 48 +++++++++ .../test/integration/blobs-etag-production.ts | 67 ------------- .../test/integration/blobs-etag-repro.ts | 72 -------------- .../netlify/test/integration/netlify.test.ts | 98 +++++++++++++++++++ 4 files changed, 146 insertions(+), 139 deletions(-) create mode 100644 packages/netlify/fixtures/netlify-dev/netlify/functions/blob-kv.mts delete mode 100644 packages/netlify/test/integration/blobs-etag-production.ts delete mode 100644 packages/netlify/test/integration/blobs-etag-repro.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/test/integration/blobs-etag-production.ts b/packages/netlify/test/integration/blobs-etag-production.ts deleted file mode 100644 index 0ed3398c6..000000000 --- a/packages/netlify/test/integration/blobs-etag-production.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ok } from "node:assert/strict"; -import { getStore } from "@netlify/blobs"; - -const siteID = process.env.NETLIFY_SITE_ID; -const token = process.env.NETLIFY_AUTH_TOKEN; -if (siteID == null || token == null) { - throw new Error("Missing NETLIFY_SITE_ID or NETLIFY_AUTH_TOKEN."); -} - -const loggingFetch: typeof fetch = async (input, init) => { - const response = await fetch(input, init); - const method = init?.method ?? - (input instanceof Request ? input.method : "GET"); - const requestUrl = new URL( - input instanceof Request ? input.url : input.toString(), - ); - console.log({ - method, - target: requestUrl.hostname === "api.netlify.com" - ? "Netlify API" - : "blob storage", - status: response.status, - etag: response.headers.get("etag"), - }); - return response; -}; - -const store = getStore({ - consistency: "strong", - fetch: loggingFetch, - name: "etag-production-reproduction", - siteID, - token, -}); -const key = `etag-test-${crypto.randomUUID()}`; - -let etags: { - readonly getMetadata: string | null; - readonly getWithMetadata: string | null; - readonly list: string | null; - readonly setJSON: string | null; -}; - -try { - const write = await store.setJSON(key, { value: 1 }); - const read = await store.getWithMetadata(key, { - consistency: "strong", - type: "json", - }); - const metadata = await store.getMetadata(key, { - consistency: "strong", - }); - const list = await store.list({ prefix: key }); - - etags = { - setJSON: write.etag ?? null, - getWithMetadata: read?.etag ?? null, - getMetadata: metadata?.etag ?? null, - list: list.blobs.find((blob) => blob.key === key)?.etag ?? null, - }; -} finally { - await store.delete(key); -} - -console.log(JSON.stringify(etags, null, 2)); -ok(etags.getWithMetadata, "getWithMetadata() did not return an ETag"); -ok(etags.getMetadata, "getMetadata() did not return an ETag"); diff --git a/packages/netlify/test/integration/blobs-etag-repro.ts b/packages/netlify/test/integration/blobs-etag-repro.ts deleted file mode 100644 index 64cf54f7c..000000000 --- a/packages/netlify/test/integration/blobs-etag-repro.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { deepStrictEqual, equal, ok } from "node:assert/strict"; -import { mkdtemp, rm } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { getStore } from "@netlify/blobs"; -import { BlobsServer } from "@netlify/blobs/server"; - -const directory = await mkdtemp(join(tmpdir(), "netlify-blobs-etag-")); -const token = "test-token"; -const server = new BlobsServer({ directory, token }); -const loggingFetch: typeof fetch = async (input, init) => { - const response = await fetch(input, init); - const method = init?.method ?? - (input instanceof Request ? input.method : "GET"); - const url = input instanceof Request ? input.url : input.toString(); - console.log(method, url, response.status, { - headers: Object.fromEntries(response.headers), - }); - return response; -}; - -let etags: { - readonly getMetadata: string | null; - readonly getWithMetadata: string | null; - readonly list: string | null; - readonly setJSON: string | null; -}; - -try { - const { address } = await server.start(); - const store = getStore({ - apiURL: address, - consistency: "strong", - fetch: loggingFetch, - name: "etag-reproduction", - siteID: "test-site", - token, - }); - const write = await store.setJSON("key", { value: 1 }); - const read = await store.getWithMetadata("key", { - consistency: "strong", - type: "json", - }); - const metadata = await store.getMetadata("key", { - consistency: "strong", - }); - const list = await store.list({ prefix: "key" }); - const unchanged = await store.getWithMetadata("key", { - consistency: "strong", - etag: write.etag, - type: "json", - }); - - etags = { - setJSON: write.etag ?? null, - getWithMetadata: read?.etag ?? null, - getMetadata: metadata?.etag ?? null, - list: list.blobs.find((blob) => blob.key === "key")?.etag ?? null, - }; - - console.log(JSON.stringify(etags, null, 2)); - ok(etags.getWithMetadata, "getWithMetadata() did not return an ETag"); - ok(etags.getMetadata, "getMetadata() did not return an ETag"); - equal(unchanged?.data, null); - equal(unchanged?.etag, write.etag); - deepStrictEqual(read?.data, { value: 1 }); - - console.log(); -} finally { - await server.stop(); - await rm(directory, { recursive: true, force: true }); -} diff --git a/packages/netlify/test/integration/netlify.test.ts b/packages/netlify/test/integration/netlify.test.ts index 7ac4d6b8f..66bf5f18b 100644 --- a/packages/netlify/test/integration/netlify.test.ts +++ b/packages/netlify/test/integration/netlify.test.ts @@ -129,6 +129,22 @@ 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( @@ -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( From ba2fe7ecb4cf55f43ce6c19cb8243cfd61d16c96 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Wed, 9 Sep 2026 18:46:25 +0900 Subject: [PATCH 12/22] Refresh dependency lockfiles Resolve the catalog conflicts left by rebasing onto upstream/main and regenerate both lockfiles from the merged dependency manifests. Changelog: none Assisted-by: Codex:gpt-5.6-sol --- deno.lock | 78 ++---- pnpm-lock.yaml | 613 ++++++++++++++++++++------------------------ pnpm-workspace.yaml | 7 +- 3 files changed, 302 insertions(+), 396 deletions(-) diff --git a/deno.lock b/deno.lock index 4c4b1bc5c..d178c4b52 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__@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__@netlify+blobs@11.0.2_@netlify+blobs@11.0.2", + "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,8 +93,7 @@ "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/blobs@^11.0.1": "11.0.2", - "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", @@ -283,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", @@ -484,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": [ @@ -3872,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": [ @@ -6997,8 +6996,7 @@ "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", @@ -7151,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": { @@ -7269,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" @@ -7431,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 @@ -8636,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==", @@ -12709,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==", @@ -15797,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", @@ -16092,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==" }, @@ -16570,14 +16554,6 @@ "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" } }, - "remote": { - "https://edge.netlify.com/": "fd941d61d88673d5f28aab283fb86fcc50f08a3bc80ee5470498fcfa88c65cfb", - "https://edge.netlify.com/bootstrap/config.ts": "6a2ce0e544e15e8f8883a5c18da5948e37fd0f2619f68cb31f3af53c51817025", - "https://edge.netlify.com/bootstrap/context.ts": "e97240232121e2f369f6546ce961490f34d961ea1ea54be3ff09633e3f08373f", - "https://edge.netlify.com/bootstrap/cookie.ts": "8b0baae708989ca183c6f3b4ab3d029e6abcbc2e43f93edeb0ff447b3bbc3a05", - "https://edge.netlify.com/bootstrap/edge_function.ts": "b8253e86aa83c67341f5cfedeba5049d77fbf84dcab7eceff7566b7728ae9b39", - "https://edge.netlify.com/bootstrap/globals/types.ts": "eaa6148ded3121d8dee62dd91c86e7fe76601df0f3ca8d7962243a30f4c8935f" - }, "workspace": { "dependencies": [ "jsr:@david/dax@~0.46.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e4982cb5..2a2dcb7d1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -179,7 +179,7 @@ catalogs: version: 3.22.3 netlify-cli: specifier: ^27.4.2 - version: 27.4.2 + version: 27.5.1 next: specifier: '>=15.4.6 <17' version: 16.2.4 @@ -1667,10 +1667,7 @@ importers: version: 0.5.1 '@netlify/blobs': specifier: 'catalog:' - version: 11.0.2 - '@netlify/database': - 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 @@ -1679,7 +1676,7 @@ importers: version: 22.19.1 netlify-cli: specifier: 'catalog:' - version: 27.4.2(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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) + 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)) @@ -5036,10 +5033,6 @@ packages: resolution: {integrity: sha512-dFpqDc6/x5LEu9L7kblCQu00CFEchH8J42jmQoXPuhKoE7avajzeLTbVKA8Olk3S/c2m9ejegrgbhL8NRA2Jyw==} engines: {node: ^14.16.0 || >=16.0.0} - '@netlify/blobs@10.7.13': - resolution: {integrity: sha512-LJnmGtQQ2/NdTo0Cm+YP2xR1vtRle6V3kkzMrAOJgRm1SEFOJOcaAFQrth7RnbxCH/IzCM8QakTaCHHKY+K2qA==} - engines: {node: ^14.16.0 || >=16.0.0} - '@netlify/blobs@10.7.9': resolution: {integrity: sha512-NEM8aNAMZCCWBWymomMM/fn5wmPGyGE8pendgsSu5mL7UNz+aXqGcHS0MiHWU/osyg+geiZuS+Rx956SVrMM/w==} engines: {node: ^14.16.0 || >=16.0.0} @@ -5065,8 +5058,8 @@ packages: engines: {node: '>=22.12.0'} hasBin: true - '@netlify/build@36.4.4': - resolution: {integrity: sha512-U4gsV3+UOqRArj/cu/kz9XhWKv1Y1AZZySIik+TSSzzIz1CVtQTXI1NAi2VHekr5s3LKlPf4BsdBuAC+YEp/Vg==} + '@netlify/build@36.4.7': + resolution: {integrity: sha512-6pBATJQP4S5Qv2USPxtRE5x79bsgrI6qbVvyJ8WGEFsGoZHvWe+88wp/moWbvpMymeP0XVDuKCM/RTDiQU/8bQ==} engines: {node: '>=22.12.0'} hasBin: true peerDependencies: @@ -5093,8 +5086,8 @@ packages: engines: {node: '>=18.14.0'} hasBin: true - '@netlify/config@25.2.3': - resolution: {integrity: sha512-1X4HFfC6y1gg1jg20FCt6HGkH4ifVfGrsNwe6tB3n3/t7QGM7Qje49EAhgn+EJHF0EoAF/xOiO4RG8CyWHhRyg==} + '@netlify/config@25.2.4': + resolution: {integrity: sha512-8sAA1Ql+Vi9YYU3tDVOaV3k2KwTkcFtqYFgqYtRmidrKiNIh40PwuumHpenaNUQPxni4Xzhq89ryORJRJAc7nA==} engines: {node: '>=22.12.0'} hasBin: true @@ -5144,10 +5137,6 @@ packages: resolution: {integrity: sha512-P6X+xS3glvhiTX6AAocYvnZtqXtWhvxMX4AdPgv2iw6cXjGL2criUveX7bSjp6DiyHfvQpNdG0ZRpeBEVAFf1g==} engines: {node: ^18.14.0 || >=20} - '@netlify/dev-utils@5.0.0': - resolution: {integrity: sha512-ICAsnvbJW9Dv9PGfmJGdjMBsX6uXdJxrA76QE3l3rnGKL5ZcyaA2cJZXacdEmE2ZmtkiVhEJogM15a9nK/ZxDw==} - engines: {node: ^18.14.0 || >=20} - '@netlify/dev-utils@6.0.1': resolution: {integrity: sha512-q5g70dO3q/M/XTBQz7uIECJxVlJoS8UBlzpjf22DV6q61UzXa8EONTPXPmvisrFcUi1I3AUKplPcHGQYZZj+Vw==} engines: {node: '>=22.12.0'} @@ -5198,8 +5187,8 @@ packages: resolution: {integrity: sha512-SSlmwe5GMfQmTDPbHfVTPe4h6lI3kbcepRxT2CKN30L9gx0NmwTGoMgns36DV64fHvabT5gNzzRxOx5sxYgzNg==} engines: {node: '>=22.12.0'} - '@netlify/functions-utils@7.1.7': - resolution: {integrity: sha512-sXnve/KKrjJjaW9GuTVGTfkEtj3ytIb9xfcZk3dWbpb5vTfWxROWrc/q4harjkO6vYrYOwm3z0xWVP1qmpo5pQ==} + '@netlify/functions-utils@7.1.9': + resolution: {integrity: sha512-W3ainnUjWRMmBHRHuJ/7r8+C1mrPUgtDvED1QCFTEvDDOH6+usruxSLdQFVi0d12YkLqk7zLqRIhBnpSRtuQaw==} engines: {node: '>=22.12.0'} '@netlify/functions@1.6.0': @@ -5354,8 +5343,8 @@ packages: peerDependencies: '@opentelemetry/api': ~1.8.0 - '@netlify/otel@6.0.6': - resolution: {integrity: sha512-KpiJ8c4V4GvgpQH5E1axg43kYdIN9saToLbzvgrDzPun4XMGwz/tLfoIkwJ4jwrVmbPj35+8+dj3gkggQAtjtg==} + '@netlify/otel@6.0.3': + resolution: {integrity: sha512-NIjIjB/aItiXKB6+wzSwfSyYqbNsVSzzlEPryxxTC5ZJiYSYSm82wAOcQ+9VdiufQyZO5t8jzHVPULo7a9L9sQ==} engines: {node: ^18.14.0 || >=20.6.1} '@netlify/otel@7.0.2': @@ -5532,8 +5521,8 @@ packages: engines: {node: '>=18.14.0'} hasBin: true - '@netlify/zip-it-and-ship-it@15.4.2': - resolution: {integrity: sha512-cP8PzqffKqpdg6EXsRcrrrwCCywiiYGbqrzCfxb5nIflUFGwgC/EX3GzwDEAX4hpWfNKwIqYD/lVDhicT23kfA==} + '@netlify/zip-it-and-ship-it@15.5.1': + resolution: {integrity: sha512-ECHwLIHkSgfkxqF+q40xLMTTSxir1/pDGK6d55oKvwKidrW4qyTyHCAkuKtjOTJ30A+E238X2iiRyI+SCDjTuA==} engines: {node: '>=22.12.0'} hasBin: true @@ -5903,8 +5892,8 @@ packages: resolution: {integrity: sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg==} engines: {node: '>=8.0.0'} - '@opentelemetry/api-logs@0.220.0': - resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==} + '@opentelemetry/api-logs@0.217.0': + resolution: {integrity: sha512-Cdq0jW2lknrNfrAm92MyEAvpe2cRsKjdnQLHUL6xRA4IVUnsWx6P65E7NcUO0Y+L4w1Aee5iV8FvjSwd+lrs9A==} engines: {node: '>=8.0.0'} '@opentelemetry/api-logs@0.221.0': @@ -5927,6 +5916,10 @@ packages: 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'} + '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} @@ -5961,12 +5954,6 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/context-async-hooks@2.9.0': - resolution: {integrity: sha512-OQ0vzvbZBiUhjqLnUaoNfYmP8553Crr3aggB4y0ZUi815mZ7idpdJXQmoKdeBKJelYttoBlLSSHubmyw3wvX4w==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@1.30.1': resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} engines: {node: '>=14'} @@ -5991,18 +5978,6 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.8.0': - resolution: {integrity: sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/core@2.9.0': - resolution: {integrity: sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/exporter-logs-otlp-grpc@0.211.0': resolution: {integrity: sha512-UhOoWENNqyaAMP/dL1YXLkXt6ZBtovkDDs1p4rxto9YwJX1+wMjwg+Obfyg2kwpcMoaiIFT3KQIcLNW8nNGNfQ==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6219,8 +6194,8 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.220.0': - resolution: {integrity: sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==} + '@opentelemetry/instrumentation@0.217.0': + resolution: {integrity: sha512-24ucQMjz7Y34Kw3trbxL2ZrssbtgWnR+Clpaa+YdeWuuyH3Cvk23Q03PcQvqiZrDvt8AmQmjgg9v6Y9PHoxG7w==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -6307,12 +6282,6 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/resources@2.9.0': - resolution: {integrity: sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-logs@0.211.0': resolution: {integrity: sha512-O5nPwzgg2JHzo59kpQTPUOTzFi0Nv5LxryG27QoXBciX3zWM3z83g+SNOHhiQVYRWFSxoWn1JM2TGD5iNjOwdA==} engines: {node: ^18.19.0 || >=20.6.0} @@ -6361,12 +6330,6 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-trace-base@2.9.0': - resolution: {integrity: sha512-cp9zmTl62R8PJrpvFcmc8N2JQU/xfa0S+61q511Nji+QxCfZ8Ifvg7H27G8cANe4crg4RTrWsVvanHiXjSp6ag==} - engines: {node: ^18.19.0 || >=20.6.0} - 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} @@ -6379,8 +6342,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/sdk-trace-node@2.9.0': - resolution: {integrity: sha512-ec9a7ps37huy5itYk0MalaZdSLlM6AXWp/FhtEjgMpp5leEGojBDvAl/UWttQnkMZOvFHKzRESn8TD3yKTF5nQ==} + '@opentelemetry/sdk-trace-node@2.7.1': + resolution: {integrity: sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -6391,12 +6354,6 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-trace@2.9.0': - resolution: {integrity: sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==} - 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'} @@ -9371,6 +9328,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -9955,6 +9916,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==} @@ -10180,8 +10145,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: @@ -10394,7 +10359,6 @@ packages: cron-parser@4.9.0: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} - deprecated: v4 is no longer maintained, upgrade to v5 cron-parser@5.10.0: resolution: {integrity: sha512-izNAxJyRWUP8ljBoDSub5WyrVOUlT4SLGShswE7eoRBpp6QUsSycYxLBMJlbshgPBMcPT/nrfgjNY2918ayv2A==} @@ -14123,8 +14087,8 @@ packages: mocked-exports@0.1.1: resolution: {integrity: sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==} - modern-tar@0.8.4: - resolution: {integrity: sha512-gN54ddmyzEg10orwZ2u4OOv+bjpMWdIl5jIkodK97bMq8QBSL5c0D7YX0lT1Ooz+99S7+PvFbnxzdjgHo1r41g==} + modern-tar@0.8.5: + resolution: {integrity: sha512-snEhs+6G5Tjd4I7tLCDOaoln2RgE0bD19RzEKgvgK2hZ5VKy3MpLhLTZ2fWpXSTg4K2cyPwp+VHATFJhxfnOeA==} engines: {node: '>=18.0.0'} module-definition@6.0.2: @@ -14247,8 +14211,8 @@ packages: resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} engines: {node: '>= 10'} - netlify-cli@27.4.2: - resolution: {integrity: sha512-BZD75LNQvlMYQYY/YqCg2EEm8pHxXy+RSe7L21hKdLKrnK3VPX/sTfmOfVBXZq/VewhqsBVeoF692FsvBfoEog==} + netlify-cli@27.5.1: + resolution: {integrity: sha512-k55Iq+/Q54pb07+5ninj6sOnNO9qDDSPOzD0Hlz5cGxcOddhTHsOKscdwEzfMnx27I0dLT/z8v043mrm+2U69g==} engines: {node: '>=22.13.0'} hasBin: true @@ -15590,6 +15554,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==} @@ -16622,6 +16590,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'} @@ -16896,6 +16868,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==} @@ -18664,7 +18640,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 @@ -18824,7 +18800,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 @@ -20868,7 +20844,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 @@ -20908,11 +20884,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 @@ -21136,26 +21112,18 @@ snapshots: '@netlify/dev-utils': 4.3.0 '@netlify/runtime-utils': 2.2.0 - '@netlify/blobs@10.7.13(supports-color@10.2.2)': - dependencies: - '@netlify/dev-utils': 5.0.0 - '@netlify/otel': 6.0.6(supports-color@10.2.2) - '@netlify/runtime-utils': 2.3.0 - transitivePeerDependencies: - - supports-color - '@netlify/blobs@10.7.9': dependencies: '@netlify/dev-utils': 4.4.6 - '@netlify/otel': 6.0.6(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)': + '@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 + '@netlify/otel': 7.0.2(supports-color@11.0.0) '@netlify/runtime-utils': 3.0.0 transitivePeerDependencies: - supports-color @@ -21185,19 +21153,19 @@ snapshots: yaml: 2.9.0 yargs: 17.7.2 - '@netlify/build@36.4.4(@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.13(supports-color@10.2.2) + '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f)(supports-color@11.0.0) '@netlify/cache-utils': 7.1.2 - '@netlify/config': 25.2.3 + '@netlify/config': 25.2.4 '@netlify/edge-bundler': 16.0.4 - '@netlify/functions-utils': 7.1.7(rollup@4.60.2)(supports-color@10.2.2) + '@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': 7.1.0 - '@netlify/zip-it-and-ship-it': 15.4.2(rollup@4.60.2)(supports-color@10.2.2) + '@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 ansis: 4.3.0 @@ -21223,7 +21191,7 @@ snapshots: rfdc: 1.4.1 safe-json-stringify: 1.2.0 semver: 7.8.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 @@ -21282,13 +21250,13 @@ snapshots: yargs: 17.7.2 zod: 4.3.6 - '@netlify/config@25.2.3': + '@netlify/config@25.2.4': dependencies: '@netlify/api': 15.1.2 '@netlify/headers-parser': 10.1.1 '@netlify/redirect-parser': 16.1.1 - chalk: 5.6.2 - cron-parser: 4.9.0 + chalk: 6.0.0 + cron-parser: 5.10.0 deepmerge: 4.3.1 dot-prop: 9.0.0 execa: 8.0.1 @@ -21700,35 +21668,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: @@ -21825,6 +21768,20 @@ 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 @@ -21866,20 +21823,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)': + '@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': 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/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' @@ -22006,10 +21963,10 @@ snapshots: '@netlify/functions-dev@2.0.5(rollup@4.60.2)': dependencies: - '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f) + '@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.4.2(rollup@4.60.2)(supports-color@10.2.2) + '@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 is-stream: 4.0.1 @@ -22027,9 +21984,9 @@ snapshots: - rollup - supports-color - '@netlify/functions-utils@7.1.7(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': 15.4.2(rollup@4.60.2)(supports-color@10.2.2) + '@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 @@ -22127,9 +22084,9 @@ snapshots: dependencies: '@netlify/headers-parser': 10.1.1 - '@netlify/images@1.3.10(@netlify/blobs@10.7.9)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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@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' @@ -22151,9 +22108,9 @@ snapshots: - ioredis - uploadthing - '@netlify/images@2.0.1(@netlify/blobs@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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/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@11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f))(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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@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' @@ -22249,21 +22206,21 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 - '@netlify/otel@6.0.6(supports-color@10.2.2)': + '@netlify/otel@6.0.3': dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-node': 2.9.0(@opentelemetry/api@1.9.1) + '@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) + '@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': + '@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) + '@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: @@ -22315,7 +22272,7 @@ snapshots: '@netlify/runtime@4.1.25': dependencies: - '@netlify/blobs': 10.7.13(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 @@ -22324,7 +22281,7 @@ snapshots: '@netlify/runtime@5.0.3': dependencies: - '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f) + '@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 @@ -22347,7 +22304,7 @@ snapshots: '@netlify/sdk--extension-api-client@2.12.6': dependencies: - '@netlify/blobs': 10.7.13(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 @@ -22915,7 +22872,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 @@ -22957,7 +22914,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 @@ -22975,14 +22932,14 @@ snapshots: - rollup - supports-color - '@netlify/zip-it-and-ship-it@15.4.2(rollup@4.60.2)(supports-color@10.2.2)': + '@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@10.2.2) + '@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 @@ -23000,12 +22957,12 @@ 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 tmp-promise: 3.0.3 - toml: 3.0.0 + toml: 4.3.0 unixify: 1.0.0 urlpattern-polyfill: 8.0.2 yargs: 17.7.2 @@ -23135,7 +23092,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 @@ -23543,7 +23500,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs@0.220.0': + '@opentelemetry/api-logs@0.217.0': dependencies: '@opentelemetry/api': 1.9.1 @@ -23565,6 +23522,8 @@ snapshots: '@opentelemetry/api@1.8.0': {} + '@opentelemetry/api@1.9.0': {} + '@opentelemetry/api@1.9.1': {} '@opentelemetry/configuration@0.211.0(@opentelemetry/api@1.9.1)': @@ -23585,11 +23544,11 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.9.1 + '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks@2.9.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -23608,17 +23567,12 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/semantic-conventions': 1.40.0 - - '@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.9.1 + '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 @@ -23941,25 +23895,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.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2)': + '@opentelemetry/instrumentation@0.217.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.220.0 + '@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)': + '@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@10.2.2) + require-in-the-middle: 8.0.1(supports-color@11.0.0) transitivePeerDependencies: - supports-color @@ -24054,16 +24008,16 @@ snapshots: '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/resources@2.9.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@opentelemetry/sdk-logs@0.211.0(@opentelemetry/api@1.9.1)': @@ -24137,19 +24091,18 @@ snapshots: '@opentelemetry/resources': 2.5.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@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)': @@ -24166,12 +24119,12 @@ snapshots: '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.5.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-node@2.9.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace-node@2.7.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.9.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.7.1(@opentelemetry/api@1.9.0) + '@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: @@ -24180,13 +24133,6 @@ snapshots: '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace@2.9.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/semantic-conventions@1.27.0': {} '@opentelemetry/semantic-conventions@1.28.0': {} @@ -24574,7 +24520,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 @@ -25722,7 +25668,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: @@ -25731,7 +25677,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: @@ -25985,7 +25931,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: @@ -25993,7 +25939,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 @@ -26596,7 +26542,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: @@ -26620,7 +26566,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: @@ -26630,7 +26576,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 @@ -26639,7 +26585,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 @@ -26648,7 +26594,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 @@ -26657,16 +26603,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 @@ -26675,7 +26621,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 @@ -26733,7 +26679,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: @@ -26746,7 +26692,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 @@ -26758,7 +26704,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 @@ -26770,7 +26716,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 @@ -26791,7 +26737,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 @@ -26808,7 +26754,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 @@ -26824,7 +26770,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 @@ -26840,7 +26786,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 @@ -26856,7 +26802,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 @@ -26865,13 +26811,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 @@ -26886,7 +26832,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 @@ -26977,7 +26923,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 @@ -27051,7 +26997,7 @@ snapshots: '@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) @@ -27070,7 +27016,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) @@ -27087,9 +27033,9 @@ snapshots: - rollup - supports-color - '@vercel/nft@1.3.1(rollup@4.60.2)(supports-color@10.2.2)': + '@vercel/nft@1.3.1(rollup@4.60.2)(supports-color@11.0.0)': 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) @@ -27108,7 +27054,7 @@ snapshots: '@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) @@ -27543,7 +27489,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 @@ -27624,6 +27570,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} ansi-to-html@0.7.2: @@ -27645,7 +27593,7 @@ snapshots: archiver-utils@5.0.2: dependencies: - glob: 10.5.0 + glob: 10.4.5 graceful-fs: 4.2.11 is-stream: 2.0.1 lazystream: 1.0.1 @@ -28176,7 +28124,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 @@ -28392,6 +28340,8 @@ snapshots: chalk@5.6.2: {} + chalk@6.0.0: {} + chance@1.1.13: {} character-entities-html4@2.1.0: {} @@ -28598,7 +28548,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 @@ -29387,11 +29337,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: @@ -29508,7 +29458,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 @@ -29546,16 +29496,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 @@ -29563,7 +29513,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 @@ -29813,7 +29763,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: @@ -30284,7 +30234,7 @@ snapshots: eslint: 9.32.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.32.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.32.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.1.1(eslint@9.32.0(jiti@2.6.1)) @@ -30321,7 +30271,7 @@ snapshots: tinyglobby: 0.2.17 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -30446,7 +30396,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -30882,7 +30832,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 @@ -30927,7 +30877,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: @@ -31152,7 +31102,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 @@ -31228,7 +31178,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: @@ -31886,7 +31836,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 @@ -31911,7 +31861,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 @@ -31945,21 +31895,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 @@ -32154,7 +32104,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 @@ -32168,7 +32118,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 @@ -32184,7 +32134,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' @@ -32207,7 +32157,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 @@ -32223,7 +32173,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' @@ -32801,7 +32751,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 @@ -33706,7 +33656,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 @@ -33855,7 +33805,7 @@ snapshots: mocked-exports@0.1.1: {} - modern-tar@0.8.4: {} + modern-tar@0.8.5: {} module-definition@6.0.2: dependencies: @@ -33974,25 +33924,25 @@ snapshots: neotraverse@0.6.18: {} - netlify-cli@27.4.2(@types/node@22.19.1)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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): + 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) - '@netlify/build': 36.4.4(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(picomatch@4.0.5)(rollup@4.60.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.3 - '@netlify/dev': 5.0.5(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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/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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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/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': 16.1.1 - '@netlify/zip-it-and-ship-it': 15.4.2(rollup@4.60.2)(supports-color@10.2.2) + '@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 @@ -34001,16 +33951,16 @@ snapshots: ascii-table: 0.0.9 backoff: 2.5.0 boxen: 8.0.1 - chalk: 5.6.2 + 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: 2.0.1 - cron-parser: 4.9.0 - debug: 4.4.3(supports-color@10.2.2) + 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 @@ -34044,7 +33994,7 @@ snapshots: log-update: 8.0.0 maxstache: 1.0.7 maxstache-stream: 1.0.4 - modern-tar: 0.8.4 + modern-tar: 0.8.5 multiparty: 4.3.0 nanospinner: 1.2.2 netlify-redirector: 0.5.0 @@ -34059,13 +34009,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: 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 @@ -35574,7 +35524,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 @@ -35585,8 +35535,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 @@ -35789,6 +35739,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 @@ -36079,15 +36034,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 @@ -36142,7 +36097,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 @@ -36303,7 +36258,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 @@ -36442,7 +36397,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 @@ -36716,7 +36671,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 @@ -36763,7 +36718,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 @@ -36773,7 +36728,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 @@ -36782,7 +36737,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 @@ -37127,6 +37082,8 @@ snapshots: supports-color@10.2.2: {} + supports-color@11.0.0: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -37468,6 +37425,8 @@ snapshots: toml@3.0.0: {} + toml@4.3.0: {} + tomlify-j0.4@3.0.0: {} totalist@3.0.1: {} @@ -38030,26 +37989,11 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 optionalDependencies: - '@netlify/blobs': 10.7.13(supports-color@10.2.2) - db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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.13)(db0@0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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: - 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': 10.7.13(supports-color@10.2.2) - db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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)) + '@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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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@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: anymatch: 3.1.3 chokidar: 5.0.0 @@ -38061,10 +38005,10 @@ snapshots: ufo: 1.6.3 optionalDependencies: '@netlify/blobs': 10.7.9 - db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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)) + 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.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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@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 @@ -38075,8 +38019,8 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.3 optionalDependencies: - '@netlify/blobs': 11.0.3(patch_hash=b483cfeb8a23f6cc4bb068e59309e0be2cb7402cbda31a591b70b9a4adcc6f4f) - db0: 0.3.4(@electric-sql/pglite@0.3.16)(better-sqlite3@12.9.0)(drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260511.1)(@electric-sql/pglite@0.3.16)(@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)) + '@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: {} @@ -38284,7 +38228,7 @@ snapshots: vite-node@3.2.4(@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: cac: 6.7.14 - debug: 4.4.3(supports-color@10.2.2) + debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 vite: 7.3.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) @@ -38341,7 +38285,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 @@ -38778,17 +38722,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 @@ -39000,9 +38933,9 @@ snapshots: wrap-ansi@9.0.2: dependencies: - ansi-styles: 6.2.3 + ansi-styles: 6.2.1 string-width: 7.2.0 - strip-ansi: 7.2.0 + strip-ansi: 7.1.0 wrappy@1.0.2: {} @@ -39169,7 +39102,7 @@ snapshots: '@poppinss/colors': 4.1.6 '@poppinss/dumper': 0.6.5 '@speed-highlight/core': 1.2.15 - cookie: 1.1.1 + cookie: 1.0.2 youch-core: 0.3.3 youch@4.1.1: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 13a9beaa4..214309801 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -73,10 +73,6 @@ catalog: "@astrojs/netlify": ^6.6.5 "@cloudflare/workers-types": ^4.20260511.1 "@electric-sql/pglite": ^0.5.8 - "@netlify/database": ^1.1.0 - netlify-cli: ^27.4.2 - "@netlify/async-workloads": ^0.0.106 - "@netlify/blobs": "^11.0.3" "@fxts/core": ^1.21.1 "@js-temporal/polyfill": ^0.5.1 "@logtape/file": ^2.2.0 @@ -84,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 @@ -111,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 From 85dcc8aa9372b8d402fa4785f0bdbf5ebff20e9b Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Thu, 10 Sep 2026 21:19:30 +0900 Subject: [PATCH 13/22] Document Netlify Blobs KV setup Make Netlify Blobs the primary database-free KV example, retain PostgreSQL as an alternative, and explain consistency, expiration, and tombstone cleanup tradeoffs. https://github.com/fedify-dev/fedify/issues/1010 Changelog: none Assisted-by: Codex:gpt-5.6-sol --- packages/netlify/README.md | 95 ++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/packages/netlify/README.md b/packages/netlify/README.md index bd5dd47b9..088d24a55 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,7 +24,9 @@ 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/ @@ -31,15 +34,59 @@ Installation ------------ ~~~~ sh -deno add jsr:@fedify/netlify npm:@netlify/async-workloads # Deno -npm add @fedify/netlify @netlify/async-workloads # npm -pnpm add @fedify/netlify @netlify/async-workloads # pnpm -yarn add @fedify/netlify @netlify/async-workloads # Yarn -bun add @fedify/netlify @netlify/async-workloads # Bun +deno add jsr:@fedify/netlify npm:@netlify/async-workloads npm:@netlify/blobs # Deno +npm add @fedify/netlify @netlify/async-workloads @netlify/blobs # npm +pnpm add @fedify/netlify @netlify/async-workloads @netlify/blobs # pnpm +yarn add @fedify/netlify @netlify/async-workloads @netlify/blobs # Yarn +bun add @fedify/netlify @netlify/async-workloads @netlify/blobs # Bun ~~~~ -The PostgreSQL-backed `orderingKv` example below also needs -`@fedify/postgres`, `@netlify/database`, and `postgres`: + +Usage +----- + +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 +96,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 +180,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 +191,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 From b549884865af9e7a48542674e84bd368124272a9 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Thu, 10 Sep 2026 21:33:39 +0900 Subject: [PATCH 14/22] Add Netlify Blobs KV changelog Describe the database-free Netlify Blobs-backed KV store and its support for expiration, prefix listing, and atomic compare-and-set operations. https://github.com/fedify-dev/fedify/issues/1010 Assisted-by: Codex:gpt-5.6-sol --- CHANGES.md | 6 ++++++ changes.d/netlify/blobs-kv-store.md | 4 ++++ 2 files changed, 10 insertions(+) create mode 100644 changes.d/netlify/blobs-kv-store.md diff --git a/CHANGES.md b/CHANGES.md index 8d4e68889..1e989ae93 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] 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,8 @@ To be released. explicit recovery for unobservable dead-letter failures. [[#930], [#934]] +[#1010]: https://github.com/fedify-dev/fedify/issues/1010 + ### @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..99f231a37 --- /dev/null +++ b/changes.d/netlify/blobs-kv-store.md @@ -0,0 +1,4 @@ + - 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] by Jiwon Kwon] From fced73fe8b96a77973d8c2f21ae93c044caba9ac Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Thu, 10 Sep 2026 21:46:30 +0900 Subject: [PATCH 15/22] Link Netlify Blobs changelog to PR Add the pull request reference to the issue-linked release note and map it to the direct GitHub pull request URL. Assisted-by: Codex:gpt-5.6-sol --- CHANGES.md | 3 ++- changes.d/netlify/blobs-kv-store.md | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1e989ae93..07589106c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -253,7 +253,7 @@ To be released. - 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] by Jiwon Kwon\] + 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 @@ -263,6 +263,7 @@ To be released. [[#930], [#934]] [#1010]: https://github.com/fedify-dev/fedify/issues/1010 +[#1029]: https://github.com/fedify-dev/fedify/pull/1029 ### @fedify/pglite diff --git a/changes.d/netlify/blobs-kv-store.md b/changes.d/netlify/blobs-kv-store.md index 99f231a37..2e71283a2 100644 --- a/changes.d/netlify/blobs-kv-store.md +++ b/changes.d/netlify/blobs-kv-store.md @@ -1,4 +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] by Jiwon Kwon] + delivery without a separate database. [[#1010], [#1029] by Jiwon Kwon] From 6bc9c68d9760ea1bdaa0522148cca900b3bcfade Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Thu, 10 Sep 2026 22:40:08 +0900 Subject: [PATCH 16/22] Declare Netlify runtime dependency Add es-toolkit to the Netlify package dependencies so clean Node.js and Bun installations can resolve the KV implementation. Assisted-by: Codex:gpt-5.6-sol --- packages/netlify/package.json | 1 + pnpm-lock.yaml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/netlify/package.json b/packages/netlify/package.json index 7ec270937..617e43a12 100644 --- a/packages/netlify/package.json +++ b/packages/netlify/package.json @@ -47,6 +47,7 @@ "package.json" ], "dependencies": { + "es-toolkit": "catalog:", "temporal-polyfill": "catalog:" }, "peerDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a2dcb7d1..b1deb4d98 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1658,6 +1658,9 @@ 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) + es-toolkit: + specifier: 'catalog:' + version: 1.46.1 temporal-polyfill: specifier: 'catalog:' version: 1.0.1 From adfa5b0311f680539ab7c25fe7fad89b66b25ad9 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Fri, 11 Sep 2026 00:01:48 +0900 Subject: [PATCH 17/22] Separate optional Blobs installation Keep the base installation focused on queue-only usage and document the additional Netlify Blobs dependency beside its KV store example. https://github.com/fedify-dev/fedify/pull/1029#discussion_r3980242119 Assisted-by: Codex:gpt-5.6-sol --- packages/netlify/README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/netlify/README.md b/packages/netlify/README.md index 088d24a55..a564f2e79 100644 --- a/packages/netlify/README.md +++ b/packages/netlify/README.md @@ -33,18 +33,30 @@ The initial release targets Netlify Functions, not Netlify Edge Functions. Installation ------------ +For queue-only usage, install the package with Netlify Async Workloads: + ~~~~ sh -deno add jsr:@fedify/netlify npm:@netlify/async-workloads npm:@netlify/blobs # Deno -npm add @fedify/netlify @netlify/async-workloads @netlify/blobs # npm -pnpm add @fedify/netlify @netlify/async-workloads @netlify/blobs # pnpm -yarn add @fedify/netlify @netlify/async-workloads @netlify/blobs # Yarn -bun add @fedify/netlify @netlify/async-workloads @netlify/blobs # Bun +deno add jsr:@fedify/netlify npm:@netlify/async-workloads # Deno +npm add @fedify/netlify @netlify/async-workloads # npm +pnpm add @fedify/netlify @netlify/async-workloads # pnpm +yarn add @fedify/netlify @netlify/async-workloads # Yarn +bun add @fedify/netlify @netlify/async-workloads # Bun ~~~~ 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 From fe1fcd1a5feba3be4489e3524d3464c6623c0f6b Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Fri, 11 Sep 2026 00:06:51 +0900 Subject: [PATCH 18/22] Fix @netlify/blobs version to 11.0.3 untill upstream fix the issue that blobs not returning etag properly --- pnpm-lock.yaml | 8 ++++---- pnpm-workspace.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1deb4d98..05b720a7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ catalogs: specifier: ^0.0.106 version: 0.0.106 '@netlify/blobs': - specifier: ^11.0.3 + specifier: 11.0.3 version: 11.0.3 '@netlify/database': specifier: ^1.1.0 @@ -30237,7 +30237,7 @@ snapshots: eslint: 9.32.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.32.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.32.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.1.1(eslint@9.32.0(jiti@2.6.1)) @@ -30274,7 +30274,7 @@ snapshots: tinyglobby: 0.2.17 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -30399,7 +30399,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.32.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)))(eslint@9.32.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 214309801..c701c71b9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -80,7 +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/blobs": 11.0.3 "@netlify/database": ^1.1.0 "@nuxt/kit": ^4.4.2 "@nuxt/schema": ^4.4.2 From 3472a0857508a05f2d50b02094aec221c86041d4 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Fri, 11 Sep 2026 13:29:37 +0900 Subject: [PATCH 19/22] Make Netlify blob keys URL-safe Encode each key component with Base64URL before passing it to the Netlify Blobs SDK. This prevents URL fragments and query strings from collapsing distinct KV keys while retaining tuple-prefix listing and the 600-byte backend limit. Add an SDK-boundary regression test for fragment and query delimiters. https://github.com/fedify-dev/fedify/pull/1029#discussion_r3981337547 Assisted-by: Codex:gpt-5.6-sol --- deno.lock | 3 +- packages/netlify/deno.json | 3 +- packages/netlify/package.json | 1 + packages/netlify/src/kv.ts | 18 +++++-- packages/netlify/test/kv.test.ts | 90 ++++++++++++++++++++++++-------- pnpm-lock.yaml | 3 ++ 6 files changed, 89 insertions(+), 29 deletions(-) diff --git a/deno.lock b/deno.lock index d178c4b52..c67c8b4e4 100644 --- a/deno.lock +++ b/deno.lock @@ -16805,7 +16805,8 @@ "packages/netlify": { "dependencies": [ "npm:@netlify/async-workloads@^0.0.106", - "npm:@netlify/blobs@^11.0.3" + "npm:@netlify/blobs@^11.0.3", + "npm:byte-encodings@^1.0.11" ] }, "packages/nuxt": { diff --git a/packages/netlify/deno.json b/packages/netlify/deno.json index 6544e99c9..489721a06 100644 --- a/packages/netlify/deno.json +++ b/packages/netlify/deno.json @@ -4,7 +4,8 @@ "license": "MIT", "imports": { "@netlify/async-workloads": "npm:@netlify/async-workloads@^0.0.106", - "@netlify/blobs": "npm:@netlify/blobs@^11.0.3" + "@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/package.json b/packages/netlify/package.json index 617e43a12..fab4d0726 100644 --- a/packages/netlify/package.json +++ b/packages/netlify/package.json @@ -47,6 +47,7 @@ "package.json" ], "dependencies": { + "byte-encodings": "catalog:", "es-toolkit": "catalog:", "temporal-polyfill": "catalog:" }, diff --git a/packages/netlify/src/kv.ts b/packages/netlify/src/kv.ts index 7dd596d9c..6223bab21 100644 --- a/packages/netlify/src/kv.ts +++ b/packages/netlify/src/kv.ts @@ -5,9 +5,13 @@ import type { KvStoreSetOptions, } from "@fedify/fedify/federation"; import type { Store } from "@netlify/blobs"; +import { decodeBase64Url, encodeBase64Url } from "byte-encodings/base64url"; import { isEqual } from "es-toolkit"; 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. @@ -26,7 +30,9 @@ export class NetlifyBlobsKvStore implements KvStore { } private serializeKey(key: KvKey): string { - const serialized = JSON.stringify(key); + 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.", @@ -36,12 +42,16 @@ export class NetlifyBlobsKvStore implements KvStore { } private deserializeKey(key: string): KvKey { - return JSON.parse(key) as 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 { - if (prefix == null) return "["; - return this.serializeKey(prefix).slice(0, -1); + return prefix == null ? BLOB_KEY_PREFIX : this.serializeKey(prefix); } private isAbsent(metadata: Record): boolean { diff --git a/packages/netlify/test/kv.test.ts b/packages/netlify/test/kv.test.ts index e4fb7b302..56498e9d0 100644 --- a/packages/netlify/test/kv.test.ts +++ b/packages/netlify/test/kv.test.ts @@ -2,7 +2,8 @@ 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 type { SetOptions, Store } from "@netlify/blobs"; +import { getStore, type SetOptions, type Store } from "@netlify/blobs"; +import { encodeBase64Url } from "byte-encodings/base64url"; import { NetlifyBlobsKvStore } from "../src/kv.ts"; interface Entry { @@ -92,6 +93,10 @@ function createKv(store: MockStore): NetlifyBlobsKvStore { return new NetlifyBlobsKvStore(store as unknown as Store); } +function encodeKey(key: KvKey): string { + return `fedify1.${key.map((part) => encodeBase64Url(part)).join(".")}.`; +} + async function collect( entries: AsyncIterable<{ key: KvKey; value: unknown }>, ) { @@ -126,7 +131,10 @@ describe("NetlifyBlobsKvStore", () => { await kv.delete(["missing"]); deepStrictEqual(await kv.get(["delete"]), undefined); - deepStrictEqual(store.deleteCalls, ['["delete"]', '["missing"]']); + deepStrictEqual(store.deleteCalls, [ + encodeKey(["delete"]), + encodeKey(["missing"]), + ]); }); it("stores TTL metadata and hides expired values", async () => { @@ -136,11 +144,11 @@ describe("NetlifyBlobsKvStore", () => { await kv.set(["future"], "visible", { ttl: Temporal.Duration.from({ seconds: 1 }), }); - const expires = store.entries.get('["future"]')?.metadata.expireIn; + const expires = store.entries.get(encodeKey(["future"]))?.metadata.expireIn; ok(typeof expires === "number"); ok(expires >= before + 1_000); - store.entries.set('["expired"]', { + store.entries.set(encodeKey(["expired"]), { data: "hidden", etag: "expired", metadata: { expireIn: Date.now() - 1 }, @@ -161,7 +169,7 @@ describe("NetlifyBlobsKvStore", () => { await kv.set(["ttl-overwrite"], "persistent"); - deepStrictEqual(store.entries.get('["ttl-overwrite"]')?.metadata, { + deepStrictEqual(store.entries.get(encodeKey(["ttl-overwrite"]))?.metadata, { expireIn: null, }); deepStrictEqual(await kv.get(["ttl-overwrite"]), "persistent"); @@ -186,7 +194,7 @@ describe("NetlifyBlobsKvStore key encoding", () => { }); deepStrictEqual(await collect(kv.list()), entries); - deepStrictEqual(store.listPrefixes, ["["]); + deepStrictEqual(store.listPrefixes, ["fedify1."]); }); it("preserves tuple prefixes without matching partial components", async () => { @@ -207,22 +215,58 @@ describe("NetlifyBlobsKvStore key encoding", () => { { key: ["actor", "alice", "inbox"], value: "descendant" }, ]); deepStrictEqual(store.listPrefixes, [ - '["actor"', - '["actor","alice"', + 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 kv = createKv(new MockStore()); + const store = new MockStore(); + const kv = createKv(store); - await kv.set(["a".repeat(596)], "exactly 600 bytes"); + await kv.set(["a".repeat(443)], "exactly 600 encoded bytes"); deepStrictEqual( - await kv.get(["a".repeat(596)]), - "exactly 600 bytes", + 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(597)], "too long"), + kv.set(["a".repeat(444)], "too long"), new RangeError( "The encoded key exceeds Netlify Blobs' 600-byte key limit.", ), @@ -239,12 +283,12 @@ describe("NetlifyBlobsKvStore key encoding", () => { const store = new MockStore(); const kv = createKv(store); await kv.set(["listed", "visible"], "value"); - store.entries.set('["listed","expired"]', { + store.entries.set(encodeKey(["listed", "expired"]), { data: "expired", etag: "expired", metadata: { expireIn: Date.now() - 1 }, }); - store.entries.set('["listed","deleted"]', { + store.entries.set(encodeKey(["listed", "deleted"]), { data: null, etag: "deleted", metadata: { tombstone: true }, @@ -274,7 +318,7 @@ describe("NetlifyBlobsKvStore.cas()", () => { const store = new MockStore(); const kv = createKv(store); await kv.set(["update"], { count: 1 }); - const etag = store.entries.get('["update"]')?.etag; + const etag = store.entries.get(encodeKey(["update"]))?.etag; store.setCalls.length = 0; equal(await kv.cas(["update"], { count: 0 }, { count: 2 }), false); @@ -302,9 +346,9 @@ describe("NetlifyBlobsKvStore.cas()", () => { deepStrictEqual(await kv.cas(["deleted"], "value", undefined), true); deepStrictEqual(await kv.get(["deleted"]), undefined); deepStrictEqual(await collect(kv.list(["deleted"])), []); - deepStrictEqual(store.entries.get('["deleted"]')?.data, null); + deepStrictEqual(store.entries.get(encodeKey(["deleted"]))?.data, null); deepStrictEqual( - store.entries.get('["deleted"]')?.metadata, + store.entries.get(encodeKey(["deleted"]))?.metadata, { tombstone: true }, ); }); @@ -314,7 +358,7 @@ describe("NetlifyBlobsKvStore.cas()", () => { const kv = createKv(store); await kv.set(["recreate"], "old"); await kv.cas(["recreate"], "old", undefined); - const tombstoneEtag = store.entries.get('["recreate"]')?.etag; + const tombstoneEtag = store.entries.get(encodeKey(["recreate"]))?.etag; store.setCalls.length = 0; equal(await kv.cas(["recreate"], undefined, "new"), true); @@ -326,7 +370,7 @@ describe("NetlifyBlobsKvStore.cas()", () => { it("replaces an expired blob with its ETag", async () => { const store = new MockStore(); const kv = createKv(store); - store.entries.set('["expired-cas"]', { + store.entries.set(encodeKey(["expired-cas"]), { data: "old", etag: "expired-etag", metadata: { expireIn: Date.now() - 1 }, @@ -385,7 +429,7 @@ describe("NetlifyBlobsKvStore.cas()", () => { await kv.set(["retry"], "old"); store.setCalls.length = 0; store.beforeNextSet = () => { - store.entries.set('["retry"]', { + store.entries.set(encodeKey(["retry"]), { data: "old", etag: "competing-etag", metadata: { expireIn: null }, @@ -403,7 +447,7 @@ describe("NetlifyBlobsKvStore.cas()", () => { await kv.set(["delete-conflict"], "old"); store.setCalls.length = 0; store.beforeNextSet = () => { - store.entries.set('["delete-conflict"]', { + store.entries.set(encodeKey(["delete-conflict"]), { data: "new", etag: "competing-etag", metadata: { expireIn: null }, @@ -427,7 +471,7 @@ describe("NetlifyBlobsKvStore.cas()", () => { it("rejects conditional writes when the ETag is missing", async () => { const store = new MockStore(); const kv = createKv(store); - store.entries.set('["missing-etag"]', { + store.entries.set(encodeKey(["missing-etag"]), { data: "old", metadata: {}, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05b720a7b..7556b1d2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1658,6 +1658,9 @@ 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 From a4ec41ee197b5234d5ce8627e06ec946bb2762fa Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Fri, 11 Sep 2026 15:50:23 +0900 Subject: [PATCH 20/22] Accept a structural Netlify Blobs store Replace the public SDK class parameter with the methods the adapter needs. This prevents bundled private Store declarations from rejecting real SDK instances and keeps Blobs optional. Test doubles now work without an unsafe cast. Compile the documented SDK usage against the built declarations to cover the npm consumer API. Package checks and the Deno, Node.js, and Bun suites passed; the credentialed integration test was skipped. Codex assisted with implementation, regression tests, and this commit. https://github.com/fedify-dev/fedify/pull/1029#discussion_r3981337553 Assisted-by: Codex:gpt-5.6-sol Assisted-by: Codex:gpt-6-astra --- packages/netlify/fixtures/public-types.ts | 7 +++ packages/netlify/src/kv.ts | 6 +-- packages/netlify/src/mod.ts | 5 +- packages/netlify/src/types.ts | 58 +++++++++++++++++++++++ packages/netlify/test/kv.test.ts | 4 +- packages/netlify/test/package.test.ts | 30 ++++++++++++ 6 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 packages/netlify/fixtures/public-types.ts 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/src/kv.ts b/packages/netlify/src/kv.ts index 6223bab21..afd3c7c53 100644 --- a/packages/netlify/src/kv.ts +++ b/packages/netlify/src/kv.ts @@ -4,9 +4,9 @@ import type { KvStoreListEntry, KvStoreSetOptions, } from "@fedify/fedify/federation"; -import type { Store } from "@netlify/blobs"; 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."; @@ -19,13 +19,13 @@ const textDecoder = new TextDecoder(); * @since 2.4.0 */ export class NetlifyBlobsKvStore implements KvStore { - readonly #store: Store; + readonly #store: NetlifyBlobsStore; /** * Creates a new Netlify Blobs-backed key-value store. * @param store The Netlify Blobs store to use. */ - constructor(store: Store) { + constructor(store: NetlifyBlobsStore) { this.#store = store; } diff --git a/packages/netlify/src/mod.ts b/packages/netlify/src/mod.ts index 89e5af7bc..ba3d48a1c 100644 --- a/packages/netlify/src/mod.ts +++ b/packages/netlify/src/mod.ts @@ -18,4 +18,7 @@ export { NetlifyMessageQueueSendError, type NetlifyQueueEventData, } from "./mq.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/kv.test.ts b/packages/netlify/test/kv.test.ts index 56498e9d0..62fd669de 100644 --- a/packages/netlify/test/kv.test.ts +++ b/packages/netlify/test/kv.test.ts @@ -2,7 +2,7 @@ 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, type Store } from "@netlify/blobs"; +import { getStore, type SetOptions } from "@netlify/blobs"; import { encodeBase64Url } from "byte-encodings/base64url"; import { NetlifyBlobsKvStore } from "../src/kv.ts"; @@ -90,7 +90,7 @@ class MockStore { } function createKv(store: MockStore): NetlifyBlobsKvStore { - return new NetlifyBlobsKvStore(store as unknown as Store); + return new NetlifyBlobsKvStore(store); } function encodeKey(key: KvKey): string { diff --git a/packages/netlify/test/package.test.ts b/packages/netlify/test/package.test.ts index 005ca2b90..cadbe9206 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,29 @@ 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, + }, () => { + 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, + ]); + }); }); From 0d5240eb28fb76fec718df20947f1433484744d7 Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Sat, 12 Sep 2026 01:01:31 +0900 Subject: [PATCH 21/22] Allow more time for Netlify public type tests Give the compiler regression test 60 seconds so slower CI runners do not hit Bun's default five-second timeout. Bound the compiler process at 55 seconds so it can terminate before the test deadline. Codex assisted with the fix and validation on Node.js and Bun. Changelog: none Assisted-by: Codex:gpt-6-astra --- packages/netlify/test/package.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/netlify/test/package.test.ts b/packages/netlify/test/package.test.ts index cadbe9206..bef6d4132 100644 --- a/packages/netlify/test/package.test.ts +++ b/packages/netlify/test/package.test.ts @@ -23,6 +23,7 @@ describe("package exports", () => { 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"); @@ -43,6 +44,6 @@ describe("package exports", () => { "--target", "ESNext", fixture, - ]); + ], { timeout: 55_000 }); }); }); From d3de6e251cff55a088bcf8da2b832c9256ddcb7d Mon Sep 17 00:00:00 2001 From: Jiwon Kwon Date: Sat, 12 Sep 2026 18:27:04 +0900 Subject: [PATCH 22/22] Document the Netlify Blobs key-value store Explain how to install and configure NetlifyBlobsKvStore so Netlify applications can choose it for persistent federation state. Describe its consistency guarantees, key limit, and retained expired blobs. Codex reviewed the documentation and prepared this commit message. Changelog: none Assisted-by: Codex:gpt-6-astra --- docs/manual/kv.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) 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` -------------------------------